From fb9145aea3994fce94eeb516bd5bc213d8c4ecc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Fri, 12 Sep 2025 10:15:44 +0800 Subject: [PATCH 1/7] Update httplib.h fix client ipv6 bug --- httplib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httplib.h b/httplib.h index e15ba44f22..200b391478 100644 --- a/httplib.h +++ b/httplib.h @@ -8510,8 +8510,8 @@ inline ClientImpl::ClientImpl(const std::string &host, int port) inline ClientImpl::ClientImpl(const std::string &host, int port, const std::string &client_cert_path, const std::string &client_key_path) - : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port), - host_and_port_(adjust_host_string(host_) + ":" + std::to_string(port)), + : host_(adjust_host_string(detail::escape_abstract_namespace_unix_domain(host))), port_(port), + host_and_port_(host_ + ":" + std::to_string(port)), client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} inline ClientImpl::~ClientImpl() { From 3ba89a40cab0702de15569adb400a64aef9b7238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Fri, 12 Sep 2025 10:25:12 +0800 Subject: [PATCH 2/7] Update test.cc add test --- test/test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test.cc b/test/test.cc index 490260675e..b1569b86ec 100644 --- a/test/test.cc +++ b/test/test.cc @@ -10285,6 +10285,14 @@ TEST(UniversalClientImplTest, Ipv6LiteralAddress) { EXPECT_EQ(cli.port(), port); } +TEST(UniversalClientImplHostTest, Ipv6LiteralAddressHost) { + std::string host = "[::1]"; + std::string ipV6TestURL = "http://" + host; + + Client cli(ipV6TestURL); + EXPECT_EQ(cli.host(), host); +} + TEST(FileSystemTest, FileAndDirExistenceCheck) { auto file_path = "./www/dir/index.html"; auto dir_path = "./www/dir"; From bd6105e8e82df8972d0c0a091b7b8d6c771ae81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Fri, 12 Sep 2025 15:59:05 +0800 Subject: [PATCH 3/7] Update test.cc fix ipv6 bug --- test/test.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test.cc b/test/test.cc index b1569b86ec..4b16b98462 100644 --- a/test/test.cc +++ b/test/test.cc @@ -2239,7 +2239,7 @@ TEST(RedirectFromPageWithContentIP6, Redirect) { res.set_content("Hello World!", "text/plain"); }); - auto th = std::thread([&]() { svr.listen("::1", 1234); }); + auto th = std::thread([&]() { svr.listen("[::1]", 1234); }); auto se = detail::scope_exit([&] { svr.stop(); th.join(); @@ -2374,7 +2374,7 @@ TEST(BindServerTest, DISABLED_BindDualStack) { EXPECT_EQ("Hello World!", res->body); } { - Client cli("::1", PORT); + Client cli("[::1]", PORT); auto res = cli.Get("/1"); ASSERT_TRUE(res); @@ -3650,7 +3650,7 @@ void performance_test(const char *host) { TEST(BenchmarkTest, localhost) { performance_test("localhost"); } -TEST(BenchmarkTest, v6) { performance_test("::1"); } +TEST(BenchmarkTest, v6) { performance_test("[::1]"); } TEST_F(ServerTest, GetEmptyFile) { auto res = cli_.Get("/empty_file"); @@ -4987,7 +4987,7 @@ TEST_F(ServerTest, GetMethodRemoteAddr) { ASSERT_TRUE(res); EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); - EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1"); + EXPECT_TRUE(res->body == "[::1]" || res->body == "127.0.0.1"); } TEST_F(ServerTest, GetMethodLocalAddr) { @@ -4995,7 +4995,7 @@ TEST_F(ServerTest, GetMethodLocalAddr) { ASSERT_TRUE(res); EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); - EXPECT_TRUE(res->body == std::string("::1:").append(to_string(PORT)) || + EXPECT_TRUE(res->body == std::string("[::1]:").append(to_string(PORT)) || res->body == std::string("127.0.0.1:").append(to_string(PORT))); } @@ -7401,7 +7401,7 @@ TEST(SNI_AutoDetectionTest, SNI_Logic) { } { - SSLClient cli("::1", PORT); + SSLClient cli("[::1]", PORT); cli.enable_server_certificate_verification(false); auto res = cli.Get("/sni?expected="); ASSERT_TRUE(res); From f746ad4de44aae5a22dbce29f09509e831844ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Mon, 15 Sep 2025 09:50:03 +0800 Subject: [PATCH 4/7] restore the code --- test/test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test.cc b/test/test.cc index 4b16b98462..c08a206107 100644 --- a/test/test.cc +++ b/test/test.cc @@ -2239,7 +2239,7 @@ TEST(RedirectFromPageWithContentIP6, Redirect) { res.set_content("Hello World!", "text/plain"); }); - auto th = std::thread([&]() { svr.listen("[::1]", 1234); }); + auto th = std::thread([&]() { svr.listen("::1", 1234); }); auto se = detail::scope_exit([&] { svr.stop(); th.join(); @@ -2374,7 +2374,7 @@ TEST(BindServerTest, DISABLED_BindDualStack) { EXPECT_EQ("Hello World!", res->body); } { - Client cli("[::1]", PORT); + Client cli("::1", PORT); auto res = cli.Get("/1"); ASSERT_TRUE(res); @@ -3650,7 +3650,7 @@ void performance_test(const char *host) { TEST(BenchmarkTest, localhost) { performance_test("localhost"); } -TEST(BenchmarkTest, v6) { performance_test("[::1]"); } +TEST(BenchmarkTest, v6) { performance_test("::1"); } TEST_F(ServerTest, GetEmptyFile) { auto res = cli_.Get("/empty_file"); From 959c88378ac0a72561c27373c083ba7841d5e1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Mon, 15 Sep 2025 10:02:28 +0800 Subject: [PATCH 5/7] restore the code --- test/test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.cc b/test/test.cc index c08a206107..706c67cd95 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7401,7 +7401,7 @@ TEST(SNI_AutoDetectionTest, SNI_Logic) { } { - SSLClient cli("[::1]", PORT); + SSLClient cli("::1", PORT); cli.enable_server_certificate_verification(false); auto res = cli.Get("/sni?expected="); ASSERT_TRUE(res); @@ -10285,7 +10285,7 @@ TEST(UniversalClientImplTest, Ipv6LiteralAddress) { EXPECT_EQ(cli.port(), port); } -TEST(UniversalClientImplHostTest, Ipv6LiteralAddressHost) { +TEST(UniversalClientImplTest, Ipv6LiteralAddressHost) { std::string host = "[::1]"; std::string ipV6TestURL = "http://" + host; From ec4bdbcbda6110ad1cfda80b0c9e7c9aca1adb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Mon, 29 Sep 2025 16:15:03 +0800 Subject: [PATCH 6/7] When Java Servlet parses the request header host, it will split the IP and port. When using the default port (not passed by default), if there is no [] distinction, Java will use the last colon of IPv6 as the port delimiter, and Java parsing will report an error --- httplib.h | 8 ++++---- test/test.cc | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/httplib.h b/httplib.h index 200b391478..d21ddda0bf 100644 --- a/httplib.h +++ b/httplib.h @@ -8510,8 +8510,8 @@ inline ClientImpl::ClientImpl(const std::string &host, int port) inline ClientImpl::ClientImpl(const std::string &host, int port, const std::string &client_cert_path, const std::string &client_key_path) - : host_(adjust_host_string(detail::escape_abstract_namespace_unix_domain(host))), port_(port), - host_and_port_(host_ + ":" + std::to_string(port)), + : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port), + host_and_port_(adjust_host_string(host_) + ":" + std::to_string(port)), client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} inline ClientImpl::~ClientImpl() { @@ -9122,13 +9122,13 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, req.set_header("Host", "localhost"); } else if (is_ssl()) { if (port_ == 443) { - req.set_header("Host", host_); + req.set_header("Host", adjust_host_string(host_)); } else { req.set_header("Host", host_and_port_); } } else { if (port_ == 80) { - req.set_header("Host", host_); + req.set_header("Host", adjust_host_string(host_)); } else { req.set_header("Host", host_and_port_); } diff --git a/test/test.cc b/test/test.cc index 706c67cd95..9f7b09eabe 100644 --- a/test/test.cc +++ b/test/test.cc @@ -4987,7 +4987,7 @@ TEST_F(ServerTest, GetMethodRemoteAddr) { ASSERT_TRUE(res); EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); - EXPECT_TRUE(res->body == "[::1]" || res->body == "127.0.0.1"); + EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1"); } TEST_F(ServerTest, GetMethodLocalAddr) { @@ -4995,7 +4995,7 @@ TEST_F(ServerTest, GetMethodLocalAddr) { ASSERT_TRUE(res); EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); - EXPECT_TRUE(res->body == std::string("[::1]:").append(to_string(PORT)) || + EXPECT_TRUE(res->body == std::string("::1:").append(to_string(PORT)) || res->body == std::string("127.0.0.1:").append(to_string(PORT))); } @@ -10285,12 +10285,41 @@ TEST(UniversalClientImplTest, Ipv6LiteralAddress) { EXPECT_EQ(cli.port(), port); } -TEST(UniversalClientImplTest, Ipv6LiteralAddressHost) { - std::string host = "[::1]"; - std::string ipV6TestURL = "http://" + host; +TEST(UniversalClientImplTest, Ipv6LiteralAddressHostDefaultPort) { + /* + When Java Servlet parses the request header host, it will split the IP and port. + When using the default port (not passed by default), if there is no [] distinction, + Java will use the last colon of IPv6 as the port delimiter, and Java parsing will report an error + */ + httplib::Server svr; + svr.Get("/", [&](const httplib::Request & req, httplib::Response &res) { + res.status = httplib::StatusCode::OK_200; + res.set_content(req.get_header_value("Host", ""), "text/plain"); + }); + + auto thread = std::thread([&]() { svr.listen("[::1]", 80); }); + auto se = httplib::detail::scope_exit([&] { + svr.stop(); + thread.join(); + ASSERT_FALSE(svr.is_running()); + }); - Client cli(ipV6TestURL); - EXPECT_EQ(cli.host(), host); + svr.wait_until_ready(); + + { + httplib::Client cli("http://[::1]"); + cli.set_keep_alive(true); + + EXPECT_EQ(cli.socket(), INVALID_SOCKET); + + auto res = cli.Get("/"); + ASSERT_TRUE(res); + + std::cout << "status:" << res->status << ", body:" << res->body << std::endl; + + EXPECT_EQ(httplib::StatusCode::OK_200, res->status); + EXPECT_EQ("[::1]", res->body); + } } TEST(FileSystemTest, FileAndDirExistenceCheck) { From 2235456d85d8ab8eb57101da50f3051221731576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?27=E5=8F=B7?= Date: Tue, 30 Sep 2025 15:49:37 +0800 Subject: [PATCH 7/7] remove debug code "std::cout ... " --- test/test.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test.cc b/test/test.cc index 9f7b09eabe..4b648cb964 100644 --- a/test/test.cc +++ b/test/test.cc @@ -10315,8 +10315,6 @@ TEST(UniversalClientImplTest, Ipv6LiteralAddressHostDefaultPort) { auto res = cli.Get("/"); ASSERT_TRUE(res); - std::cout << "status:" << res->status << ", body:" << res->body << std::endl; - EXPECT_EQ(httplib::StatusCode::OK_200, res->status); EXPECT_EQ("[::1]", res->body); }