summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2016-01-23 17:23:37 -0500
committerDan Winship <danw@gnome.org>2016-01-23 17:23:37 -0500
commitdcf45cb5defb419d682d40ee0a5b14f6658c5835 (patch)
treedae17a5e298c05f2dbb9e26eabf4dff7e6d8fa67
parent45cf9db7d46ff6ecabd6bbd4e7ae99cfefbc1626 (diff)
downloadlibsoup-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.c23
-rw-r--r--tests/header-parsing.c60
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,