Refactor fail/clode code

This commit is contained in:
Vinnie Falco
2017-08-02 13:25:53 -07:00
parent 34c982b0e7
commit 756de5d703
6 changed files with 107 additions and 65 deletions

View File

@ -10,6 +10,7 @@ Version 100:
WebSocket:
* Remove obsolete frame tests
* Refactor fail/clode code
--------------------------------------------------------------------------------

View File

@ -39,7 +39,8 @@ class stream<NextLayer>::fail_op
stream<NextLayer>& ws_;
int step_ = 0;
bool dispatched_ = false;
fail_how how_;
close_code code_;
error_code ev_;
token tok_;
public:
@ -51,27 +52,12 @@ public:
fail_op(
DeducedHandler&& h,
stream<NextLayer>& ws,
close_code code)
close_code code,
error_code ev)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
, how_(fail_how::code)
, tok_(ws_.t_.unique())
{
ws_.rd_.fb.consume(ws_.rd_.fb.size());
ws_.template write_close<
flat_static_buffer_base>(
ws_.rd_.fb, code);
}
// maybe send frame in fb, then teardown
template<class DeducedHandler>
fail_op(
DeducedHandler&& h,
stream<NextLayer>& ws,
fail_how how)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
, how_(how)
, code_(code)
, ev_(ev)
, tok_(ws_.t_.unique())
{
}
@ -168,12 +154,16 @@ operator()(error_code ec, std::size_t)
ec = boost::asio::error::operation_aborted;
break;
}
if(how_ == fail_how::teardown)
if(code_ == close_code::none)
goto go_teardown;
if(ws_.wr_close_)
goto go_teardown;
// send close frame
step_ = do_teardown;
ws_.rd_.fb.consume(ws_.rd_.fb.size());
ws_.template write_close<
flat_static_buffer_base>(
ws_.rd_.fb, code_);
ws_.wr_close_ = true;
return boost::asio::async_write(
ws_.stream_, ws_.rd_.fb.data(),
@ -192,13 +182,12 @@ operator()(error_code ec, std::size_t)
BOOST_ASSERT(ws_.wr_block_ == tok_);
step_ = do_teardown + 1;
websocket_helpers::call_async_teardown(
ws_.next_layer(), std::move(*this));
ws_.stream_, std::move(*this));
return;
case do_teardown + 1:
BOOST_ASSERT(ws_.wr_block_ == tok_);
dispatched_ = true;
ws_.failed_ = true;
ws_.wr_block_.reset();
if(ec == boost::asio::error::eof)
{
@ -207,15 +196,8 @@ operator()(error_code ec, std::size_t)
ec.assign(0, ec.category());
}
if(! ec)
{
switch(how_)
{
default:
case fail_how::code:
case fail_how::teardown: ec = error::failed; break;
case fail_how::close: ec = error::closed; break;
}
}
ec = ev_;
ws_.failed_ = true;
break;
}
// upcall
@ -230,6 +212,61 @@ operator()(error_code ec, std::size_t)
h_(ec, 0);
}
//------------------------------------------------------------------------------
/* _Fail the WebSocket Connection_
*/
template<class NextLayer>
void
stream<NextLayer>::
do_fail(
close_code code, // if set, send a close frame first
error_code ev, // error code to use upon success
error_code& ec) // set to the error, else set to ev
{
BOOST_ASSERT(ev);
if(code != close_code::none && ! wr_close_)
{
wr_close_ = true;
detail::frame_streambuf fb;
write_close<flat_static_buffer_base>(fb, code);
boost::asio::write(stream_, fb.data(), ec);
failed_ = !!ec;
if(failed_)
return;
}
websocket_helpers::call_teardown(stream_, ec);
if(ec == boost::asio::error::eof)
{
// Rationale:
// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
ec.assign(0, ec.category());
}
failed_ = !!ec;
if(failed_)
return;
ec = ev;
failed_ = true;
}
/* _Fail the WebSocket Connection_
*/
template<class NextLayer>
template<class Handler>
void
stream<NextLayer>::
do_async_fail(
close_code code, // if set, send a close frame first
error_code ev, // error code to use upon success
Handler&& handler)
{
fail_op<typename std::decay<Handler>::type>{
std::forward<Handler>(handler),
*this,
code,
ev}();
}
} // websocket
} // beast
} // boost

View File

