From c6ff3812704a75ec4920578a32aad488745830eb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 16 Nov 2012 11:38:53 -0500 Subject: [PATCH] Remove internal ws from multiline http headers correctly According to RFC2616: All linear white space, including folding, has the same semantics as SP. A recipient MAY replace any linear white space with a single SP before interpreting the field value or forwarding the message downstream. --- http.c | 13 ++++++++++--- test/regress_http.c | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 42a44f71..c4c72f6e 100644 --- a/http.c +++ b/http.c @@ -1870,7 +1870,7 @@ evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer) } static int -evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line) +evhttp_append_to_last_header(struct evkeyvalq *headers, char *line) { struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); char *newval; @@ -1880,13 +1880,20 @@ evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line) return (-1); old_len = strlen(header->value); + + /* Strip space from start and end of line. */ + while (*line == ' ' || *line == '\t') + ++line; + evutil_rtrim_lws_(line); + line_len = strlen(line); - newval = mm_realloc(header->value, old_len + line_len + 1); + newval = mm_realloc(header->value, old_len + line_len + 2); if (newval == NULL) return (-1); - memcpy(newval + old_len, line, line_len + 1); + newval[old_len] = ' '; + memcpy(newval + old_len + 1, line, line_len + 1); header->value = newval; return (0); diff --git a/test/regress_http.c b/test/regress_http.c index cc755de2..adc78ab5 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -256,6 +256,9 @@ http_errorcb(struct bufferevent *bev, short what, void *arg) event_base_loopexit(arg, NULL); } +static int found_multi = 0; +static int found_multi2 = 0; + static void http_basic_cb(struct evhttp_request *req, void *arg) { @@ -267,14 +270,23 @@ http_basic_cb(struct evhttp_request *req, void *arg) /* For multi-line headers test */ { const char *multi = - evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi"); + evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi"); if (multi) { + found_multi = !strcmp(multi,"aaaaaaaa a END"); if (strcmp("END", multi + strlen(multi) - 3) == 0) test_ok++; if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last")) test_ok++; } } + { + const char *multi2 = + evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS"); + if (multi2) { + found_multi2 = !strcmp(multi2,"libevent 2.1"); + } + } + /* injecting a bad content-length */ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative")) @@ -3276,6 +3288,8 @@ http_multi_line_header_test(void *arg) "GET /test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" + "X-Multi-Extra-WS: libevent \r\n" + "\t\t\t2.1 \r\n" "X-Multi: aaaaaaaa\r\n" " a\r\n" "\tEND\r\n" @@ -3283,9 +3297,12 @@ http_multi_line_header_test(void *arg) "\r\n"; bufferevent_write(bev, http_start_request, strlen(http_start_request)); + found_multi = found_multi2 = 0; event_base_dispatch(data->base); + tt_int_op(found_multi, ==, 1); + tt_int_op(found_multi2, ==, 1); tt_int_op(test_ok, ==, 4); end: if (bev) -- 2.50.1