mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-11-06 15:51:46 +00:00
Ignore a Range header with a unit other than bytes (#2657)
RFC 9110 14.2 says an origin server MUST ignore a Range header field with a range unit it does not understand. parse_range_header() accepts only bytes=, so a request such as "Range: items=1-2" got a 416 instead of the full response. The unit is now checked first, and only a bytes range is parsed and answered with a 416 when it is invalid.
This commit is contained in:
1 parent
a1ba73a256
commit
39c98d4671
2 files changed
+33
-1
No files matched your search
@@ -15292,7 +15292,10 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
|
|||||||
if ((req.method == "GET" || req.method == "HEAD") &&
|
if ((req.method == "GET" || req.method == "HEAD") &&
|
||||||
req.has_header("Range")) {
|
req.has_header("Range")) {
|
||||||
const auto &range_header_value = req.get_header_value("Range");
|
const auto &range_header_value = req.get_header_value("Range");
|
||||||
if (!detail::parse_range_header(range_header_value, req.ranges)) {
|
// RFC 9110 14.2: a range unit other than bytes must be ignored
|
||||||
|
auto unit = range_header_value.substr(0, range_header_value.find('='));
|
||||||
|
if (detail::case_ignore::equal(unit, "bytes") &&
|
||||||
|
!detail::parse_range_header(range_header_value, req.ranges)) {
|
||||||
connection_closed = true;
|
connection_closed = true;
|
||||||
res.status = StatusCode::RangeNotSatisfiable_416;
|
res.status = StatusCode::RangeNotSatisfiable_416;
|
||||||
output_error_log(Error::InvalidRangeHeader, &req);
|
output_error_log(Error::InvalidRangeHeader, &req);
|
||||||
|
|||||||
@@ -2818,6 +2818,35 @@ TEST(RangeTest, IgnoredForPost) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RangeTest, IgnoredForUnknownUnit) {
|
||||||
|
Server svr;
|
||||||
|
svr.Get("/", [](const Request &, Response &res) {
|
||||||
|
res.set_content("abcdefg", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
auto port = svr.bind_to_any_port(HOST);
|
||||||
|
ASSERT_GT(port, 0);
|
||||||
|
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();
|
||||||
|
|
||||||
|
Client cli(HOST, port);
|
||||||
|
for (auto range : {"items=1-2", "none=x"}) {
|
||||||
|
auto res = cli.Get("/", Headers{{"Range", range}});
|
||||||
|
ASSERT_TRUE(res) << range << ": " << to_string(res.error());
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status) << range;
|
||||||
|
EXPECT_EQ("abcdefg", res->body) << range;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = cli.Get("/", Headers{{"Range", "bytes=x"}});
|
||||||
|
ASSERT_TRUE(res) << to_string(res.error());
|
||||||
|
EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(GetAddrInfoDanglingRefTest, LongTimeout) {
|
TEST(GetAddrInfoDanglingRefTest, LongTimeout) {
|
||||||
auto host = "unresolvableaddress.local";
|
auto host = "unresolvableaddress.local";
|
||||||
auto path = std::string{"/"};
|
auto path = std::string{"/"};
|
||||||
|
|||||||
Reference in new issue
Block a user