Refactor WebSocket errors (API Change):

fix #949

* New error codes are introduced for WebSocket failures

* More verbose messages for error codes

* Error codes are mapped to conditions for ease of testing

* error::failed and error::handshake_failed are deprecated (don't use)

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.
This commit is contained in:
Vinnie Falco committed 2018-01-12 07:35:26 -08:00
1 parent 08a9ed4c25
commit cc43b46c42
19 files changed
+705 -346

No files matched your search

+62 -53
View File
@@ -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"
+3 -3
View File
@@ -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);
+36 -15
View File
@@ -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<std::underlying_type<error>::type>(e),
ec.category().default_error_condition(
static_cast<std::underlying_type<error>::type>(e))));
BEAST_EXPECT(detail::get_error_category().equivalent(
ec, static_cast<std::underlying_type<error>::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);
}
};
+42 -24
View File
@@ -137,7 +137,7 @@ public:
});
auto const check =
[&](std::string const& s)
[&](error e, std::string const& s)
{
stream<test::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
+1 -1
View File
@@ -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});
});
+11 -11
View File
@@ -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