[libsoup] soup_headers_parse: deal with NUL bytes in headers



commit dcf45cb5defb419d682d40ee0a5b14f6658c5835
Author: Dan Winship <danw gnome org>
Date:   Sat Jan 23 17:23:37 2016 -0500

    soup_headers_parse: deal with NUL bytes in headers
    
    https://bugzilla.gnome.org/show_bug.cgi?id=760832

 libsoup/soup-headers.c |   23 ++++++++++++-----
 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 21e78d6..9ad0a21 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 7bea1e9..b19ef11 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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]