From 59ffd21d30ff388a8efc283e1e9ba6d8e05dd2d3 Mon Sep 17 00:00:00 2001 From: Sergey Bobrenok Date: Mon, 23 Dec 2024 23:32:55 +0700 Subject: [PATCH] Treat out-of-range last_pos as the end of the content RFC-9110 '14.1.2. Byte Ranges': A client can limit the number of bytes requested without knowing the size of the selected representation. If the last-pos value is absent, or if the value is greater than or equal to the current length of the representation data, the byte range is interpreted as the remainder of the representation (i.e., the server replaces the value of last-pos with a value that is one less than the current length of the selected representation). https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2-6 --- httplib.h | 13 ++++++++++++- test/test.cc | 13 ++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/httplib.h b/httplib.h index 1a722d5203..60d6b4c014 100644 --- a/httplib.h +++ b/httplib.h @@ -5156,7 +5156,18 @@ inline bool range_error(Request &req, Response &res) { last_pos = contant_len - 1; } - if (last_pos == -1) { last_pos = contant_len - 1; } + // NOTE: RFC-9110 '14.1.2. Byte Ranges': + // A client can limit the number of bytes requested without knowing the + // size of the selected representation. If the last-pos value is absent, + // or if the value is greater than or equal to the current length of the + // representation data, the byte range is interpreted as the remainder of + // the representation (i.e., the server replaces the value of last-pos + // with a value that is one less than the current length of the selected + // representation). + // https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2-6 + if (last_pos == -1 || last_pos >= contant_len) { + last_pos = contant_len - 1; + } // Range must be within content length if (!(0 <= first_pos && first_pos <= last_pos && diff --git a/test/test.cc b/test/test.cc index da34ea9cb7..a82912adfe 100644 --- a/test/test.cc +++ b/test/test.cc @@ -3795,11 +3795,14 @@ TEST_F(ServerTest, GetRangeWithMaxLongLength) { auto res = cli_.Get( "/with-range", {{"Range", - "bytes=0-" + std::to_string(std::numeric_limits::max())}}); - EXPECT_EQ(StatusCode::RangeNotSatisfiable_416, res->status); - EXPECT_EQ("0", res->get_header_value("Content-Length")); - EXPECT_EQ(false, res->has_header("Content-Range")); - EXPECT_EQ(0U, res->body.size()); + "bytes=0-" + std::to_string(std::numeric_limits::max())}, + {"Accept-Encoding", ""}}); + ASSERT_TRUE(res); + EXPECT_EQ(StatusCode::PartialContent_206, res->status); + EXPECT_EQ("7", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); + EXPECT_EQ("bytes 0-6/7", res->get_header_value("Content-Range")); + EXPECT_EQ(std::string("abcdefg"), res->body); } TEST_F(ServerTest, GetRangeWithZeroToInfinite) {