diff options
author | Dan Winship <danw@gnome.org> | 2016-01-23 17:23:37 -0500 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2016-01-23 17:23:37 -0500 |
commit | dcf45cb5defb419d682d40ee0a5b14f6658c5835 (patch) | |
tree | dae17a5e298c05f2dbb9e26eabf4dff7e6d8fa67 | |
parent | 45cf9db7d46ff6ecabd6bbd4e7ae99cfefbc1626 (diff) | |
download | libsoup-dcf45cb5defb419d682d40ee0a5b14f6658c5835.tar.gz |
soup_headers_parse: deal with NUL bytes in headers
https://bugzilla.gnome.org/show_bug.cgi?id=760832
-rw-r--r-- | libsoup/soup-headers.c | 23 | ||||
-rw-r--r-- | tests/header-parsing.c | 60 |
2 files changed, 50 insertions, 33 deletions
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c index 21e78d65..9ad0a213 100644 --- a/libsoup/soup-headers.c +++ b/libsoup/soup-headers.c @@ -39,17 +39,12 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) const char *headers_start; char *headers_copy, *name, *name_end, *value, *value_end; char *eol, *sol, *p; + gsize copy_len; gboolean success = FALSE; g_return_val_if_fail (str != NULL, FALSE); g_return_val_if_fail (dest != NULL, FALSE); - /* RFC 2616 does allow NUL bytes in the headers, but httpbis - * is changing that, and we can't deal with them anyway. - */ - if (memchr (str, '\0', len)) - return FALSE; - /* As per RFC 2616 section 19.3, we treat '\n' as the * line terminator, and '\r', if it appears, merely as * ignorable trailing whitespace. @@ -59,14 +54,28 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) headers_start = memchr (str, '\n', len); if (!headers_start) return FALSE; + /* No '\0's in the Request-Line / Status-Line */ + if (memchr (str, '\0', headers_start - str)) + return FALSE; /* We work on a copy of the headers, which we can write '\0's * into, so that we don't have to individually g_strndup and * then g_free each header name and value. */ - headers_copy = g_strndup (headers_start, len - (headers_start - str)); + copy_len = len - (headers_start - str); + headers_copy = g_malloc (copy_len + 1); + memcpy (headers_copy, headers_start, copy_len); + headers_copy[copy_len] = '\0'; value_end = headers_copy; + /* There shouldn't be any '\0's in the headers already, but + * this is the web we're talking about. + */ + while ((p = memchr (headers_copy, '\0', copy_len))) { + memmove (p, p + 1, copy_len - (p - headers_copy)); + copy_len--; + } + while (*(value_end + 1)) { name = value_end + 1; name_end = strchr (name, ':'); diff --git a/tests/header-parsing.c b/tests/header-parsing.c index 7bea1e95..b19ef11b 100644 --- a/tests/header-parsing.c +++ b/tests/header-parsing.c @@ -358,6 +358,24 @@ static struct RequestTest { } }, + { "NUL in header name", "760832", + "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36, + SOUP_STATUS_OK, + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } + } + }, + + { "NUL in header value", "760832", + "GET / HTTP/1.1\r\nHost: example\x00" "com\r\n", 35, + SOUP_STATUS_OK, + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "examplecom" }, + { NULL } + } + }, + /************************/ /*** INVALID REQUESTS ***/ /************************/ @@ -418,20 +436,6 @@ static struct RequestTest { { { NULL } } }, - { "NUL in header name", "666316", - "GET / HTTP/1.1\r\n\x00: silly\r\n", 37, - SOUP_STATUS_BAD_REQUEST, - NULL, NULL, -1, - { { NULL } } - }, - - { "NUL in header value", NULL, - "GET / HTTP/1.1\r\nHost: example\x00com\r\n", 37, - SOUP_STATUS_BAD_REQUEST, - NULL, NULL, -1, - { { NULL } } - }, - { "No terminating CRLF", NULL, "GET / HTTP/1.1\r\nHost: example.com", -1, SOUP_STATUS_BAD_REQUEST, @@ -608,6 +612,22 @@ static struct ResponseTest { { NULL } } }, + { "NUL in header name", "760832", + "HTTP/1.1 200 OK\r\nF\x00oo: bar\r\n", 28, + SOUP_HTTP_1_1, SOUP_STATUS_OK, "OK", + { { "Foo", "bar" }, + { NULL } + } + }, + + { "NUL in header value", "760832", + "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28, + SOUP_HTTP_1_1, SOUP_STATUS_OK, "OK", + { { "Foo", "bar" }, + { NULL } + } + }, + /********************************/ /*** VALID CONTINUE RESPONSES ***/ /********************************/ @@ -702,18 +722,6 @@ static struct ResponseTest { { { NULL } } }, - { "NUL in header name", NULL, - "HTTP/1.1 200 OK\r\nF\x00oo: bar\r\n", 28, - -1, 0, NULL, - { { NULL } } - }, - - { "NUL in header value", NULL, - "HTTP/1.1 200 OK\r\nFoo: b\x00ar\r\n", 28, - -1, 0, NULL, - { { NULL } } - }, - /* Failing test from Cockpit */ { "Partial response stops after HTTP/", NULL, |