From 213029685abddd6b9f84b1fd1ee82ed940aecd2c Mon Sep 17 00:00:00 2001 From: KBS Date: Thu, 8 Oct 2026 11:20:53 +0900 Subject: [PATCH] Serve the whole body for a suffix range longer than it (#2615) RFC 9110 14.1.2: if the representation is shorter than the suffix-length, the entire representation is used. range_error computed a negative first byte position for bytes=-8 on a 7-byte body and answered 416. Clamp it at 0, as #711 did before the range handling was reworked. Co-authored-by: youdie006 --- httplib.h | 4 +++- test/test.cc | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/httplib.h b/httplib.h index a964b0f1..001fa68c 100644 --- a/httplib.h +++ b/httplib.h @@ -9910,8 +9910,10 @@ inline bool range_error(Request &req, Response &res) { last_pos = content_len; } + // RFC 9110 14.1.2: a suffix-length longer than the representation + // selects the entire representation. if (first_pos == -1) { - first_pos = content_len - last_pos; + first_pos = (std::max)(static_cast(0), content_len - last_pos); last_pos = content_len - 1; } diff --git a/test/test.cc b/test/test.cc index f1decea7..3694941a 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7242,8 +7242,21 @@ TEST_F(ServerTest, GetStreamedWithRangeSuffix1) { } TEST_F(ServerTest, GetStreamedWithRangeSuffix2) { + // RFC 9110 14.1.2: a suffix-length longer than the representation selects + // the entire representation. + for (auto range : {"bytes=-8", "bytes=-9999"}) { + auto res = cli_.Get("/streamed-with-range", Headers{{"Range", range}}); + ASSERT_TRUE(res) << "Error: " << to_string(res.error()); + EXPECT_EQ(StatusCode::PartialContent_206, res->status) << range; + EXPECT_EQ("7", res->get_header_value("Content-Length")) << range; + EXPECT_EQ("bytes 0-6/7", res->get_header_value("Content-Range")) << range; + EXPECT_EQ(std::string("abcdefg"), res->body) << range; + } +} + +TEST_F(ServerTest, GetStreamedWithRangeSuffixZero) { auto res = - cli_.Get("/streamed-with-range?error", Headers{{"Range", "bytes=-9999"}}); + cli_.Get("/streamed-with-range?error", Headers{{"Range", "bytes=-0"}}); ASSERT_TRUE(res) << "Error: " << to_string(res.error()); EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status); EXPECT_EQ("0", res->get_header_value("Content-Length"));