forked from boostorg/beast
beast support per-op cancellation
- websocket supports cancellation. - Iterating test for ws cancellation. - Only terminal cancellation is forwarded by default. - basic_stream supports cancellation. - supported cancellation is documented. - http cancellation additions. - Added cancellation_slot tests to http, utils and saved_handler. - Added post to write.cpp, to avoid SIGSEV in test. - Refresher describes cancellation in more detail.
This commit is contained in:
committed by
Klemens Morgenstern
parent
0bf3d971a0
commit
3ebff60b1a
@@ -22,8 +22,13 @@
|
||||
#include <boost/beast/_experimental/test/stream.hpp>
|
||||
#include <boost/beast/test/yield_to.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/bind_cancellation_slot.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/connect_pipe.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/asio/writable_pipe.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -1050,6 +1055,69 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
testCancellation(yield_context do_yield)
|
||||
{
|
||||
// this is tested on a pipe
|
||||
// because the test::stream doesn't implement cancellation
|
||||
{
|
||||
response<string_body> m;
|
||||
m.version(10);
|
||||
m.result(status::ok);
|
||||
m.set(field::server, "test");
|
||||
m.set(field::content_length, "5");
|
||||
// make the content big enough so it overflows the buffer
|
||||
// that'll make the op never complete if we don't cancel
|
||||
m.body().assign(10000000, '*');
|
||||
error_code ec;
|
||||
net::writable_pipe ts{ioc_};
|
||||
net::readable_pipe tr{ioc_};
|
||||
net::connect_pipe(tr, ts);
|
||||
net::cancellation_signal cl;
|
||||
net::post(ioc_, [&]{cl.emit(net::cancellation_type::all);});
|
||||
net::steady_timer timeout(ioc_, std::chrono::seconds(5));
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
BEAST_EXPECT(ec == net::error::operation_aborted);
|
||||
if (!ec) // this means the cancel failed!
|
||||
ts.close();
|
||||
});
|
||||
|
||||
async_write(ts, m, net::bind_cancellation_slot(cl.slot(), do_yield[ec]));
|
||||
timeout.cancel();
|
||||
net::post(ioc_, do_yield); // wait for the timeout to finish
|
||||
BEAST_EXPECT(ec == net::error::operation_aborted);
|
||||
}
|
||||
{
|
||||
response<string_body> m;
|
||||
m.version(11);
|
||||
m.result(status::ok);
|
||||
m.set(field::server, "test");
|
||||
m.set(field::transfer_encoding, "chunked");
|
||||
m.body().assign(10000000, '*');
|
||||
error_code ec;
|
||||
net::writable_pipe ts{ioc_};
|
||||
net::readable_pipe tr{ioc_};
|
||||
net::connect_pipe(tr, ts);
|
||||
net::cancellation_signal cl;
|
||||
net::post(ioc_, [&]{cl.emit(net::cancellation_type::all);});
|
||||
net::steady_timer timeout(ioc_, std::chrono::seconds(5));
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
BEAST_EXPECT(ec == net::error::operation_aborted);
|
||||
if (!ec) // this means the cancel failed!
|
||||
ts.close();
|
||||
});
|
||||
async_write(ts, m, net::bind_cancellation_slot(cl.slot(), do_yield[ec]));
|
||||
timeout.cancel();
|
||||
net::post(ioc_, do_yield); // wait for the timeout to finish
|
||||
BEAST_EXPECT(ec == net::error::operation_aborted);
|
||||
}
|
||||
// the timer handler may be invoked after the test suite is complete if we don't post.
|
||||
asio::post(ioc_, do_yield);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
@@ -1077,6 +1145,11 @@ public:
|
||||
#if BOOST_ASIO_HAS_CO_AWAIT
|
||||
boost::ignore_unused(&write_test::testAwaitableCompiles);
|
||||
#endif
|
||||
yield_to(
|
||||
[&](yield_context yield)
|
||||
{
|
||||
testCancellation(yield);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user