mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
websocket read tests
This commit is contained in:
@@ -11,6 +11,7 @@ WebSocket:
|
|||||||
* Fix websocket close_op resume state
|
* Fix websocket close_op resume state
|
||||||
* websocket write tests
|
* websocket write tests
|
||||||
* split up websocket tests
|
* split up websocket tests
|
||||||
|
* websocket read tests
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@ public:
|
|||||||
const char*
|
const char*
|
||||||
name() const noexcept override
|
name() const noexcept override
|
||||||
{
|
{
|
||||||
return "beast.websocket";
|
return "boost.beast.websocket";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
@@ -38,13 +38,11 @@ public:
|
|||||||
{
|
{
|
||||||
switch(static_cast<error>(ev))
|
switch(static_cast<error>(ev))
|
||||||
{
|
{
|
||||||
case error::closed: return "WebSocket connection closed normally";
|
|
||||||
case error::failed: return "WebSocket connection failed due to a protocol violation";
|
|
||||||
case error::handshake_failed: return "WebSocket Upgrade handshake failed";
|
|
||||||
case error::buffer_overflow: return "buffer overflow";
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "beast.websocket error";
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -351,8 +351,7 @@ operator()(
|
|||||||
}
|
}
|
||||||
if(! ws_.pmd_ || ! ws_.pmd_->rd_set)
|
if(! ws_.pmd_ || ! ws_.pmd_->rd_set)
|
||||||
{
|
{
|
||||||
// Check for empty final frame
|
if(ws_.rd_.remain > 0)
|
||||||
if(ws_.rd_.remain > 0 || ! ws_.rd_.fh.fin)
|
|
||||||
{
|
{
|
||||||
if(ws_.rd_.buf.size() == 0 && ws_.rd_.buf.max_size() >
|
if(ws_.rd_.buf.size() == 0 && ws_.rd_.buf.max_size() >
|
||||||
(std::min)(clamp(ws_.rd_.remain),
|
(std::min)(clamp(ws_.rd_.remain),
|
||||||
@@ -589,13 +588,13 @@ template<
|
|||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
class Handler>
|
class Handler>
|
||||||
class stream<NextLayer>::read_op
|
class stream<NextLayer>::read_op
|
||||||
|
: public boost::asio::coroutine
|
||||||
{
|
{
|
||||||
Handler h_;
|
Handler h_;
|
||||||
stream<NextLayer>& ws_;
|
stream<NextLayer>& ws_;
|
||||||
DynamicBuffer& b_;
|
DynamicBuffer& b_;
|
||||||
std::size_t limit_;
|
std::size_t limit_;
|
||||||
std::size_t bytes_written_ = 0;
|
std::size_t bytes_written_ = 0;
|
||||||
int step_ = 0;
|
|
||||||
bool some_;
|
bool some_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -644,8 +643,8 @@ public:
|
|||||||
bool asio_handler_is_continuation(read_op* op)
|
bool asio_handler_is_continuation(read_op* op)
|
||||||
{
|
{
|
||||||
using boost::asio::asio_handler_is_continuation;
|
using boost::asio::asio_handler_is_continuation;
|
||||||
return op->step_ >= 2 ||
|
return asio_handler_is_continuation(
|
||||||
asio_handler_is_continuation(std::addressof(op->h_));
|
std::addressof(op->h_));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Function>
|
template<class Function>
|
||||||
@@ -668,54 +667,41 @@ operator()(
|
|||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
using beast::detail::clamp;
|
using beast::detail::clamp;
|
||||||
switch(ec ? 3 : step_)
|
using buffers_type = typename
|
||||||
|
DynamicBuffer::mutable_buffers_type;
|
||||||
|
boost::optional<buffers_type> mb;
|
||||||
|
BOOST_ASIO_CORO_REENTER(*this)
|
||||||
{
|
{
|
||||||
case 0:
|
do
|
||||||
{
|
|
||||||
if(ws_.failed_)
|
|
||||||
{
|
{
|
||||||
// Reads after failure are aborted
|
try
|
||||||
ec = boost::asio::error::operation_aborted;
|
{
|
||||||
break;
|
mb.emplace(b_.prepare(clamp(
|
||||||
|
ws_.read_size_hint(b_), limit_)));
|
||||||
|
}
|
||||||
|
catch(std::length_error const&)
|
||||||
|
{
|
||||||
|
ec = error::buffer_overflow;
|
||||||
|
}
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
ws_.get_io_service().post(
|
||||||
|
bind_handler(std::move(*this),
|
||||||
|
error::buffer_overflow, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
read_some_op<buffers_type, read_op>{
|
||||||
|
std::move(*this), ws_, *mb}();
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
b_.commit(bytes_transferred);
|
||||||
|
bytes_written_ += bytes_transferred;
|
||||||
}
|
}
|
||||||
step_ = 1;
|
while(! some_ && ! ws_.is_message_done());
|
||||||
do_read:
|
|
||||||
using buffers_type = typename
|
|
||||||
DynamicBuffer::mutable_buffers_type;
|
|
||||||
auto const size = clamp(
|
|
||||||
ws_.read_size_hint(b_), limit_);
|
|
||||||
boost::optional<buffers_type> mb;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mb.emplace(b_.prepare(size));
|
|
||||||
}
|
|
||||||
catch(std::length_error const&)
|
|
||||||
{
|
|
||||||
ec = error::buffer_overflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return read_some_op<buffers_type, read_op>{
|
|
||||||
std::move(*this), ws_, *mb}();
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
b_.commit(bytes_transferred);
|
|
||||||
bytes_written_ += bytes_transferred;
|
|
||||||
if(some_ || ws_.is_message_done())
|
|
||||||
break;
|
|
||||||
step_ = 2;
|
|
||||||
goto do_read;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(step_ == 0)
|
|
||||||
return ws_.get_io_service().post(
|
|
||||||
bind_handler(std::move(h_),
|
|
||||||
ec, bytes_written_));
|
|
||||||
else
|
|
||||||
h_(ec, bytes_written_);
|
h_(ec, bytes_written_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -747,12 +733,6 @@ read(DynamicBuffer& buffer, error_code& ec)
|
|||||||
"SyncStream requirements not met");
|
"SyncStream requirements not met");
|
||||||
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
// Make sure the stream is open
|
|
||||||
if(failed_)
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::operation_aborted;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
std::size_t bytes_written = 0;
|
std::size_t bytes_written = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -822,12 +802,6 @@ read_some(
|
|||||||
"SyncStream requirements not met");
|
"SyncStream requirements not met");
|
||||||
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
// Make sure the stream is open
|
|
||||||
if(failed_)
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::operation_aborted;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
using beast::detail::clamp;
|
using beast::detail::clamp;
|
||||||
if(! limit)
|
if(! limit)
|
||||||
limit = (std::numeric_limits<std::size_t>::max)();
|
limit = (std::numeric_limits<std::size_t>::max)();
|
||||||
@@ -1017,17 +991,12 @@ loop:
|
|||||||
rd_.buf.consume(len);
|
rd_.buf.consume(len);
|
||||||
if(ctrl_cb_)
|
if(ctrl_cb_)
|
||||||
ctrl_cb_(frame_type::close, cr_.reason);
|
ctrl_cb_(frame_type::close, cr_.reason);
|
||||||
if(! wr_close_)
|
BOOST_ASSERT(! wr_close_);
|
||||||
{
|
// _Start the WebSocket Closing Handshake_
|
||||||
// _Start the WebSocket Closing Handshake_
|
do_fail(
|
||||||
do_fail(
|
cr.code == close_code::none ?
|
||||||
cr.code == close_code::none ?
|
close_code::normal : cr.code,
|
||||||
close_code::normal : cr.code,
|
error::closed, ec);
|
||||||
error::closed, ec);
|
|
||||||
return bytes_written;
|
|
||||||
}
|
|
||||||
// _Close the WebSocket Connection_
|
|
||||||
do_fail(close_code::none, error::closed, ec);
|
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1044,8 +1013,7 @@ loop:
|
|||||||
}
|
}
|
||||||
if(! pmd_ || ! pmd_->rd_set)
|
if(! pmd_ || ! pmd_->rd_set)
|
||||||
{
|
{
|
||||||
// Check for empty final frame
|
if(rd_.remain > 0)
|
||||||
if(rd_.remain > 0 || ! rd_.fh.fin)
|
|
||||||
{
|
{
|
||||||
if(rd_.buf.size() == 0 && rd_.buf.max_size() >
|
if(rd_.buf.size() == 0 && rd_.buf.max_size() >
|
||||||
(std::min)(clamp(rd_.remain),
|
(std::min)(clamp(rd_.remain),
|
||||||
@@ -1116,10 +1084,8 @@ loop:
|
|||||||
! rd_.utf8.finish()))
|
! rd_.utf8.finish()))
|
||||||
{
|
{
|
||||||
// _Fail the WebSocket Connection_
|
// _Fail the WebSocket Connection_
|
||||||
do_fail(
|
do_fail(close_code::bad_payload,
|
||||||
close_code::bad_payload,
|
error::failed, ec);
|
||||||
error::failed,
|
|
||||||
ec);
|
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1226,10 +1192,8 @@ loop:
|
|||||||
if(rd_msg_max_ && beast::detail::sum_exceeds(
|
if(rd_msg_max_ && beast::detail::sum_exceeds(
|
||||||
rd_.size, zs.total_out, rd_msg_max_))
|
rd_.size, zs.total_out, rd_msg_max_))
|
||||||
{
|
{
|
||||||
do_fail(
|
do_fail(close_code::too_big,
|
||||||
close_code::too_big,
|
error::failed, ec);
|
||||||
error::failed,
|
|
||||||
ec);
|
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
cb.consume(zs.total_out);
|
cb.consume(zs.total_out);
|
||||||
@@ -1246,10 +1210,8 @@ loop:
|
|||||||
rd_.done && ! rd_.utf8.finish()))
|
rd_.done && ! rd_.utf8.finish()))
|
||||||
{
|
{
|
||||||
// _Fail the WebSocket Connection_
|
// _Fail the WebSocket Connection_
|
||||||
do_fail(
|
do_fail(close_code::bad_payload,
|
||||||
close_code::bad_payload,
|
error::failed, ec);
|
||||||
error::failed,
|
|
||||||
ec);
|
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,12 +27,18 @@ public:
|
|||||||
pmd.client_enable = false;
|
pmd.client_enable = false;
|
||||||
pmd.server_enable = false;
|
pmd.server_enable = false;
|
||||||
|
|
||||||
// normal close
|
// close
|
||||||
doTest(pmd, [&](ws_type& ws)
|
doTest(pmd, [&](ws_type& ws)
|
||||||
{
|
{
|
||||||
w.close(ws, {});
|
w.close(ws, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// close with code
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.close(ws, close_code::going_away);
|
||||||
|
});
|
||||||
|
|
||||||
// double close
|
// double close
|
||||||
{
|
{
|
||||||
echo_server es{log};
|
echo_server es{log};
|
||||||
|
@@ -37,10 +37,10 @@ public:
|
|||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
check("beast.websocket", error::closed);
|
check("boost.beast.websocket", error::closed);
|
||||||
check("beast.websocket", error::failed);
|
check("boost.beast.websocket", error::failed);
|
||||||
check("beast.websocket", error::handshake_failed);
|
check("boost.beast.websocket", error::handshake_failed);
|
||||||
check("beast.websocket", error::buffer_overflow);
|
check("boost.beast.websocket", error::buffer_overflow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -19,18 +19,287 @@ namespace websocket {
|
|||||||
class stream_read_test : public websocket_test_suite
|
class stream_read_test : public websocket_test_suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
template<class Wrap>
|
||||||
|
void
|
||||||
|
doReadTest(
|
||||||
|
Wrap const& w,
|
||||||
|
ws_type& ws,
|
||||||
|
close_code code)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
fail("", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(system_error const& se)
|
||||||
|
{
|
||||||
|
if(se.code() != error::closed)
|
||||||
|
throw;
|
||||||
|
BEAST_EXPECT(
|
||||||
|
ws.reason().code == code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Wrap>
|
||||||
|
void
|
||||||
|
doFailTest(
|
||||||
|
Wrap const& w,
|
||||||
|
ws_type& ws,
|
||||||
|
error_code ev)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
fail("", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(system_error const& se)
|
||||||
|
{
|
||||||
|
if(se.code() != ev)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<class Wrap>
|
template<class Wrap>
|
||||||
void
|
void
|
||||||
doTestRead(Wrap const& w)
|
doTestRead(Wrap const& w)
|
||||||
{
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
|
||||||
permessage_deflate pmd;
|
permessage_deflate pmd;
|
||||||
pmd.client_enable = false;
|
pmd.client_enable = false;
|
||||||
pmd.server_enable = false;
|
pmd.server_enable = false;
|
||||||
|
|
||||||
// Read close frames
|
// empty, fragmented message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
{
|
{
|
||||||
// VFALCO What about asynchronous??
|
ws.next_layer().append(
|
||||||
|
string_view(
|
||||||
|
"\x01\x00" "\x80\x00", 4));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(b.size() == 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// two part message
|
||||||
|
// this triggers "fill the read buffer first"
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.write_raw(ws, sbuf(
|
||||||
|
"\x01\x81\xff\xff\xff\xff"));
|
||||||
|
w.write_raw(ws, sbuf(
|
||||||
|
"\xd5"));
|
||||||
|
w.write_raw(ws, sbuf(
|
||||||
|
"\x80\x81\xff\xff\xff\xff\xd5"));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "**");
|
||||||
|
});
|
||||||
|
|
||||||
|
// ping
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
put(ws.next_layer().buffer(), cbuf(
|
||||||
|
0x89, 0x00));
|
||||||
|
bool invoked = false;
|
||||||
|
auto cb = [&](frame_type kind, string_view)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(! invoked);
|
||||||
|
BEAST_EXPECT(kind == frame_type::ping);
|
||||||
|
invoked = true;
|
||||||
|
};
|
||||||
|
ws.control_callback(cb);
|
||||||
|
w.write(ws, sbuf("Hello"));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(invoked);
|
||||||
|
BEAST_EXPECT(ws.got_text());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
||||||
|
});
|
||||||
|
|
||||||
|
// ping
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
put(ws.next_layer().buffer(), cbuf(
|
||||||
|
0x88, 0x00));
|
||||||
|
bool invoked = false;
|
||||||
|
auto cb = [&](frame_type kind, string_view)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(! invoked);
|
||||||
|
BEAST_EXPECT(kind == frame_type::close);
|
||||||
|
invoked = true;
|
||||||
|
};
|
||||||
|
ws.control_callback(cb);
|
||||||
|
w.write(ws, sbuf("Hello"));
|
||||||
|
doReadTest(w, ws, close_code::none);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ping then message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
bool once = false;
|
||||||
|
auto cb =
|
||||||
|
[&](frame_type kind, string_view s)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(kind == frame_type::pong);
|
||||||
|
BEAST_EXPECT(! once);
|
||||||
|
once = true;
|
||||||
|
BEAST_EXPECT(s == "");
|
||||||
|
};
|
||||||
|
ws.control_callback(cb);
|
||||||
|
w.ping(ws, "");
|
||||||
|
ws.binary(true);
|
||||||
|
w.write(ws, sbuf("Hello"));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(once);
|
||||||
|
BEAST_EXPECT(ws.got_binary());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
||||||
|
});
|
||||||
|
|
||||||
|
// ping then fragmented message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
bool once = false;
|
||||||
|
auto cb =
|
||||||
|
[&](frame_type kind, string_view s)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(kind == frame_type::pong);
|
||||||
|
BEAST_EXPECT(! once);
|
||||||
|
once = true;
|
||||||
|
BEAST_EXPECT(s == "payload");
|
||||||
|
};
|
||||||
|
ws.control_callback(cb);
|
||||||
|
ws.ping("payload");
|
||||||
|
w.write_some(ws, false, sbuf("Hello, "));
|
||||||
|
w.write_some(ws, false, sbuf(""));
|
||||||
|
w.write_some(ws, true, sbuf("World!"));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(once);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "Hello, World!");
|
||||||
|
});
|
||||||
|
|
||||||
|
// already closed
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.close(ws, {});
|
||||||
|
multi_buffer b;
|
||||||
|
doFailTest(w, ws,
|
||||||
|
boost::asio::error::operation_aborted);
|
||||||
|
});
|
||||||
|
|
||||||
|
// buffer overflow
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "Hello, world!";
|
||||||
|
ws.auto_fragment(false);
|
||||||
|
ws.binary(false);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
multi_buffer b(3);
|
||||||
|
w.read(ws, b);
|
||||||
|
fail("", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(system_error const& se)
|
||||||
|
{
|
||||||
|
if(se.code() != error::buffer_overflow)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// bad utf8, big
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
auto const s = std::string(2000, '*') +
|
||||||
|
random_string();
|
||||||
|
ws.text(true);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
doReadTest(w, ws, close_code::bad_payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
// invalid fixed frame header
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.write_raw(ws, cbuf(
|
||||||
|
0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
|
||||||
|
doReadTest(w, ws, close_code::protocol_error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// receive bad close
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
put(ws.next_layer().buffer(), cbuf(
|
||||||
|
0x88, 0x02, 0x03, 0xed));
|
||||||
|
doFailTest(w, ws, error::failed);
|
||||||
|
});
|
||||||
|
|
||||||
|
// expected cont
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.write_some(ws, false, boost::asio::null_buffers{});
|
||||||
|
w.write_raw(ws, cbuf(
|
||||||
|
0x81, 0x80, 0xff, 0xff, 0xff, 0xff));
|
||||||
|
doReadTest(w, ws, close_code::protocol_error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// message size above 2^64
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.write_some(ws, false, sbuf("*"));
|
||||||
|
w.write_raw(ws, cbuf(
|
||||||
|
0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
|
||||||
|
doReadTest(w, ws, close_code::too_big);
|
||||||
|
});
|
||||||
|
|
||||||
|
// message size exceeds max
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
ws.read_message_max(1);
|
||||||
|
w.write(ws, sbuf("**"));
|
||||||
|
doFailTest(w, ws, error::failed);
|
||||||
|
});
|
||||||
|
|
||||||
|
// unexpected cont
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
w.write_raw(ws, cbuf(
|
||||||
|
0x80, 0x80, 0xff, 0xff, 0xff, 0xff));
|
||||||
|
doReadTest(w, ws, close_code::protocol_error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// bad utf8
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
put(ws.next_layer().buffer(), cbuf(
|
||||||
|
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
||||||
|
doFailTest(w, ws, error::failed);
|
||||||
|
});
|
||||||
|
|
||||||
|
// incomplete utf8
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s =
|
||||||
|
"Hello, world!" "\xc0";
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
doReadTest(w, ws, close_code::bad_payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
// incomplete utf8, big
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s =
|
||||||
|
random_string() +
|
||||||
|
"Hello, world!" "\xc0";
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
doReadTest(w, ws, close_code::bad_payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
// close frames
|
||||||
|
{
|
||||||
auto const check =
|
auto const check =
|
||||||
[&](error_code ev, string_view s)
|
[&](error_code ev, string_view s)
|
||||||
{
|
{
|
||||||
@@ -71,8 +340,24 @@ public:
|
|||||||
"\x88\x06\xfc\x15utf8");
|
"\x88\x06\xfc\x15utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// permessage-deflate
|
||||||
|
//
|
||||||
|
|
||||||
pmd.client_enable = true;
|
pmd.client_enable = true;
|
||||||
pmd.server_enable = true;
|
pmd.server_enable = true;
|
||||||
|
pmd.client_max_window_bits = 9;
|
||||||
|
pmd.server_max_window_bits = 9;
|
||||||
|
pmd.compLevel = 1;
|
||||||
|
|
||||||
|
// message size limit
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = std::string(128, '*');
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
ws.read_message_max(32);
|
||||||
|
doFailTest(w, ws, error::failed);
|
||||||
|
});
|
||||||
|
|
||||||
// invalid inflate block
|
// invalid inflate block
|
||||||
doTest(pmd, [&](ws_type& ws)
|
doTest(pmd, [&](ws_type& ws)
|
||||||
@@ -99,18 +384,136 @@ public:
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// no_context_takeover
|
||||||
|
pmd.server_no_context_takeover = true;
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
auto const& s = random_string();
|
||||||
|
ws.binary(true);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
pmd.client_no_context_takeover = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Wrap>
|
||||||
|
void
|
||||||
|
doTestRead(
|
||||||
|
permessage_deflate const& pmd,
|
||||||
|
Wrap const& w)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
|
||||||
|
// message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "Hello, world!";
|
||||||
|
ws.auto_fragment(false);
|
||||||
|
ws.binary(false);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(ws.got_text());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// empty message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "";
|
||||||
|
ws.text(true);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(ws.got_text());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// partial message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "Hello";
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
char buf[3];
|
||||||
|
auto const bytes_written =
|
||||||
|
w.read_some(ws, buffer(buf, sizeof(buf)));
|
||||||
|
BEAST_EXPECT(bytes_written > 0);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
string_view(buf, 3).substr(0, bytes_written) ==
|
||||||
|
s.substr(0, bytes_written));
|
||||||
|
});
|
||||||
|
|
||||||
|
// partial message, dynamic buffer
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "Hello, world!";
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
auto bytes_written =
|
||||||
|
w.read_some(ws, 3, b);
|
||||||
|
BEAST_EXPECT(bytes_written > 0);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) ==
|
||||||
|
s.substr(0, b.size()));
|
||||||
|
w.read_some(ws, 256, b);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// big message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
auto const& s = random_string();
|
||||||
|
ws.binary(true);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// message, bad utf8
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
std::string const s = "\x03\xea\xf0\x28\x8c\xbc";
|
||||||
|
ws.auto_fragment(false);
|
||||||
|
ws.text(true);
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
doReadTest(w, ws, close_code::bad_payload);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testRead()
|
testRead()
|
||||||
{
|
{
|
||||||
doTestRead(SyncClient{});
|
using boost::asio::buffer;
|
||||||
|
|
||||||
|
doTestRead(SyncClient{});
|
||||||
yield_to([&](yield_context yield)
|
yield_to([&](yield_context yield)
|
||||||
{
|
{
|
||||||
doTestRead(AsyncClient{yield});
|
doTestRead(AsyncClient{yield});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
permessage_deflate pmd;
|
||||||
|
pmd.client_enable = false;
|
||||||
|
pmd.server_enable = false;
|
||||||
|
doTestRead(pmd, SyncClient{});
|
||||||
|
yield_to([&](yield_context yield)
|
||||||
|
{
|
||||||
|
doTestRead(pmd, AsyncClient{yield});
|
||||||
|
});
|
||||||
|
|
||||||
|
pmd.client_enable = true;
|
||||||
|
pmd.server_enable = true;
|
||||||
|
pmd.client_max_window_bits = 9;
|
||||||
|
pmd.server_max_window_bits = 9;
|
||||||
|
pmd.compLevel = 1;
|
||||||
|
doTestRead(pmd, SyncClient{});
|
||||||
|
yield_to([&](yield_context yield)
|
||||||
|
{
|
||||||
|
doTestRead(pmd, AsyncClient{yield});
|
||||||
|
});
|
||||||
|
|
||||||
// Read close frames
|
// Read close frames
|
||||||
{
|
{
|
||||||
auto const check =
|
auto const check =
|
||||||
@@ -144,6 +547,39 @@ public:
|
|||||||
check(error::closed,
|
check(error::closed,
|
||||||
"\x88\x06\xfc\x15utf8");
|
"\x88\x06\xfc\x15utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// suspend on write
|
||||||
|
{
|
||||||
|
echo_server es{log};
|
||||||
|
error_code ec;
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
stream<test::stream> ws{ios};
|
||||||
|
ws.next_layer().connect(es.stream());
|
||||||
|
ws.handshake("localhost", "/", ec);
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
// insert a ping
|
||||||
|
ws.next_layer().append(string_view(
|
||||||
|
"\x89\x00", 2));
|
||||||
|
std::size_t count = 0;
|
||||||
|
multi_buffer b;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
ws.async_read(b,
|
||||||
|
[&](error_code ec, std::size_t)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
ws.async_write(buffer(s),
|
||||||
|
[&](error_code ec)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
});
|
||||||
|
BEAST_EXPECT(ws.wr_block_);
|
||||||
|
ios.run();
|
||||||
|
BEAST_EXPECT(count == 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -47,102 +47,6 @@ public:
|
|||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
|
|
||||||
// send empty message
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
ws.text(true);
|
|
||||||
w.write(ws, boost::asio::null_buffers{});
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
BEAST_EXPECT(ws.got_text());
|
|
||||||
BEAST_EXPECT(b.size() == 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// send message
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
ws.auto_fragment(false);
|
|
||||||
ws.binary(false);
|
|
||||||
w.write(ws, sbuf("Hello"));
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
BEAST_EXPECT(ws.got_text());
|
|
||||||
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
||||||
});
|
|
||||||
|
|
||||||
// read_some
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.write(ws, sbuf("Hello"));
|
|
||||||
char buf[10];
|
|
||||||
auto const bytes_written =
|
|
||||||
w.read_some(ws, buffer(buf, sizeof(buf)));
|
|
||||||
BEAST_EXPECT(bytes_written > 0);
|
|
||||||
buf[bytes_written] = 0;
|
|
||||||
BEAST_EXPECT(
|
|
||||||
string_view(buf).substr(0, bytes_written) ==
|
|
||||||
string_view("Hello").substr(0, bytes_written));
|
|
||||||
});
|
|
||||||
|
|
||||||
// close, no payload
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.close(ws, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
// close with code
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.close(ws, close_code::going_away);
|
|
||||||
});
|
|
||||||
|
|
||||||
// send ping and message
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
bool once = false;
|
|
||||||
auto cb =
|
|
||||||
[&](frame_type kind, string_view s)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT(kind == frame_type::pong);
|
|
||||||
BEAST_EXPECT(! once);
|
|
||||||
once = true;
|
|
||||||
BEAST_EXPECT(s == "");
|
|
||||||
};
|
|
||||||
ws.control_callback(cb);
|
|
||||||
w.ping(ws, "");
|
|
||||||
ws.binary(true);
|
|
||||||
w.write(ws, sbuf("Hello"));
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
BEAST_EXPECT(once);
|
|
||||||
BEAST_EXPECT(ws.got_binary());
|
|
||||||
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
||||||
});
|
|
||||||
|
|
||||||
// send ping and fragmented message
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
bool once = false;
|
|
||||||
auto cb =
|
|
||||||
[&](frame_type kind, string_view s)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT(kind == frame_type::pong);
|
|
||||||
BEAST_EXPECT(! once);
|
|
||||||
once = true;
|
|
||||||
BEAST_EXPECT(s == "payload");
|
|
||||||
};
|
|
||||||
ws.control_callback(cb);
|
|
||||||
ws.ping("payload");
|
|
||||||
w.write_some(ws, false, sbuf("Hello, "));
|
|
||||||
w.write_some(ws, false, sbuf(""));
|
|
||||||
w.write_some(ws, true, sbuf("World!"));
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
BEAST_EXPECT(once);
|
|
||||||
BEAST_EXPECT(to_string(b.data()) == "Hello, World!");
|
|
||||||
ws.control_callback();
|
|
||||||
});
|
|
||||||
|
|
||||||
// send pong
|
// send pong
|
||||||
doTest(pmd, [&](ws_type& ws)
|
doTest(pmd, [&](ws_type& ws)
|
||||||
{
|
{
|
||||||
@@ -170,109 +74,6 @@ public:
|
|||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
});
|
});
|
||||||
|
|
||||||
// unexpected cont
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.write_raw(ws, cbuf(
|
|
||||||
0x80, 0x80, 0xff, 0xff, 0xff, 0xff));
|
|
||||||
doCloseTest(w, ws, close_code::protocol_error);
|
|
||||||
});
|
|
||||||
|
|
||||||
// invalid fixed frame header
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.write_raw(ws, cbuf(
|
|
||||||
0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
|
|
||||||
doCloseTest(w, ws, close_code::protocol_error);
|
|
||||||
});
|
|
||||||
|
|
||||||
if(! pmd.client_enable)
|
|
||||||
{
|
|
||||||
// expected cont
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.write_some(ws, false, boost::asio::null_buffers{});
|
|
||||||
w.write_raw(ws, cbuf(
|
|
||||||
0x81, 0x80, 0xff, 0xff, 0xff, 0xff));
|
|
||||||
doCloseTest(w, ws, close_code::protocol_error);
|
|
||||||
});
|
|
||||||
|
|
||||||
// message size above 2^64
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
w.write_some(ws, false, cbuf(0x00));
|
|
||||||
w.write_raw(ws, cbuf(
|
|
||||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
|
|
||||||
doCloseTest(w, ws, close_code::too_big);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
// message size exceeds max
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
// VFALCO This was never implemented correctly
|
|
||||||
ws.read_message_max(1);
|
|
||||||
w.write(ws, cbuf(0x81, 0x02, '*', '*'));
|
|
||||||
doCloseTest(w, ws, close_code::too_big);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// receive ping
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
put(ws.next_layer().buffer(), cbuf(
|
|
||||||
0x89, 0x00));
|
|
||||||
bool invoked = false;
|
|
||||||
auto cb = [&](frame_type kind, string_view)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT(! invoked);
|
|
||||||
BEAST_EXPECT(kind == frame_type::ping);
|
|
||||||
invoked = true;
|
|
||||||
};
|
|
||||||
ws.control_callback(cb);
|
|
||||||
w.write(ws, sbuf("Hello"));
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
BEAST_EXPECT(invoked);
|
|
||||||
BEAST_EXPECT(ws.got_text());
|
|
||||||
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
||||||
});
|
|
||||||
|
|
||||||
// receive ping
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
put(ws.next_layer().buffer(), cbuf(
|
|
||||||
0x88, 0x00));
|
|
||||||
bool invoked = false;
|
|
||||||
auto cb = [&](frame_type kind, string_view)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT(! invoked);
|
|
||||||
BEAST_EXPECT(kind == frame_type::close);
|
|
||||||
invoked = true;
|
|
||||||
};
|
|
||||||
ws.control_callback(cb);
|
|
||||||
w.write(ws, sbuf("Hello"));
|
|
||||||
doCloseTest(w, ws, close_code::none);
|
|
||||||
});
|
|
||||||
|
|
||||||
// receive bad utf8
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
put(ws.next_layer().buffer(), cbuf(
|
|
||||||
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
|
||||||
doFailTest(w, ws, error::failed);
|
|
||||||
});
|
|
||||||
|
|
||||||
// receive bad close
|
|
||||||
doTest(pmd, [&](ws_type& ws)
|
|
||||||
{
|
|
||||||
put(ws.next_layer().buffer(), cbuf(
|
|
||||||
0x88, 0x02, 0x03, 0xed));
|
|
||||||
doFailTest(w, ws, error::failed);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@@ -303,6 +104,7 @@ public:
|
|||||||
|
|
||||||
testOptions();
|
testOptions();
|
||||||
|
|
||||||
|
#if 0
|
||||||
auto const testStream =
|
auto const testStream =
|
||||||
[this](permessage_deflate const& pmd)
|
[this](permessage_deflate const& pmd)
|
||||||
{
|
{
|
||||||
@@ -336,6 +138,7 @@ public:
|
|||||||
pmd.compLevel = 1;
|
pmd.compLevel = 1;
|
||||||
pmd.memLevel = 1;
|
pmd.memLevel = 1;
|
||||||
testStream(pmd);
|
testStream(pmd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -70,8 +70,9 @@ public:
|
|||||||
, ws_(ts_)
|
, ws_(ts_)
|
||||||
{
|
{
|
||||||
permessage_deflate pmd;
|
permessage_deflate pmd;
|
||||||
pmd.client_enable = true;
|
|
||||||
pmd.server_enable = true;
|
pmd.server_enable = true;
|
||||||
|
pmd.server_max_window_bits = 9;
|
||||||
|
pmd.compLevel = 1;
|
||||||
ws_.set_option(pmd);
|
ws_.set_option(pmd);
|
||||||
|
|
||||||
switch(k)
|
switch(k)
|
||||||
@@ -238,48 +239,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Wrap>
|
|
||||||
void
|
|
||||||
doCloseTest(
|
|
||||||
Wrap const& w,
|
|
||||||
ws_type& ws,
|
|
||||||
close_code code)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
fail("", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
catch(system_error const& se)
|
|
||||||
{
|
|
||||||
if(se.code() != error::closed)
|
|
||||||
throw;
|
|
||||||
BEAST_EXPECT(
|
|
||||||
ws.reason().code == code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Wrap>
|
|
||||||
void
|
|
||||||
doFailTest(
|
|
||||||
Wrap const& w,
|
|
||||||
ws_type& ws,
|
|
||||||
error_code ev)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
multi_buffer b;
|
|
||||||
w.read(ws, b);
|
|
||||||
fail("", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
catch(system_error const& se)
|
|
||||||
{
|
|
||||||
if(se.code() != ev)
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Test>
|
template<class Test>
|
||||||
void
|
void
|
||||||
doTestLoop(Test const& f)
|
doTestLoop(Test const& f)
|
||||||
|
@@ -23,10 +23,36 @@ public:
|
|||||||
void
|
void
|
||||||
doTestWrite(Wrap const& w)
|
doTestWrite(Wrap const& w)
|
||||||
{
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
|
||||||
permessage_deflate pmd;
|
permessage_deflate pmd;
|
||||||
pmd.client_enable = false;
|
pmd.client_enable = false;
|
||||||
pmd.server_enable = false;
|
pmd.server_enable = false;
|
||||||
|
|
||||||
|
// message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
ws.auto_fragment(false);
|
||||||
|
ws.binary(false);
|
||||||
|
std::string const s = "Hello, world!";
|
||||||
|
w.write(ws, buffer(s));
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(ws.got_text());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// empty message
|
||||||
|
doTest(pmd, [&](ws_type& ws)
|
||||||
|
{
|
||||||
|
ws.text(true);
|
||||||
|
w.write(ws, boost::asio::null_buffers{});
|
||||||
|
multi_buffer b;
|
||||||
|
w.read(ws, b);
|
||||||
|
BEAST_EXPECT(ws.got_text());
|
||||||
|
BEAST_EXPECT(b.size() == 0);
|
||||||
|
});
|
||||||
|
|
||||||
// continuation
|
// continuation
|
||||||
doTest(pmd, [&](ws_type& ws)
|
doTest(pmd, [&](ws_type& ws)
|
||||||
{
|
{
|
||||||
@@ -34,8 +60,8 @@ public:
|
|||||||
std::size_t const chop = 3;
|
std::size_t const chop = 3;
|
||||||
BOOST_ASSERT(chop < s.size());
|
BOOST_ASSERT(chop < s.size());
|
||||||
w.write_some(ws, false,
|
w.write_some(ws, false,
|
||||||
boost::asio::buffer(s.data(), chop));
|
buffer(s.data(), chop));
|
||||||
w.write_some(ws, true, boost::asio::buffer(
|
w.write_some(ws, true, buffer(
|
||||||
s.data() + chop, s.size() - chop));
|
s.data() + chop, s.size() - chop));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
@@ -47,7 +73,7 @@ public:
|
|||||||
{
|
{
|
||||||
ws.auto_fragment(false);
|
ws.auto_fragment(false);
|
||||||
std::string const s = "Hello";
|
std::string const s = "Hello";
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -59,7 +85,7 @@ public:
|
|||||||
ws.auto_fragment(false);
|
ws.auto_fragment(false);
|
||||||
ws.write_buffer_size(16);
|
ws.write_buffer_size(16);
|
||||||
std::string const s(32, '*');
|
std::string const s(32, '*');
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -70,7 +96,7 @@ public:
|
|||||||
{
|
{
|
||||||
ws.auto_fragment(true);
|
ws.auto_fragment(true);
|
||||||
std::string const s(16384, '*');
|
std::string const s(16384, '*');
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -88,7 +114,7 @@ public:
|
|||||||
w.accept(ws);
|
w.accept(ws);
|
||||||
ws.auto_fragment(false);
|
ws.auto_fragment(false);
|
||||||
std::string const s = "Hello";
|
std::string const s = "Hello";
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -114,7 +140,7 @@ public:
|
|||||||
w.accept(ws);
|
w.accept(ws);
|
||||||
ws.auto_fragment(true);
|
ws.auto_fragment(true);
|
||||||
std::string const s(16384, '*');
|
std::string const s(16384, '*');
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -130,13 +156,14 @@ public:
|
|||||||
|
|
||||||
pmd.client_enable = true;
|
pmd.client_enable = true;
|
||||||
pmd.server_enable = true;
|
pmd.server_enable = true;
|
||||||
|
pmd.compLevel = 1;
|
||||||
|
|
||||||
// deflate
|
// deflate
|
||||||
doTest(pmd, [&](ws_type& ws)
|
doTest(pmd, [&](ws_type& ws)
|
||||||
{
|
{
|
||||||
auto const& s = random_string();
|
auto const& s = random_string();
|
||||||
ws.binary(true);
|
ws.binary(true);
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -151,8 +178,8 @@ public:
|
|||||||
// This call should produce no
|
// This call should produce no
|
||||||
// output due to compression latency.
|
// output due to compression latency.
|
||||||
w.write_some(ws, false,
|
w.write_some(ws, false,
|
||||||
boost::asio::buffer(s.data(), chop));
|
buffer(s.data(), chop));
|
||||||
w.write_some(ws, true, boost::asio::buffer(
|
w.write_some(ws, true, buffer(
|
||||||
s.data() + chop, s.size() - chop));
|
s.data() + chop, s.size() - chop));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
@@ -165,7 +192,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto const& s = random_string();
|
auto const& s = random_string();
|
||||||
ws.binary(true);
|
ws.binary(true);
|
||||||
w.write(ws, boost::asio::buffer(s));
|
w.write(ws, buffer(s));
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
w.read(ws, b);
|
w.read(ws, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -175,6 +202,8 @@ public:
|
|||||||
void
|
void
|
||||||
testWrite()
|
testWrite()
|
||||||
{
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
|
||||||
doTestWrite(SyncClient{});
|
doTestWrite(SyncClient{});
|
||||||
|
|
||||||
yield_to([&](yield_context yield)
|
yield_to([&](yield_context yield)
|
||||||
@@ -249,7 +278,7 @@ public:
|
|||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
std::string const s(16384, '*');
|
std::string const s(16384, '*');
|
||||||
ws.auto_fragment(true);
|
ws.auto_fragment(true);
|
||||||
ws.async_write(boost::asio::buffer(s),
|
ws.async_write(buffer(s),
|
||||||
[&](error_code ec)
|
[&](error_code ec)
|
||||||
{
|
{
|
||||||
++count;
|
++count;
|
||||||
@@ -295,7 +324,7 @@ public:
|
|||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
std::string const s(16384, '*');
|
std::string const s(16384, '*');
|
||||||
ws.auto_fragment(true);
|
ws.auto_fragment(true);
|
||||||
ws.async_write(boost::asio::buffer(s),
|
ws.async_write(buffer(s),
|
||||||
[&](error_code ec)
|
[&](error_code ec)
|
||||||
{
|
{
|
||||||
++count;
|
++count;
|
||||||
@@ -338,6 +367,7 @@ public:
|
|||||||
{
|
{
|
||||||
permessage_deflate pmd;
|
permessage_deflate pmd;
|
||||||
pmd.client_enable = true;
|
pmd.client_enable = true;
|
||||||
|
pmd.compLevel = 1;
|
||||||
ws.set_option(pmd);
|
ws.set_option(pmd);
|
||||||
}
|
}
|
||||||
ws.next_layer().connect(es.stream());
|
ws.next_layer().connect(es.stream());
|
||||||
@@ -346,7 +376,7 @@ public:
|
|||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
auto const& s = random_string();
|
auto const& s = random_string();
|
||||||
ws.binary(true);
|
ws.binary(true);
|
||||||
ws.async_write(boost::asio::buffer(s),
|
ws.async_write(buffer(s),
|
||||||
[&](error_code ec)
|
[&](error_code ec)
|
||||||
{
|
{
|
||||||
++count;
|
++count;
|
||||||
|
Reference in New Issue
Block a user