mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 12:57:31 +02:00
websocket handshake uses coroutine
This commit is contained in:
@ -4,6 +4,7 @@ WebSocket:
|
|||||||
|
|
||||||
* Fix async_read_some handler signature
|
* Fix async_read_some handler signature
|
||||||
* websocket close fixes and tests
|
* websocket close fixes and tests
|
||||||
|
* websocket handshake uses coroutine
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <boost/beast/http/write.hpp>
|
#include <boost/beast/http/write.hpp>
|
||||||
#include <boost/beast/core/handler_ptr.hpp>
|
#include <boost/beast/core/handler_ptr.hpp>
|
||||||
#include <boost/beast/core/type_traits.hpp>
|
#include <boost/beast/core/type_traits.hpp>
|
||||||
|
#include <boost/asio/coroutine.hpp>
|
||||||
#include <boost/asio/handler_alloc_hook.hpp>
|
#include <boost/asio/handler_alloc_hook.hpp>
|
||||||
#include <boost/asio/handler_continuation_hook.hpp>
|
#include <boost/asio/handler_continuation_hook.hpp>
|
||||||
#include <boost/asio/handler_invoke_hook.hpp>
|
#include <boost/asio/handler_invoke_hook.hpp>
|
||||||
@ -35,19 +36,18 @@ namespace websocket {
|
|||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
template<class Handler>
|
template<class Handler>
|
||||||
class stream<NextLayer>::handshake_op
|
class stream<NextLayer>::handshake_op
|
||||||
|
: public boost::asio::coroutine
|
||||||
{
|
{
|
||||||
struct data
|
struct data
|
||||||
{
|
{
|
||||||
bool cont;
|
|
||||||
stream<NextLayer>& ws;
|
stream<NextLayer>& ws;
|
||||||
response_type* res_p;
|
response_type* res_p;
|
||||||
detail::sec_ws_key_type key;
|
detail::sec_ws_key_type key;
|
||||||
http::request<http::empty_body> req;
|
http::request<http::empty_body> req;
|
||||||
response_type res;
|
response_type res;
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
template<class Decorator>
|
template<class Decorator>
|
||||||
data(Handler& handler, stream<NextLayer>& ws_,
|
data(Handler&, stream<NextLayer>& ws_,
|
||||||
response_type* res_p_,
|
response_type* res_p_,
|
||||||
string_view host,
|
string_view host,
|
||||||
string_view target,
|
string_view target,
|
||||||
@ -57,8 +57,6 @@ class stream<NextLayer>::handshake_op
|
|||||||
, req(ws.build_request(key,
|
, req(ws.build_request(key,
|
||||||
host, target, decorator))
|
host, target, decorator))
|
||||||
{
|
{
|
||||||
using boost::asio::asio_handler_is_continuation;
|
|
||||||
cont = asio_handler_is_continuation(std::addressof(handler));
|
|
||||||
ws.reset();
|
ws.reset();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -75,11 +73,10 @@ public:
|
|||||||
: d_(std::forward<DeducedHandler>(h),
|
: d_(std::forward<DeducedHandler>(h),
|
||||||
ws, std::forward<Args>(args)...)
|
ws, std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
(*this)(error_code{}, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator()(error_code ec, bool again = true);
|
operator()(error_code ec = {});
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void* asio_handler_allocate(
|
void* asio_handler_allocate(
|
||||||
@ -102,7 +99,9 @@ public:
|
|||||||
friend
|
friend
|
||||||
bool asio_handler_is_continuation(handshake_op* op)
|
bool asio_handler_is_continuation(handshake_op* op)
|
||||||
{
|
{
|
||||||
return op->d_->cont;
|
using boost::asio::asio_handler_is_continuation;
|
||||||
|
return asio_handler_is_continuation(
|
||||||
|
std::addressof(op->d_.handler()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Function>
|
template<class Function>
|
||||||
@ -119,52 +118,38 @@ template<class NextLayer>
|
|||||||
template<class Handler>
|
template<class Handler>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::handshake_op<Handler>::
|
stream<NextLayer>::handshake_op<Handler>::
|
||||||
operator()(error_code ec, bool again)
|
operator()(error_code ec)
|
||||||
{
|
{
|
||||||
auto& d = *d_;
|
auto& d = *d_;
|
||||||
d.cont = d.cont || again;
|
BOOST_ASIO_CORO_REENTER(*this)
|
||||||
while(! ec && d.state != 99)
|
|
||||||
{
|
{
|
||||||
switch(d.state)
|
// Send HTTP Upgrade
|
||||||
{
|
pmd_read(d.ws.pmd_config_, d.req);
|
||||||
case 0:
|
BOOST_ASIO_CORO_YIELD
|
||||||
{
|
http::async_write(d.ws.stream_,
|
||||||
// send http upgrade
|
d.req, std::move(*this));
|
||||||
d.state = 1;
|
if(ec)
|
||||||
// VFALCO Do we need the ability to move
|
goto upcall;
|
||||||
// a message on the async_write?
|
|
||||||
//
|
|
||||||
pmd_read(d.ws.pmd_config_, d.req);
|
|
||||||
http::async_write(d.ws.stream_,
|
|
||||||
d.req, std::move(*this));
|
|
||||||
// TODO We don't need d.req now. Figure
|
|
||||||
// out a way to make it a parameter instead
|
|
||||||
// of a state variable to reduce footprint.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sent upgrade
|
// VFALCO We could pre-serialize the request to
|
||||||
case 1:
|
// a single buffer, send that instead,
|
||||||
// read http response
|
// and delete the buffer here. The buffer
|
||||||
d.state = 2;
|
// could be a variable block at the end
|
||||||
http::async_read(d.ws.next_layer(),
|
// of handler_ptr's allocation.
|
||||||
d.ws.rd_.buf, d.res,
|
|
||||||
std::move(*this));
|
|
||||||
return;
|
|
||||||
|
|
||||||
// got response
|
// Read HTTP response
|
||||||
case 2:
|
BOOST_ASIO_CORO_YIELD
|
||||||
{
|
http::async_read(d.ws.next_layer(),
|
||||||
d.ws.on_response(d.res, d.key, ec);
|
d.ws.rd_.buf, d.res,
|
||||||
// call handler
|
std::move(*this));
|
||||||
d.state = 99;
|
if(ec)
|
||||||
break;
|
goto upcall;
|
||||||
}
|
d.ws.on_response(d.res, d.key, ec);
|
||||||
}
|
if(d.res_p)
|
||||||
|
swap(d.res, *d.res_p);
|
||||||
|
upcall:
|
||||||
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
if(d.res_p)
|
|
||||||
swap(d.res, *d.res_p);
|
|
||||||
d_.invoke(ec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
@ -183,7 +168,7 @@ async_handshake(string_view host,
|
|||||||
handshake_op<handler_type<
|
handshake_op<handler_type<
|
||||||
HandshakeHandler, void(error_code)>>{
|
HandshakeHandler, void(error_code)>>{
|
||||||
init.completion_handler, *this, nullptr, host,
|
init.completion_handler, *this, nullptr, host,
|
||||||
target, &default_decorate_req};
|
target, &default_decorate_req}();
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +189,7 @@ async_handshake(response_type& res,
|
|||||||
handshake_op<handler_type<
|
handshake_op<handler_type<
|
||||||
HandshakeHandler, void(error_code)>>{
|
HandshakeHandler, void(error_code)>>{
|
||||||
init.completion_handler, *this, &res, host,
|
init.completion_handler, *this, &res, host,
|
||||||
target, &default_decorate_req};
|
target, &default_decorate_req}();
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +213,7 @@ async_handshake_ex(string_view host,
|
|||||||
handshake_op<handler_type<
|
handshake_op<handler_type<
|
||||||
HandshakeHandler, void(error_code)>>{
|
HandshakeHandler, void(error_code)>>{
|
||||||
init.completion_handler, *this, nullptr, host,
|
init.completion_handler, *this, nullptr, host,
|
||||||
target, decorator};
|
target, decorator}();
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +238,7 @@ async_handshake_ex(response_type& res,
|
|||||||
handshake_op<handler_type<
|
handshake_op<handler_type<
|
||||||
HandshakeHandler, void(error_code)>>{
|
HandshakeHandler, void(error_code)>>{
|
||||||
init.completion_handler, *this, &res, host,
|
init.completion_handler, *this, &res, host,
|
||||||
target, decorator};
|
target, decorator}();
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user