httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Yann Ylavic <ylavic....@gmail.com>
Subject Re: stop copying footers to r->headers_in?
Date Tue, 22 Oct 2013 18:18:08 GMT
Hi,

even if I don't really need the footers (don't know what to do with yet), I
need them to fully parsed in ap_http_filter(), in blocking and non-blocking
modes: so I'm diligent (and volonteer) for at least a part of the work...

The following patch introduces r->footers_in and the new ap_rgetline_ex()
and ap_get_mime_headers_ex() functions.

Their relation with the existing *_core() functions is as follow :

+AP_DECLARE(apr_status_t) ap_rgetline_ex(char **s, apr_size_t n,
+                                        apr_size_t *read, request_rec *r,
+                                        int fold, apr_bucket_brigade *bb,
+                                        apr_read_type_e block,
+                                        ap_filter_t *from);
AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
                                          apr_size_t *read, request_rec *r,
                                          int fold, apr_bucket_brigade *bb)
{
    return ap_rgetline_ex(s, n, read, r, fold, bb, APR_BLOCK_READ, NULL);
}

+AP_DECLARE(apr_status_t)
+ap_get_mime_headers_ex(request_rec *r, apr_bucket_brigade *bb, apr_table_t
*to,
+                       ap_filter_t *from, apr_read_type_e block,
+                       ap_mime_headers_ctx_t **pctx);
AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
apr_bucket_brigade *bb)
{
    (void)ap_get_mime_headers_ex(r, bb, r->headers_in, NULL,
APR_BLOCK_READ, NULL);
}

The new ap_mime_headers_ctx_t struct aim to give ap_get_mime_headers_ex()
reentrance, with an (opaque) parsing context providable by the caller
(likely when non-blocking). The context is local (one shot) if pctx is NULL
or created if *pctx is NULL.


r->footers_in is created/copied wherever r->headers_in is, and filled in
ap_http_filter() in both blocking and non-blocking modes.

What this patch does not is merging r->footers_in and r->headers_in
whenever it should be, I need to have a closer look at the RFC on this
point.

Hope it can be useful.

Regards,
Yann.

Index: server/protocol.c
===================================================================
--- server/protocol.c    (revision 1534668)
+++ server/protocol.c    (working copy)
@@ -193,7 +193,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
  * stricter protocol adherence and better input filter behavior during
  * chunked trailer processing (for http).
  *
- * If s is NULL, ap_rgetline_core will allocate necessary memory from
r->pool.
+ * If s is NULL, ap_rgetline_ex will allocate necessary memory from
r->pool.
  *
  * Returns APR_SUCCESS if there are no problems and sets *read to be
  * the full length of s.
@@ -210,9 +210,11 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
  *        If no LF is detected on the last line due to a dropped connection
  *        or a full buffer, that's considered an error.
  */
-AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
-                                          apr_size_t *read, request_rec *r,
-                                          int fold, apr_bucket_brigade *bb)
+AP_DECLARE(apr_status_t) ap_rgetline_ex(char **s, apr_size_t n,
+                                        apr_size_t *read, request_rec *r,
+                                        int fold, apr_bucket_brigade *bb,
+                                        apr_read_type_e block,
+                                        ap_filter_t *from)
 {
     apr_status_t rv;
     apr_bucket *e;
@@ -220,6 +222,10 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
     char *pos, *last_char = *s;
     int do_alloc = (*s == NULL), saw_eos = 0;

+    if (from == NULL) {
+        from = r->proto_input_filters;
+    }
+
     /*
      * Initialize last_char as otherwise a random value will be compared
      * against APR_ASCII_LF at the end of the loop if bb only contains
@@ -230,8 +236,26 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques

     for (;;) {
         apr_brigade_cleanup(bb);
-        rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE,
-                            APR_BLOCK_READ, 0);
+        rv = ap_get_brigade(from, bb, AP_MODE_GETLINE, block, 0);
+        if (block == APR_NONBLOCK_READ
+                && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
+                        || APR_STATUS_IS_EAGAIN(rv))) {
+            *read = bytes_handled;
+            if (*s) {
+                /* ensure this string is NUL terminated */
+                if (n < bytes_handled + 1) {
+                    if (bytes_handled > 0) {
+                        (*s)[bytes_handled-1] = '\0';
+                    }
+                    else {
+                        (*s)[0] = '\0';
+                    }
+                    return APR_ENOSPC;
+                }
+                (*s)[bytes_handled] = '\0';
+            }
+            return APR_EAGAIN;
+        }
         if (rv != APR_SUCCESS) {
             return rv;
         }
