mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
@ -56,7 +56,7 @@
|
||||
* All asynchronous operations use Asio's
|
||||
[@boost:/doc/html/boost_asio/reference/async_initiate.html `async_initiate`]
|
||||
for efficient integration with Coroutines TS.
|
||||
* New [@boost:/doc/html/beast/example/websocket/server/chat-multi websocket-chat-multi]
|
||||
* New [@../../example/websocket/server/chat-multi websocket-chat-multi]
|
||||
multi-threaded websocket chat server with a JavaScript browser client.
|
||||
* New [link beast.using_io.asio_refresher Networking Refresher] explains basic concepts.
|
||||
* OpenSSL is required to build tests and examples
|
||||
@ -262,6 +262,8 @@ Enlarged scope
|
||||
* ([issue 1418]) `test::stream`
|
||||
maintains a handler work guard
|
||||
|
||||
* ([issue 1460]) Large WebSocket Upgrade response no longer overflows
|
||||
|
||||
* `buffers_cat`
|
||||
correctly skips empty buffers when iterated
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <boost/beast/http/read.hpp>
|
||||
#include <boost/beast/http/write.hpp>
|
||||
#include <boost/beast/core/async_op_base.hpp>
|
||||
#include <boost/beast/core/flat_buffer.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@ -43,7 +44,10 @@ class stream<NextLayer, deflateSupported>::handshake_op
|
||||
// VFALCO This really should be two separate
|
||||
// composed operations, to save on memory
|
||||
http::request<http::empty_body> req;
|
||||
response_type res;
|
||||
http::response_parser<
|
||||
typename response_type::body_type> p;
|
||||
flat_buffer fb;
|
||||
bool overflow;
|
||||
};
|
||||
|
||||
boost::weak_ptr<impl_type> wp_;
|
||||
@ -100,16 +104,52 @@ public:
|
||||
// read HTTP response
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
http::async_read(impl.stream,
|
||||
impl.rd_buf, d_.res,
|
||||
impl.rd_buf, d_.p,
|
||||
std::move(*this));
|
||||
if(ec == http::error::buffer_overflow)
|
||||
{
|
||||
// If the response overflows the internal
|
||||
// read buffer, switch to a dynamically
|
||||
// allocated flat buffer.
|
||||
|
||||
d_.fb.commit(net::buffer_copy(
|
||||
d_.fb.prepare(impl.rd_buf.size()),
|
||||
impl.rd_buf.data()));
|
||||
impl.rd_buf.clear();
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
http::async_read(impl.stream,
|
||||
d_.fb, d_.p, std::move(*this));
|
||||
|
||||
if(! ec)
|
||||
{
|
||||
// Copy any leftovers back into the read
|
||||
// buffer, since this represents websocket
|
||||
// frame data.
|
||||
|
||||
if(d_.fb.size() <= impl.rd_buf.capacity())
|
||||
{
|
||||
impl.rd_buf.commit(net::buffer_copy(
|
||||
impl.rd_buf.prepare(d_.fb.size()),
|
||||
d_.fb.data()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = http::error::buffer_overflow;
|
||||
}
|
||||
}
|
||||
|
||||
// Do this before the upcall
|
||||
d_.fb.clear();
|
||||
}
|
||||
if(impl.check_stop_now(ec))
|
||||
goto upcall;
|
||||
|
||||
// success
|
||||
impl.reset_idle();
|
||||
impl.on_response(d_.res, key_, ec);
|
||||
impl.on_response(d_.p.get(), key_, ec);
|
||||
if(res_p_)
|
||||
swap(d_.res, *res_p_);
|
||||
swap(d_.p.get(), *res_p_);
|
||||
|
||||
upcall:
|
||||
this->invoke(cont ,ec);
|
||||
@ -130,24 +170,62 @@ do_handshake(
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
response_type res;
|
||||
impl_->change_status(status::handshake);
|
||||
impl_->reset();
|
||||
auto& impl = *impl_;
|
||||
impl.change_status(status::handshake);
|
||||
impl.reset();
|
||||
detail::sec_ws_key_type key;
|
||||
{
|
||||
auto const req = impl_->build_request(
|
||||
auto const req = impl.build_request(
|
||||
key, host, target, decorator);
|
||||
this->impl_->do_pmd_config(req);
|
||||
http::write(impl_->stream, req, ec);
|
||||
impl.do_pmd_config(req);
|
||||
http::write(impl.stream, req, ec);
|
||||
}
|
||||
if(ec)
|
||||
if(impl.check_stop_now(ec))
|
||||
return;
|
||||
http::read(next_layer(), impl_->rd_buf, res, ec);
|
||||
if(ec)
|
||||
http::response_parser<
|
||||
typename response_type::body_type> p;
|
||||
http::read(next_layer(), impl.rd_buf, p, ec);
|
||||
if(ec == http::error::buffer_overflow)
|
||||
{
|
||||
// If the response overflows the internal
|
||||
// read buffer, switch to a dynamically
|
||||
// allocated flat buffer.
|
||||
|
||||
flat_buffer fb;
|
||||
fb.commit(net::buffer_copy(
|
||||
fb.prepare(impl.rd_buf.size()),
|
||||
impl.rd_buf.data()));
|
||||
impl.rd_buf.clear();
|
||||
|
||||
http::read(next_layer(), fb, p, ec);;
|
||||
|
||||
if(! ec)
|
||||
{
|
||||
// Copy any leftovers back into the read
|
||||
// buffer, since this represents websocket
|
||||
// frame data.
|
||||
|
||||
if(fb.size() <= impl.rd_buf.capacity())
|
||||
{
|
||||
impl.rd_buf.commit(net::buffer_copy(
|
||||
impl.rd_buf.prepare(fb.size()),
|
||||
fb.data()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = http::error::buffer_overflow;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(impl.check_stop_now(ec))
|
||||
return;
|
||||
impl_->on_response(res, key, ec);
|
||||
|
||||
impl.on_response(p.get(), key, ec);
|
||||
if(impl.check_stop_now(ec))
|
||||
return;
|
||||
|
||||
if(res_p)
|
||||
*res_p = std::move(res);
|
||||
*res_p = p.release();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <thread>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
@ -609,6 +610,99 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/boostorg/beast/issues/1460
|
||||
void
|
||||
testIssue1460()
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto const make_big = [](response_type& res)
|
||||
{
|
||||
res.insert("Date", "Mon, 18 Feb 2019 12:48:36 GMT");
|
||||
res.insert("Set-Cookie",
|
||||
"__cfduid=de1e209833e7f05aaa1044c6d448994761550494116; "
|
||||
"expires=Tue, 18-Feb-20 12:48:36 GMT; path=/; domain=.cryptofacilities.com; HttpOnly; Secure");
|
||||
res.insert("Feature-Policy",
|
||||
"accelerometer 'none'; ambient-light-sensor 'none'; "
|
||||
"animations 'none'; autoplay 'none'; camera 'none'; document-write 'none'; "
|
||||
"encrypted-media 'none'; geolocation 'none'; gyroscope 'none'; legacy-image-formats 'none'; "
|
||||
"magnetometer 'none'; max-downscaling-image 'none'; microphone 'none'; midi 'none'; "
|
||||
"payment 'none'; picture-in-picture 'none'; unsized-media 'none'; usb 'none'; vr 'none'");
|
||||
res.insert("Referrer-Policy", "origin");
|
||||
res.insert("Strict-Transport-Security", "max-age=15552000; includeSubDomains; preload");
|
||||
res.insert("X-Content-Type-Options", "nosniff");
|
||||
res.insert("Content-Security-Policy",
|
||||
"default-src 'none'; manifest-src 'self'; object-src 'self'; "
|
||||
"child-src 'self' https://www.google.com; "
|
||||
"font-src 'self' https://use.typekit.net https://maxcdn.bootstrapcdn.com https://fonts.gstatic.com data:; "
|
||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.cloudflare.com https://use.typekit.net "
|
||||
"https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com https://www.googleadservices.com "
|
||||
"https://googleads.g.doubleclick.net https://www.gstatic.com; connect-src 'self' wss://*.cryptofacilities.com/ws/v1 wss://*.cryptofacilities.com/ws/indices "
|
||||
"https://uat.cryptofacilities.com https://uat.cf0.io wss://*.cf0.io https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com "
|
||||
"https://fonts.googleapis.com https://google-analytics.com https://use.typekit.net https://p.typekit.net https://fonts.gstatic.com https://www.gstatic.com "
|
||||
"https://chart.googleapis.com; worker-src 'self'; img-src 'self' https://chart.googleapis.com https://p.typekit.net https://www.google.co.uk https://www.google.com "
|
||||
"https://www.google-analytics.com https://stats.g.doubleclick.net data:; style-src 'self' 'unsafe-inline' https://use.typekit.net https://p.typekit.net "
|
||||
"https://fonts.googleapis.com https://maxcdn.bootstrapcdn.com");
|
||||
res.insert("X-Frame-Options", "SAMEORIGIN");
|
||||
res.insert("X-Xss-Protection", "1; mode=block");
|
||||
res.insert("Expect-CT", "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"");
|
||||
res.insert("Server", "cloudflare");
|
||||
res.insert("CF-RAY", "4ab09be1a9d0cb06-ARN");
|
||||
res.insert("Bulk",
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************"
|
||||
"****************************************************************************************************");
|
||||
};
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws2.set_option(stream_base::decorator(make_big));
|
||||
error_code ec;
|
||||
ws2.async_accept(test::success_handler());
|
||||
std::thread t(
|
||||
[&ioc]
|
||||
{
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
});
|
||||
ws1.handshake("test", "/", ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
t.join();
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws2.set_option(stream_base::decorator(make_big));
|
||||
error_code ec;
|
||||
ws2.async_accept(test::success_handler());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@ -618,6 +712,7 @@ public:
|
||||
testExtNegotiate();
|
||||
testMoveOnly();
|
||||
testAsync();
|
||||
testIssue1460();
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user