mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-17 10:59:39 +00:00
apply Range only to a 206 response in write_content_with_provider
This commit is contained in:
1 parent
34b7c846d4
commit
23fef15e07
2 files changed
+49
-1
No files matched your search
@@ -11777,7 +11777,16 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (res.content_length_ > 0) {
|
if (res.content_length_ > 0) {
|
||||||
if (req.ranges.empty()) {
|
// Only a 206 response is served as a partial representation. That is the
|
||||||
|
// condition `apply_ranges()` used when it decided the Content-Length and
|
||||||
|
// the multipart boundary, and `detail::range_error()` only validates
|
||||||
|
// `req.ranges` against the content length for a 2xx status. Honouring the
|
||||||
|
// ranges here under any other status would write a body that disagrees
|
||||||
|
// with the header we already sent, from an offset nothing has checked.
|
||||||
|
auto partial =
|
||||||
|
!req.ranges.empty() && res.status == StatusCode::PartialContent_206;
|
||||||
|
|
||||||
|
if (!partial) {
|
||||||
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) {
|
||||||
|
|||||||
@@ -4419,6 +4419,24 @@ protected:
|
|||||||
delete data;
|
delete data;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
.Get("/streamed-with-range-and-error-status",
|
||||||
|
[&](const Request & /*req*/, Response &res) {
|
||||||
|
auto data = new std::string("abcdefg");
|
||||||
|
res.status = StatusCode::Forbidden_403;
|
||||||
|
res.set_content_provider(
|
||||||
|
data->size(), "text/plain",
|
||||||
|
[data](size_t offset, size_t length, DataSink &sink) {
|
||||||
|
size_t DATA_CHUNK_SIZE = 4;
|
||||||
|
const auto &d = *data;
|
||||||
|
auto out_len =
|
||||||
|
std::min(static_cast<size_t>(length), DATA_CHUNK_SIZE);
|
||||||
|
auto ret =
|
||||||
|
sink.write(&d[static_cast<size_t>(offset)], out_len);
|
||||||
|
EXPECT_TRUE(ret);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[data](bool /*success*/) { delete data; });
|
||||||
|
})
|
||||||
.Get("/streamed-cancel",
|
.Get("/streamed-cancel",
|
||||||
[&](const Request & /*req*/, Response &res) {
|
[&](const Request & /*req*/, Response &res) {
|
||||||
res.set_content_provider(
|
res.set_content_provider(
|
||||||
@@ -5932,6 +5950,27 @@ TEST_F(ServerTest, GetStreamedWithRangeSuffix2) {
|
|||||||
EXPECT_EQ(0U, res->body.size());
|
EXPECT_EQ(0U, res->body.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, GetStreamedWithRangeAndErrorStatus) {
|
||||||
|
// The handler answers with a non-2xx status, so `detail::range_error()`
|
||||||
|
// never validated the ranges and `apply_ranges()` reported the full
|
||||||
|
// content length. The body must match that header and the content provider
|
||||||
|
// must not be asked for an offset outside the representation.
|
||||||
|
auto res = cli_.Get("/streamed-with-range-and-error-status",
|
||||||
|
Headers{{make_range_header({{3, 5}})}});
|
||||||
|
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||||
|
EXPECT_EQ(StatusCode::Forbidden_403, res->status);
|
||||||
|
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
||||||
|
EXPECT_EQ(false, res->has_header("Content-Range"));
|
||||||
|
EXPECT_EQ(std::string("abcdefg"), res->body);
|
||||||
|
|
||||||
|
auto res2 = cli_.Get("/streamed-with-range-and-error-status",
|
||||||
|
Headers{{"Range", "bytes=100000-100200"}});
|
||||||
|
ASSERT_TRUE(res2) << "Error: " << to_string(res2.error());
|
||||||
|
EXPECT_EQ(StatusCode::Forbidden_403, res2->status);
|
||||||
|
EXPECT_EQ("7", res2->get_header_value("Content-Length"));
|
||||||
|
EXPECT_EQ(std::string("abcdefg"), res2->body);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, GetStreamedWithRangeError) {
|
TEST_F(ServerTest, GetStreamedWithRangeError) {
|
||||||
auto res =
|
auto res =
|
||||||
cli_.Get("/streamed-with-range",
|
cli_.Get("/streamed-with-range",
|
||||||
|
|||||||
Reference in new issue
Block a user