mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-14 10:29:35 +00:00
Reject an ambiguous or invalid Host in a request
A request with more than one Host field line, or with a Host value holding a byte that cannot appear in uri-host [ ":" port ], is now answered with 400 (RFC 9112 §3.2). The handler sees only the first Host line, so such a request could reach it with an authority that differs from the one an intermediary acted on. Only the byte set is checked, not the full grammar. An empty value stays valid, and a request without a Host line is still accepted. Close #2623
This commit is contained in:
1 parent
1f12bbaabb
commit
0acbee16dc
2 files changed
+74
No files matched your search
@@ -19686,6 +19686,58 @@ TEST(RequestSmugglingTest, DuplicateContentLengthSameValues) {
|
||||
ASSERT_EQ("HTTP/1.1 200 OK", response.substr(0, response.find("\r\n")));
|
||||
}
|
||||
|
||||
TEST(HostHeaderValidationTest, AmbiguousOrInvalidHostRejected) {
|
||||
Server svr;
|
||||
svr.Get("/test", [](const Request &, Response &res) {
|
||||
res.set_content("ok", "text/plain");
|
||||
});
|
||||
|
||||
auto port = svr.bind_to_any_port(HOST);
|
||||
thread t = thread([&] { svr.listen_after_bind(); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
svr.stop();
|
||||
t.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
auto status_line = [&](const std::string &host_lines) {
|
||||
std::string res;
|
||||
send_request(
|
||||
5, "GET /test HTTP/1.1\r\n" + host_lines + "Connection: close\r\n\r\n",
|
||||
&res, port);
|
||||
return res.substr(0, res.find("\r\n"));
|
||||
};
|
||||
|
||||
const char *accepted[] = {
|
||||
"Host: localhost\r\n",
|
||||
"Host: a.example:8080\r\n",
|
||||
"Host: my_service\r\n",
|
||||
"Host: [::1]:8080\r\n",
|
||||
"Host: [fe80::1%25eth0]\r\n",
|
||||
"Host: \r\n", // RFC 9110 §7.2: the target URI has no authority
|
||||
};
|
||||
for (auto host_lines : accepted) {
|
||||
EXPECT_EQ("HTTP/1.1 200 OK", status_line(host_lines)) << host_lines;
|
||||
}
|
||||
|
||||
const char *rejected[] = {
|
||||
"Host: a.example\r\nHost: b.example\r\n",
|
||||
"Host: a.example\r\nHost: a.example\r\n",
|
||||
"Host: a@b.example\r\n",
|
||||
"Host: a.example/b\r\n",
|
||||
"Host: a.example\\b\r\n",
|
||||
"Host: a.example?b\r\n",
|
||||
"Host: a.example#b\r\n",
|
||||
"Host: a.example b.example\r\n",
|
||||
};
|
||||
for (auto host_lines : rejected) {
|
||||
EXPECT_EQ("HTTP/1.1 400 Bad Request", status_line(host_lines))
|
||||
<< host_lines;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HeaderSmugglingTest, ChunkedTrailerHeadersMerged) {
|
||||
Server svr;
|
||||
|
||||
|
||||
Reference in new issue
Block a user