@@ -287,7 +311,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
                 /* We'll assume the common case where one bucket is
enough. */
                 if (!*s) {
                     current_alloc = len;
-                    *s = apr_palloc(r->pool, current_alloc);
+                    *s = apr_palloc(r->pool, current_alloc + 1);
                 }
                 else if (bytes_handled + len > current_alloc) {
                     /* Increase the buffer size */
@@ -298,7 +322,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
                         new_size = (bytes_handled + len) * 2;
                     }

-                    new_buffer = apr_palloc(r->pool, new_size);
+                    new_buffer = apr_palloc(r->pool, new_size + 1);

                     /* Copy what we already had. */
                     memcpy(new_buffer, *s, bytes_handled);
@@ -329,6 +353,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
     }
     *last_char = '\0';
     bytes_handled = last_char - *s;
+    *read = bytes_handled;

     /* If we're folding, we have more work to do.
      *
@@ -344,8 +369,12 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
             apr_brigade_cleanup(bb);

             /* We only care about the first byte. */
-            rv = ap_get_brigade(r->proto_input_filters, bb,
AP_MODE_SPECULATIVE,
-                                APR_BLOCK_READ, 1);
+            rv = ap_get_brigade(from, bb, AP_MODE_SPECULATIVE, block, 1);
+            if (block == APR_NONBLOCK_READ
+                    && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
+                            || APR_STATUS_IS_EAGAIN(rv))) {
+                return APR_EAGAIN;
+            }
             if (rv != APR_SUCCESS) {
                 return rv;
             }
@@ -402,13 +431,11 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques

                     next_size = n - bytes_handled;

-                    rv = ap_rgetline_core(&tmp, next_size,
-                                          &next_len, r, 0, bb);
-                    if (rv != APR_SUCCESS) {
-                        return rv;
-                    }
-
-                    if (do_alloc && next_len > 0) {
+                    rv = ap_rgetline_ex(&tmp, next_size,
+                                        &next_len, r, 0, bb, block, from);
+                    if (rv == APR_SUCCESS || (block == APR_NONBLOCK_READ &&
+                                              APR_STATUS_IS_EAGAIN(rv))) {
+                        if (do_alloc && next_len > 0) {
                         char *new_buffer;
                         apr_size_t new_size = bytes_handled + next_len + 1;

@@ -419,12 +446,18 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
                         memcpy(new_buffer, *s, bytes_handled);

                         /* copy the new line, including the trailing null
*/
-                        memcpy(new_buffer + bytes_handled, tmp, next_len +
1);
+                        last_char = new_buffer + bytes_handled;
+                        memcpy(last_char, tmp, next_len + 1);
                         *s = new_buffer;
+                        }
+
+                        last_char += next_len;
+                        bytes_handled += next_len;
+                        *read = bytes_handled;
                     }
-
-                    last_char += next_len;
-                    bytes_handled += next_len;
+                    if (rv != APR_SUCCESS) {
+                        return rv;
+                    }
                 }
             }
             else { /* next character is not tab or space */
@@ -432,7 +465,6 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
             }
         }
     }
-    *read = bytes_handled;

     /* PR#43039: We shouldn't accept NULL bytes within the line */
     if (strlen(*s) < bytes_handled) {
@@ -442,6 +474,13 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(reques
     return APR_SUCCESS;
 }

+AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
+                                          apr_size_t *read, request_rec *r,
+                                          int fold, apr_bucket_brigade *bb)
+{
+    return ap_rgetline_ex(s, n, read, r, fold, bb, APR_BLOCK_READ, NULL);
+}
+
 #if APR_CHARSET_EBCDIC
 AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n,
                                      apr_size_t *read, request_rec *r,
@@ -755,18 +794,38 @@ static int field_name_len(const char *field)
     return end - field;
 }

-AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
apr_bucket_brigade *bb)
+struct ap_mime_headers_ctx_t {
+    int fields_read;
+    char *last_field;
+    apr_size_t last_len;
+    apr_size_t alloc_len;
+    unsigned int fold :1,
+                 done :1;
+};
+
+AP_DECLARE(apr_status_t)
+ap_get_mime_headers_ex(request_rec *r, apr_bucket_brigade *bb, apr_table_t
*to,
+                       ap_filter_t *from, apr_read_type_e block,
+                       ap_mime_headers_ctx_t **pctx)
 {
-    char *last_field = NULL;
-    apr_size_t last_len = 0;
-    apr_size_t alloc_len = 0;
     char *field;
     char *value;
     apr_size_t len;
-    int fields_read = 0;
     char *tmp_field;
+    ap_mime_headers_ctx_t thectx, *ctx;
     core_server_config *conf =
ap_get_core_module_config(r->server->module_config);

+    if (!pctx) {
+        ctx = &thectx;
+        memset(ctx, 0, sizeof *ctx);
+    }
+    else if (!(ctx = *pctx)) {
+        *pctx = ctx = apr_pcalloc(r->pool, sizeof(ap_mime_headers_ctx_t));
+    }
+    else if (ctx->done) {
+        return APR_EOF;
+    }
+
     /*
      * Read header lines until we get the empty separator line, a read
error,
      * the connection closes (EOF), reach the server limit, or we timeout.
@@ -776,10 +835,15 @@ static int field_name_len(const char *field)
         int folded = 0;

         field = NULL;
-        rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2,
-                         &len, r, 0, bb);
+        rv = ap_rgetline_ex(&field, r->server->limit_req_fieldsize + 2,
+                            &len, r, 0, bb, block, from);

-        if (rv != APR_SUCCESS) {
+        if (block == APR_NONBLOCK_READ && APR_STATUS_IS_EAGAIN(rv)) {
+            if (len == 0) {
+                return rv;
+            }
+        }
+        else if (rv != APR_SUCCESS) {
             if (APR_STATUS_IS_TIMEUP(rv)) {
                 r->status = HTTP_REQUEST_TIME_OUT;
             }
@@ -787,7 +851,7 @@ static int field_name_len(const char *field)
                 r->status = HTTP_BAD_REQUEST;
             }

-            /* ap_rgetline returns APR_ENOSPC if it fills up the buffer
before
+            /* ap_rgetline* returns APR_ENOSPC if it fills up the buffer
before
              * finding the end-of-line.  This is only going to happen if it
              * exceeds the configured limit for a field size.
              */
@@ -815,18 +879,18 @@ static int field_name_len(const char *field)
                               *field ? ": " : "",
                               field_name_len(field), field);
             }
-            return;
+            return rv;
         }

-        if (last_field != NULL) {
-            if ((len > 0) && ((*field == '\t') || *field == ' ')) {
+        if (ctx->last_field != NULL) {
+            if ((len > 0) && (*field == '\t' || *field == ' ' ||
ctx->fold)) {
                 /* This line is a continuation of the preceding line(s),
                  * so append it to the line that we've set aside.
                  * Note: this uses a power-of-two allocator to avoid
                  * doing O(n) allocs and using O(n^2) space for
                  * continuations that span many many lines.
                  */
-                apr_size_t fold_len = last_len + len + 1; /* trailing null
*/
+                apr_size_t fold_len = ctx->last_len + len + 1; /* trailing
null */

                 if (fold_len >=
(apr_size_t)(r->server->limit_req_fieldsize)) {
                     r->status = HTTP_BAD_REQUEST;
@@ -839,33 +903,35 @@ static int field_name_len(const char *field)
                                                "after folding "
                                                "exceeds server limit.<br
/>\n"
                                                "<pre>\n%.*s\n</pre>\n",
-                                               field_name_len(last_field),
-                                               ap_escape_html(r->pool,
last_field)));
+
field_name_len(ctx->last_field),
+                                               ap_escape_html(r->pool,
ctx->last_field)));
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(00562)
                                   "Request header exceeds
LimitRequestFieldSize "
                                   "after folding: %.*s",
-                                  field_name_len(last_field), last_field);
-                    return;
+                                  field_name_len(ctx->last_field),
ctx->last_field);
+                    return APR_ENOSPC;
                 }