@ -155,7 +155,7 @@ operator()(error_code ec, bool again)
// got response
case 2:
{
d.ws.do_response(d.res, d.key, ec);
d.ws.on_response(d.res, d.key, ec);
// call handler
d.state = 99;
break;
@ -416,7 +416,7 @@ do_handshake(
http::read(next_layer(), rd_.buf, res, ec);
if(ec)
return;
do_response(res, key, ec);
on_response(res, key, ec);
if(res_p)
*res_p = std::move(res);
}

View File

@ -139,11 +139,9 @@ operator()(
if(! ws_.parse_fh(ws_.rd_.fh, ws_.rd_.buf, code))
{
if(code != close_code::none)
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{
std::move(h_), ws_, code}();
}
return ws_.do_async_fail(
code, error::failed, std::move(h_));
step_ = do_loop + 1;
return ws_.stream_.async_read_some(
ws_.rd_.buf.prepare(read_size(
@ -202,19 +200,17 @@ operator()(
if(code != close_code::none)
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{
std::move(h_), ws_, code}();
return ws_.do_async_fail(
code, error::failed, std::move(h_));
}
ws_.rd_.buf.consume(len);
if(ws_.ctrl_cb_)
ws_.ctrl_cb_(frame_type::close,
ws_.cr_.reason);
if(ws_.wr_close_)
{
// _Close the WebSocket Connection_
return fail_op<Handler>{
std::move(h_), ws_, fail_how::close}();
}
return ws_.do_async_fail(close_code::none,
error::closed, std::move(h_));
auto cr = ws_.cr_;
if(cr.code == close_code::none)
cr.code = close_code::normal;
@ -224,8 +220,11 @@ operator()(
flat_static_buffer_base>(
ws_.rd_.fb, cr);
// _Start the WebSocket Closing Handshake_
return fail_op<Handler>{
std::move(h_), ws_, fail_how::close}();
return ws_.do_async_fail(
cr.code == close_code::none ?
close_code::normal :
static_cast<close_code>(cr.code),
error::closed, std::move(h_));
}
}
if(ws_.rd_.fh.len == 0 && ! ws_.rd_.fh.fin)
@ -485,11 +484,9 @@ operator()(
if(! ws_.rd_.utf8.write(mb) ||
(ws_.rd_.remain == 0 && ws_.rd_.fh.fin &&
! ws_.rd_.utf8.finish()))
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{std::move(h_),
ws_, close_code::bad_payload}({}, 0);
}
return ws_.do_async_fail(close_code::bad_payload,
error::failed, std::move(h_));
}
bytes_written_ += bytes_transferred;
ws_.rd_.size += bytes_transferred;
@ -520,11 +517,9 @@ operator()(
if(! ws_.rd_.utf8.write(mb) ||
(ws_.rd_.remain == 0 && ws_.rd_.fh.fin &&
! ws_.rd_.utf8.finish()))
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{std::move(h_),
ws_, close_code::bad_payload}();
}
return ws_.do_async_fail(close_code::bad_payload,
error::failed, std::move(h_));
}
bytes_written_ += bytes_transferred;
ws_.rd_.size += bytes_transferred;
@ -614,11 +609,9 @@ operator()(
break;
if(ws_.rd_msg_max_ && beast::detail::sum_exceeds(
ws_.rd_.size, zs.total_out, ws_.rd_msg_max_))
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{std::move(h_),
ws_, close_code::too_big}();
}
return ws_.do_async_fail(close_code::too_big,
error::failed, std::move(h_));
cb_.consume(zs.total_out);
ws_.rd_.size += zs.total_out;
ws_.rd_.remain -= zs.total_in;
@ -632,11 +625,9 @@ operator()(
buffer_prefix(bytes_written_, cb_.get())) || (
ws_.rd_.remain == 0 && ws_.rd_.fh.fin &&
! ws_.rd_.utf8.finish()))
{
// _Fail the WebSocket Connection_
return fail_op<Handler>{std::move(h_),
ws_, close_code::bad_payload}();
}
return ws_.do_async_fail(close_code::bad_payload,
error::failed, std::move(h_));
}
break;
}

View File

@ -631,7 +631,7 @@ build_response(http::request<Body,
template<class NextLayer>
void
stream<NextLayer>::
do_response(response_type const& res,
on_response(response_type const& res,
detail::sec_ws_key_type const& key, error_code& ec)
{
bool const success = [&]()

View File

@ -3791,6 +3791,10 @@ private:
http::basic_fields<Allocator>> const& req,
Decorator const& decorator);
void
on_response(response_type const& resp,
detail::sec_ws_key_type const& key, error_code& ec);
template<class Decorator>
void
do_accept(Decorator const& decorator,
@ -3811,8 +3815,17 @@ private:
error_code& ec);
void
do_response(response_type const& resp,
detail::sec_ws_key_type const& key, error_code& ec);
do_fail(
close_code code,
error_code ev,
error_code& ec);
template<class Handler>
void
do_async_fail(
close_code code,
error_code ev,
Handler&& handler);
};
} // websocket