@@ -, +, @@ --- server/protocol.c | 56 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) --- a/server/protocol.c +++ a/server/protocol.c @@ -989,6 +989,39 @@ static int table_do_fn_check_lengths(void *r_, const char *key, return 0; } +typedef struct { + apr_pool_t *p; + const char *first; + apr_array_header_t *merged; + int entries; +} cookie_hdrs_state; + +static int table_do_fn_collect_cookies(void *v, const char *key, + const char *value) { + cookie_hdrs_state *state = (cookie_hdrs_state *)v; + const char **elt; + + if (!state->first) { + /* fast path for common case (only one Cookie header) that doesn't allocate + * any memory */ + state->first = value; + return 1; + } + + if (!state->merged) { + state->merged = apr_array_make(state->p, 10, sizeof(const char *)); + /* push first found value */ + elt = apr_array_push(state->merged); + *elt = state->first; + state->entries++; + } + elt = apr_array_push(state->merged); + *elt = value; + state->entries++; + + return 1; +} + AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb) { char *last_field = NULL; @@ -1239,10 +1272,25 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb last_len = len; } - /* 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); + { + cookie_hdrs_state state = {r->pool, NULL, NULL, 0}; + + /* prepare for the case if there are multiple Cookie headers */ + apr_table_do(table_do_fn_collect_cookies, &state, r->headers_in, + "Cookie", NULL); + + /* 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); + + if (state.entries > 1) { + /* replace compressed Cookie header value by string consisting of + * semicolon-separated cookie-pairs */ + apr_table_set(r->headers_in, "Cookie", + apr_array_pstrcat(r->pool, state.merged, ';')); + } + } /* enforce LimitRequestFieldSize for merged headers */ apr_table_do(table_do_fn_check_lengths, r, r->headers_in, NULL); --