]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-url - Fix handling of double slash in request target URL.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Thu, 31 Oct 2019 08:07:42 +0000 (09:07 +0100)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 6 Nov 2019 20:34:08 +0000 (20:34 +0000)
A origin-form URL starting with double slash caused the initial path segment to
be erroneously recognized as the URL authority, making the path part
unexpectedly empty (NULL). This could cause the HTTP server to crash.

src/lib-http/http-url.c
src/lib-http/test-http-request-parser.c
src/lib-http/test-http-url.c

index 39526e5e545d08988e93d8730c4599934136244a..78af18babf31ca6c5a047d48f60c733a33899b9c 100644 (file)
@@ -345,7 +345,8 @@ static bool http_url_do_parse(struct http_url_parser *url_parser)
         * ["//"] authority ; when parsing a request target
         */
        if (parser->cur < parser->end && parser->cur[0] == '/') {
-               if ((parser->cur + 1) < parser->end && parser->cur[1] == '/') {
+               if ((have_scheme || !url_parser->request_target) &&
+                   (parser->cur + 1) < parser->end && parser->cur[1] == '/') {
                        parser->cur += 2;
                        relative = FALSE;
                        have_authority = TRUE;
index 981d12308772e8c35c77d546b28dc23266e40198..414e66b9f3375f8e12372e2411cff18f93b89a44 100644 (file)
@@ -260,6 +260,24 @@ valid_request_parse_tests[] = {
                },
                .version_major = 1, .version_minor = 1,
        },
+       {
+               .request =
+                       "GET //index.php HTTP/1.1\r\n"
+                       "Date: Sun, 07 Oct 2012 19:52:03 GMT\r\n"
+                       "Host: example.com\r\n"
+                       "Date: Sun, 13 Oct 2013 13:13:13 GMT\r\n"
+                       "\r\n",
+               .method = "GET",
+               .target_raw = "//index.php",
+               .target = {
+                       .format = HTTP_REQUEST_TARGET_FORMAT_ORIGIN,
+                       .url = {
+                               .host = { .name = "example.com" },
+                               .path = "//index.php",
+                       },
+               },
+               .version_major = 1, .version_minor = 1,
+       },
 };
 
 static const unsigned int valid_request_parse_test_count =
index 64096e269cf670ae1d179b9c4b57b7f5e066f855..a9fdf241e6ed462991609469ef6ed0d9e1f311e8 100644 (file)
@@ -98,6 +98,88 @@ static struct valid_http_url_test valid_url_tests[] = {
                        .enc_query = "question=What%20are%20you%20doing%3f&answer=Nothing.",
                },
        },
+       /* Empty path segments */
+       {
+               .url = "http://target//index.php",
+               .url_parsed = {
+                       .path = "//index.php",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "http://target//path//index.php",
+               .url_parsed = {
+                       .path = "//path//index.php",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "http://target//path/",
+               .url_parsed = {
+                       .path = "//path/",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "http://target//path//",
+               .url_parsed = {
+                       .path = "//path//",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "http://target//path//to//./index.php",
+               .url_parsed = {
+                       .path = "//path//to//index.php",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "http://target//path//to//../index.php",
+               .url_parsed = {
+                       .path = "//path//to/index.php",
+                       .host = { .name = "target" },
+               },
+       },
+       {
+               .url = "/index.php",
+               .url_base = {
+                       .host = { .name = "target" },
+               },
+               .url_parsed = {
+                       .host = { .name = "target" },
+                       .path = "/index.php",
+               },
+       },
+       {
+               .url = "//index.php",
+               .url_base = {
+                       .host = { .name = "target" },
+               },
+               .url_parsed = {
+                       .host = { .name = "index.php" },
+               },
+       },
+       {
+               .url = "/path/to/index.php",
+               .url_base = {
+                       .host = { .name = "target" },
+               },
+               .url_parsed = {
+                       .host = { .name = "target" },
+                       .path = "/path/to/index.php",
+               },
+       },
+       {
+               .url = "//path//to//index.php",
+               .url_base = {
+                       .host = { .name = "target" },
+               },
+               .url_parsed = {
+                       .host = { .name = "path" },
+                       .path = "//to//index.php",
+               },
+       },
        /* These next 2 URLs don't follow the recommendations in
           http://tools.ietf.org/html/rfc1034#section-3.5 and
           http://tools.ietf.org/html/rfc3696