yhirose 4 years ago
parent
commit
06bfa7e08b
2 changed files with 79 additions and 18 deletions
  1. 8 5
      httplib.h
  2. 71 13
      test/test.cc

+ 8 - 5
httplib.h

@@ -5611,7 +5611,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
   if (location.empty()) { return false; }
 
   const static std::regex re(
-      R"(^(?:(https?):)?(?://([^:/?#]*)(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
+      R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
 
   std::smatch m;
   if (!std::regex_match(location, m, re)) { return false; }
@@ -5620,8 +5620,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
 
   auto next_scheme = m[1].str();
   auto next_host = m[2].str();
-  auto port_str = m[3].str();
-  auto next_path = m[4].str();
+  if (next_host.empty()) { next_host = m[3].str(); }
+  auto port_str = m[4].str();
+  auto next_path = m[5].str();
 
   auto next_port = port_;
   if (!port_str.empty()) {
@@ -7266,7 +7267,8 @@ inline Client::Client(const char *scheme_host_port)
 inline Client::Client(const char *scheme_host_port,
                       const std::string &client_cert_path,
                       const std::string &client_key_path) {
-  const static std::regex re(R"(^(?:([a-z]+)://)?([^:/?#]+)(?::(\d+))?)");
+  const static std::regex re(
+      R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
 
   std::cmatch m;
   if (std::regex_match(scheme_host_port, m, re)) {
@@ -7285,8 +7287,9 @@ inline Client::Client(const char *scheme_host_port,
     auto is_ssl = scheme == "https";
 
     auto host = m[2].str();
+    if (host.empty()) { host = m[3].str(); }
 
-    auto port_str = m[3].str();
+    auto port_str = m[4].str();
     auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
 
     if (is_ssl) {

+ 71 - 13
test/test.cc

@@ -839,6 +839,18 @@ TEST(HttpsToHttpRedirectTest3, Redirect) {
   EXPECT_EQ(200, res->status);
 }
 
+TEST(UrlWithSpace, Redirect) {
+  SSLClient cli("edge.forgecdn.net");
+  cli.set_follow_location(true);
+
+  auto res = cli.Get("/files/2595/310/Neat 1.4-17.jar");
+  ASSERT_TRUE(res);
+  EXPECT_EQ(200, res->status);
+  EXPECT_EQ(18527, res->get_header_value<uint64_t>("Content-Length"));
+}
+
+#endif
+
 TEST(RedirectToDifferentPort, Redirect) {
   Server svr8080;
   Server svr8081;
@@ -878,16 +890,6 @@ TEST(RedirectToDifferentPort, Redirect) {
   ASSERT_FALSE(svr8081.is_running());
 }
 
-TEST(UrlWithSpace, Redirect) {
-  SSLClient cli("edge.forgecdn.net");
-  cli.set_follow_location(true);
-
-  auto res = cli.Get("/files/2595/310/Neat 1.4-17.jar");
-  ASSERT_TRUE(res);
-  EXPECT_EQ(200, res->status);
-  EXPECT_EQ(18527, res->get_header_value<uint64_t>("Content-Length"));
-}
-
 TEST(RedirectFromPageWithContent, Redirect) {
   Server svr;
 
@@ -943,7 +945,61 @@ TEST(RedirectFromPageWithContent, Redirect) {
   ASSERT_FALSE(svr.is_running());
 }
 
-#endif
+TEST(RedirectFromPageWithContentIP6, Redirect) {
+  Server svr;
+
+  svr.Get("/1", [&](const Request & /*req*/, Response &res) {
+    res.set_content("___", "text/plain");
+    // res.set_redirect("/2");
+    res.set_redirect("http://[::1]:1234/2");
+  });
+
+  svr.Get("/2", [&](const Request & /*req*/, Response &res) {
+    res.set_content("Hello World!", "text/plain");
+  });
+
+  auto th = std::thread([&]() { svr.listen("::1", 1234); });
+
+  while (!svr.is_running()) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(1));
+  }
+
+  // Give GET time to get a few messages.
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+
+  {
+    Client cli("http://[::1]:1234");
+    cli.set_follow_location(true);
+
+    std::string body;
+    auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+      body.append(data, data_length);
+      return true;
+    });
+
+    ASSERT_TRUE(res);
+    EXPECT_EQ(200, res->status);
+    EXPECT_EQ("Hello World!", body);
+  }
+
+  {
+    Client cli("http://[::1]:1234");
+
+    std::string body;
+    auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
+      body.append(data, data_length);
+      return true;
+    });
+
+    ASSERT_TRUE(res);
+    EXPECT_EQ(302, res->status);
+    EXPECT_EQ("___", body);
+  }
+
+  svr.stop();
+  th.join();
+  ASSERT_FALSE(svr.is_running());
+}
 
 TEST(PathUrlEncodeTest, PathUrlEncode) {
   Server svr;
@@ -2717,10 +2773,12 @@ TEST_F(ServerTest, PutLargeFileWithGzip) {
 
 TEST_F(ServerTest, PutLargeFileWithGzip2) {
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  Client cli("https://localhost:1234");
+  std::string s = std::string("https://") + HOST + ":" + std::to_string(PORT);
+  Client cli(s.c_str());
   cli.enable_server_certificate_verification(false);
 #else
-  Client cli("http://localhost:1234");
+  std::string s = std::string("http://") + HOST + ":" + std::to_string(PORT);
+  Client cli(s.c_str());
 #endif
   cli.set_compress(true);