Просмотр исходного кода

reject trailing bytes after IPv6 host literal in parse_url (#2536)

metsw24-max 1 день назад
Родитель
Сommit
2d8e49dd9b
2 измененных файлов с 26 добавлено и 0 удалено
  1. 9 0
      httplib.h
  2. 17 0
      test/test.cc

+ 9 - 0
httplib.h

@@ -851,6 +851,15 @@ inline bool parse_url(const std::string &url, UrlComponents &uc) {
       }
 
       pos = close + 1;
+
+      // The IPv6 literal is the whole host, so ']' must be followed by a port,
+      // path, query or fragment delimiter (or the end of input). Otherwise the
+      // trailing bytes would be folded into the path while the connection
+      // still targets the bracketed address.
+      if (pos < url.size() && url[pos] != ':' && url[pos] != '/' &&
+          url[pos] != '?' && url[pos] != '#') {
+        return false;
+      }
     } else {
       auto end = url.find_first_of(":/?#", pos);
       if (end == std::string::npos) { end = url.size(); }

+ 17 - 0
test/test.cc

@@ -15563,6 +15563,23 @@ TEST(ParseUrlTest, VariousPatterns) {
     detail::UrlComponents uc;
     ASSERT_FALSE(detail::parse_url("http://[::1/path", uc));
   }
+  {
+    // Bytes after the IPv6 literal must be a delimiter, not folded into
+    // the path while the connection still targets the bracketed host.
+    detail::UrlComponents uc;
+    ASSERT_FALSE(detail::parse_url("http://[::1]evil.com/", uc));
+  }
+  {
+    detail::UrlComponents uc;
+    ASSERT_FALSE(detail::parse_url("http://[::1]evil", uc));
+  }
+  {
+    detail::UrlComponents uc;
+    ASSERT_TRUE(detail::parse_url("http://[::1]/path", uc));
+    EXPECT_EQ("::1", uc.host);
+    EXPECT_TRUE(uc.port.empty());
+    EXPECT_EQ("/path", uc.path);
+  }
   {
     detail::UrlComponents uc;
     ASSERT_TRUE(detail::parse_url("//example.com/path?q=1", uc));