-                if (fold_len > alloc_len) {
+                if (fold_len > ctx->alloc_len) {
                     char *fold_buf;
-                    alloc_len += alloc_len;
-                    if (fold_len > alloc_len) {
-                        alloc_len = fold_len;
+                    ctx->alloc_len += ctx->alloc_len;
+                    if (fold_len > ctx->alloc_len) {
+                        ctx->alloc_len = fold_len;
                     }
-                    fold_buf = (char *)apr_palloc(r->pool, alloc_len);
-                    memcpy(fold_buf, last_field, last_len);
-                    last_field = fold_buf;
+                    fold_buf = (char *)apr_palloc(r->pool, ctx->alloc_len);
+                    memcpy(fold_buf, ctx->last_field, ctx->last_len);
+                    ctx->last_field = fold_buf;
                 }
-                memcpy(last_field + last_len, field, len +1); /* +1 for
nul */
-                last_len += len;
+                memcpy(ctx->last_field + ctx->last_len,
+                       field, len +1); /* +1 for nul */
+                ctx->last_len += len;
+                ctx->fold = 0;
                 folded = 1;
             }
             else /* not a continuation line */ {

                 if (r->server->limit_req_fields
-                    && (++fields_read > r->server->limit_req_fields)) {
+                    && (++ctx->fields_read > r->server->limit_req_fields))
{
                     r->status = HTTP_BAD_REQUEST;
                     apr_table_setn(r->notes, "error-notes",
                                    "The number of request header fields "
@@ -873,10 +939,10 @@ static int field_name_len(const char *field)
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(00563)
                                   "Number of request headers exceeds "
                                   "LimitRequestFields");
-                    return;
+                    return APR_ENOSPC;
                 }

-                if (!(value = strchr(last_field, ':'))) { /* Find ':'
or    */
+                if (!(value = strchr(ctx->last_field, ':'))) { /* Find ':'
or    */
                     r->status = HTTP_BAD_REQUEST;      /* abort bad
request */
                     apr_table_setn(r->notes, "error-notes",
                                    apr_psprintf(r->pool,
@@ -885,12 +951,12 @@ static int field_name_len(const char *field)
                                                "<pre>\n%.*s</pre>\n",
                                                (int)LOG_NAME_MAX_LEN,
                                                ap_escape_html(r->pool,
-
last_field)));
+
ctx->last_field)));
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(00564)
                                   "Request header field is missing ':' "
                                   "separator: %.*s", (int)LOG_NAME_MAX_LEN,
-                                  last_field);
-                    return;
+                                  ctx->last_field);
+                    return APR_EINVAL;
                 }

                 tmp_field = value - 1; /* last character of field-name */
@@ -902,13 +968,13 @@ static int field_name_len(const char *field)
                 }

                 /* Strip LWS after field-name: */
-                while (tmp_field > last_field
+                while (tmp_field > ctx->last_field
                        && (*tmp_field == ' ' || *tmp_field == '\t')) {
                     *tmp_field-- = '\0';
                 }

                 /* Strip LWS after field-value: */
-                tmp_field = last_field + last_len - 1;
+                tmp_field = ctx->last_field + ctx->last_len - 1;
                 while (tmp_field > value
                        && (*tmp_field == ' ' || *tmp_field == '\t')) {
                     *tmp_field-- = '\0';
@@ -917,66 +983,81 @@ static int field_name_len(const char *field)
                 if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
                     int err = 0;

-                    if (*last_field == '\0') {
+                    if (*ctx->last_field == '\0') {
                         err = HTTP_BAD_REQUEST;
                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(02425)
                                       "Empty request header field name not
allowed");
                     }
-                    else if (ap_has_cntrl(last_field)) {
+                    else if (ap_has_cntrl(ctx->last_field)) {
                         err = HTTP_BAD_REQUEST;
                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(02426)
                                       "[HTTP strict] Request header field
name contains "
                                       "control character: %.*s",
-                                      (int)LOG_NAME_MAX_LEN, last_field);
+                                      (int)LOG_NAME_MAX_LEN,
ctx->last_field);
                     }
                     else if (ap_has_cntrl(value)) {
                         err = HTTP_BAD_REQUEST;
                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
APLOGNO(02427)
                                       "Request header field '%.*s'
contains"
                                       "control character",
(int)LOG_NAME_MAX_LEN,
-                                      last_field);
+                                      ctx->last_field);
                     }
                     if (err && !(conf->http_conformance &
AP_HTTP_CONFORMANCE_LOGONLY)) {
                         r->status = err;
-                        return;
+                        return APR_EINVAL;
                     }
                 }
