diff -up libsoup-2.48.1/libsoup/soup-headers.c.nul-in-headers libsoup-2.48.1/libsoup/soup-headers.c
--- libsoup-2.48.1/libsoup/soup-headers.c.nul-in-headers 2014-11-30 16:32:58.000000000 +0100
+++ libsoup-2.48.1/libsoup/soup-headers.c 2016-04-13 09:05:32.947147115 +0200
@@ -35,17 +35,12 @@ soup_headers_parse (const char *str, int
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.
@@ -55,14 +50,28 @@ soup_headers_parse (const char *str, int
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 -up libsoup-2.48.1/tests/header-parsing.c.nul-in-headers libsoup-2.48.1/tests/header-parsing.c
--- libsoup-2.48.1/tests/header-parsing.c.nul-in-headers 2014-12-07 15:55:22.000000000 +0100
+++ libsoup-2.48.1/tests/header-parsing.c 2016-04-13 09:09:15.631137526 +0200
@@ -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 }
+ }
+ },
+
/*************************/
/*** INVALID RESPONSES ***/
/*************************/
@@ -677,18 +697,6 @@ static struct ResponseTest {
-1, 0, NULL,
{ { 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 } }
- },
};
static const int num_resptests = G_N_ELEMENTS (resptests);