Skip to content

Commit c5c704c

Browse files
committed
Fix #1724
1 parent 115a786 commit c5c704c

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

httplib.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ class DataSink {
382382
DataSink &operator=(DataSink &&) = delete;
383383

384384
std::function<bool(const char *data, size_t data_len)> write;
385+
std::function<bool()> is_writable;
385386
std::function<void()> done;
386387
std::function<void(const Headers &trailer)> done_with_trailer;
387388
std::ostream os;
@@ -3959,6 +3960,8 @@ inline bool write_content(Stream &strm, const ContentProvider &content_provider,
39593960
return ok;
39603961
};
39613962

3963+
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
3964+
39623965
while (offset < end_offset && !is_shutting_down()) {
39633966
if (!strm.is_writable()) {
39643967
error = Error::Write;
@@ -4003,6 +4006,8 @@ write_content_without_length(Stream &strm,
40034006
return ok;
40044007
};
40054008

4009+
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
4010+
40064011
data_sink.done = [&](void) { data_available = false; };
40074012

40084013
while (data_available && !is_shutting_down()) {
@@ -4053,6 +4058,8 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider,
40534058
return ok;
40544059
};
40554060

4061+
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
4062+
40564063
auto done_with_trailer = [&](const Headers *trailer) {
40574064
if (!ok) { return; }
40584065

test/test.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4464,6 +4464,43 @@ TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
44644464
EXPECT_EQ("helloworld", res->body);
44654465
}
44664466

4467+
TEST(LongPollingTest, ClientCloseDetection) {
4468+
Server svr;
4469+
4470+
svr.Get("/events", [&](const Request & /*req*/, Response &res) {
4471+
res.set_chunked_content_provider(
4472+
"text/plain", [](std::size_t const, DataSink &sink) -> bool {
4473+
EXPECT_TRUE(sink.is_writable()); // the socket is alive
4474+
sink.os << "hello";
4475+
4476+
auto count = 10;
4477+
while (count > 0 && sink.is_writable()) {
4478+
this_thread::sleep_for(chrono::milliseconds(10));
4479+
}
4480+
EXPECT_FALSE(sink.is_writable()); // the socket is closed
4481+
return true;
4482+
});
4483+
});
4484+
4485+
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
4486+
auto se = detail::scope_exit([&] {
4487+
svr.stop();
4488+
listen_thread.join();
4489+
ASSERT_FALSE(svr.is_running());
4490+
});
4491+
4492+
svr.wait_until_ready();
4493+
4494+
Client cli("localhost", PORT);
4495+
4496+
auto res = cli.Get("/events", [&](const char *data, size_t data_length) {
4497+
EXPECT_EQ("hello", string(data, data_length));
4498+
return false; // close the socket immediately.
4499+
});
4500+
4501+
ASSERT_FALSE(res);
4502+
}
4503+
44674504
TEST(GetWithParametersTest, GetWithParameters) {
44684505
Server svr;
44694506

0 commit comments

Comments
 (0)