WebSocket refactoring and tests:

websocket:

* Move echo server to test/
* Fix warnings
* Fix maskgen being uncopyable
* Simplify utf8_checker special member declarations
* Fix stream move assignable when owning the next layer
* Add javadocs for stream special members
* Add stream unit tests
* Move throwing member definitions to the .ipp file
* Use get_lowest_layer in stream declaration
* Perform type checks at each call site instead of constructor
* Demote close_code to a non-class enum:
    Otherwise, application specific close codes
    cannot be assigned without using static_cast.

core:

* Add streambuf_readstream special members tests
* Add move assignment operator to streambuf_readstream
* Add detail/get_lowest_layer trait
* Add static_string tests
* Move static_string from websocket to core
This commit is contained in:
Vinnie Falco
2016-04-30 13:00:33 -04:00
parent 47dc31d8c2
commit 9390eb016c
38 changed files with 1792 additions and 567 deletions

View File

@@ -124,7 +124,7 @@ operator()(error_code const& ec,
case 0:
// read message
d.state = 1;
http::async_read(d.ws.next_layer_,
http::async_read(d.ws.next_layer(),
d.ws.stream_.buffer(), d.req,
std::move(*this));
return;

View File

@@ -134,7 +134,7 @@ stream<NextLayer>::handshake_op<
case 1:
// read http response
d.state = 2;
http::async_read(d.ws.next_layer_,
http::async_read(d.ws.next_layer(),
d.ws.stream_.buffer(), d.resp,
std::move(*this));
return;

View File

@@ -132,7 +132,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
{
auto& d = *d_;
d.cont = d.cont || again;
close_code code;
close_code::value code = close_code::none;
while(! ec && d.state != 99)
{
switch(d.state)
@@ -195,7 +195,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
d.state = 4;
break;
}
// call handler
case 4:
d.state = 99;
@@ -397,7 +397,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
case 11:
d.state = 12;
wsproto_helpers::call_async_teardown(
d.ws.next_layer_, std::move(*this));
d.ws.next_layer(), std::move(*this));
return;
case 12:
@@ -483,7 +483,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
case 19:
d.state = 20;
wsproto_helpers::call_async_teardown(
d.ws.next_layer_, std::move(*this));
d.ws.next_layer(), std::move(*this));
return;
case 20:

View File

@@ -113,7 +113,7 @@ operator()(error_code ec, bool again)
case 0:
// send response
d.state = 1;
http::async_write(d.ws.next_layer_,
http::async_write(d.ws.next_layer(),
d.resp, std::move(*this));
return;

View File

@@ -41,7 +41,7 @@ namespace detail {
template<class _>
void
stream_base::prepare_fh(close_code& code)
stream_base::prepare_fh(close_code::value& code)
{
// continuation without an active message
if(! rd_cont_ && rd_fh_.op == opcode::cont)
@@ -170,11 +170,20 @@ template<class NextLayer>
template<class... Args>
stream<NextLayer>::
stream(Args&&... args)
: next_layer_(std::forward<Args>(args)...)
, stream_(next_layer_)
: stream_(std::forward<Args>(args)...)
{
static_assert(is_Stream<next_layer_type>::value,
"Stream requirements not met");
}
template<class NextLayer>
void
stream<NextLayer>::
accept()
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
accept(boost::asio::null_buffers{}, ec);
detail::maybe_throw(ec, "accept");
}
template<class NextLayer>
@@ -182,6 +191,8 @@ void
stream<NextLayer>::
accept(error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
accept(boost::asio::null_buffers{}, ec);
}
@@ -192,6 +203,8 @@ typename async_completion<
stream<NextLayer>::
async_accept(AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
return async_accept(boost::asio::null_buffers{},
std::forward<AcceptHandler>(handler));
}
@@ -202,6 +215,8 @@ void
stream<NextLayer>::
accept(ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -216,6 +231,8 @@ void
stream<NextLayer>::
accept(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -225,7 +242,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
stream_.buffer().prepare(
buffer_size(buffers)), buffers));
http::request<http::empty_body> m;
http::read(next_layer_, stream_.buffer(), m, ec);
http::read(next_layer(), stream_.buffer(), m, ec);
if(ec)
return;
accept(m, ec);
@@ -238,6 +255,8 @@ typename async_completion<
stream<NextLayer>::
async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -255,6 +274,8 @@ void
stream<NextLayer>::
accept(http::message<true, Body, Headers> const& request)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
accept(request, ec);
detail::maybe_throw(ec, "accept");
@@ -267,6 +288,8 @@ stream<NextLayer>::
accept(http::message<true, Body, Headers> const& req,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
auto resp = build_response(req);
http::write(stream_, resp, ec);
if(resp.status != 101)
@@ -287,6 +310,8 @@ stream<NextLayer>::
async_accept(http::message<true, Body, Headers> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
beast::async_completion<
AcceptHandler, void(error_code)
> completion(handler);
@@ -297,19 +322,34 @@ async_accept(http::message<true, Body, Headers> const& req,
return completion.result.get();
}
template<class NextLayer>
void
stream<NextLayer>::
handshake(boost::string_ref const& host,
boost::string_ref const& resource)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
handshake(host, resource, ec);
detail::maybe_throw(ec, "upgrade");
}
template<class NextLayer>
void
stream<NextLayer>::
handshake(boost::string_ref const& host,
boost::string_ref const& resource, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
std::string key;
http::write(stream_,
build_request(host, resource, key), ec);
if(ec)
return;
http::response<http::string_body> resp;
http::read(next_layer_, stream_.buffer(), resp, ec);
http::read(next_layer(), stream_.buffer(), resp, ec);
if(ec)
return;
do_response(resp, key, ec);
@@ -323,6 +363,8 @@ stream<NextLayer>::
async_handshake(boost::string_ref const& host,
boost::string_ref const& resource, HandshakeHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements not met");
beast::async_completion<
HandshakeHandler, void(error_code)
> completion(handler);
@@ -331,11 +373,25 @@ async_handshake(boost::string_ref const& host,
return completion.result.get();
}
template<class NextLayer>
void
stream<NextLayer>::
close(close_reason const& cr)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
close(cr, ec);
detail::maybe_throw(ec, "close");
}
template<class NextLayer>
void
stream<NextLayer>::
close(close_reason const& cr, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
assert(! wr_close_);
wr_close_ = true;
detail::frame_streambuf fb;
@@ -351,6 +407,8 @@ typename async_completion<
stream<NextLayer>::
async_close(close_reason const& cr, CloseHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements not met");
beast::async_completion<
CloseHandler, void(error_code)
> completion(handler);
@@ -359,12 +417,27 @@ async_close(close_reason const& cr, CloseHandler&& handler)
return completion.result.get();
}
template<class NextLayer>
template<class Streambuf>
void
stream<NextLayer>::
read(opcode& op, Streambuf& streambuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
read(op, streambuf, ec);
detail::maybe_throw(ec, "read");
}
template<class NextLayer>
template<class Streambuf>
void
stream<NextLayer>::
read(opcode& op, Streambuf& streambuf, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
frame_info fi;
for(;;)
{
@@ -385,6 +458,8 @@ stream<NextLayer>::
async_read(opcode& op,
Streambuf& streambuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
beast::async_completion<
@@ -395,13 +470,28 @@ async_read(opcode& op,
return completion.result.get();
}
template<class NextLayer>
template<class Streambuf>
void
stream<NextLayer>::
read_frame(frame_info& fi, Streambuf& streambuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
read_frame(fi, streambuf, ec);
detail::maybe_throw(ec, "read_some");
}
template<class NextLayer>
template<class Streambuf>
void
stream<NextLayer>::
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
{
close_code code{};
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
close_code::value code{};
for(;;)
{
if(rd_need_ == 0)
@@ -409,7 +499,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
// read header
detail::frame_streambuf fb;
do_read_fh(fb, code, ec);
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
if(code != close_code::none)
break;
@@ -421,7 +512,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
auto const mb = fb.prepare(
static_cast<std::size_t>(rd_fh_.len));
fb.commit(boost::asio::read(stream_, mb, ec));
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
if(rd_fh_.mask)
detail::mask_inplace(mb, rd_key_);
@@ -437,7 +529,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
write_ping<static_streambuf>(
fb, opcode::pong, data);
boost::asio::write(stream_, fb.data(), ec);
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
continue;
}
@@ -445,7 +538,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
{
ping_payload_type data;
detail::read(data, fb.data(), code);
if((error_ = ec != 0))
if(code != close_code::none)
break;
// VFALCO How to notify callers using
// the synchronous interface?
@@ -466,7 +559,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
wr_close_ = true;
write_close<static_streambuf>(fb, cr);
boost::asio::write(stream_, fb.data(), ec);
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
}
break;
@@ -483,7 +577,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
detail::clamp(rd_need_));
auto const bytes_transferred =
stream_.read_some(smb, ec);
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
rd_need_ -= bytes_transferred;
auto const pb = prepare_buffers(
@@ -514,18 +609,20 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
detail::frame_streambuf fb;
write_close<static_streambuf>(fb, code);
boost::asio::write(stream_, fb.data(), ec);
if((error_ = ec != 0))
error_ = ec != 0;
if(error_)
return;
}
wsproto_helpers::call_teardown(next_layer_, ec);
if((error_ = ec != 0))
wsproto_helpers::call_teardown(next_layer(), ec);
error_ = ec != 0;
if(error_)
return;
ec = error::failed;
error_ = true;
return;
}
if(! ec)
wsproto_helpers::call_teardown(next_layer_, ec);
wsproto_helpers::call_teardown(next_layer(), ec);
if(! ec)
ec = error::closed;
error_ = ec != 0;
@@ -539,6 +636,8 @@ stream<NextLayer>::
async_read_frame(frame_info& fi,
Streambuf& streambuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
beast::async_completion<
@@ -548,12 +647,27 @@ async_read_frame(frame_info& fi,
return completion.result.get();
}
template<class NextLayer>
template<class ConstBufferSequence>
void
stream<NextLayer>::
write(ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
write(buffers, ec);
detail::maybe_throw(ec, "write");
}
template<class NextLayer>
template<class ConstBufferSequence>
void
stream<NextLayer>::
write(ConstBufferSequence const& bs, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -582,6 +696,8 @@ typename async_completion<
stream<NextLayer>::
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -592,12 +708,27 @@ async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
return completion.result.get();
}
template<class NextLayer>
template<class ConstBufferSequence>
void
stream<NextLayer>::
write_frame(bool fin, ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
write_frame(fin, buffers, ec);
detail::maybe_throw(ec, "write");
}
template<class NextLayer>
template<class ConstBufferSequence>
void
stream<NextLayer>::
write_frame(bool fin, ConstBufferSequence const& bs, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -678,6 +809,8 @@ stream<NextLayer>::
async_write_frame(bool fin,
ConstBufferSequence const& bs, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -792,7 +925,7 @@ template<class NextLayer>
void
stream<NextLayer>::
do_read_fh(detail::frame_streambuf& fb,
close_code& code, error_code& ec)
close_code::value& code, error_code& ec)
{
fb.commit(boost::asio::read(
stream_, fb.prepare(2), ec));

View File

@@ -61,7 +61,8 @@ class stream<NextLayer>::write_frame_op
fh.rsv2 = 0;
fh.rsv3 = 0;
fh.len = boost::asio::buffer_size(cb);
if((fh.mask = (ws.role_ == role_type::client)))
fh.mask = ws.role_ == role_type::client;
if(fh.mask)
{
fh.key = ws.maskgen_();
detail::prepare_key(key, fh.key);