-                apr_table_addn(r->headers_in, last_field, value);
+                apr_table_addn(to, ctx->last_field, value);

                 /* reset the alloc_len so that we'll allocate a new
                  * buffer if we have to do any more folding: we can't
                  * use the previous buffer because its contents are
-                 * now part of r->headers_in
+                 * now part of *to
                  */
-                alloc_len = 0;
+                ctx->alloc_len = 0;

             } /* end if current line is not a continuation starting with
tab */
         }

-        /* Found a blank line, stop. */
-        if (len == 0) {
-            break;
-        }
-
         /* Keep track of this line so that we can parse it on
          * the next loop iteration.  (In the folded case, last_field
          * has been updated already.)
          */
         if (!folded) {
-            last_field = field;
-            last_len = len;
+            ctx->last_field = field;
+            ctx->last_len = len;
         }
+
+        /* We may still be EAGAIN here */
+        if (rv != APR_SUCCESS) {
+            ctx->fold = 1;
+            return rv;
+        }
+
+        /* Found a blank line, stop. */
+        if (len == 0) {
+            ctx->done = 1;
+            break;
+        }
     }

     /* Combine multiple message-header fields with the same
      * field-name, following RFC 2616, 4.2.
      */
-    apr_table_compress(r->headers_in, APR_OVERLAP_TABLES_MERGE);
+    apr_table_compress(to, APR_OVERLAP_TABLES_MERGE);

     /* enforce LimitRequestFieldSize for merged headers */
-    apr_table_do(table_do_fn_check_lengths, r, r->headers_in, NULL);
+    apr_table_do(table_do_fn_check_lengths, r, to, NULL);
+
+    return APR_SUCCESS;
 }

+AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
apr_bucket_brigade *bb)
+{
+    (void)ap_get_mime_headers_ex(r, bb, r->headers_in, NULL,
+                                 APR_BLOCK_READ, NULL);
+}
+
 AP_DECLARE(void) ap_get_mime_headers(request_rec *r)
 {
     apr_bucket_brigade *tmp_bb;
@@ -1010,6 +1091,7 @@ request_rec *ap_read_request(conn_rec *conn)
     r->allowed_methods = ap_make_method_list(p, 2);

     r->headers_in      = apr_table_make(r->pool, 25);
+    r->footers_in      = apr_table_make(r->pool, 5);
     r->subprocess_env  = apr_table_make(r->pool, 25);
     r->headers_out     = apr_table_make(r->pool, 12);
     r->err_headers_out = apr_table_make(r->pool, 5);
@@ -1280,6 +1362,7 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_r
     rnew->status          = HTTP_OK;

     rnew->headers_in      = apr_table_copy(rnew->pool, r->headers_in);
+    rnew->footers_in      = apr_table_copy(rnew->pool, r->footers_in);

     /* did the original request have a body?  (e.g. POST w/SSI tags)
      * if so, make sure the subrequest doesn't inherit body headers
Index: modules/http/http_filters.c
===================================================================
--- modules/http/http_filters.c    (revision 1534668)
+++ modules/http/http_filters.c    (working copy)
@@ -66,6 +66,8 @@ typedef struct http_filter_ctx
     apr_off_t limit_used;
     apr_int32_t chunk_used;
     apr_int16_t chunkbits;
+    ap_mime_headers_ctx_t *mime_hdrs_ctx;
+    apr_bucket_brigade *tmp_bb;
     enum
     {
         BODY_NONE, /* streamed data */
@@ -384,17 +386,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bu

                 apr_bucket_delete(e);
                 e = APR_BRIGADE_FIRST(b);
-                again = 1; /* come around again */
             }

-            if (ctx->state == BODY_CHUNK_TRAILER) {
-                ap_get_mime_headers(f->r);
-                e = apr_bucket_eos_create(f->c->bucket_alloc);
-                APR_BRIGADE_INSERT_TAIL(b, e);
-                ctx->eos_sent = 1;
-                return APR_SUCCESS;
-            }
-
+            again = 1; /* come around again */
             break;
         }
         case BODY_NONE:
