From 10aadd57f7ebc9cea125ca78f091db35811d0405 Mon Sep 17 00:00:00 2001 From: KBS Date: Sat, 3 Oct 2026 10:07:34 +0900 Subject: [PATCH] Reject trailing characters in URL port numbers (#2593) parse_port checked only the error code of from_chars, which stops at the first non-digit, so http://host:80abc was accepted as port 80, and a redirect Location with such a port was followed. RFC 3986 defines port as *DIGIT. Require the whole string to be consumed, as #2590 does for quality values. --- httplib.h | 4 +++- test/test.cc | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/httplib.h b/httplib.h index 32e7880c..c8aa168b 100644 --- a/httplib.h +++ b/httplib.h @@ -834,7 +834,9 @@ inline from_chars_result from_chars(const char *first, const char *last, inline bool parse_port(const char *s, size_t len, int &port) { int val = 0; auto r = from_chars(s, s + len, val); - if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; } + if (r.ec != std::errc{} || r.ptr != s + len || val < 1 || val > 65535) { + return false; + } port = val; return true; } diff --git a/test/test.cc b/test/test.cc index fbba9bd3..21952987 100644 --- a/test/test.cc +++ b/test/test.cc @@ -3754,6 +3754,34 @@ TEST(RedirectToDifferentPort, OverflowPortNumber) { EXPECT_FALSE(res); } +TEST(RedirectToDifferentPort, TrailingCharactersInPort) { + Server svr; + auto port = svr.bind_to_any_port(HOST); + svr.Get("/redir", [&](const Request & /*req*/, Response &res) { + // The server's own port followed by junk must not be followed + res.set_redirect("http://" + std::string(HOST) + ":" + + std::to_string(port) + "junk/target"); + }); + svr.Get("/target", [&](const Request & /*req*/, Response &res) { + res.set_content("target", "text/plain"); + }); + + auto thread = std::thread([&]() { svr.listen_after_bind(); }); + auto se = detail::scope_exit([&] { + svr.stop(); + thread.join(); + ASSERT_FALSE(svr.is_running()); + }); + + svr.wait_until_ready(); + + Client cli(HOST, port); + cli.set_follow_location(true); + + auto res = cli.Get("/redir"); + EXPECT_FALSE(res); +} + TEST(RedirectFromPageWithContent, Redirect) { Server svr; @@ -13848,6 +13876,11 @@ TEST(HostAndPortPropertiesTest, PortOutOfRange) { ASSERT_FALSE(cli.is_valid()); } +TEST(HostAndPortPropertiesTest, TrailingCharactersInPort) { + httplib::Client cli("http://www.google.com:80abc"); + ASSERT_FALSE(cli.is_valid()); +} + #ifdef CPPHTTPLIB_SSL_ENABLED TEST(HostAndPortPropertiesTest, SSL) { httplib::SSLClient cli("www.google.com");