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
@@ -3968,6 +3968,7 @@ bool is_field_content(const std::string &s);
|
||||
bool is_field_value(const std::string &s);
|
||||
bool is_field_valid(const std::string &name, const std::string &value);
|
||||
bool is_request_target(const std::string &s);
|
||||
bool is_host(const std::string &s);
|
||||
|
||||
} // namespace fields
|
||||
} // namespace detail
|
||||
@@ -10322,6 +10323,17 @@ inline bool is_request_target(const std::string &s) {
|
||||
return std::all_of(s.begin(), s.end(), is_field_vchar);
|
||||
}
|
||||
|
||||
// RFC 9110 §7.2: the bytes of uri-host [ ":" port ], i.e. unreserved,
|
||||
// sub-delims, "%", ":" and the IP-literal brackets. An empty value is valid.
|
||||
inline bool is_host(const std::string &s) {
|
||||
return std::all_of(s.begin(), s.end(), [](char c) {
|
||||
return is_ascii_alnum(c) || c == '-' || c == '.' || c == '_' || c == '~' ||
|
||||
c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' ||
|
||||
c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
|
||||
c == '=' || c == '%' || c == ':' || c == '[' || c == ']';
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fields
|
||||
|
||||
inline bool perform_websocket_handshake(Stream &strm, Request &req,
|
||||
@@ -14580,6 +14592,16 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
|
||||
return write_response(strm, close_connection, req, res);
|
||||
}
|
||||
|
||||
// RFC 9112 §3.2: Reject more than one Host field line or an invalid Host
|
||||
// value, so that every recipient of the request sees the same authority.
|
||||
if (req.get_header_value_count("Host") > 1 ||
|
||||
!detail::fields::is_host(req.get_header_value("Host"))) {
|
||||
connection_closed = true;
|
||||
res.status = StatusCode::BadRequest_400;
|
||||
output_error_log(Error::InvalidHeaders, &req);
|
||||
return write_response(strm, close_connection, req, res);
|
||||
}
|
||||
|
||||
// Check if the request URI doesn't exceed the limit
|
||||
if (req.target.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
|
||||
connection_closed = true;
|
||||
|
||||
Reference in new issue
Block a user