mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Fix #1694
This commit is contained in:
parent
2ce7c22218
commit
420c9759c6
2 changed files with 54 additions and 41 deletions
77
httplib.h
77
httplib.h
|
@ -8,7 +8,7 @@
|
||||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||||
#define CPPHTTPLIB_HTTPLIB_H
|
#define CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
#define CPPHTTPLIB_VERSION "0.15.0"
|
#define CPPHTTPLIB_VERSION "0.14.3"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration
|
* Configuration
|
||||||
|
@ -141,11 +141,11 @@ using ssize_t = long;
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#ifndef S_ISREG
|
#ifndef S_ISREG
|
||||||
#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG)
|
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
||||||
#endif // S_ISREG
|
#endif // S_ISREG
|
||||||
|
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
|
#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
|
||||||
#endif // S_ISDIR
|
#endif // S_ISDIR
|
||||||
|
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
|
@ -4647,7 +4647,8 @@ inline std::string random_string(size_t length) {
|
||||||
static std::random_device seed_gen;
|
static std::random_device seed_gen;
|
||||||
|
|
||||||
// Request 128 bits of entropy for initialization
|
// Request 128 bits of entropy for initialization
|
||||||
static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
|
static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(),
|
||||||
|
seed_gen()};
|
||||||
|
|
||||||
static std::mt19937 engine(seed_sequence);
|
static std::mt19937 engine(seed_sequence);
|
||||||
|
|
||||||
|
@ -4720,32 +4721,41 @@ serialize_multipart_formdata(const MultipartFormDataItems &items,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<size_t, size_t>
|
inline std::pair<size_t, size_t>
|
||||||
get_range_offset_and_length(const Request &req, size_t content_length,
|
get_range_offset_and_length(Range range, size_t content_length) {
|
||||||
size_t index) {
|
if (range.first == -1 && range.second == -1) {
|
||||||
auto r = req.ranges[index];
|
|
||||||
|
|
||||||
if (r.first == -1 && r.second == -1) {
|
|
||||||
return std::make_pair(0, content_length);
|
return std::make_pair(0, content_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto slen = static_cast<ssize_t>(content_length);
|
auto slen = static_cast<ssize_t>(content_length);
|
||||||
|
|
||||||
if (r.first == -1) {
|
if (range.first == -1) {
|
||||||
r.first = (std::max)(static_cast<ssize_t>(0), slen - r.second);
|
range.first = (std::max)(static_cast<ssize_t>(0), slen - range.second);
|
||||||
r.second = slen - 1;
|
range.second = slen - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.second == -1) { r.second = slen - 1; }
|
if (range.second == -1) { range.second = slen - 1; }
|
||||||
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
|
return std::make_pair(range.first,
|
||||||
|
static_cast<size_t>(range.second - range.first) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::pair<size_t, size_t>
|
||||||
|
get_range_offset_and_length(const Request &req, size_t content_length,
|
||||||
|
size_t index) {
|
||||||
|
return get_range_offset_and_length(req.ranges[index], content_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string
|
inline std::string
|
||||||
make_content_range_header_field(const std::pair<ssize_t, ssize_t> &range,
|
make_content_range_header_field(const std::pair<ssize_t, ssize_t> &range,
|
||||||
size_t content_length) {
|
size_t content_length) {
|
||||||
|
|
||||||
|
auto ret = get_range_offset_and_length(range, content_length);
|
||||||
|
auto st = ret.first;
|
||||||
|
auto ed = (std::min)(st + ret.second - 1, content_length - 1);
|
||||||
|
|
||||||
std::string field = "bytes ";
|
std::string field = "bytes ";
|
||||||
if (range.first != -1) { field += std::to_string(range.first); }
|
field += std::to_string(st);
|
||||||
field += "-";
|
field += "-";
|
||||||
if (range.second != -1) { field += std::to_string(range.second); }
|
field += std::to_string(ed);
|
||||||
field += "/";
|
field += "/";
|
||||||
field += std::to_string(content_length);
|
field += std::to_string(content_length);
|
||||||
return field;
|
return field;
|
||||||
|
@ -4773,9 +4783,9 @@ bool process_multipart_ranges_data(const Request &req, Response &res,
|
||||||
ctoken("\r\n");
|
ctoken("\r\n");
|
||||||
ctoken("\r\n");
|
ctoken("\r\n");
|
||||||
|
|
||||||
auto offsets = get_range_offset_and_length(req, res.content_length_, i);
|
auto ret = get_range_offset_and_length(req, res.content_length_, i);
|
||||||
auto offset = offsets.first;
|
auto offset = ret.first;
|
||||||
auto length = offsets.second;
|
auto length = ret.second;
|
||||||
if (!content(offset, length)) { return false; }
|
if (!content(offset, length)) { return false; }
|
||||||
ctoken("\r\n");
|
ctoken("\r\n");
|
||||||
}
|
}
|
||||||
|
@ -4838,18 +4848,6 @@ inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<size_t, size_t>
|
|
||||||
get_range_offset_and_length(const Request &req, const Response &res,
|
|
||||||
size_t index) {
|
|
||||||
auto r = req.ranges[index];
|
|
||||||
|
|
||||||
if (r.second == -1) {
|
|
||||||
r.second = static_cast<ssize_t>(res.content_length_) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(r.first, r.second - r.first + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool expect_content(const Request &req) {
|
inline bool expect_content(const Request &req) {
|
||||||
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
|
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
|
||||||
req.method == "PRI" || req.method == "DELETE") {
|
req.method == "PRI" || req.method == "DELETE") {
|
||||||
|
@ -6045,10 +6043,10 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||||
return detail::write_content(strm, res.content_provider_, 0,
|
return detail::write_content(strm, res.content_provider_, 0,
|
||||||
res.content_length_, is_shutting_down);
|
res.content_length_, is_shutting_down);
|
||||||
} else if (req.ranges.size() == 1) {
|
} else if (req.ranges.size() == 1) {
|
||||||
auto offsets =
|
auto ret =
|
||||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||||
auto offset = offsets.first;
|
auto offset = ret.first;
|
||||||
auto length = offsets.second;
|
auto length = ret.second;
|
||||||
return detail::write_content(strm, res.content_provider_, offset, length,
|
return detail::write_content(strm, res.content_provider_, offset, length,
|
||||||
is_shutting_down);
|
is_shutting_down);
|
||||||
} else {
|
} else {
|
||||||
|
@ -6465,9 +6463,9 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||||
if (req.ranges.empty()) {
|
if (req.ranges.empty()) {
|
||||||
length = res.content_length_;
|
length = res.content_length_;
|
||||||
} else if (req.ranges.size() == 1) {
|
} else if (req.ranges.size() == 1) {
|
||||||
auto offsets =
|
auto ret =
|
||||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||||
length = offsets.second;
|
length = ret.second;
|
||||||
|
|
||||||
auto content_range = detail::make_content_range_header_field(
|
auto content_range = detail::make_content_range_header_field(
|
||||||
req.ranges[0], res.content_length_);
|
req.ranges[0], res.content_length_);
|
||||||
|
@ -6497,10 +6495,9 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||||
req.ranges[0], res.body.size());
|
req.ranges[0], res.body.size());
|
||||||
res.set_header("Content-Range", content_range);
|
res.set_header("Content-Range", content_range);
|
||||||
|
|
||||||
auto offsets =
|
auto ret = detail::get_range_offset_and_length(req, res.body.size(), 0);
|
||||||
detail::get_range_offset_and_length(req, res.body.size(), 0);
|
auto offset = ret.first;
|
||||||
auto offset = offsets.first;
|
auto length = ret.second;
|
||||||
auto length = offsets.second;
|
|
||||||
|
|
||||||
if (offset < res.body.size()) {
|
if (offset < res.body.size()) {
|
||||||
res.body = res.body.substr(offset, length);
|
res.body = res.body.substr(offset, length);
|
||||||
|
|
18
test/test.cc
18
test/test.cc
|
@ -2540,6 +2540,7 @@ TEST_F(ServerTest, StaticFileRange) {
|
||||||
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
||||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 2-3/5", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("cd"), res->body);
|
EXPECT_EQ(std::string("cd"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2553,7 +2554,7 @@ TEST_F(ServerTest, StaticFileRanges) {
|
||||||
.find(
|
.find(
|
||||||
"multipart/byteranges; boundary=--cpp-httplib-multipart-data-") ==
|
"multipart/byteranges; boundary=--cpp-httplib-multipart-data-") ==
|
||||||
0);
|
0);
|
||||||
EXPECT_EQ("265", res->get_header_value("Content-Length"));
|
EXPECT_EQ("266", res->get_header_value("Content-Length"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, StaticFileRangeHead) {
|
TEST_F(ServerTest, StaticFileRangeHead) {
|
||||||
|
@ -2563,6 +2564,7 @@ TEST_F(ServerTest, StaticFileRangeHead) {
|
||||||
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
||||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 2-3/5", res->get_header_value("Content-Range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, StaticFileRangeBigFile) {
|
TEST_F(ServerTest, StaticFileRangeBigFile) {
|
||||||
|
@ -2572,6 +2574,8 @@ TEST_F(ServerTest, StaticFileRangeBigFile) {
|
||||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||||
EXPECT_EQ("5", res->get_header_value("Content-Length"));
|
EXPECT_EQ("5", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 1048571-1048575/1048576",
|
||||||
|
res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ("LAST\n", res->body);
|
EXPECT_EQ("LAST\n", res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2582,6 +2586,7 @@ TEST_F(ServerTest, StaticFileRangeBigFile2) {
|
||||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||||
EXPECT_EQ("4097", res->get_header_value("Content-Length"));
|
EXPECT_EQ("4097", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 1-4097/1048576", res->get_header_value("Content-Range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, StaticFileBigFile) {
|
TEST_F(ServerTest, StaticFileBigFile) {
|
||||||
|
@ -2908,6 +2913,8 @@ TEST_F(ServerTest, GetStreamed2) {
|
||||||
ASSERT_TRUE(res);
|
ASSERT_TRUE(res);
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||||
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 2-3/6", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("ab"), res->body);
|
EXPECT_EQ(std::string("ab"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2925,6 +2932,7 @@ TEST_F(ServerTest, GetStreamedWithRange1) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 3-5/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("def"), res->body);
|
EXPECT_EQ(std::string("def"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2934,6 +2942,7 @@ TEST_F(ServerTest, GetStreamedWithRange2) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 1-6/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("bcdefg"), res->body);
|
EXPECT_EQ(std::string("bcdefg"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2943,6 +2952,7 @@ TEST_F(ServerTest, GetStreamedWithRangeSuffix1) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 4-6/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("efg"), res->body);
|
EXPECT_EQ(std::string("efg"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2952,6 +2962,7 @@ TEST_F(ServerTest, GetStreamedWithRangeSuffix2) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
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);
|
EXPECT_EQ(std::string("abcdefg"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2968,6 +2979,7 @@ TEST_F(ServerTest, GetRangeWithMaxLongLength) {
|
||||||
cli_.Get("/with-range", {{"Range", "bytes=0-9223372036854775807"}});
|
cli_.Get("/with-range", {{"Range", "bytes=0-9223372036854775807"}});
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
||||||
|
EXPECT_EQ("bytes 0-6/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
EXPECT_EQ(std::string("abcdefg"), res->body);
|
EXPECT_EQ(std::string("abcdefg"), res->body);
|
||||||
}
|
}
|
||||||
|
@ -3029,6 +3041,7 @@ TEST_F(ServerTest, GetWithRange1) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 3-5/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("def"), res->body);
|
EXPECT_EQ(std::string("def"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3038,6 +3051,7 @@ TEST_F(ServerTest, GetWithRange2) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 1-6/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("bcdefg"), res->body);
|
EXPECT_EQ(std::string("bcdefg"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3047,6 +3061,7 @@ TEST_F(ServerTest, GetWithRange3) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("1", res->get_header_value("Content-Length"));
|
EXPECT_EQ("1", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 0-0/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("a"), res->body);
|
EXPECT_EQ(std::string("a"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3056,6 +3071,7 @@ TEST_F(ServerTest, GetWithRange4) {
|
||||||
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
EXPECT_EQ(StatusCode::PartialContent_206, res->status);
|
||||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ("bytes 5-6/7", res->get_header_value("Content-Range"));
|
||||||
EXPECT_EQ(std::string("fg"), res->body);
|
EXPECT_EQ(std::string("fg"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue