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: WebSocket:
* Remove obsolete frame tests * Remove obsolete frame tests
* Refactor fail/clode code
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -39,7 +39,8 @@ class stream<NextLayer>::fail_op
stream<NextLayer>& ws_; stream<NextLayer>& ws_;
int step_ = 0; int step_ = 0;
bool dispatched_ = false; bool dispatched_ = false;
fail_how how_; close_code code_;
error_code ev_;
token tok_; token tok_;
public: public:
@@ -51,27 +52,12 @@ public:
fail_op( fail_op(
DeducedHandler&& h, DeducedHandler&& h,
stream<NextLayer>& ws, stream<NextLayer>& ws,
close_code code) close_code code,
error_code ev)
: h_(std::forward<DeducedHandler>(h)) : h_(std::forward<DeducedHandler>(h))
, ws_(ws) , ws_(ws)
, how_(fail_how::code) , code_(code)
, tok_(ws_.t_.unique()) , ev_(ev)
{
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)
, tok_(ws_.t_.unique()) , tok_(ws_.t_.unique())
{ {
} }
@@ -168,12 +154,16 @@ operator()(error_code ec, std::size_t)
ec = boost::asio::error::operation_aborted; ec = boost::asio::error::operation_aborted;
break; break;
} }
if(how_ == fail_how::teardown) if(code_ == close_code::none)
goto go_teardown; goto go_teardown;
if(ws_.wr_close_) if(ws_.wr_close_)
goto go_teardown; goto go_teardown;
// send close frame // send close frame
step_ = do_teardown; 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; ws_.wr_close_ = true;
return boost::asio::async_write( return boost::asio::async_write(
ws_.stream_, ws_.rd_.fb.data(), ws_.stream_, ws_.rd_.fb.data(),
@@ -192,13 +182,12 @@ operator()(error_code ec, std::size_t)
BOOST_ASSERT(ws_.wr_block_ == tok_); BOOST_ASSERT(ws_.wr_block_ == tok_);
step_ = do_teardown + 1; step_ = do_teardown + 1;
websocket_helpers::call_async_teardown( websocket_helpers::call_async_teardown(
ws_.next_layer(), std::move(*this)); ws_.stream_, std::move(*this));
return; return;
case do_teardown + 1: case do_teardown + 1:
BOOST_ASSERT(ws_.wr_block_ == tok_); BOOST_ASSERT(ws_.wr_block_ == tok_);
dispatched_ = true; dispatched_ = true;
ws_.failed_ = true;
ws_.wr_block_.reset(); ws_.wr_block_.reset();
if(ec == boost::asio::error::eof) if(ec == boost::asio::error::eof)
{ {
@@ -207,15 +196,8 @@ operator()(error_code ec, std::size_t)
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
if(! ec) if(! ec)
{ ec = ev_;
switch(how_) ws_.failed_ = true;
{
default:
case fail_how::code:
case fail_how::teardown: ec = error::failed; break;
case fail_how::close: ec = error::closed; break;
}
}
break; break;
} }
// upcall // upcall
@@ -230,6 +212,61 @@ operator()(error_code ec, std::size_t)
h_(ec, 0); 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 } // websocket
} // beast } // beast
} // boost } // boost

View File

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

View File

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

View File

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

View File

@@ -3791,6 +3791,10 @@ private:
http::basic_fields<Allocator>> const& req, http::basic_fields<Allocator>> const& req,
Decorator const& decorator); Decorator const& decorator);
void
on_response(response_type const& resp,
detail::sec_ws_key_type const& key, error_code& ec);
template<class Decorator> template<class Decorator>
void void
do_accept(Decorator const& decorator, do_accept(Decorator const& decorator,
@@ -3811,8 +3815,17 @@ private:
error_code& ec); error_code& ec);
void void
do_response(response_type const& resp, do_fail(
detail::sec_ws_key_type const& key, error_code& ec); 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 } // websocket