From c899462e753ebd35e6afec030364695586c9b044 Mon Sep 17 00:00:00 2001 From: yhirose Date: Sat, 3 Aug 2019 22:12:24 +0900 Subject: [PATCH] Added 'Content-Range' header for single range request --- httplib.h | 30 +++++++++++++++++++++++------- test/test.cc | 8 ++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/httplib.h b/httplib.h index 711558f..847a226 100644 --- a/httplib.h +++ b/httplib.h @@ -65,10 +65,10 @@ typedef int socket_t; #include #include #include +#include #include #include #include -#include #include #include #include @@ -1690,6 +1690,18 @@ get_range_offset_and_length(const Request &req, uint64_t content_length, return std::make_pair(r.first, r.second - r.first + 1); } +inline std::string make_content_range_header_field(uint64_t offset, + uint64_t length, + uint64_t content_length) { + std::string field = "bytes "; + field += std::to_string(offset); + field += "-"; + field += std::to_string(offset + length - 1); + field += "/"; + field += std::to_string(content_length); + return field; +} + template bool process_multipart_ranges_data(const Request &req, Response &res, const std::string &boundary, @@ -1710,12 +1722,8 @@ bool process_multipart_ranges_data(const Request &req, Response &res, auto offset = offsets.first; auto length = offsets.second; - ctoken("Content-Range: bytes "); - stoken(std::to_string(offset)); - ctoken("-"); - stoken(std::to_string(offset + length - 1)); - ctoken("/"); - stoken(std::to_string(res.body.size())); + ctoken("Content-Range: "); + stoken(make_content_range_header_field(offset, length, res.body.size())); ctoken("\r\n"); ctoken("\r\n"); if (!content(offset, length)) { return false; } @@ -1824,6 +1832,7 @@ make_basic_authentication_header(const std::string &username, auto field = "Basic " + detail::base64_encode(username + ":" + password); return std::make_pair("Authorization", field); } + // Request implementation inline bool Request::has_header(const char *key) const { return detail::has_header(headers, key); @@ -2182,7 +2191,11 @@ inline bool Server::write_response(Stream &strm, bool last_connection, } else if (req.ranges.size() == 1) { auto offsets = detail::get_range_offset_and_length(req, res.content_length, 0); + auto offset = offsets.first; length = offsets.second; + auto content_range = detail::make_content_range_header_field( + offset, length, res.content_length); + res.set_header("Content-Range", content_range); } else { length = detail::get_multipart_ranges_data_length(req, res, boundary, content_type); @@ -2203,6 +2216,9 @@ inline bool Server::write_response(Stream &strm, bool last_connection, detail::get_range_offset_and_length(req, res.body.size(), 0); auto offset = offsets.first; auto length = offsets.second; + auto content_range = detail::make_content_range_header_field( + offset, length, res.body.size()); + res.set_header("Content-Range", content_range); res.body = res.body.substr(offset, length); } else { res.body = diff --git a/test/test.cc b/test/test.cc index b2c73f4..87e4e97 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1146,6 +1146,7 @@ TEST_F(ServerTest, GetStreamedWithRange1) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("3", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("def"), res->body); } @@ -1154,6 +1155,7 @@ TEST_F(ServerTest, GetStreamedWithRange2) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("6", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("bcdefg"), res->body); } @@ -1163,6 +1165,7 @@ TEST_F(ServerTest, GetStreamedWithRangeMultipart) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("269", res->get_header_value("Content-Length")); + EXPECT_EQ(false, res->has_header("Content-Range")); EXPECT_EQ(269, res->body.size()); } @@ -1171,6 +1174,7 @@ TEST_F(ServerTest, GetWithRange1) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("3", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("def"), res->body); } @@ -1179,6 +1183,7 @@ TEST_F(ServerTest, GetWithRange2) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("6", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("bcdefg"), res->body); } @@ -1187,6 +1192,7 @@ TEST_F(ServerTest, GetWithRange3) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("1", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("a"), res->body); } @@ -1195,6 +1201,7 @@ TEST_F(ServerTest, GetWithRange4) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("2", res->get_header_value("Content-Length")); + EXPECT_EQ(true, res->has_header("Content-Range")); EXPECT_EQ(std::string("fg"), res->body); } @@ -1203,6 +1210,7 @@ TEST_F(ServerTest, GetWithRangeMultipart) { ASSERT_TRUE(res != nullptr); EXPECT_EQ(206, res->status); EXPECT_EQ("269", res->get_header_value("Content-Length")); + EXPECT_EQ(false, res->has_header("Content-Range")); EXPECT_EQ(269, res->body.size()); }