Make websocket::close_code a proper enum:

fix #311

This changes close_code to be a proper enumeration.
This commit is contained in:
Vinnie Falco
2017-04-21 11:46:51 -07:00
parent bd4ad15856
commit 9774ed0e19
6 changed files with 109 additions and 71 deletions

View File

@@ -2,6 +2,7 @@
* Add Appveyor build scripts and badge * Add Appveyor build scripts and badge
* Tidy up MSVC CMake configuration * Tidy up MSVC CMake configuration
* Make close_code a proper enum
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -67,33 +67,31 @@ is_control(opcode op)
return op >= opcode::close; return op >= opcode::close;
} }
// Returns `true` if a close code is valid
inline inline
bool bool
is_valid(close_code::value code) is_valid_close_code(std::uint16_t v)
{ {
auto const v = code;
switch(v) switch(v)
{ {
case 1000: case close_code::normal: // 1000
case 1001: case close_code::going_away: // 1001
case 1002: case close_code::protocol_error: // 1002
case 1003: case close_code::unknown_data: // 1003
case 1007: case close_code::bad_payload: // 1007
case 1008: case close_code::policy_error: // 1008
case 1009: case close_code::too_big: // 1009
case 1010: case close_code::needs_extension: // 1010
case 1011: case close_code::internal_error: // 1011
case 1012: case close_code::service_restart: // 1012
case 1013: case close_code::try_again_later: // 1013
return true; return true;
// explicitly reserved // explicitly reserved
case 1004: case close_code::reserved1: // 1004
case 1005: case close_code::no_status: // 1005
case 1006: case close_code::abnormal: // 1006
case 1014: case close_code::reserved2: // 1014
case 1015: case close_code::reserved3: // 1015
return false; return false;
} }
// reserved // reserved
@@ -175,7 +173,7 @@ read(ping_data& data, Buffers const& bs)
template<class Buffers> template<class Buffers>
void void
read(close_reason& cr, read(close_reason& cr,
Buffers const& bs, close_code::value& code) Buffers const& bs, close_code& code)
{ {
using boost::asio::buffer; using boost::asio::buffer;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
@@ -201,7 +199,7 @@ read(close_reason& cr,
cr.code = big_uint16_to_native(&b[0]); cr.code = big_uint16_to_native(&b[0]);
cb.consume(2); cb.consume(2);
n -= 2; n -= 2;
if(! is_valid(cr.code)) if(! is_valid_close_code(cr.code))
{ {
code = close_code::protocol_error; code = close_code::protocol_error;
return; return;

View File

@@ -175,12 +175,12 @@ protected:
template<class DynamicBuffer> template<class DynamicBuffer>
std::size_t std::size_t
read_fh1(detail::frame_header& fh, read_fh1(detail::frame_header& fh,
DynamicBuffer& db, close_code::value& code); DynamicBuffer& db, close_code& code);
template<class DynamicBuffer> template<class DynamicBuffer>
void void
read_fh2(detail::frame_header& fh, read_fh2(detail::frame_header& fh,
DynamicBuffer& db, close_code::value& code); DynamicBuffer& db, close_code& code);
// Called before receiving the first frame of each message // Called before receiving the first frame of each message
template<class = void> template<class = void>
@@ -264,13 +264,13 @@ template<class DynamicBuffer>
std::size_t std::size_t
stream_base:: stream_base::
read_fh1(detail::frame_header& fh, read_fh1(detail::frame_header& fh,
DynamicBuffer& db, close_code::value& code) DynamicBuffer& db, close_code& code)
{ {
using boost::asio::buffer; using boost::asio::buffer;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
using boost::asio::buffer_size; using boost::asio::buffer_size;
auto const err = auto const err =
[&](close_code::value cv) [&](close_code cv)
{ {
code = cv; code = cv;
return 0; return 0;
@@ -372,7 +372,7 @@ template<class DynamicBuffer>
void void
stream_base:: stream_base::
read_fh2(detail::frame_header& fh, read_fh2(detail::frame_header& fh,
DynamicBuffer& db, close_code::value& code) DynamicBuffer& db, close_code& code)
{ {
using boost::asio::buffer; using boost::asio::buffer;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;

View File

@@ -173,7 +173,7 @@ operator()(error_code ec,
if(! ec) if(! ec)
{ {
d.cont = d.cont || again; d.cont = d.cont || again;
close_code::value code = close_code::none; close_code code = close_code::none;
do do
{ {
switch(d.state) switch(d.state)
@@ -727,7 +727,7 @@ read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
using boost::asio::buffer; using boost::asio::buffer;
using boost::asio::buffer_cast; using boost::asio::buffer_cast;
using boost::asio::buffer_size; using boost::asio::buffer_size;
close_code::value code{}; close_code code{};
for(;;) for(;;)
{ {
// Read frame header // Read frame header

View File

@@ -45,48 +45,87 @@ enum class opcode : std::uint8_t
@see <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 7.4.1 Defined Status Codes</a> @see <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 7.4.1 Defined Status Codes</a>
*/ */
#if GENERATING_DOCS
enum close_code enum close_code
#else
namespace close_code {
using value = std::uint16_t;
enum
#endif
{ {
/// used internally to mean "no error" /// Normal closure; the connection successfully completed whatever purpose for which it was created.
none = 0,
normal = 1000, normal = 1000,
/// The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.
going_away = 1001, going_away = 1001,
/// The endpoint is terminating the connection due to a protocol error.
protocol_error = 1002, protocol_error = 1002,
/// The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a text-only endpoint received binary data).
unknown_data = 1003, unknown_data = 1003,
/// Indicates a received close frame has no close code /// The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., non-UTF-8 data within a text message).
//no_code = 1005, // TODO
/// Indicates the connection was closed without receiving a close frame
no_close = 1006,
bad_payload = 1007, bad_payload = 1007,
/// The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
policy_error = 1008, policy_error = 1008,
/// The endpoint is terminating the connection because a data frame was received that is too large.
too_big = 1009, too_big = 1009,
/// The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.
needs_extension = 1010, needs_extension = 1010,
/// The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
internal_error = 1011, internal_error = 1011,
/// The server is terminating the connection because it is restarting.
service_restart = 1012, service_restart = 1012,
/// The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.
try_again_later = 1013, try_again_later = 1013,
reserved1 = 1004, //----
no_status = 1005, // illegal on wire //
abnormal = 1006, // illegal on wire // The following are illegal on the wire
reserved2 = 1015, //
last = 5000 // satisfy warnings /** Used internally to mean "no error"
This code is reserved and may not be sent.
*/
none = 0,
/** Reserved for future use by the WebSocket standard.
This code is reserved and may not be sent.
*/
reserved1 = 1004,
/** No status code was provided even though one was expected.
This code is reserved and may not be sent.
*/
no_status = 1005,
/** Connection was closed without receiving a close frame
This code is reserved and may not be sent.
*/
abnormal = 1006,
/** Reserved for future use by the WebSocket standard.
This code is reserved and may not be sent.
*/
reserved2 = 1014,
/** Reserved for future use by the WebSocket standard.
This code is reserved and may not be sent.
*/
reserved3 = 1015
//
//----
//last = 5000 // satisfy warnings
}; };
#if ! GENERATING_DOCS
} // close_code
#endif
/// The type representing the reason string in a close frame. /// The type representing the reason string in a close frame.
using reason_string = static_string<123, char>; using reason_string = static_string<123, char>;
@@ -102,7 +141,7 @@ using ping_data = static_string<125, char>;
struct close_reason struct close_reason
{ {
/// The close code. /// The close code.
close_code::value code = close_code::none; std::uint16_t code = close_code::none;
/// The optional utf8-encoded reason string. /// The optional utf8-encoded reason string.
reason_string reason; reason_string reason;
@@ -115,7 +154,7 @@ struct close_reason
close_reason() = default; close_reason() = default;
/// Construct from a code. /// Construct from a code.
close_reason(close_code::value code_) close_reason(std::uint16_t code_)
: code(code_) : code(code_)
{ {
} }
@@ -130,7 +169,7 @@ struct close_reason
/// Construct from a code and reason. /// Construct from a code and reason.
template<std::size_t N> template<std::size_t N>
close_reason(close_code::value code_, close_reason(close_code code_,
char const (&reason_)[N]) char const (&reason_)[N])
: code(code_) : code(code_)
, reason(reason_) , reason(reason_)

View File

@@ -35,20 +35,20 @@ class frame_test : public beast::unit_test::suite
public: public:
void testCloseCodes() void testCloseCodes()
{ {
BEAST_EXPECT(! is_valid(0)); BEAST_EXPECT(! is_valid_close_code(0));
BEAST_EXPECT(! is_valid(1)); BEAST_EXPECT(! is_valid_close_code(1));
BEAST_EXPECT(! is_valid(999)); BEAST_EXPECT(! is_valid_close_code(999));
BEAST_EXPECT(! is_valid(1004)); BEAST_EXPECT(! is_valid_close_code(1004));
BEAST_EXPECT(! is_valid(1005)); BEAST_EXPECT(! is_valid_close_code(1005));
BEAST_EXPECT(! is_valid(1006)); BEAST_EXPECT(! is_valid_close_code(1006));
BEAST_EXPECT(! is_valid(1016)); BEAST_EXPECT(! is_valid_close_code(1016));
BEAST_EXPECT(! is_valid(2000)); BEAST_EXPECT(! is_valid_close_code(2000));
BEAST_EXPECT(! is_valid(2999)); BEAST_EXPECT(! is_valid_close_code(2999));
BEAST_EXPECT(is_valid(1000)); BEAST_EXPECT(is_valid_close_code(1000));
BEAST_EXPECT(is_valid(1002)); BEAST_EXPECT(is_valid_close_code(1002));
BEAST_EXPECT(is_valid(3000)); BEAST_EXPECT(is_valid_close_code(3000));
BEAST_EXPECT(is_valid(4000)); BEAST_EXPECT(is_valid_close_code(4000));
BEAST_EXPECT(is_valid(5000)); BEAST_EXPECT(is_valid_close_code(5000));
} }
struct test_fh : frame_header struct test_fh : frame_header
@@ -77,7 +77,7 @@ public:
{ {
fh_streambuf sb; fh_streambuf sb;
write(sb, fh); write(sb, fh);
close_code::value code; close_code code;
stream_base stream; stream_base stream;
stream.open(role); stream.open(role);
detail::frame_header fh1; detail::frame_header fh1;
@@ -129,7 +129,7 @@ public:
{ {
fh_streambuf sb; fh_streambuf sb;
write(sb, fh); write(sb, fh);
close_code::value code; close_code code;
stream_base stream; stream_base stream;
stream.open(role); stream.open(role);
detail::frame_header fh1; detail::frame_header fh1;
@@ -197,7 +197,7 @@ public:
sb.commit(buffer_copy(sb.prepare(v.size()), buffer(v))); sb.commit(buffer_copy(sb.prepare(v.size()), buffer(v)));
stream_base stream; stream_base stream;
stream.open(role); stream.open(role);
close_code::value code; close_code code;
detail::frame_header fh; detail::frame_header fh;
auto const n = auto const n =
stream.read_fh1(fh, sb, code); stream.read_fh1(fh, sb, code);