mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-23 11:54:42 +00:00
Add port validation and corresponding tests to prevent overflow and out-of-range values
This commit is contained in:
1 parent
1e97c28e36
commit
b3a8af80b9
2 files changed
+58
-3
No files matched your search
@@ -689,6 +689,14 @@ inline from_chars_result<double> from_chars(const char *first, const char *last,
|
|||||||
return {first + (endptr - s.c_str()), std::errc{}};
|
return {first + (endptr - s.c_str()), std::errc{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool parse_port(const std::string &s, int &port) {
|
||||||
|
int val = 0;
|
||||||
|
auto r = from_chars(s.data(), s.data() + s.size(), val);
|
||||||
|
if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; }
|
||||||
|
port = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
enum SSLVerifierResponse {
|
enum SSLVerifierResponse {
|
||||||
@@ -12722,7 +12730,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
|||||||
|
|
||||||
auto next_port = port_;
|
auto next_port = port_;
|
||||||
if (!port_str.empty()) {
|
if (!port_str.empty()) {
|
||||||
next_port = std::stoi(port_str);
|
if (!detail::parse_port(port_str, next_port)) { return false; }
|
||||||
} else if (!next_scheme.empty()) {
|
} else if (!next_scheme.empty()) {
|
||||||
next_port = next_scheme == "https" ? 443 : 80;
|
next_port = next_scheme == "https" ? 443 : 80;
|
||||||
}
|
}
|
||||||
@@ -14493,7 +14501,8 @@ inline Client::Client(const std::string &scheme_host_port,
|
|||||||
if (host.empty()) { host = m[3].str(); }
|
if (host.empty()) { host = m[3].str(); }
|
||||||
|
|
||||||
auto port_str = m[4].str();
|
auto port_str = m[4].str();
|
||||||
auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
|
auto port = is_ssl ? 443 : 80;
|
||||||
|
if (!port_str.empty() && !detail::parse_port(port_str, port)) { return; }
|
||||||
|
|
||||||
if (is_ssl) {
|
if (is_ssl) {
|
||||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||||
@@ -19906,7 +19915,8 @@ inline WebSocketClient::WebSocketClient(
|
|||||||
if (host_.empty()) { host_ = m[3].str(); }
|
if (host_.empty()) { host_ = m[3].str(); }
|
||||||
|
|
||||||
auto port_str = m[4].str();
|
auto port_str = m[4].str();
|
||||||
port_ = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
|
port_ = is_ssl ? 443 : 80;
|
||||||
|
if (!port_str.empty() && !detail::parse_port(port_str, port_)) { return; }
|
||||||
|
|
||||||
path_ = m[5].str();
|
path_ = m[5].str();
|
||||||
|
|
||||||
|
|||||||
@@ -2330,6 +2330,31 @@ TEST(RedirectToDifferentPort, Redirect) {
|
|||||||
EXPECT_EQ("Hello World!", res->body);
|
EXPECT_EQ("Hello World!", res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RedirectToDifferentPort, OverflowPortNumber) {
|
||||||
|
Server svr;
|
||||||
|
svr.Get("/redir", [&](const Request & /*req*/, Response &res) {
|
||||||
|
// Port number that overflows int — should not crash
|
||||||
|
res.set_redirect("http://localhost:99999999999999999999/target");
|
||||||
|
});
|
||||||
|
|
||||||
|
auto port = svr.bind_to_any_port(HOST);
|
||||||
|
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");
|
||||||
|
// Should fail gracefully, not crash (no valid response due to bad port)
|
||||||
|
EXPECT_FALSE(res);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RedirectFromPageWithContent, Redirect) {
|
TEST(RedirectFromPageWithContent, Redirect) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
@@ -9441,6 +9466,18 @@ TEST(HostAndPortPropertiesTest, NoSSLWithSimpleAPI) {
|
|||||||
ASSERT_EQ(1234, cli.port());
|
ASSERT_EQ(1234, cli.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(HostAndPortPropertiesTest, OverflowPortNumber) {
|
||||||
|
// Port number that overflows int — should not crash, client becomes invalid
|
||||||
|
httplib::Client cli("http://www.google.com:99999999999999999999");
|
||||||
|
ASSERT_FALSE(cli.is_valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HostAndPortPropertiesTest, PortOutOfRange) {
|
||||||
|
// Port 99999 exceeds valid range (1-65535) — should not crash
|
||||||
|
httplib::Client cli("http://www.google.com:99999");
|
||||||
|
ASSERT_FALSE(cli.is_valid());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||||
TEST(HostAndPortPropertiesTest, SSL) {
|
TEST(HostAndPortPropertiesTest, SSL) {
|
||||||
httplib::SSLClient cli("www.google.com");
|
httplib::SSLClient cli("www.google.com");
|
||||||
@@ -16485,6 +16522,14 @@ TEST(WebSocketTest, InvalidURL) {
|
|||||||
// Missing host
|
// Missing host
|
||||||
ws::WebSocketClient ws4("ws://:8080/path");
|
ws::WebSocketClient ws4("ws://:8080/path");
|
||||||
EXPECT_FALSE(ws4.is_valid());
|
EXPECT_FALSE(ws4.is_valid());
|
||||||
|
|
||||||
|
// Port number overflow — should not crash
|
||||||
|
ws::WebSocketClient ws5("ws://localhost:99999999999999999999/path");
|
||||||
|
EXPECT_FALSE(ws5.is_valid());
|
||||||
|
|
||||||
|
// Port out of range
|
||||||
|
ws::WebSocketClient ws6("ws://localhost:99999/path");
|
||||||
|
EXPECT_FALSE(ws6.is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WebSocketTest, UnsupportedScheme) {
|
TEST(WebSocketTest, UnsupportedScheme) {
|
||||||
|
|||||||
Reference in new issue
Block a user