mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-24 12:04:40 +00:00
Fix crash on empty X-Forwarded-For with trusted proxies configured
This commit is contained in:
1 parent
811dd0b6f2
commit
5c9285776e
2 files changed
+54
-1
No files matched your search
@@ -11888,6 +11888,11 @@ get_client_ip(const std::string &x_forwarded_for,
|
|||||||
ip_list.emplace_back(std::string(b + r.first, b + r.second));
|
ip_list.emplace_back(std::string(b + r.first, b + r.second));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A malformed X-Forwarded-For (empty, comma-only, whitespace-only) yields
|
||||||
|
// no segments. Signal "no client IP derived" with an empty string so the
|
||||||
|
// caller can fall back to the connection-level remote address.
|
||||||
|
if (ip_list.empty()) { return std::string(); }
|
||||||
|
|
||||||
for (size_t i = 0; i < ip_list.size(); ++i) {
|
for (size_t i = 0; i < ip_list.size(); ++i) {
|
||||||
auto ip = ip_list[i];
|
auto ip = ip_list[i];
|
||||||
|
|
||||||
@@ -11978,7 +11983,8 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
|
|||||||
|
|
||||||
if (!trusted_proxies_.empty() && req.has_header("X-Forwarded-For")) {
|
if (!trusted_proxies_.empty() && req.has_header("X-Forwarded-For")) {
|
||||||
auto x_forwarded_for = req.get_header_value("X-Forwarded-For");
|
auto x_forwarded_for = req.get_header_value("X-Forwarded-For");
|
||||||
req.remote_addr = get_client_ip(x_forwarded_for, trusted_proxies_);
|
auto derived = get_client_ip(x_forwarded_for, trusted_proxies_);
|
||||||
|
req.remote_addr = derived.empty() ? remote_addr : derived;
|
||||||
} else {
|
} else {
|
||||||
req.remote_addr = remote_addr;
|
req.remote_addr = remote_addr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14251,6 +14251,53 @@ TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
|
|||||||
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
|
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An X-Forwarded-For header whose value parses to zero IP segments must not
|
||||||
|
// crash the server (it used to call front() on an empty vector inside
|
||||||
|
// get_client_ip). The connection-level remote address must be retained instead.
|
||||||
|
static void run_malformed_xff_test(const std::string &xff_value) {
|
||||||
|
Server svr;
|
||||||
|
svr.set_trusted_proxies({"192.0.2.45"});
|
||||||
|
|
||||||
|
std::string observed_remote_addr;
|
||||||
|
svr.Get("/ip", [&](const Request &req, Response &res) {
|
||||||
|
observed_remote_addr = req.remote_addr;
|
||||||
|
res.set_content("ok", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
int port = 0;
|
||||||
|
thread t = thread([&]() {
|
||||||
|
port = svr.bind_to_any_port(HOST);
|
||||||
|
svr.listen_after_bind();
|
||||||
|
});
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
Client cli(HOST, port);
|
||||||
|
auto res = cli.Get("/ip", {{"X-Forwarded-For", xff_value}});
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_TRUE(observed_remote_addr == "::1" ||
|
||||||
|
observed_remote_addr == "127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForwardedHeadersTest, EmptyXForwardedFor_DoesNotCrash) {
|
||||||
|
run_malformed_xff_test("");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForwardedHeadersTest, CommaOnlyXForwardedFor_DoesNotCrash) {
|
||||||
|
run_malformed_xff_test(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForwardedHeadersTest, MultipleCommasXForwardedFor_DoesNotCrash) {
|
||||||
|
run_malformed_xff_test(", , ,");
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
TEST(ServerRequestParsingTest, RequestWithoutContentLengthOrTransferEncoding) {
|
TEST(ServerRequestParsingTest, RequestWithoutContentLengthOrTransferEncoding) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|||||||
Reference in new issue
Block a user