On Tue, Apr 1, 2014 at 11:35 PM, Yann Ylavic <[email protected]> wrote:
> On Tue, Apr 1, 2014 at 8:36 PM, Eric Covener <[email protected]> wrote:
>>

>> Can you say roughly how much it has changed, I was largely through a review
>> of the previous patch.
>>
>
> Actually, aside from funcs/vars/params renaming, the only difference
> is ap_proxy_fill_hdrbrgd() and its use in stream_reqbody_chunked(), so
> that trailers_in are forwarded.
> All the remaining was already there in the previous patch.

Attached is the diff between the 2 patches applied.
--- ../trunk-r1536297/server/protocol.c 2014-04-01 22:32:53.000000000 +0200
+++ server/protocol.c   2014-04-01 22:32:36.000000000 +0200
@@ -193,12 +193,13 @@ AP_DECLARE(apr_time_t) ap_rationalize_mt
  * stricter protocol adherence and better input filter behavior during
  * chunked trailer processing (for http).
  *
- * If s is NULL, ap_rgetline_from 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.
  *
  * APR_ENOSPC is returned if there is not enough buffer space.
+ * APR_EAGAIN is returned if a non-blocking read would have blocked.
  * Other errors may be returned on other errors.
  *
  * The LF is *not* returned in the buffer.  Therefore, a *read of 0
@@ -210,11 +211,10 @@ AP_DECLARE(apr_time_t) ap_rationalize_mt
  *        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_from(char **s, apr_size_t n,
-                                          apr_size_t *read, request_rec *r,
-                                          int fold, apr_bucket_brigade *bb,
-                                          ap_filter_t *from,
-                                          apr_read_type_e block)
+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 *f)
 {
     apr_status_t rv;
     apr_bucket *e;
@@ -222,8 +222,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_fro
     char *pos, *last_char = *s;
     int do_alloc = (*s == NULL), saw_eos = 0;
 
-    if (from == NULL) {
-        from = r->proto_input_filters;
+    if (f == NULL) {
+        f = r->proto_input_filters;
     }
 
     /*
@@ -236,10 +236,10 @@ AP_DECLARE(apr_status_t) ap_rgetline_fro
 
     for (;;) {
         apr_brigade_cleanup(bb);
-        rv = ap_get_brigade(from, bb, AP_MODE_GETLINE, block, 0);
+        rv = ap_get_brigade(f, bb, AP_MODE_GETLINE, block, 0);
         if (block == APR_NONBLOCK_READ
-                && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
-                        || APR_STATUS_IS_EAGAIN(rv))) {
+                && (APR_STATUS_IS_EAGAIN(rv)
+                    || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)))) {
             *read = bytes_handled;
             if (*s) {
                 /* ensure this string is NUL terminated */
@@ -371,10 +371,10 @@ AP_DECLARE(apr_status_t) ap_rgetline_fro
             apr_brigade_cleanup(bb);
 
             /* We only care about the first byte. */
-            rv = ap_get_brigade(from, bb, AP_MODE_SPECULATIVE, block, 1);
+            rv = ap_get_brigade(f, bb, AP_MODE_SPECULATIVE, block, 1);
             if (block == APR_NONBLOCK_READ
-                    && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))
-                            || APR_STATUS_IS_EAGAIN(rv))) {
+                    && (APR_STATUS_IS_EAGAIN(rv)
+                        || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)))) {
                 if (rv == APR_SUCCESS) {
                     rv = APR_EAGAIN;
                 }
@@ -435,26 +435,27 @@ AP_DECLARE(apr_status_t) ap_rgetline_fro
 
                     next_size = n - bytes_handled;
 
-                    rv = ap_rgetline_from(&tmp, next_size, &next_len, r, 0, bb,
-                                          from, block);
-                    if ((rv == APR_SUCCESS || (block == APR_NONBLOCK_READ &&
-                                               APR_STATUS_IS_EAGAIN(rv)))
+                    rv = ap_rgetline_ex(&tmp, next_size, &next_len, r, 0, bb,
+                                        block, f);
+                    if ((rv == APR_SUCCESS
+                                || (block == APR_NONBLOCK_READ
+                                    && APR_STATUS_IS_EAGAIN(rv)))
                             && (next_len > 0)) {
 
                         if (do_alloc) {
-                        char *new_buffer;
-                        apr_size_t new_size = bytes_handled + next_len + 1;
+                            char *new_buffer;
+                            apr_size_t new_size = bytes_handled + next_len + 1;
 
-                        /* we need to alloc an extra byte for a null */
-                        new_buffer = apr_palloc(r->pool, new_size);
+                            /* we need to alloc an extra byte for a nul */
+                            new_buffer = apr_palloc(r->pool, new_size);
 
-                        /* Copy what we already had. */
-                        memcpy(new_buffer, *s, bytes_handled);
+                            /* Copy what we already had. */
+                            memcpy(new_buffer, *s, bytes_handled);
 
-                        /* copy the new line, including the trailing null */
-                        last_char = new_buffer + bytes_handled;
-                        memcpy(last_char, tmp, next_len + 1);
-                        *s = new_buffer;
+                            /* copy the new line, including the trailing nul */
+                            last_char = new_buffer + bytes_handled;
+                            memcpy(last_char, tmp, next_len + 1);
+                            *s = new_buffer;
                         }
 
                         last_char += next_len;
@@ -484,7 +485,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_cor
                                           apr_size_t *read, request_rec *r,
                                           int fold, apr_bucket_brigade *bb)
 {
-    return ap_rgetline_from(s, n, read, r, fold, bb, NULL, APR_BLOCK_READ);
+    return ap_rgetline_ex(s, n, read, r, fold, bb, APR_BLOCK_READ, NULL);
 }
 
 #if APR_CHARSET_EBCDIC
@@ -800,7 +801,7 @@ static int field_name_len(const char *fi
     return end - field;
 }
 
-struct ap_mime_headers_ctx_t {
+struct ap_mime_state_t {
     int fields_read;
     char *last_field;
     apr_size_t last_len;
@@ -809,33 +810,28 @@ struct ap_mime_headers_ctx_t {
                  done :1;
 };
 
-static int ap_parse_mime_headers(request_rec *r, apr_bucket_brigade *bb,
-                                 ap_filter_t *from, apr_read_type_e block,
-                                 apr_table_t *to, ap_mime_headers_ctx_t **ctx,
-                                 int *status, const char **html_notes)
+static int parse_mime_headers(request_rec *r,
+                              apr_bucket_brigade *bb,
+                              apr_read_type_e block,
+                              ap_filter_t *f, apr_table_t *t,
+                              int *status, const char **html_notes,
+                              ap_mime_state_t **state)
 {
     char *field;
     char *value;
     apr_size_t len;
     char *tmp_field;
-    ap_mime_headers_ctx_t thectx, *x;
+    ap_mime_state_t x, *s;
     core_server_config *conf = 
ap_get_core_module_config(r->server->module_config);
 
-    if (status) {
-        *status = OK;
-    }
-    if (html_notes) {
-        *html_notes = NULL;
+    if (!state) {
+        s = &x;
+        memset(s, 0, sizeof *s);
     }
-
-    if (!ctx) {
-        x = &thectx;
-        memset(x, 0, sizeof *x);
+    else if (!(s = *state)) {
+        *state = s = apr_pcalloc(r->pool, sizeof(ap_mime_state_t));
     }
-    else if (!(x = *ctx)) {
-        *ctx = x = apr_pcalloc(r->pool, sizeof(ap_mime_headers_ctx_t));
-    }
-    else if (x->done) {
+    else if (s->done) {
         return APR_EOF;
     }
 
@@ -848,10 +844,11 @@ static int ap_parse_mime_headers(request
         int folded = 0;
 
         field = NULL;
-        rv = ap_rgetline_from(&field, r->server->limit_req_fieldsize + 2, &len,
-                            r, 0, bb, from, block);
+        rv = ap_rgetline_ex(&field, r->server->limit_req_fieldsize + 2, &len,
+                            r, 0, bb, block, f);
 
-        if (block == APR_NONBLOCK_READ && APR_STATUS_IS_EAGAIN(rv)) {
+        if (block == APR_NONBLOCK_READ
+                && APR_STATUS_IS_EAGAIN(rv)) {
             if (len == 0) {
                 return rv;
             }
@@ -898,15 +895,15 @@ static int ap_parse_mime_headers(request
             return rv;
         }
 
-        if (x->last_field != NULL) {
-            if ((len > 0) && (*field == '\t' || *field == ' ' || x->fold)) {
+        if (s->last_field != NULL) {
+            if ((len > 0) && (*field == '\t' || *field == ' ' || s->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 = x->last_len + len + 1; /* trailing nul */
+                apr_size_t fold_len = s->last_len + len + 1; /* trailing nul */
 
                 if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) {
                     if (status) {
@@ -921,37 +918,37 @@ static int ap_parse_mime_headers(request
                                                "after folding "
                                                "exceeds server limit.<br />\n"
                                                "<pre>\n%.*s\n</pre>\n", 
-                                               field_name_len(x->last_field), 
+                                               field_name_len(s->last_field), 
                                                ap_escape_html(r->pool,
-                                                              x->last_field));
+                                                              s->last_field));
                     }
                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00562)
                                   "Request header exceeds 
LimitRequestFieldSize "
                                   "after folding: %.*s",
-                                  field_name_len(x->last_field),
-                                  x->last_field);
+                                  field_name_len(s->last_field),
+                                  s->last_field);
                     return APR_ENOSPC;
                 }
 
-                if (fold_len > x->alloc_len) {
+                if (fold_len > s->alloc_len) {
                     char *fold_buf;
-                    x->alloc_len += x->alloc_len;
-                    if (fold_len > x->alloc_len) {
-                        x->alloc_len = fold_len;
+                    s->alloc_len += s->alloc_len;
+                    if (fold_len > s->alloc_len) {
+                        s->alloc_len = fold_len;
                     }
-                    fold_buf = (char *)apr_palloc(r->pool, x->alloc_len);
-                    memcpy(fold_buf, x->last_field, x->last_len);
-                    x->last_field = fold_buf;
+                    fold_buf = (char *)apr_palloc(r->pool, s->alloc_len);
+                    memcpy(fold_buf, s->last_field, s->last_len);
+                    s->last_field = fold_buf;
                 }
-                memcpy(x->last_field + x->last_len, field, len +1); /* +nul */
-                x->last_len += len;
-                x->fold = 0;
+                memcpy(s->last_field + s->last_len, field, len +1); /* +nul */
+                s->last_len += len;
+                s->fold = 0;
                 folded = 1;
             }
             else /* not a continuation line */ {
 
                 if (r->server->limit_req_fields
-                        && (++x->fields_read > r->server->limit_req_fields)) {
+                        && (++s->fields_read > r->server->limit_req_fields)) {
                     if (status) {
                         *status = HTTP_BAD_REQUEST;
                     }
@@ -965,7 +962,7 @@ static int ap_parse_mime_headers(request
                     return APR_ENOSPC;
                 }
 
-                if (!(value = strchr(x->last_field, ':'))) { /* ':' or */
+                if (!(value = strchr(s->last_field, ':'))) { /* ':' or */
                     if (status) {
                         *status = HTTP_BAD_REQUEST; /* abort bad request */
                     }
@@ -976,12 +973,12 @@ static int ap_parse_mime_headers(request
                                                "<pre>\n%.*s</pre>\n", 
                                                (int)LOG_NAME_MAX_LEN,
                                                ap_escape_html(r->pool,
-                                                              x->last_field));
+                                                              s->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,
-                                  x->last_field);
+                                  s->last_field);
                     return APR_EINVAL;
                 }
 
@@ -994,13 +991,13 @@ static int ap_parse_mime_headers(request
                 }
 
                 /* Strip LWS after field-name: */
-                while (tmp_field > x->last_field
+                while (tmp_field > s->last_field
                        && (*tmp_field == ' ' || *tmp_field == '\t')) {
                     *tmp_field-- = '\0';
                 }
 
                 /* Strip LWS after field-value: */
-                tmp_field = x->last_field + x->last_len - 1;
+                tmp_field = s->last_field + s->last_len - 1;
                 while (tmp_field > value
                        && (*tmp_field == ' ' || *tmp_field == '\t')) {
                     *tmp_field-- = '\0';
@@ -1009,24 +1006,24 @@ static int ap_parse_mime_headers(request
                 if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
                     int err = 0;
 
-                    if (*x->last_field == '\0') {
+                    if (*s->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(x->last_field)) {
+                    else if (ap_has_cntrl(s->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, x->last_field);
+                                      (int)LOG_NAME_MAX_LEN, s->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"
+                                      "Request header field '%.*s' contains "
                                       "control character", 
(int)LOG_NAME_MAX_LEN,
-                                      x->last_field);
+                                      s->last_field);
                     }
                     if (err && !(conf->http_conformance & 
AP_HTTP_CONFORMANCE_LOGONLY)) {
                         if (status) {
@@ -1035,37 +1032,42 @@ static int ap_parse_mime_headers(request
                         return APR_EINVAL;
                     }
                 }
-                apr_table_addn(to, x->last_field, value);
+                apr_table_addn(t, s->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 *to
+                 * now part of *t
                  */
-                x->alloc_len = 0;
+                s->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) {
-            x->last_field = field;
-            x->last_len = len;
+            s->last_field = field;
+            s->last_len = len;
         }
 
         /* We may still be EAGAIN here */
         if (rv != APR_SUCCESS) {
             AP_DEBUG_ASSERT(APR_STATUS_IS_EAGAIN(rv));
-            x->fold = 1;
+            s->fold = 1;
             return rv;
         }
 
         /* Found a blank line, stop. */
         if (len == 0) {
-            x->done = 1;
+            s->done = 1;
             break;
         }
     }
@@ -1073,21 +1075,21 @@ static int ap_parse_mime_headers(request
     /* Combine multiple message-header fields with the same
      * field-name, following RFC 2616, 4.2.
      */
-    apr_table_compress(to, APR_OVERLAP_TABLES_MERGE);
+    apr_table_compress(t, APR_OVERLAP_TABLES_MERGE);
 
     /* enforce LimitRequestFieldSize for merged headers */
-    apr_table_do(table_do_fn_check_lengths, r, to, NULL);
+    apr_table_do(table_do_fn_check_lengths, r, t, NULL);
 
     return APR_SUCCESS;
 }
 
-AP_DECLARE(apr_status_t)
-ap_get_mime_headers_from(request_rec *r, apr_bucket_brigade *bb,
-                         ap_filter_t *from, apr_read_type_e block,
-                         apr_table_t *to, ap_mime_headers_ctx_t **ctx)
+AP_DECLARE(apr_status_t) ap_get_mime_headers_ex(request_rec *r,
+                                                apr_bucket_brigade *bb,
+                                                apr_read_type_e block,
+                                                ap_filter_t *f, apr_table_t *t,
+                                                ap_mime_state_t **state)
 {
-    return ap_parse_mime_headers(r, bb, NULL, APR_BLOCK_READ,
-                                 r->headers_in, ctx, NULL, NULL);
+    return parse_mime_headers(r, bb, block, f, t, NULL, NULL, state);
 }
 
 AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r,
@@ -1096,8 +1098,8 @@ AP_DECLARE(void) ap_get_mime_headers_cor
     int status = OK;
     const char *notes = NULL;
 
-    (void)ap_parse_mime_headers(r, bb, NULL, APR_BLOCK_READ,
-                                r->headers_in, NULL, &status, &notes);
+    (void)parse_mime_headers(r, bb, APR_BLOCK_READ, NULL, r->headers_in,
+                             &status, &notes, NULL);
     if (status != OK) {
         r->status = status;
     }
--- ../trunk-r1536297/modules/http/http_filters.c       2014-04-01 
22:32:53.000000000 +0200
+++ modules/http/http_filters.c 2014-04-01 22:32:36.000000000 +0200
@@ -66,7 +66,7 @@ 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;
+    ap_mime_state_t *mime_state;
     apr_bucket_brigade *tmp_bb;
     enum
     {
@@ -469,11 +483,10 @@ apr_status_t ap_http_filter(ap_filter_t
                 ctx->tmp_bb = apr_brigade_create(f->r->pool,
                                                  f->c->bucket_alloc);
             }
-            rv = ap_get_mime_headers_from(f->r, ctx->tmp_bb,
-                                          f->next, block, f->r->trailers_in,
-                                          &ctx->mime_hdrs_ctx);
+            rv = ap_get_mime_headers_ex(f->r, ctx->tmp_bb, block,
+                                        f->next, f->r->trailers_in,
+                                        &ctx->mime_state);
             apr_brigade_cleanup(ctx->tmp_bb);
-
             if (rv != APR_SUCCESS) {
                 return rv;
             }
--- ../trunk-r1536297/modules/http/chunk_filter.c       2014-04-01 
22:32:53.000000000 +0200
+++ modules/http/chunk_filter.c 2014-04-01 22:32:36.000000000 +0200
@@ -178,26 +178,23 @@ apr_status_t ap_http_chunk_filter(ap_fil
          * now.
          */
         if (eos && !f->ctx) {
-            if (!apr_is_empty_table(f->r->trailers_out)) {
+            /* TODO: make this configurable. */
+            if (apr_is_empty_table(f->r->trailers_out)) {
+                e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
+                                               ASCII_CRLF, 5, c->bucket_alloc);
+                APR_BUCKET_INSERT_BEFORE(eos, e);
+            }
+            else {
                 const apr_array_header_t *trailers_elts;
                 const apr_table_entry_t *trailers;
                 int counter;
 
-                /* Prevent HTTP Response Splitting */
-                if (APR_BUCKET_NEXT(eos) != APR_BRIGADE_SENTINEL(b)) {
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO()
-                            "Sent more bytes of response body than expected");
-                    return APR_EGENERAL;
-                }
-                APR_BUCKET_REMOVE(eos);
-
+                /* Last chunk */
                 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF, 3,
                                                c->bucket_alloc);
-                APR_BRIGADE_INSERT_TAIL(b, e);
+                APR_BUCKET_INSERT_BEFORE(eos, e);
 
-                /* Put the trailers in the output brigade (code stolen from
-                 * ap_proxy_fill_hdrbrgd).
-                 */
+                /* Trailer */
                 trailers_elts = apr_table_elts(f->r->trailers_out);
                 trailers = (const apr_table_entry_t *)trailers_elts->elts;
                 for (counter = 0; counter < trailers_elts->nelts; counter++) {
@@ -207,19 +204,13 @@ apr_status_t ap_http_chunk_filter(ap_fil
                     ap_xlate_proto_to_ascii(buf, strlen(buf));
                     e = apr_bucket_pool_create(buf, strlen(buf), f->r->pool,
                                                c->bucket_alloc);
-                    APR_BRIGADE_INSERT_TAIL(b, e);
+                    APR_BUCKET_INSERT_BEFORE(eos, e);
                 }
 
+                /* End of chunked */
                 e = apr_bucket_immortal_create(ASCII_CRLF, 2,
                                                c->bucket_alloc);
-                APR_BRIGADE_INSERT_TAIL(b, e);
-
-                APR_BRIGADE_INSERT_TAIL(b, eos);
-            }
-            else {
-            e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
-                                           ASCII_CRLF, 5, c->bucket_alloc);
-            APR_BUCKET_INSERT_BEFORE(eos, e);
+                APR_BUCKET_INSERT_BEFORE(eos, e);
             }
         }
 
--- ../trunk-r1536297/modules/proxy/proxy_util.c        2014-04-01 
22:30:38.000000000 +0200
+++ modules/proxy/proxy_util.c  2014-04-01 22:32:36.000000000 +0200
@@ -3114,11 +3199,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbr
                                             char **old_te_val)
 {
     conn_rec *c = r->connection;
-    int counter;
     char *buf;
-    const apr_array_header_t *headers_in_array;
-    const apr_table_entry_t *headers_in;
-    apr_table_t *headers_in_copy;
     apr_bucket *e;
     int do_100_continue;
     conn_rec *origin = p_conn->connection;
@@ -3278,19 +3359,44 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbr
     }
 
     proxy_run_fixups(r);
+
+    return ap_proxy_fill_hdrbrgd(p, header_brigade, r, c->bucket_alloc,
+                                 r->headers_in, old_cl_val, old_te_val);
+}
+
+PROXY_DECLARE(int) ap_proxy_fill_hdrbrgd(apr_pool_t *p,
+                                         apr_bucket_brigade *header_brigade,
+                                         request_rec *r,
+                                         apr_bucket_alloc_t *bucket_alloc,
+                                         const apr_table_t *headers_table,
+                                         char **old_cl_val, char **old_te_val)
+{
+    char *buf;
+    int counter;
+    const apr_array_header_t *headers_in_array;
+    const apr_table_entry_t *headers_in;
+    apr_table_t *headers_in_copy;
+    apr_bucket *e;
+
+    /* Easy path first. */
+    if (apr_is_empty_table(headers_table)) {
+        return OK;
+    }
+
     /*
-     * Make a copy of the headers_in table before clearing the connection
+     * Make a copy of the headers_table before clearing the connection
      * headers as we need the connection headers later in the http output
      * filter to prepare the correct response headers.
      *
      * Note: We need to take r->pool for apr_table_copy as the key / value
-     * pairs in r->headers_in have been created out of r->pool and
-     * p might be (and actually is) a longer living pool.
+     * pairs in headers_table (eg. r->headers/trailers_in) have been created
+     * out of r->pool and p might be (and actually is) a longer living pool.
      * This would trigger the bad pool ancestry abort in apr_table_copy if
      * apr is compiled with APR_POOL_DEBUG.
      */
-    headers_in_copy = apr_table_copy(r->pool, r->headers_in);
+    headers_in_copy = apr_table_copy(r->pool, headers_table);
     ap_proxy_clear_connection(r, headers_in_copy);
+
     /* send request headers */
     headers_in_array = apr_table_elts(headers_in_copy);
     headers_in = (const apr_table_entry_t *) headers_in_array->elts;
@@ -3328,11 +3434,17 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbr
         /* Skip Transfer-Encoding and Content-Length for now.
          */
         if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
-            *old_te_val = headers_in[counter].val;
+            if (old_te_val) {
+                /* Copy to avoid const away */
+                *old_te_val = apr_pstrdup(r->pool, headers_in[counter].val);
+            }
             continue;
         }
         if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
-            *old_cl_val = headers_in[counter].val;
+            if (old_cl_val) {
+                /* Copy to avoid const away */
+                *old_cl_val = apr_pstrdup(r->pool, headers_in[counter].val);
+            }
             continue;
         }
 
@@ -3351,7 +3463,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbr
                           headers_in[counter].val, CRLF,
                           NULL);
         ap_xlate_proto_to_ascii(buf, strlen(buf));
-        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+        e = apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc);
         APR_BRIGADE_INSERT_TAIL(header_brigade, e);
     }
     return OK;
--- ../trunk-r1536297/modules/proxy/mod_proxy_http.c    2014-04-01 
22:30:38.000000000 +0200
+++ modules/proxy/mod_proxy_http.c      2014-04-01 22:32:36.000000000 +0200
@@ -339,11 +344,26 @@ static int stream_reqbody_chunked(apr_po
         bb = input_brigade;
     }
 
-    e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
-                                   /* <trailers> */
-                                   ASCII_CRLF,
-                                   5, bucket_alloc);
-    APR_BRIGADE_INSERT_TAIL(bb, e);
+    /* Send the trailers if any. */
+    /* TODO: make this configurable. */
+       if (apr_is_empty_table(r->trailers_in)) {
+        e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF ASCII_CRLF,
+                                       7, bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(bb, e);
+    }
+    else {
+        /* Last chunk */
+        e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF, 3, bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(bb, e);
+
+        /* Trailer */
+        ap_proxy_fill_hdrbrgd(p, bb, r, bucket_alloc, r->trailers_in, NULL, 
NULL);
+
+       
+        /* End of chunked */
+        e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(bb, e);
+    }
 
     if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
         e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
--- ../trunk-r1536297/modules/proxy/mod_proxy.h 2014-04-01 22:30:38.000000000 
+0200
+++ modules/proxy/mod_proxy.h   2014-04-01 22:32:36.000000000 +0200
@@ -971,6 +980,23 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbr
                                            char **old_te_val);
 
 /**
+ * Fill a HTTP request header brigade,  old_cl_val and old_te_val as required.
+ * @param p               pool
+ * @param header_brigade  header brigade to fill
+ * @param r               request
+ * @param bucket_alloc    bucket allocator
+ * @param headers_table   headers table to use
+ * @param old_cl_val      stored old content-len val (if not NULL)
+ * @param old_te_val      stored old TE val (if not NULL)
+ * @return                OK
+ */
+PROXY_DECLARE(int) ap_proxy_fill_hdrbrgd(apr_pool_t *p,
+                                         apr_bucket_brigade *header_brigade,
+                                         request_rec *r,
+                                         apr_bucket_alloc_t *bucket_alloc,
+                                         const apr_table_t *headers_table,
+                                         char **old_cl_val, char **old_te_val);
+/**
  * @param bucket_alloc  bucket allocator
  * @param r             request
  * @param p_conn        proxy connection
--- ../trunk-r1536297/modules/examples/mod_example_hooks.c      2014-04-01 
22:30:43.000000000 +0200
+++ modules/examples/mod_example_hooks.c        2014-04-01 22:32:36.000000000 
+0200
@@ -1227,6 +1227,22 @@ static int x_header_parser(request_rec *
     return DECLINED;
 }
 
+/*
+ * this routine gives our module another chance to examine the request
+ * trailers and to take special action.
+ *
+ * This is a RUN_ALL hook.
+ */
+static int x_trailer_parser(request_rec *r)
+{
+    /*
+     * We don't actually *do* anything here, except note the fact that we were
+     * called.
+     */
+    trace_request(r, "x_trailer_parser()");
+    return DECLINED;
+}
+
 
 /*
  * This routine is called to check for any module-specific restrictions placed
@@ -1469,6 +1485,7 @@ static void x_register_hooks(apr_pool_t
     ap_hook_translate_name(x_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_map_to_storage(x_map_to_storage, NULL,NULL, APR_HOOK_MIDDLE);
     ap_hook_header_parser(x_header_parser, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_trailer_parser(x_trailer_parser, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_fixups(x_fixups, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_type_checker(x_type_checker, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_check_access(x_check_access, NULL, NULL, APR_HOOK_MIDDLE,
--- ../trunk-r1536297/include/http_protocol.h   2014-04-01 22:32:53.000000000 
+0200
+++ include/http_protocol.h     2014-04-01 22:32:36.000000000 +0200
@@ -75,26 +75,27 @@ AP_DECLARE(void) ap_get_mime_headers(req
 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;
+typedef struct ap_mime_state_t ap_mime_state_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 from The filter to read from (r->proto_input_filters if NULL)
  * @param block Read blocking mode
- * @param to The table to put the headers/trailers to
- * @param ctx If not NULL, allows for reentrant non-blocking call
+ * @param f The filter to read from (r->proto_input_filters if NULL)
+ * @param t The table to put the headers/trailers to
+ * @param state If not NULL, allows for reentrant (non-blocking) call,
+ *              use *state = NULL on the first call to get an opaque
+ *              record reusable in subsequent (reentrant) calls.
  * @return APR_SUCCESS when done, APR_EAGAIN when non-blocking, or
  *         an unrecoverable APR error.
  */
-AP_DECLARE(apr_status_t) ap_get_mime_headers_from(request_rec *r,
-                                                  apr_bucket_brigade *bb,
-                                                  ap_filter_t *from,
-                                                  apr_read_type_e block,
-                                                  apr_table_t *to,
-                                                  ap_mime_headers_ctx_t **ctx);
+AP_DECLARE(apr_status_t) ap_get_mime_headers_ex(request_rec *r,
+                                                apr_bucket_brigade *bb,
+                                                apr_read_type_e block,
+                                                ap_filter_t *f, apr_table_t *t,
+                                                ap_mime_state_t **state);
 
 /* Finish up stuff after a request */
 
@@ -654,11 +655,10 @@ AP_DECLARE(apr_status_t) ap_rgetline_cor
                                           apr_bucket_brigade *bb);
 
 /** @see ap_rgetline */
-AP_DECLARE(apr_status_t) ap_rgetline_from(char **s, apr_size_t n,
-                                          apr_size_t *read, request_rec *r,
-                                          int fold, apr_bucket_brigade *bb,
-                                          ap_filter_t *from,
-                                          apr_read_type_e block);
+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 *f);
 /**
  * Get the method number associated with the given string, assumed to
  * contain an HTTP method.  Returns M_INVALID if not recognized.

Reply via email to