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 committed 2017-07-20 08:12:05 -07:00
1 parent a0b04bdff2
commit 4104eca1f1
38 files changed
+1792 -567

No files matched your search

+10 -18
View File
@@ -9,11 +9,11 @@
#define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
#include <beast/websocket/rfc6455.hpp>
#include <beast/websocket/static_string.hpp>
#include <beast/websocket/detail/endian.hpp>
#include <beast/websocket/detail/utf8_checker.hpp>
#include <beast/consuming_buffers.hpp>
#include <beast/static_streambuf.hpp>
#include <beast/static_string.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/endian/buffers.hpp>
#include <cassert>
@@ -70,10 +70,9 @@ is_control(opcode op)
// Returns `true` if a close code is valid
inline
bool
is_valid(close_code code)
is_valid(close_code::value code)
{
auto const v = static_cast<
std::uint16_t>(code);
auto const v = code;
switch(v)
{
case 1000:
@@ -154,7 +153,7 @@ write(Streambuf& sb, frame_header const& fh)
template<class Streambuf>
std::size_t
read_fh1(frame_header& fh, Streambuf& sb,
role_type role, close_code& code)
role_type role, close_code::value& code)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -171,7 +170,8 @@ read_fh1(frame_header& fh, Streambuf& sb,
default:
need = 0;
}
if((fh.mask = (b[1] & 0x80) != 0))
fh.mask = (b[1] & 0x80) != 0;
if(fh.mask)
need += 4;
fh.op = static_cast<opcode>(b[0] & 0x0f);
fh.fin = (b[0] & 0x80) != 0;
@@ -230,7 +230,7 @@ read_fh1(frame_header& fh, Streambuf& sb,
template<class Streambuf>
void
read_fh2(frame_header& fh, Streambuf& sb,
role_type role, close_code& code)
role_type role, close_code::value& code)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -301,7 +301,7 @@ read_fh2(frame_header& fh, Streambuf& sb,
template<class Buffers>
void
read(ping_payload_type& data,
Buffers const& bs, close_code& code)
Buffers const& bs, close_code::value& code)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
@@ -318,7 +318,7 @@ read(ping_payload_type& data,
template<class Buffers>
void
read(close_reason& cr,
Buffers const& bs, close_code& code)
Buffers const& bs, close_code::value& code)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -341,15 +341,7 @@ read(close_reason& cr,
{
std::uint8_t b[2];
buffer_copy(buffer(b), cb);
#if 0
// Causes strict-aliasing warning in gcc
cr.code = static_cast<close_code>(
reinterpret_cast<
big_uint16_buf_t const*>(&b[0])->value());
#else
cr.code = static_cast<close_code>(
big_uint16_to_native(&b[0]));
#endif
cr.code = big_uint16_to_native(&b[0]);
cb.consume(2);
n -= 2;
if(! is_valid(cr.code))
@@ -85,8 +85,6 @@ public:
#endif
invokable() = default;
invokable(invokable const&) = delete;
invokable& operator=(invokable const&) = delete;
invokable(invokable&& other)
{
-3
View File
@@ -41,9 +41,6 @@ class maskgen_t
public:
using result_type = typename std::mt19937::result_type;
maskgen_t(maskgen_t const&) = delete;
maskgen_t& operator=(maskgen_t const&) = delete;
maskgen_t();
result_type
@@ -108,7 +108,7 @@ protected:
template<class = void>
void
prepare_fh(close_code& code);
prepare_fh(close_code::value& code);
template<class Streambuf>
void
@@ -73,12 +73,6 @@ class utf8_checker_t
std::uint32_t codepoint_ = 0;
public:
utf8_checker_t() = default;
utf8_checker_t(utf8_checker_t&&) = default;
utf8_checker_t(utf8_checker_t const&) = default;
utf8_checker_t& operator=(utf8_checker_t&&) = default;
utf8_checker_t& operator=(utf8_checker_t const&) = default;
void
reset();
+1 -1
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;
@@ -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;
@@ -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:
+1 -1
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;
+152 -19
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));
@@ -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);
+8 -5
View File
@@ -8,7 +8,7 @@
#ifndef BEAST_WEBSOCKET_RFC6455_HPP
#define BEAST_WEBSOCKET_RFC6455_HPP
#include <beast/websocket/static_string.hpp>
#include <beast/static_string.hpp>
#include <boost/optional.hpp>
#include <array>
#include <cstdint>
@@ -44,7 +44,9 @@ enum class opcode : std::uint8_t
@see RFC 6455 7.4.1 Defined Status Codes
https://tools.ietf.org/html/rfc6455#section-7.4.1
*/
enum class close_code : std::uint16_t
namespace close_code {
using value = std::uint16_t;
enum
{
// used internally to mean "no error"
none = 0,
@@ -69,6 +71,7 @@ enum class close_code : std::uint16_t
last = 5000 // satisfy warnings
};
} // close_code
#if ! GENERATING_DOCS
@@ -89,7 +92,7 @@ using ping_payload_type =
struct close_reason
{
/// The close code.
close_code code = close_code::none;
close_code::value code = close_code::none;
/// The optional utf8-encoded reason string.
reason_string_type reason;
@@ -102,7 +105,7 @@ struct close_reason
close_reason() = default;
/// Construct from a code.
close_reason(close_code code_)
close_reason(close_code::value code_)
: code(code_)
{
}
@@ -117,7 +120,7 @@ struct close_reason
/// Construct from a code and reason.
template<class CharT>
close_reason(close_code code_,
close_reason(close_code::value code_,
CharT const* reason_)
: code(code_)
, reason(reason_)
-337
View File
@@ -1,337 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
#include <stdexcept>
#include <string>
namespace beast {
namespace websocket {
/** A string with a fixed-size storage area.
`static_string` objects behave like `std::string` except that
the storage is not dynamically allocated but rather fixed in
size.
These strings offer performance advantages when a protocol
imposes a natural small upper limit on the size of a value.
*/
template<std::size_t N, class CharT,
class Traits = std::char_traits<CharT>>
class static_string
{
std::size_t n_;
std::array<CharT, N+1> s_;
public:
using traits_type = Traits;
using value_type = typename Traits::char_type;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
using const_pointer = value_type const*;
using const_reference = value_type const&;
using iterator = value_type*;
using const_iterator = value_type const*;
using reverse_iterator =
std::reverse_iterator<iterator>;
using const_reverse_iterator =
std::reverse_iterator<const_iterator>;
static_string()
{
resize(0);
}
static_string(static_string const& s)
: n_(s.n_)
{
std::copy(&s.s_[0], &s.s_[0]+s.n_+1, &s_[0]);
}
static_string&
operator=(static_string const& s)
{
n_ = s.n_;
std::copy(&s.s_[0], &s.s_[0]+s.n_+1, &s_[0]);
return *this;
}
static_string(CharT const* s)
{
assign(s);
}
static_string& operator=(CharT const* s)
{
assign(s);
return *this;
}
reference
at(size_type pos)
{
if(pos >= n_)
throw std::out_of_range("static_string::at");
return s_[pos];
}
const_reference
at(size_type pos) const
{
if(pos >= n_)
throw std::out_of_range("static_string::at");
return s_[pos];
}
reference
operator[](size_type pos);
const_reference
operator[](size_type pos) const;
CharT&
front()
{
return s_[0];
}
CharT const&
front() const
{
return s_[0];
}
CharT&
back()
{
return s_[n_-1];
}
CharT const&
back() const
{
return s_[n_-1];
}
CharT*
data()
{
return &s_[0];
}
CharT const*
data() const
{
return &s_[0];
}
CharT const*
c_str() const
{
s_[n_] = 0;
return &s_[0];
}
iterator
begin()
{
return &s_[0];
}
const_iterator
begin() const
{
return &s_[0];
}
const_iterator
cbegin() const
{
return &s_[0];
}
iterator
end()
{
return &s_[n_];
}
const_iterator
end() const
{
return &s_[n_];
}
const_iterator
cend() const
{
return &s_[n_];
}
reverse_iterator
rbegin()
{
return reverse_iterator{end()};
}
const_reverse_iterator
rbegin() const
{
return reverse_iterator{end()};
}
const_reverse_iterator
crbegin() const
{
return reverse_iterator{cend()};
}
reverse_iterator
rend()
{
return reverse_iterator{begin()};
}
const_reverse_iterator
rend() const
{
return reverse_iterator{begin()};
}
const_reverse_iterator
crend() const
{
return reverse_iterator{cbegin()};
}
bool
empty() const
{
return n_ == 0;
}
size_type
size() const
{
return n_;
}
size_type constexpr
max_size() const
{
return N;
}
size_type
capacity() const
{
return N;
}
void
shrink_to_fit()
{
// no-op
}
void
clear()
{
resize(0);
}
// Does not perform value-initialization
void
resize(std::size_t n);
std::basic_string<CharT, Traits>
to_string() const
{
return std::basic_string<
CharT, Traits>{&s_[0], n_};
}
private:
void
assign(CharT const* s);
};
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
operator[](size_type pos) ->
reference
{
static CharT null{0};
if(pos == n_)
return null;
return s_[pos];
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
operator[](size_type pos) const ->
const_reference
{
static CharT constexpr null{0};
if(pos == n_)
return null;
return s_[pos];
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
resize(std::size_t n)
{
if(n > N)
throw std::length_error(
"static_string overflow");
n_ = n;
s_[n_] = 0;
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
assign(CharT const* s)
{
size_type n = 0;
for(auto p = s; *p; ++p)
++n;
if(n > N)
throw std::out_of_range(
"too large");
std::copy(s, s+n, s_.begin());
}
} // websocket
} // beast
#endif
+28 -63
View File
@@ -12,6 +12,7 @@
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/streambuf_readstream.hpp>
#include <beast/async_completion.hpp>
#include <beast/detail/get_lowest_layer.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <boost/asio.hpp>
@@ -80,8 +81,7 @@ class stream : public detail::stream_base
{
friend class ws_test;
NextLayer next_layer_;
streambuf_readstream<NextLayer&, streambuf> stream_;
streambuf_readstream<NextLayer, streambuf> stream_;
public:
/// The type of the next layer.
@@ -90,26 +90,26 @@ public:
/// The type of the lowest layer.
using lowest_layer_type =
typename next_layer_type::lowest_layer_type;
typename beast::detail::get_lowest_layer<
next_layer_type>::type;
/// The type of endpoint of the lowest layer.
using endpoint_type =
typename lowest_layer_type::endpoint_type;
/** Move-construct a stream.
/// The protocol of the next layer.
using protocol_type =
typename lowest_layer_type::protocol_type;
If @c NextLayer is move constructible, this function
will move-construct a new stream from the existing stream.
/// The type of resolver of the next layer.
using resolver_type =
typename protocol_type::resolver;
/// Move constructor.
@note The behavior of move assignment on or from streams
with active or pending operations is undefined.
*/
stream(stream&&) = default;
/** Move assignment.
Undefined behavior if operations are active or pending.
If @c NextLayer is move constructible, this function
will move-construct a new stream from the existing stream.
@note The behavior of move assignment on or from streams
with active or pending operations is undefined.
*/
stream& operator=(stream&&) = default;
@@ -217,7 +217,7 @@ public:
boost::asio::io_service&
get_io_service()
{
return next_layer_.lowest_layer().get_io_service();
return stream_.get_io_service();
}
/** Get a reference to the next layer.
@@ -231,7 +231,7 @@ public:
next_layer_type&
next_layer()
{
return next_layer_;
return stream_.next_layer();
}
/** Get a reference to the next layer.
@@ -245,7 +245,7 @@ public:
next_layer_type const&
next_layer() const
{
return next_layer_;
return stream_.next_layer();
}
/** Get a reference to the lowest layer.
@@ -259,7 +259,7 @@ public:
lowest_layer_type&
lowest_layer()
{
return next_layer_.lowest_layer();
return stream_.lowest_layer();
}
/** Get a reference to the lowest layer.
@@ -273,7 +273,7 @@ public:
lowest_layer_type const&
lowest_layer() const
{
return next_layer_.lowest_layer();
return stream_.lowest_layer();
}
/** Returns the close reason received from the peer.
@@ -309,12 +309,7 @@ public:
@throws boost::system::system_error Thrown on failure.
*/
void
accept()
{
error_code ec;
accept(boost::asio::null_buffers{}, ec);
detail::maybe_throw(ec, "accept");
}
accept();
/** Read and respond to a WebSocket HTTP Upgrade request.
@@ -603,12 +598,7 @@ public:
*/
void
handshake(boost::string_ref const& host,
boost::string_ref const& resource)
{
error_code ec;
handshake(host, resource, ec);
detail::maybe_throw(ec, "upgrade");
}
boost::string_ref const& resource);
/** Send a WebSocket Upgrade request.
@@ -692,12 +682,7 @@ public:
@param cr The reason for the close.
*/
void
close(close_reason const& cr)
{
error_code ec;
close(cr, ec);
detail::maybe_throw(ec, "close");
}
close(close_reason const& cr);
/** Perform a WebSocket close.
@@ -773,12 +758,7 @@ public:
*/
template<class Streambuf>
void
read(opcode& op, Streambuf& streambuf)
{
error_code ec;
read(op, streambuf, ec);
detail::maybe_throw(ec, "read");
}
read(opcode& op, Streambuf& streambuf);
/** Read a message.
@@ -868,12 +848,7 @@ public:
*/
template<class Streambuf>
void
read_frame(frame_info& fi, Streambuf& streambuf)
{
error_code ec;
read_frame(fi, streambuf, ec);
detail::maybe_throw(ec, "read_some");
}
read_frame(frame_info& fi, Streambuf& streambuf);
/** Read a message frame.
@@ -978,12 +953,7 @@ public:
*/
template<class ConstBufferSequence>
void
write(ConstBufferSequence const& buffers)
{
error_code ec;
write(buffers, ec);
detail::maybe_throw(ec, "write");
}
write(ConstBufferSequence const& buffers);
/** Send a message.
@@ -1081,12 +1051,7 @@ public:
*/
template<class ConstBufferSequence>
void
write_frame(bool fin, ConstBufferSequence const& buffers)
{
error_code ec;
write_frame(fin, buffers, ec);
detail::maybe_throw(ec, "write");
}
write_frame(bool fin, ConstBufferSequence const& buffers);
/** Send a frame.
@@ -1180,7 +1145,7 @@ private:
void
do_read_fh(detail::frame_streambuf& fb,
close_code& code, error_code& ec);
close_code::value& code, error_code& ec);
};
} // websocket