Implemented #946 in a different way
This commit is contained in:
parent
0104614656
commit
5a43bb8149
@ -266,7 +266,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||||
return true; // return 'false' if you want to cancel the process.
|
return true; // return 'false' if you want to cancel the process.
|
||||||
},
|
},
|
||||||
[data] { delete data; });
|
[data](bool success) { delete data; });
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
12
httplib.h
12
httplib.h
@ -337,7 +337,7 @@ using ContentProvider =
|
|||||||
using ContentProviderWithoutLength =
|
using ContentProviderWithoutLength =
|
||||||
std::function<bool(size_t offset, DataSink &sink)>;
|
std::function<bool(size_t offset, DataSink &sink)>;
|
||||||
|
|
||||||
using ContentProviderResourceReleaser = std::function<void()>;
|
using ContentProviderResourceReleaser = std::function<void(bool success)>;
|
||||||
|
|
||||||
using ContentReceiverWithProgress =
|
using ContentReceiverWithProgress =
|
||||||
std::function<bool(const char *data, size_t data_length, uint64_t offset,
|
std::function<bool(const char *data, size_t data_length, uint64_t offset,
|
||||||
@ -465,7 +465,7 @@ struct Response {
|
|||||||
Response &operator=(Response &&) = default;
|
Response &operator=(Response &&) = default;
|
||||||
~Response() {
|
~Response() {
|
||||||
if (content_provider_resource_releaser_) {
|
if (content_provider_resource_releaser_) {
|
||||||
content_provider_resource_releaser_();
|
content_provider_resource_releaser_(content_provider_success_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,6 +474,7 @@ struct Response {
|
|||||||
ContentProvider content_provider_;
|
ContentProvider content_provider_;
|
||||||
ContentProviderResourceReleaser content_provider_resource_releaser_;
|
ContentProviderResourceReleaser content_provider_resource_releaser_;
|
||||||
bool is_chunked_content_provider_ = false;
|
bool is_chunked_content_provider_ = false;
|
||||||
|
bool content_provider_success_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Stream {
|
class Stream {
|
||||||
@ -4614,8 +4615,11 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
|||||||
if (!res.body.empty()) {
|
if (!res.body.empty()) {
|
||||||
if (!strm.write(res.body)) { ret = false; }
|
if (!strm.write(res.body)) { ret = false; }
|
||||||
} else if (res.content_provider_) {
|
} else if (res.content_provider_) {
|
||||||
if (!write_content_with_provider(strm, req, res, boundary,
|
if (write_content_with_provider(strm, req, res, boundary,
|
||||||
content_type)) {
|
content_type)) {
|
||||||
|
res.content_provider_success_ = true;
|
||||||
|
} else {
|
||||||
|
res.content_provider_success_ = false;
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
test/test.cc
48
test/test.cc
@ -1378,7 +1378,10 @@ protected:
|
|||||||
(*i)++;
|
(*i)++;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[i] { delete i; });
|
[i](bool success) {
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
delete i;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.Get("/streamed",
|
.Get("/streamed",
|
||||||
[&](const Request & /*req*/, Response &res) {
|
[&](const Request & /*req*/, Response &res) {
|
||||||
@ -1405,7 +1408,10 @@ protected:
|
|||||||
EXPECT_TRUE(ret);
|
EXPECT_TRUE(ret);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[data] { delete data; });
|
[data](bool success) {
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
delete data;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.Get("/streamed-cancel",
|
.Get("/streamed-cancel",
|
||||||
[&](const Request & /*req*/, Response &res) {
|
[&](const Request & /*req*/, Response &res) {
|
||||||
@ -3567,6 +3573,44 @@ TEST(KeepAliveTest, ReadTimeout) {
|
|||||||
ASSERT_FALSE(svr.is_running());
|
ASSERT_FALSE(svr.is_running());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClientProblemDetectionTest, ContentProvider) {
|
||||||
|
Server svr;
|
||||||
|
|
||||||
|
size_t content_length = 1024 * 1024;
|
||||||
|
|
||||||
|
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_content_provider(
|
||||||
|
content_length, "text/plain",
|
||||||
|
[&](size_t offset, size_t length, DataSink &sink) {
|
||||||
|
auto out_len = std::min(length, static_cast<size_t>(1024));
|
||||||
|
std::string out(out_len, '@');
|
||||||
|
sink.write(out.data(), out_len);
|
||||||
|
return offset < 4096;
|
||||||
|
},
|
||||||
|
[](bool success) { ASSERT_FALSE(success); });
|
||||||
|
});
|
||||||
|
|
||||||
|
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give GET time to get a few messages.
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
|
||||||
|
Client cli("localhost", PORT);
|
||||||
|
|
||||||
|
auto res = cli.Get("/hi", [&](const char * /*data*/, size_t /*data_length*/) {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(res);
|
||||||
|
|
||||||
|
svr.stop();
|
||||||
|
listen_thread.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
|
TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user