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, ¬es);
+ (void)parse_mime_headers(r, bb, APR_BLOCK_READ, NULL, r->headers_in,
+ &status, ¬es, 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.