diff --git a/CHANGELOG.md b/CHANGELOG.md index 819a9e47..c9af5879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Version 100: WebSocket: * Remove obsolete frame tests +* Refactor fail/clode code -------------------------------------------------------------------------------- diff --git a/include/boost/beast/websocket/impl/fail.ipp b/include/boost/beast/websocket/impl/fail.ipp index 37c5e696..aaeeb333 100644 --- a/include/boost/beast/websocket/impl/fail.ipp +++ b/include/boost/beast/websocket/impl/fail.ipp @@ -39,7 +39,8 @@ class stream::fail_op stream& 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& ws, - close_code code) + close_code code, + error_code ev) : h_(std::forward(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 - fail_op( - DeducedHandler&& h, - stream& ws, - fail_how how) - : h_(std::forward(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 +void +stream:: +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(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 +template +void +stream:: +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::type>{ + std::forward(handler), + *this, + code, + ev}(); +} + } // websocket } // beast } // boost diff --git a/include/boost/beast/websocket/impl/handshake.ipp b/include/boost/beast/websocket/impl/handshake.ipp index 1c4bc5c4..ccc19037 100644 --- a/include/boost/beast/websocket/impl/handshake.ipp +++ b/include/boost/beast/websocket/impl/handshake.ipp @@ -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); } diff --git a/include/boost/beast/websocket/impl/read.ipp b/include/boost/beast/websocket/impl/read.ipp index f2a21bdf..8420c06f 100644 --- a/include/boost/beast/websocket/impl/read.ipp +++ b/include/boost/beast/websocket/impl/read.ipp @@ -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{ - 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{ - 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{ - 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{ - std::move(h_), ws_, fail_how::close}(); + return ws_.do_async_fail( + cr.code == close_code::none ? + close_code::normal : + static_cast(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{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{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{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{std::move(h_), - ws_, close_code::bad_payload}(); - } + return ws_.do_async_fail(close_code::bad_payload, + error::failed, std::move(h_)); } break; } diff --git a/include/boost/beast/websocket/impl/stream.ipp b/include/boost/beast/websocket/impl/stream.ipp index 55cd8454..3c119d9b 100644 --- a/include/boost/beast/websocket/impl/stream.ipp +++ b/include/boost/beast/websocket/impl/stream.ipp @@ -631,7 +631,7 @@ build_response(http::request void stream:: -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 = [&]() diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index b02ac871..4cce349d 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -3791,6 +3791,10 @@ private: http::basic_fields> const& req, Decorator const& decorator); + void + on_response(response_type const& resp, + detail::sec_ws_key_type const& key, error_code& ec); + template 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 + void + do_async_fail( + close_code code, + error_code ev, + Handler&& handler); }; } // websocket