@@ -471,20 +465,23 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bu
         }
         case BODY_CHUNK_TRAILER: {

-            rv = ap_get_brigade(f->next, b, mode, block, readbytes);
-
-            /* for timeout */
-            if (block == APR_NONBLOCK_READ
-                    && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b))
-                            || (APR_STATUS_IS_EAGAIN(rv)))) {
-                return APR_EAGAIN;
+            if (ctx->tmp_bb == NULL) {
+                ctx->tmp_bb = apr_brigade_create(f->r->pool,
+                                                 f->c->bucket_alloc);
             }
-
+            else {
+                apr_brigade_cleanup(ctx->tmp_bb);
+            }
+            rv = ap_get_mime_headers_ex(f->r, ctx->tmp_bb,
f->r->footers_in,
+                                        f->next, block,
&ctx->mime_hdrs_ctx);
             if (rv != APR_SUCCESS) {
                 return rv;
             }

-            break;
+            e = apr_bucket_eos_create(f->c->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            ctx->eos_sent = 1;
+            return APR_SUCCESS;
         }
         default: {
             break;
Index: modules/http/http_request.c
===================================================================
--- modules/http/http_request.c    (revision 1534668)
+++ modules/http/http_request.c    (working copy)
@@ -463,6 +463,7 @@ static request_rec *internal_internal_redirect(con
     new->main            = r->main;

     new->headers_in      = r->headers_in;
+    new->footers_in      = r->footers_in;
     new->headers_out     = apr_table_make(r->pool, 12);
     if (ap_is_HTTP_REDIRECT(new->status)) {
         const char *location = apr_table_get(r->headers_out, "Location");
Index: modules/proxy/mod_proxy_http.c
===================================================================
--- modules/proxy/mod_proxy_http.c    (revision 1534668)
+++ modules/proxy/mod_proxy_http.c    (working copy)
@@ -994,6 +994,7 @@ static request_rec *make_fake_req(conn_rec *c, req
     rp->status          = HTTP_OK;

     rp->headers_in      = apr_table_make(pool, 50);
+    rp->footers_in      = apr_table_make(pool, 5);
     rp->subprocess_env  = apr_table_make(pool, 50);
     rp->headers_out     = apr_table_make(pool, 12);
     rp->err_headers_out = apr_table_make(pool, 5);
Index: include/http_protocol.h
===================================================================
--- include/http_protocol.h    (revision 1534668)
+++ include/http_protocol.h    (working copy)
@@ -75,6 +75,25 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *
 AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
                                           apr_bucket_brigade *bb);

+typedef struct ap_mime_headers_ctx_t ap_mime_headers_ctx_t;
+/**
+ * Full version of ap_get_mime_headers() that requires a
+ * temporary brigade, a blocking mode, a destination table
+ * and an non-blocking (optional) context to work with
+ * @param r The current request
+ * @param bb temp brigade
+ * @param to The table to put the headers/footers to
+ * @param from The filter to read from (r->proto_input_filters if NULL)
+ * @param block Read blocking mode
+ * @param pctx If not NULL, allows for reentrant non-blocking call
+ * @return APR_SUCCESS when done, APR_EAGAIN when non-blocking, or
+ *         an unrecoverable APR error.
+ */
+AP_DECLARE(apr_status_t)
+ap_get_mime_headers_ex(request_rec *r, apr_bucket_brigade *bb, apr_table_t
*to,
+                       ap_filter_t *from, apr_read_type_e block,
+                       ap_mime_headers_ctx_t **pctx);
+
 /* Finish up stuff after a request */

 /**
@@ -632,6 +651,12 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s
                                           request_rec *r, int fold,
                                           apr_bucket_brigade *bb);

+/** @see ap_rgetline */
+AP_DECLARE(apr_status_t) ap_rgetline_ex(char **s, apr_size_t n,
+                                        apr_size_t *read, request_rec *r,
+                                        int fold, apr_bucket_brigade *bb,
+                                        apr_read_type_e block,
+                                        ap_filter_t *from);
 /**
  * Get the method number associated with the given string, assumed to
  * contain an HTTP method.  Returns M_INVALID if not recognized.
Index: include/httpd.h
===================================================================
--- include/httpd.h    (revision 1534668)
+++ include/httpd.h    (working copy)
@@ -913,6 +913,8 @@ struct request_rec {

     /** MIME header environment from the request */
     apr_table_t *headers_in;
+    /** MIME footer environment from the request */
+    apr_table_t *footers_in;
     /** MIME header environment for the response */
     apr_table_t *headers_out;
     /** MIME header environment for the response, printed even on errors
and
[EOS]

Mime
View raw message