diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9b39300..c3f23135 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,20 @@ WebSocket:
* Refactor error headers
* Add WebSocket error conditions
+API Changes:
+
+* Refactor WebSocket errors (API Change):
+
+Actions Required:
+
+* Code which explicitly compares error_code values against the
+ constant `websocket::error::handshake_failed` should compare
+ against `websocket::condition::handshake_failed` instead.
+
+* Code which explicitly compares error_code values against the
+ constant `websocket::error::failed` should compare
+ against `websocket::condition::protocol_violation` instead.
+
--------------------------------------------------------------------------------
Version 151:
diff --git a/doc/qbk/06_websocket/1_streams.qbk b/doc/qbk/06_websocket/1_streams.qbk
index fc2bc595..47e7dbad 100644
--- a/doc/qbk/06_websocket/1_streams.qbk
+++ b/doc/qbk/06_websocket/1_streams.qbk
@@ -18,8 +18,8 @@ An instance of the stream wraps an existing network transport object
or other type of octet oriented stream. The wrapped object is called
the "next layer" and must meet the requirements of __SyncStream__ if
synchronous operations are performed, __AsyncStream__ if asynchronous
-operations are performed, or both. Any arguments supplied during
-construction of the stream wrapper are passed to next layer's constructor.
+operations are performed, or both. Any arguments supplied to the
+constructor of the stream wrapper are forwarded to next layer's constructor.
The value of `deflateSupported` determines if the stream will support
(but not require) the permessage-deflate extension
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index e282fc23..f3681dc7 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -145,6 +145,7 @@
Constants
close_code
+ condition
error
frame_type
role_type
diff --git a/include/boost/beast/websocket/detail/error.hpp b/include/boost/beast/websocket/detail/error.hpp
index 7c3ee3e8..57b837bd 100644
--- a/include/boost/beast/websocket/detail/error.hpp
+++ b/include/boost/beast/websocket/detail/error.hpp
@@ -41,79 +41,34 @@ namespace detail {
class error_codes : public error_category
{
- template
- string_view
- message(error e) const;
-
public:
const char*
- name() const noexcept override
- {
- return "boost.beast.websocket";
- }
+ name() const noexcept override;
std::string
- message(int ev) const override
- {
- return message(
- static_cast(ev)).to_string();
- }
+ message(int ev) const override;
+
+ error_condition
+ default_error_condition(int ev) const noexcept override;
};
class error_conditions : public error_category
{
- template
- string_view
- message(condition c) const;
-
- template
- bool
- equivalent(error_code const& ec,
- condition c) const noexcept;
-
public:
const char*
- name() const noexcept override
- {
- return "boost.beast.websocket";
- }
+ name() const noexcept override;
std::string
- message(int cv) const override
- {
- return message(
- static_cast(cv)).to_string();
- }
-
- bool
- equivalent(
- error_code const& ec,
- int cv) const noexcept
- {
- return equivalent(ec,
- static_cast(cv));
- }
+ message(int cv) const override;
};
} // detail
-inline
error_code
-make_error_code(error e)
-{
- static detail::error_codes const cat{};
- return error_code{static_cast<
- std::underlying_type::type>(e), cat};
-}
+make_error_code(error e);
-inline
error_condition
-make_error_condition(condition c)
-{
- static detail::error_conditions const cat{};
- return error_condition{static_cast<
- std::underlying_type::type>(c), cat};
-}
+make_error_condition(condition c);
} // websocket
} // beast
diff --git a/include/boost/beast/websocket/detail/frame.hpp b/include/boost/beast/websocket/detail/frame.hpp
index c75a8cc0..c3bd1690 100644
--- a/include/boost/beast/websocket/detail/frame.hpp
+++ b/include/boost/beast/websocket/detail/frame.hpp
@@ -10,6 +10,7 @@
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
#define BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
+#include
#include
#include
#include
@@ -244,8 +245,10 @@ read_ping(ping_data& data, Buffers const& bs)
//
template
void
-read_close(close_reason& cr,
- Buffers const& bs, close_code& code)
+read_close(
+ close_reason& cr,
+ Buffers const& bs,
+ error_code& ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -256,12 +259,13 @@ read_close(close_reason& cr,
if(n == 0)
{
cr = close_reason{};
- code = close_code::none;
+ ec.assign(0, ec.category());
return;
}
if(n == 1)
{
- code = close_code::protocol_error;
+ // invalid payload size == 1
+ ec = error::bad_close_size;
return;
}
buffers_suffix cb(bs);
@@ -273,7 +277,8 @@ read_close(close_reason& cr,
n -= 2;
if(! is_valid_close_code(cr.code))
{
- code = close_code::protocol_error;
+ // invalid close code
+ ec = error::bad_close_code;
return;
}
}
@@ -284,7 +289,8 @@ read_close(close_reason& cr,
if(! check_utf8(
cr.reason.data(), cr.reason.size()))
{
- code = close_code::protocol_error;
+ // not valid utf-8
+ ec = error::bad_close_payload;
return;
}
}
@@ -292,7 +298,7 @@ read_close(close_reason& cr,
{
cr.reason = "";
}
- code = close_code::none;
+ ec.assign(0, ec.category());
}
} // detail
diff --git a/include/boost/beast/websocket/error.hpp b/include/boost/beast/websocket/error.hpp
index 03303428..d4e51971 100644
--- a/include/boost/beast/websocket/error.hpp
+++ b/include/boost/beast/websocket/error.hpp
@@ -21,32 +21,228 @@ namespace websocket {
/// Error codes returned from @ref beast::websocket::stream operations.
enum class error
{
- /// Both sides performed a WebSocket close
+ /** The WebSocket stream was gracefully closed at both endpoints
+ */
closed = 1,
- /// WebSocket connection failed, protocol violation
- failed,
+/* The error codes error::failed and error::handshake_failed
+ are no longer in use. Please change your code to compare values
+ of type error_code against condition::handshake_failed
+ and condition::protocol_violation instead.
+
+ Apologies for the inconvenience.
- /// Upgrade handshake failed
- handshake_failed,
+ - VFALCO
+*/
+#if ! BOOST_BEAST_DOXYGEN
+ unused1 = 2, // failed
+ unused2 = 3, // handshake_failed
+#endif
- /// buffer overflow
+ /** The WebSocket operation caused a dynamic buffer overflow
+ */
buffer_overflow,
- /// partial deflate block
- partial_deflate_block
+ /** The WebSocket stream produced an incomplete deflate block
+ */
+ partial_deflate_block,
+
+ /** The WebSocket message exceeded the locally configured limit
+ */
+ message_too_big,
+
+ //
+ // Handshake failure errors
+ //
+ // These will compare equal to condition::handshake_failed
+ //
+
+ /** The WebSocket handshake was not HTTP/1.1
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_http_version,
+
+ /** The WebSocket handshake method was not GET
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_method,
+
+ /** The WebSocket handshake Host field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_host,
+
+ /** The WebSocket handshake Connection field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_connection,
+
+ /** The WebSocket handshake Connection field is missing the upgrade token
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_connection_upgrade,
+
+ /** The WebSocket handshake Upgrade field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_upgrade,
+
+ /** The WebSocket handshake Upgrade field is missing the websocket token
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_upgrade_websocket,
+
+ /** The WebSocket handshake Sec-WebSocket-Key field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_key,
+
+ /** The WebSocket handshake Sec-WebSocket-Key field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_key,
+
+ /** The WebSocket handshake Sec-WebSocket-Version field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_version,
+
+ /** The WebSocket handshake Sec-WebSocket-Version field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_version,
+
+ /** The WebSocket handshake Sec-WebSocket-Accept field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_accept,
+
+ /** The WebSocket handshake Sec-WebSocket-Accept field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_accept,
+
+ /** The WebSocket handshake was declined by the remote peer
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ upgrade_declined,
+
+ //
+ // Protocol errors
+ //
+ // These will compare equal to condition::protocol_violation
+ //
+
+ /** The WebSocket frame contained an illegal opcode
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_opcode,
+
+ /** The WebSocket data frame was unexpected
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_data_frame,
+
+ /** The WebSocket continuation frame was unexpected
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_continuation,
+
+ /** The WebSocket frame contained illegal reserved bits
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_reserved_bits,
+
+ /** The WebSocket control frame was fragmented
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_control_fragment,
+
+ /** The WebSocket control frame size was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_control_size,
+
+ /** The WebSocket frame was unmasked
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_unmasked_frame,
+
+ /** The WebSocket frame was masked
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_masked_frame,
+
+ /** The WebSocket frame size was not canonical
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_size,
+
+ /** The WebSocket frame payload was not valid utf8
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_frame_payload,
+
+ /** The WebSocket close frame reason code was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_code,
+
+ /** The WebSocket close frame payload size was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_size,
+
+ /** The WebSocket close frame payload was not valid utf8
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_payload
};
/// Error conditions corresponding to sets of error codes.
enum class condition
{
- /** Handshake failed
+ /** The WebSocket handshake failed
This condition indicates that the WebSocket handshake failed. If
the corresponding HTTP response indicates the keep-alive behavior,
then the handshake may be reattempted.
*/
handshake_failed = 1,
+
+ /** A WebSocket protocol violation occurred
+
+ This condition indicates that the remote peer on the WebSocket
+ connection sent data which violated the protocol.
+ */
+ protocol_violation
};
} // websocket
diff --git a/include/boost/beast/websocket/impl/accept.ipp b/include/boost/beast/websocket/impl/accept.ipp
index bbacad3f..0dff87d2 100644
--- a/include/boost/beast/websocket/impl/accept.ipp
+++ b/include/boost/beast/websocket/impl/accept.ipp
@@ -42,6 +42,7 @@ class stream::response_op
struct data
{
stream& ws;
+ error_code result;
response_type res;
template
@@ -52,7 +53,7 @@ class stream::response_op
http::basic_fields> const& req,
Decorator const& decorator)
: ws(ws_)
- , res(ws_.build_response(req, decorator))
+ , res(ws_.build_response(req, decorator, result))
{
}
};
@@ -120,9 +121,8 @@ operator()(
BOOST_ASIO_CORO_YIELD
http::async_write(d.ws.next_layer(),
d.res, std::move(*this));
- if(! ec && d.res.result() !=
- http::status::switching_protocols)
- ec = error::handshake_failed;
+ if(! ec)
+ ec = d.result;
if(! ec)
{
d.ws.do_pmd_config(d.res, is_deflate_supported{});
@@ -742,13 +742,14 @@ do_accept(
Decorator const& decorator,
error_code& ec)
{
- auto const res = build_response(req, decorator);
+ error_code result;
+ auto const res = build_response(req, decorator, result);
http::write(stream_, res, ec);
if(ec)
return;
- if(res.result() != http::status::switching_protocols)
+ ec = result;
+ if(ec)
{
- ec = error::handshake_failed;
// VFALCO TODO Respect keep alive setting, perform
// teardown if Connection: close.
return;
diff --git a/include/boost/beast/websocket/impl/close.ipp b/include/boost/beast/websocket/impl/close.ipp
index 7a7bb579..17697139 100644
--- a/include/boost/beast/websocket/impl/close.ipp
+++ b/include/boost/beast/websocket/impl/close.ipp
@@ -121,7 +121,6 @@ operator()(
{
using beast::detail::clamp;
auto& d = *d_;
- close_code code{};
d.cont = cont;
BOOST_ASIO_CORO_REENTER(*this)
{
@@ -219,13 +218,10 @@ operator()(
{
// Read frame header
while(! d.ws.parse_fh(
- d.ws.rd_fh_, d.ws.rd_buf_, code))
+ d.ws.rd_fh_, d.ws.rd_buf_, d.ev))
{
- if(code != close_code::none)
- {
- d.ev = error::failed;
+ if(d.ev)
goto teardown;
- }
BOOST_ASIO_CORO_YIELD
d.ws.stream_.async_read_some(
d.ws.rd_buf_.prepare(read_size(d.ws.rd_buf_,
@@ -247,13 +243,9 @@ operator()(
d.ws.rd_buf_.data());
if(d.ws.rd_fh_.len > 0 && d.ws.rd_fh_.mask)
detail::mask_inplace(mb, d.ws.rd_key_);
- detail::read_close(d.ws.cr_, mb, code);
- if(code != close_code::none)
- {
- // Protocol error
- d.ev = error::failed;
+ detail::read_close(d.ws.cr_, mb, d.ev);
+ if(d.ev)
goto teardown;
- }
d.ws.rd_buf_.consume(clamp(d.ws.rd_fh_.len));
goto teardown;
}
@@ -364,18 +356,18 @@ close(close_reason const& cr, error_code& ec)
if(! check_ok(ec))
return;
status_ = status::closing;
+ error_code result;
// Drain the connection
- close_code code{};
if(rd_remain_ > 0)
goto read_payload;
for(;;)
{
// Read frame header
- while(! parse_fh(rd_fh_, rd_buf_, code))
+ while(! parse_fh(rd_fh_, rd_buf_, result))
{
- if(code != close_code::none)
- return do_fail(close_code::none,
- error::failed, ec);
+ if(result)
+ return do_fail(
+ close_code::none, result, ec);
auto const bytes_transferred =
stream_.read_some(
rd_buf_.prepare(read_size(rd_buf_,
@@ -396,12 +388,12 @@ close(close_reason const& cr, error_code& ec)
rd_buf_.data());
if(rd_fh_.len > 0 && rd_fh_.mask)
detail::mask_inplace(mb, rd_key_);
- detail::read_close(cr_, mb, code);
- if(code != close_code::none)
+ detail::read_close(cr_, mb, result);
+ if(result)
{
- // Protocol error
- return do_fail(close_code::none,
- error::failed, ec);
+ // Protocol violation
+ return do_fail(
+ close_code::none, result, ec);
}
rd_buf_.consume(clamp(rd_fh_.len));
break;
diff --git a/include/boost/beast/websocket/impl/error.ipp b/include/boost/beast/websocket/impl/error.ipp
index f5b78279..56a20e25 100644
--- a/include/boost/beast/websocket/impl/error.ipp
+++ b/include/boost/beast/websocket/impl/error.ipp
@@ -15,59 +15,146 @@ namespace beast {
namespace websocket {
namespace detail {
-template
-string_view
+inline
+const char*
error_codes::
-message(error e) const
+name() const noexcept
{
- switch(e)
+ return "boost.beast.websocket";
+}
+
+inline
+std::string
+error_codes::
+message(int ev) const
+{
+ switch(static_cast(ev))
{
default:
- case error::failed: return "WebSocket connection failed due to a protocol violation";
- case error::closed: return "WebSocket connection closed normally";
- case error::handshake_failed: return "WebSocket upgrade handshake failed";
- case error::buffer_overflow: return "WebSocket dynamic buffer overflow";
- case error::partial_deflate_block: return "WebSocket partial deflate block";
+ case error::closed: return "The WebSocket stream was gracefully closed at both endpoints";
+ case error::buffer_overflow: return "The WebSocket operation caused a dynamic buffer overflow";
+ case error::partial_deflate_block: return "The WebSocket stream produced an incomplete deflate block";
+ case error::message_too_big: return "The WebSocket message exceeded the locally configured limit";
+
+ case error::bad_http_version: return "The WebSocket handshake was not HTTP/1.1";
+ case error::bad_method: return "The WebSocket handshake method was not GET";
+ case error::no_host: return "The WebSocket handshake Host field is missing";
+ case error::no_connection: return "The WebSocket handshake Connection field is missing";
+ case error::no_connection_upgrade: return "The WebSocket handshake Connection field is missing the upgrade token";
+ case error::no_upgrade: return "The WebSocket handshake Upgrade field is missing";
+ case error::no_upgrade_websocket: return "The WebSocket handshake Upgrade field is missing the websocket token";
+ case error::no_sec_key: return "The WebSocket handshake Sec-WebSocket-Key field is missing";
+ case error::bad_sec_key: return "The WebSocket handshake Sec-WebSocket-Key field is invalid";
+ case error::no_sec_version: return "The WebSocket handshake Sec-WebSocket-Version field is missing";
+ case error::bad_sec_version: return "The WebSocket handshake Sec-WebSocket-Version field is invalid";
+ case error::no_sec_accept: return "The WebSocket handshake Sec-WebSocket-Accept field is missing";
+ case error::bad_sec_accept: return "The WebSocket handshake Sec-WebSocket-Accept field is invalid";
+ case error::upgrade_declined: return "The WebSocket handshake was declined by the remote peer";
+
+ case error::bad_opcode: return "The WebSocket frame contained an illegal opcode";
+ case error::bad_data_frame: return "The WebSocket data frame was unexpected";
+ case error::bad_continuation: return "The WebSocket continuation frame was unexpected";
+ case error::bad_reserved_bits: return "The WebSocket frame contained illegal reserved bits";
+ case error::bad_control_fragment: return "The WebSocket control frame was fragmented";
+ case error::bad_control_size: return "The WebSocket control frame size was invalid";
+ case error::bad_unmasked_frame: return "The WebSocket frame was unmasked";
+ case error::bad_masked_frame: return "The WebSocket frame was masked";
+ case error::bad_size: return "The WebSocket frame size was not canonical";
+ case error::bad_frame_payload: return "The WebSocket frame payload was not valid utf8";
+ case error::bad_close_code: return "The WebSocket close frame reason code was invalid";
+ case error::bad_close_size: return "The WebSocket close frame payload size was invalid";
+ case error::bad_close_payload: return "The WebSocket close frame payload was not valid utf8";
}
}
-template
-string_view
-error_conditions::
-message(condition c) const
+inline
+error_condition
+error_codes::
+default_error_condition(int ev) const noexcept
{
- switch(c)
+ switch(static_cast(ev))
{
default:
- case condition::handshake_failed: return "WebSocket upgrade handshake failed";
+ case error::closed:
+ case error::buffer_overflow:
+ case error::partial_deflate_block:
+ case error::message_too_big:
+ return {ev, *this};
+
+ case error::bad_http_version:
+ case error::bad_method:
+ case error::no_host:
+ case error::no_connection:
+ case error::no_connection_upgrade:
+ case error::no_upgrade:
+ case error::no_upgrade_websocket:
+ case error::no_sec_key:
+ case error::bad_sec_key:
+ case error::no_sec_version:
+ case error::bad_sec_version:
+ case error::no_sec_accept:
+ case error::bad_sec_accept:
+ case error::upgrade_declined:
+ return condition::handshake_failed;
+
+ case error::bad_opcode:
+ case error::bad_data_frame:
+ case error::bad_continuation:
+ case error::bad_reserved_bits:
+ case error::bad_control_fragment:
+ case error::bad_control_size:
+ case error::bad_unmasked_frame:
+ case error::bad_masked_frame:
+ case error::bad_size:
+ case error::bad_frame_payload:
+ case error::bad_close_code:
+ case error::bad_close_size:
+ case error::bad_close_payload:
+ return condition::protocol_violation;
}
}
-template
-bool
+inline
+const char*
error_conditions::
-equivalent(
- error_code const& ec,
- condition c) const noexcept
+name() const noexcept
{
- if(ec.category() == error_code{error{}}.category())
- {
- switch(c)
- {
- case condition::handshake_failed:
- switch(static_cast(ec.value()))
- {
- case error::handshake_failed:
- return true;
- }
- return false;
- }
- }
- return false;
+ return "boost.beast.websocket";
}
+inline
+std::string
+error_conditions::
+message(int cv) const
+{
+ switch(static_cast(cv))
+ {
+ default:
+ case condition::handshake_failed: return "The WebSocket handshake failed";
+ case condition::protocol_violation: return "A WebSocket protocol violation occurred";
+ }
+}
} // detail
+
+inline
+error_code
+make_error_code(error e)
+{
+ static detail::error_codes const cat{};
+ return error_code{static_cast<
+ std::underlying_type::type>(e), cat};
+}
+
+inline
+error_condition
+make_error_condition(condition c)
+{
+ static detail::error_conditions const cat{};
+ return error_condition{static_cast<
+ std::underlying_type::type>(c), cat};
+}
+
} // websocket
} // beast
} // boost
diff --git a/include/boost/beast/websocket/impl/read.ipp b/include/boost/beast/websocket/impl/read.ipp
index 5489133d..b27149bd 100644
--- a/include/boost/beast/websocket/impl/read.ipp
+++ b/include/boost/beast/websocket/impl/read.ipp
@@ -84,7 +84,7 @@ class stream::read_some_op
MutableBufferSequence bs_;
buffers_suffix cb_;
std::size_t bytes_written_ = 0;
- error_code ev_;
+ error_code result_;
token tok_;
close_code code_;
bool did_read_ = false;
@@ -160,7 +160,6 @@ operator()(
using beast::detail::clamp;
using boost::asio::buffer;
using boost::asio::buffer_size;
- close_code code{};
cont_ = cont;
BOOST_ASIO_CORO_REENTER(*this)
{
@@ -220,13 +219,15 @@ operator()(
{
// Read frame header
while(! ws_.parse_fh(
- ws_.rd_fh_, ws_.rd_buf_, code))
+ ws_.rd_fh_, ws_.rd_buf_, result_))
{
- if(code != close_code::none)
+ if(result_)
{
// _Fail the WebSocket Connection_
- code_ = code;
- ev_ = error::failed;
+ if(result_ == error::message_too_big)
+ code_ = close_code::too_big;
+ else
+ code_ = close_code::protocol_error;
goto close;
}
BOOST_ASSERT(ws_.rd_block_ == tok_);
@@ -370,7 +371,6 @@ operator()(
ws_.rd_fh_.len), ws_.rd_buf_.data());
auto const len = buffer_size(cb);
BOOST_ASSERT(len == ws_.rd_fh_.len);
- code = close_code::none;
ping_data payload;
detail::read_ping(payload, cb);
ws_.rd_buf_.consume(len);
@@ -400,12 +400,11 @@ operator()(
BOOST_ASSERT(! ws_.rd_close_);
ws_.rd_close_ = true;
close_reason cr;
- detail::read_close(cr, cb, code);
- if(code != close_code::none)
+ detail::read_close(cr, cb, result_);
+ if(result_)
{
// _Fail the WebSocket Connection_
- code_ = code;
- ev_ = error::failed;
+ code_ = close_code::protocol_error;
goto close;
}
ws_.cr_ = cr;
@@ -419,14 +418,14 @@ operator()(
// _Close the WebSocket Connection_
BOOST_ASSERT(ws_.wr_close_);
code_ = close_code::none;
- ev_ = error::closed;
+ result_ = error::closed;
goto close;
}
// _Start the WebSocket Closing Handshake_
code_ = cr.code == close_code::none ?
close_code::normal :
static_cast(cr.code);
- ev_ = error::closed;
+ result_ = error::closed;
goto close;
}
}
@@ -477,7 +476,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -511,7 +510,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -604,7 +603,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::too_big;
- ev_ = error::failed;
+ result_ = error::message_too_big;
goto close;
}
cb_.consume(zs.total_out);
@@ -622,7 +621,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -698,7 +697,7 @@ operator()(
ec.assign(0, ec.category());
}
if(! ec)
- ec = ev_;
+ ec = result_;
if(ec && ec != error::closed)
ws_.status_ = status::failed;
else
@@ -1049,12 +1048,17 @@ loop:
if(rd_remain_ == 0 && (! rd_fh_.fin || rd_done_))
{
// Read frame header
- while(! parse_fh(rd_fh_, rd_buf_, code))
+ error_code result;
+ while(! parse_fh(rd_fh_, rd_buf_, result))
{
- if(code != close_code::none)
+ if(result)
{
// _Fail the WebSocket Connection_
- do_fail(code, error::failed, ec);
+ if(result == error::message_too_big)
+ code = close_code::too_big;
+ else
+ code = close_code::protocol_error;
+ do_fail(code, result, ec);
return bytes_written;
}
auto const bytes_transferred =
@@ -1121,11 +1125,12 @@ loop:
BOOST_ASSERT(! rd_close_);
rd_close_ = true;
close_reason cr;
- detail::read_close(cr, b, code);
- if(code != close_code::none)
+ detail::read_close(cr, b, result);
+ if(result)
{
// _Fail the WebSocket Connection_
- do_fail(code, error::failed, ec);
+ do_fail(close_code::protocol_error,
+ result, ec);
return bytes_written;
}
cr_ = cr;
@@ -1190,10 +1195,8 @@ loop:
! rd_utf8_.finish()))
{
// _Fail the WebSocket Connection_
- do_fail(
- close_code::bad_payload,
- error::failed,
- ec);
+ do_fail(close_code::bad_payload,
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
@@ -1227,7 +1230,7 @@ loop:
{
// _Fail the WebSocket Connection_
do_fail(close_code::bad_payload,
- error::failed, ec);
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
@@ -1325,7 +1328,7 @@ loop:
rd_size_, zs.total_out, rd_msg_max_))
{
do_fail(close_code::too_big,
- error::failed, ec);
+ error::message_too_big, ec);
return bytes_written;
}
cb.consume(zs.total_out);
@@ -1343,7 +1346,7 @@ loop:
{
// _Fail the WebSocket Connection_
do_fail(close_code::bad_payload,
- error::failed, ec);
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
diff --git a/include/boost/beast/websocket/impl/rfc6455.ipp b/include/boost/beast/websocket/impl/rfc6455.ipp
index d688b63d..07fdc306 100644
--- a/include/boost/beast/websocket/impl/rfc6455.ipp
+++ b/include/boost/beast/websocket/impl/rfc6455.ipp
@@ -26,9 +26,9 @@ is_upgrade(http::header::
parse_fh(
detail::frame_header& fh,
DynamicBuffer& b,
- close_code& code)
+ error_code& ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
- auto const err =
- [&](close_code cv)
- {
- code = cv;
- return false;
- };
if(buffer_size(b.data()) < 2)
{
- code = close_code::none;
+ // need more bytes
+ ec.assign(0, ec.category());
return false;
}
buffers_suffixrd_deflated(fh.rsv1))
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
break;
@@ -399,12 +397,14 @@ parse_fh(
if(! rd_cont_)
{
// continuation without an active message
- return err(close_code::protocol_error);
+ ec = error::bad_continuation;
+ return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
break;
@@ -412,31 +412,41 @@ parse_fh(
if(detail::is_reserved(fh.op))
{
// reserved opcode
- return err(close_code::protocol_error);
+ ec = error::bad_opcode;
+ return false;
}
if(! fh.fin)
{
// fragmented control message
- return err(close_code::protocol_error);
+ ec = error::bad_control_fragment;
+ return false;
}
if(fh.len > 125)
{
// invalid length for control message
- return err(close_code::protocol_error);
+ ec = error::bad_control_size;
+ return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
break;
}
- // unmasked frame from client
if(role_ == role_type::server && ! fh.mask)
- return err(close_code::protocol_error);
- // masked frame from server
+ {
+ // unmasked frame from client
+ ec = error::bad_unmasked_frame;
+ return false;
+ }
if(role_ == role_type::client && fh.mask)
- return err(close_code::protocol_error);
+ {
+ // masked frame from server
+ ec = error::bad_masked_frame;
+ return false;
+ }
if(detail::is_control(fh.op) &&
buffer_size(cb) < need + fh.len)
{
@@ -452,9 +462,12 @@ parse_fh(
BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
cb.consume(buffer_copy(buffer(tmp), cb));
fh.len = detail::big_uint16_to_native(&tmp[0]);
- // length not canonical
if(fh.len < 126)
- return err(close_code::protocol_error);
+ {
+ // length not canonical
+ ec = error::bad_size;
+ return false;
+ }
break;
}
case 127:
@@ -463,9 +476,12 @@ parse_fh(
BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
cb.consume(buffer_copy(buffer(tmp), cb));
fh.len = detail::big_uint64_to_native(&tmp[0]);
- // length not canonical
if(fh.len < 65536)
- return err(close_code::protocol_error);
+ {
+ // length not canonical
+ ec = error::bad_size;
+ return false;
+ }
break;
}
}
@@ -493,19 +509,27 @@ parse_fh(
{
if(rd_size_ > (std::numeric_limits<
std::uint64_t>::max)() - fh.len)
- return err(close_code::too_big);
+ {
+ // message size exceeds configured limit
+ ec = error::message_too_big;
+ return false;
+ }
}
if(! this->rd_deflated())
{
if(rd_msg_max_ && beast::detail::sum_exceeds(
rd_size_, fh.len, rd_msg_max_))
- return err(close_code::too_big);
+ {
+ // message size exceeds configured limit
+ ec = error::message_too_big;
+ return false;
+ }
}
rd_cont_ = ! fh.fin;
rd_remain_ = fh.len;
}
b.consume(b.size() - buffer_size(cb));
- code = close_code::none;
+ ec.assign(0, ec.category());
return true;
}
@@ -652,7 +676,8 @@ stream::
build_response(
http::request> const& req,
- Decorator const& decorator)
+ Decorator const& decorator,
+ error_code& result)
{
auto const decorate =
[&decorator](response_type& res)
@@ -666,40 +691,58 @@ build_response(
}
};
auto err =
- [&](std::string const& text)
+ [&](error e)
{
+ result = e;
response_type res;
res.version(req.version());
res.result(http::status::bad_request);
- res.body() = text;
+ res.body() = result.message();
res.prepare_payload();
decorate(res);
return res;
};
- if(req.version() < 11)
- return err("HTTP version 1.1 required");
+ if(req.version() != 11)
+ return err(error::bad_http_version);
if(req.method() != http::verb::get)
- return err("Wrong method");
- if(! is_upgrade(req))
- return err("Expected Upgrade request");
+ return err(error::bad_method);
if(! req.count(http::field::host))
- return err("Missing Host");
- if(! req.count(http::field::sec_websocket_key))
- return err("Missing Sec-WebSocket-Key");
- auto const key = req[http::field::sec_websocket_key];
- if(key.size() > detail::sec_ws_key_type::max_size_n)
- return err("Invalid Sec-WebSocket-Key");
+ return err(error::no_host);
{
- auto const version =
- req[http::field::sec_websocket_version];
- if(version.empty())
- return err("Missing Sec-WebSocket-Version");
- if(version != "13")
+ auto const it = req.find(http::field::connection);
+ if(it == req.end())
+ return err(error::no_connection);
+ if(! http::token_list{it->value()}.exists("upgrade"))
+ return err(error::no_connection_upgrade);
+ }
+ {
+ auto const it = req.find(http::field::upgrade);
+ if(it == req.end())
+ return err(error::no_upgrade);
+ if(! http::token_list{it->value()}.exists("websocket"))
+ return err(error::no_upgrade_websocket);
+ }
+ string_view key;
+ {
+ auto const it = req.find(http::field::sec_websocket_key);
+ if(it == req.end())
+ return err(error::no_sec_key);
+ key = it->value();
+ if(key.size() > detail::sec_ws_key_type::max_size_n)
+ return err(error::bad_sec_key);
+ }
+ {
+ auto const it = req.find(http::field::sec_websocket_version);
+ if(it == req.end())
+ return err(error::no_sec_version);
+ if(it->value() != "13")
{
response_type res;
res.result(http::status::upgrade_required);
res.version(req.version());
res.set(http::field::sec_websocket_version, "13");
+ result = error::bad_sec_version;
+ res.body() = result.message();
res.prepare_payload();
decorate(res);
return res;
@@ -707,7 +750,6 @@ build_response(
}
response_type res;
- build_response_pmd(res, req, is_deflate_supported{});
res.result(http::status::switching_protocols);
res.version(req.version());
res.set(http::field::upgrade, "websocket");
@@ -717,7 +759,9 @@ build_response(
detail::make_sec_ws_accept(acc, key);
res.set(http::field::sec_websocket_accept, acc);
}
+ build_response_pmd(res, req, is_deflate_supported{});
decorate(res);
+ result = {};
return res;
}
@@ -747,30 +791,39 @@ on_response(
detail::sec_ws_key_type const& key,
error_code& ec)
{
- bool const success = [&]()
+ auto const err =
+ [&](error e)
+ {
+ ec = e;
+ };
+ if(res.result() != http::status::switching_protocols)
+ return err(error::upgrade_declined);
+ if(res.version() != 11)
+ return err(error::bad_http_version);
{
- if(res.version() < 11)
- return false;
- if(res.result() != http::status::switching_protocols)
- return false;
- if(! http::token_list{res[http::field::connection]}.exists("upgrade"))
- return false;
- if(! http::token_list{res[http::field::upgrade]}.exists("websocket"))
- return false;
- if(res.count(http::field::sec_websocket_accept) != 1)
- return false;
+ auto const it = res.find(http::field::connection);
+ if(it == res.end())
+ return err(error::no_connection);
+ if(! http::token_list{it->value()}.exists("upgrade"))
+ return err(error::no_connection_upgrade);
+ }
+ {
+ auto const it = res.find(http::field::upgrade);
+ if(it == res.end())
+ return err(error::no_upgrade);
+ if(! http::token_list{it->value()}.exists("websocket"))
+ return err(error::no_upgrade_websocket);
+ }
+ {
+ auto const it = res.find(http::field::sec_websocket_accept);
+ if(it == res.end())
+ return err(error::no_sec_accept);
detail::sec_ws_accept_type acc;
detail::make_sec_ws_accept(acc, key);
- if(acc.compare(
- res[http::field::sec_websocket_accept]) != 0)
- return false;
- return true;
- }();
- if(! success)
- {
- ec = error::handshake_failed;
- return;
+ if(acc.compare(it->value()) != 0)
+ return err(error::bad_sec_accept);
}
+
ec.assign(0, ec.category());
on_response_pmd(res, is_deflate_supported{});
open(role_type::client);
diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp
index 46090d93..9706d75d 100644
--- a/include/boost/beast/websocket/stream.hpp
+++ b/include/boost/beast/websocket/stream.hpp
@@ -3446,8 +3446,10 @@ private:
template
bool
- parse_fh(detail::frame_header& fh,
- DynamicBuffer& b, close_code& code);
+ parse_fh(
+ detail::frame_header& fh,
+ DynamicBuffer& b,
+ error_code& ec);
template
void
@@ -3483,7 +3485,8 @@ private:
build_response(
http::request> const& req,
- Decorator const& decorator);
+ Decorator const& decorator,
+ error_code& ec);
template
void
diff --git a/test/beast/websocket/accept.cpp b/test/beast/websocket/accept.cpp
index 71ae0768..18c3cf08 100644
--- a/test/beast/websocket/accept.cpp
+++ b/test/beast/websocket/accept.cpp
@@ -406,7 +406,7 @@ public:
catch(system_error const& e)
{
if( e.code() !=
- websocket::error::handshake_failed &&
+ websocket::error::no_sec_key &&
e.code() !=
boost::asio::error::eof)
throw;
@@ -483,8 +483,8 @@ public:
}
};
- // wrong version
- check(error::handshake_failed,
+ // bad version
+ check(error::bad_http_version,
"GET / HTTP/1.0\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
@@ -493,8 +493,8 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // wrong method
- check(error::handshake_failed,
+ // bad method
+ check(error::bad_method,
"POST / HTTP/1.1\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
@@ -503,8 +503,8 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // missing Host
- check(error::handshake_failed,
+ // no Host
+ check(error::no_host,
"GET / HTTP/1.1\r\n"
"Upgrade: WebSocket\r\n"
"Connection: keep-alive,upgrade\r\n"
@@ -512,46 +512,17 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // missing Sec-WebSocket-Key
- check(error::handshake_failed,
+ // no Connection
+ check(error::no_connection,
"GET / HTTP/1.1\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
- "Connection: keep-alive,upgrade\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n"
- );
- // missing Sec-WebSocket-Version
- check(error::handshake_failed,
- "GET / HTTP/1.1\r\n"
- "Host: localhost:80\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: keep-alive,upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "\r\n"
- );
- // wrong Sec-WebSocket-Version
- check(error::handshake_failed,
- "GET / HTTP/1.1\r\n"
- "Host: localhost:80\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: keep-alive,upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Version: 1\r\n"
- "\r\n"
- );
- // missing upgrade token
- check(error::handshake_failed,
- "GET / HTTP/1.1\r\n"
- "Host: localhost:80\r\n"
- "Upgrade: HTTP/2\r\n"
- "Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // missing connection token
- check(error::handshake_failed,
+ // no Connection upgrade
+ check(error::no_connection_upgrade,
"GET / HTTP/1.1\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
@@ -560,8 +531,36 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // oversize key
- check(error::handshake_failed,
+ // no Upgrade
+ check(error::no_upgrade,
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost:80\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
+ // no Upgrade websocket
+ check(error::no_upgrade_websocket,
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost:80\r\n"
+ "Upgrade: HTTP/2\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
+ // no Sec-WebSocket-Key
+ check(error::no_sec_key,
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost:80\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: keep-alive,upgrade\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
+ // bad Sec-WebSocket-Key
+ check(error::bad_sec_key,
"GET / HTTP/1.1\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
@@ -570,8 +569,27 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // bad version
- check(error::handshake_failed,
+ // no Sec-WebSocket-Version
+ check(error::no_sec_version,
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost:80\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: keep-alive,upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "\r\n"
+ );
+ // bad Sec-WebSocket-Version
+ check(error::bad_sec_version,
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost:80\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: keep-alive,upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 1\r\n"
+ "\r\n"
+ );
+ // bad Sec-WebSocket-Version
+ check(error::bad_sec_version,
"GET / HTTP/1.1\r\n"
"Host: localhost:80\r\n"
"Upgrade: WebSocket\r\n"
@@ -580,15 +598,6 @@ public:
"Sec-WebSocket-Version: 12\r\n"
"\r\n"
);
- // missing version
- check(error::handshake_failed,
- "GET / HTTP/1.1\r\n"
- "Host: localhost:80\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "\r\n"
- );
// valid request
check({},
"GET / HTTP/1.1\r\n"
diff --git a/test/beast/websocket/close.cpp b/test/beast/websocket/close.cpp
index 2c215206..cc896d4a 100644
--- a/test/beast/websocket/close.cpp
+++ b/test/beast/websocket/close.cpp
@@ -108,7 +108,7 @@ public:
catch(system_error const& se)
{
BEAST_EXPECTS(
- se.code() == error::failed,
+ se.code() == error::bad_masked_frame,
se.code().message());
}
}
@@ -128,7 +128,7 @@ public:
catch(system_error const& se)
{
BEAST_EXPECTS(
- se.code() == error::failed,
+ se.code() == error::bad_close_size,
se.code().message());
}
}
@@ -292,7 +292,7 @@ public:
ws.async_read(b,
[&](error_code ec, std::size_t)
{
- if(ec != error::failed)
+ if(ec != error::bad_control_fragment)
BOOST_THROW_EXCEPTION(
system_error{ec});
BEAST_EXPECT(++count == 1);
diff --git a/test/beast/websocket/error.cpp b/test/beast/websocket/error.cpp
index ff89071e..61632c20 100644
--- a/test/beast/websocket/error.cpp
+++ b/test/beast/websocket/error.cpp
@@ -25,32 +25,53 @@ public:
auto const ec = make_error_code(e);
ec.category().name();
BEAST_EXPECT(! ec.message().empty());
-#if 0
- BEAST_EXPECT(std::addressof(ec.category()) ==
- std::addressof(detail::get_error_category()));
- BEAST_EXPECT(detail::get_error_category().equivalent(
- static_cast::type>(e),
- ec.category().default_error_condition(
- static_cast::type>(e))));
- BEAST_EXPECT(detail::get_error_category().equivalent(
- ec, static_cast::type>(e)));
-#endif
+ BEAST_EXPECT(ec != condition::handshake_failed);
+ BEAST_EXPECT(ec != condition::protocol_violation);
}
- void check(error e, condition c)
+ void check(condition c, error e)
{
- BEAST_EXPECT(error_code{e} == c);
+ auto const ec = make_error_code(e);
+ BEAST_EXPECT(ec.category().name() != nullptr);
+ BEAST_EXPECT(! ec.message().empty());
+ BEAST_EXPECT(ec == c);
}
void run() override
{
check(error::closed);
- check(error::failed);
- check(error::handshake_failed);
check(error::buffer_overflow);
check(error::partial_deflate_block);
+ check(error::message_too_big);
- check(error::handshake_failed, condition::handshake_failed);
+ check(condition::protocol_violation, error::bad_opcode);
+ check(condition::protocol_violation, error::bad_data_frame);
+ check(condition::protocol_violation, error::bad_continuation);
+ check(condition::protocol_violation, error::bad_reserved_bits);
+ check(condition::protocol_violation, error::bad_control_fragment);
+ check(condition::protocol_violation, error::bad_control_size);
+ check(condition::protocol_violation, error::bad_unmasked_frame);
+ check(condition::protocol_violation, error::bad_masked_frame);
+ check(condition::protocol_violation, error::bad_size);
+ check(condition::protocol_violation, error::bad_frame_payload);
+ check(condition::protocol_violation, error::bad_close_code);
+ check(condition::protocol_violation, error::bad_close_size);
+ check(condition::protocol_violation, error::bad_close_payload);
+
+ check(condition::handshake_failed, error::bad_http_version);
+ check(condition::handshake_failed, error::bad_method);
+ check(condition::handshake_failed, error::no_host);
+ check(condition::handshake_failed, error::no_connection);
+ check(condition::handshake_failed, error::no_connection_upgrade);
+ check(condition::handshake_failed, error::no_upgrade);
+ check(condition::handshake_failed, error::no_upgrade_websocket);
+ check(condition::handshake_failed, error::no_sec_key);
+ check(condition::handshake_failed, error::bad_sec_key);
+ check(condition::handshake_failed, error::no_sec_version);
+ check(condition::handshake_failed, error::bad_sec_version);
+ check(condition::handshake_failed, error::no_sec_accept);
+ check(condition::handshake_failed, error::bad_sec_accept);
+ check(condition::handshake_failed, error::upgrade_declined);
}
};
diff --git a/test/beast/websocket/handshake.cpp b/test/beast/websocket/handshake.cpp
index acf27f91..48ef70af 100644
--- a/test/beast/websocket/handshake.cpp
+++ b/test/beast/websocket/handshake.cpp
@@ -137,7 +137,7 @@ public:
});
auto const check =
- [&](std::string const& s)
+ [&](error e, std::string const& s)
{
stream ws{ioc_};
auto tr = connect(ws.next_layer());
@@ -150,11 +150,11 @@ public:
}
catch(system_error const& se)
{
- BEAST_EXPECT(se.code() == error::handshake_failed);
+ BEAST_EXPECTS(se.code() == e, se.what());
}
};
- // wrong HTTP version
- check(
+ // bad HTTP version
+ check(error::bad_http_version,
"HTTP/1.0 101 Switching Protocols\r\n"
"Server: beast\r\n"
"Upgrade: WebSocket\r\n"
@@ -163,28 +163,17 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // wrong status
- check(
- "HTTP/1.1 200 OK\r\n"
- "Server: beast\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n"
- );
- // missing upgrade token
- check(
+ // no Connection
+ check(error::no_connection,
"HTTP/1.1 101 Switching Protocols\r\n"
"Server: beast\r\n"
- "Upgrade: HTTP/2\r\n"
- "Connection: upgrade\r\n"
+ "Upgrade: WebSocket\r\n"
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // missing connection token
- check(
+ // no Connection upgrade
+ check(error::no_connection_upgrade,
"HTTP/1.1 101 Switching Protocols\r\n"
"Server: beast\r\n"
"Upgrade: WebSocket\r\n"
@@ -193,8 +182,27 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // missing accept key
- check(
+ // no Upgrade
+ check(error::no_upgrade,
+ "HTTP/1.1 101 Switching Protocols\r\n"
+ "Server: beast\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
+ // no Upgrade websocket
+ check(error::no_upgrade_websocket,
+ "HTTP/1.1 101 Switching Protocols\r\n"
+ "Server: beast\r\n"
+ "Upgrade: HTTP/2\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
+ // no Sec-WebSocket-Accept
+ check(error::no_sec_accept,
"HTTP/1.1 101 Switching Protocols\r\n"
"Server: beast\r\n"
"Upgrade: WebSocket\r\n"
@@ -202,8 +210,8 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
- // wrong accept key
- check(
+ // bad Sec-WebSocket-Accept
+ check(error::bad_sec_accept,
"HTTP/1.1 101 Switching Protocols\r\n"
"Server: beast\r\n"
"Upgrade: WebSocket\r\n"
@@ -212,6 +220,16 @@ public:
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+ // declined
+ check(error::upgrade_declined,
+ "HTTP/1.1 200 OK\r\n"
+ "Server: beast\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ );
}
// Compression Extensions for WebSocket
diff --git a/test/beast/websocket/ping.cpp b/test/beast/websocket/ping.cpp
index 4c467816..9cbb0a99 100644
--- a/test/beast/websocket/ping.cpp
+++ b/test/beast/websocket/ping.cpp
@@ -218,7 +218,7 @@ public:
[&](error_code ec, std::size_t)
{
++count;
- if(ec != error::failed)
+ if(ec != error::bad_control_fragment)
BOOST_THROW_EXCEPTION(
system_error{ec});
});
diff --git a/test/beast/websocket/read1.cpp b/test/beast/websocket/read1.cpp
index a8930bfc..c34df34b 100644
--- a/test/beast/websocket/read1.cpp
+++ b/test/beast/websocket/read1.cpp
@@ -317,7 +317,7 @@ public:
{
put(ws.next_layer().buffer(), cbuf(
0x88, 0x02, 0x03, 0xed));
- doFailTest(w, ws, error::failed);
+ doFailTest(w, ws, error::bad_close_code);
});
// message size above 2^64
@@ -337,7 +337,7 @@ public:
{
ws.read_message_max(1);
w.write(ws, sbuf("**"));
- doFailTest(w, ws, error::failed);
+ doFailTest(w, ws, error::message_too_big);
});
// bad utf8
@@ -346,7 +346,7 @@ public:
{
put(ws.next_layer().buffer(), cbuf(
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
- doFailTest(w, ws, error::failed);
+ doFailTest(w, ws, error::bad_frame_payload);
});
// incomplete utf8
@@ -378,7 +378,7 @@ public:
}
catch(system_error const& se)
{
- if(se.code() != error::failed)
+ if(se.code() != error::bad_frame_payload)
throw;
}
});
@@ -409,15 +409,15 @@ public:
};
// payload length 1
- check(error::failed,
+ check(error::bad_close_size,
"\x88\x01\x01");
// invalid close code 1005
- check(error::failed,
+ check(error::bad_close_code,
"\x88\x02\x03\xed");
// invalid utf8
- check(error::failed,
+ check(error::bad_close_payload,
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
// good utf8
@@ -446,7 +446,7 @@ public:
std::string const s = std::string(128, '*');
w.write(ws, buffer(s));
ws.read_message_max(32);
- doFailTest(w, ws, error::failed);
+ doFailTest(w, ws, error::message_too_big);
});
// invalid inflate block
@@ -656,15 +656,15 @@ public:
};
// payload length 1
- check(error::failed,
+ check(error::bad_close_size,
"\x88\x01\x01");
// invalid close code 1005
- check(error::failed,
+ check(error::bad_close_code,
"\x88\x02\x03\xed");
// invalid utf8
- check(error::failed,
+ check(error::bad_close_payload,
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
// good utf8