From 8794792baa1b2a14eceedd590f6d2f2b837dce39 Mon Sep 17 00:00:00 2001 From: Sergey Bobrenok Date: Tue, 24 Dec 2024 01:14:36 +0700 Subject: [PATCH] Treat out-of-range last_pos as the end of the content (#2009) 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 1a722d5..60d6b4c 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 da34ea9..a82912a 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) {