mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-18 11:09:39 +00:00
Ignore empty list elements in the Accept header (Fix #2567)
parse_accept_header() rejected any Accept value with a leading, trailing or doubled comma, and Server::process_request() validates Accept before routing, so "Accept: text/html," was answered 400 Bad Request on every route. RFC 9110 Section 5.6.1.2 requires a recipient to parse and ignore empty list elements in a #rule list, so those values are legal. split() already trims each element and skips the empty ones, which made the guard inside the callback unreachable as well; drop both and let the empty elements fall away. The header length limit bounds how many a sender can send, so ignoring all of them cannot be used as a denial-of-service vector. get_combined_header_value() keeps skipping empty field lines, but that skip is no longer observable through a request now that a stray comma parses cleanly, so it gets its own test.
This commit is contained in:
1 parent
2addb41089
commit
e96a52e9dd
2 files changed
+57
-24
No files matched your search
@@ -7858,8 +7858,7 @@ inline std::string get_combined_header_value(const Headers &headers,
|
||||
for (auto it = rng.first; it != rng.second; ++it) {
|
||||
// RFC 9110 Section 5.6.1.2: a recipient has to parse and ignore empty list
|
||||
// elements, so an empty field line must not contribute a bare comma to the
|
||||
// combined value. parse_accept_header() rejects a leading comma outright,
|
||||
// which would turn a legal request into 400 Bad Request.
|
||||
// combined value.
|
||||
if (it->second.empty()) { continue; }
|
||||
if (!combined.empty()) { combined += ", "; }
|
||||
combined += it->second;
|
||||
@@ -8836,12 +8835,6 @@ inline bool parse_accept_header(const std::string &s,
|
||||
// Empty string is considered valid (no preference)
|
||||
if (s.empty()) { return true; }
|
||||
|
||||
// Check for invalid patterns: leading/trailing commas or consecutive commas
|
||||
if (s.front() == ',' || s.back() == ',' ||
|
||||
s.find(",,") != std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct AcceptEntry {
|
||||
std::string media_type;
|
||||
double quality;
|
||||
@@ -8852,16 +8845,16 @@ inline bool parse_accept_header(const std::string &s,
|
||||
int order = 0;
|
||||
bool has_invalid_entry = false;
|
||||
|
||||
// Split by comma and parse each entry
|
||||
// Split by comma and parse each entry. RFC 9110 Section 5.6.1.2: a recipient
|
||||
// has to parse and ignore empty list elements, so a leading, trailing or
|
||||
// doubled comma must not turn a legal Accept value into 400 Bad Request.
|
||||
// split() skips them, and the header length limit bounds how many a sender
|
||||
// can send, so ignoring all of them cannot be used as a denial-of-service
|
||||
// vector.
|
||||
split(s.data(), s.data() + s.size(), ',', [&](const char *b, const char *e) {
|
||||
std::string entry(b, e);
|
||||
entry = trim_copy(entry);
|
||||
|
||||
if (entry.empty()) {
|
||||
has_invalid_entry = true;
|
||||
return;
|
||||
}
|
||||
|
||||
AcceptEntry accept_entry;
|
||||
accept_entry.order = order++;
|
||||
|
||||
|
||||
Reference in new issue
Block a user