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"));