update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -11,7 +11,6 @@
#define BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/core/exchange.hpp>
#include <boost/type_traits/make_void.hpp>
#include <algorithm>
@@ -213,7 +212,7 @@ struct decorator::vtable_impl<F, true>
void
move(storage& dst, storage& src) noexcept
{
auto& f = *reinterpret_cast<F*>(&src.buf_);
auto& f = *beast::detail::launder_cast<F*>(&src.buf_);
::new (&dst.buf_) F(std::move(f));
}
@@ -221,7 +220,7 @@ struct decorator::vtable_impl<F, true>
void
destroy(storage& dst) noexcept
{
reinterpret_cast<F*>(&dst.buf_)->~F();
beast::detail::launder_cast<F*>(&dst.buf_)->~F();
}
static
@@ -229,7 +228,7 @@ struct decorator::vtable_impl<F, true>
invoke_req(storage& dst, request_type& req)
{
maybe_invoke<F, request_type>{}(
*reinterpret_cast<F*>(&dst.buf_), req);
*beast::detail::launder_cast<F*>(&dst.buf_), req);
}
static
@@ -237,7 +236,7 @@ struct decorator::vtable_impl<F, true>
invoke_res(storage& dst, response_type& res)
{
maybe_invoke<F, response_type>{}(
*reinterpret_cast<F*>(&dst.buf_), res);
*beast::detail::launder_cast<F*>(&dst.buf_), res);
}
static

View File

@@ -14,20 +14,10 @@
#include <boost/beast/websocket/error.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/websocket/detail/utf8_checker.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/static_string.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
// This is for <boost/endian/buffers.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, > 0)
# pragma warning (push)
# pragma warning (disable: 4127) // conditional expression is constant
#endif
#include <boost/endian/buffers.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, > 0)
# pragma warning (pop)
#endif
#include <boost/endian/conversion.hpp>
#include <cstdint>
namespace boost {
@@ -35,56 +25,6 @@ namespace beast {
namespace websocket {
namespace detail {
inline
std::uint16_t
big_uint16_to_native(void const* buf)
{
auto const p = static_cast<
std::uint8_t const*>(buf);
return (p[0]<<8) + p[1];
}
inline
std::uint64_t
big_uint64_to_native(void const* buf)
{
auto const p = static_cast<
std::uint8_t const*>(buf);
return
(static_cast<std::uint64_t>(p[0])<<56) +
(static_cast<std::uint64_t>(p[1])<<48) +
(static_cast<std::uint64_t>(p[2])<<40) +
(static_cast<std::uint64_t>(p[3])<<32) +
(static_cast<std::uint64_t>(p[4])<<24) +
(static_cast<std::uint64_t>(p[5])<<16) +
(static_cast<std::uint64_t>(p[6])<< 8) +
p[7];
}
inline
std::uint32_t
little_uint32_to_native(void const* buf)
{
auto const p = static_cast<
std::uint8_t const*>(buf);
return
p[0] +
(static_cast<std::uint32_t>(p[1])<< 8) +
(static_cast<std::uint32_t>(p[2])<<16) +
(static_cast<std::uint32_t>(p[3])<<24);
}
inline
void
native_to_little_uint32(std::uint32_t v, void* buf)
{
auto p = static_cast<std::uint8_t*>(buf);
p[0] = v & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
}
// frame header opcodes
enum class opcode : std::uint8_t
{
@@ -193,7 +133,6 @@ template<class DynamicBuffer>
void
write(DynamicBuffer& db, frame_header const& fh)
{
using namespace boost::endian;
std::size_t n;
std::uint8_t b[14];
b[0] = (fh.fin ? 0x80 : 0x00) | static_cast<std::uint8_t>(fh.op);
@@ -212,19 +151,24 @@ write(DynamicBuffer& db, frame_header const& fh)
else if(fh.len <= 65535)
{
b[1] |= 126;
::new(&b[2]) big_uint16_buf_t{
(std::uint16_t)fh.len};
auto len_be = endian::native_to_big(
static_cast<std::uint16_t>(fh.len));
std::memcpy(&b[2], &len_be, sizeof(len_be));
n = 4;
}
else
{
b[1] |= 127;
::new(&b[2]) big_uint64_buf_t{fh.len};
auto len_be = endian::native_to_big(
static_cast<std::uint64_t>(fh.len));
std::memcpy(&b[2], &len_be, sizeof(len_be));
n = 10;
}
if(fh.mask)
{
native_to_little_uint32(fh.key, &b[n]);
auto key_le = endian::native_to_little(
static_cast<std::uint32_t>(fh.key));
std::memcpy(&b[n], &key_le, sizeof(key_le));
n += 4;
}
db.commit(net::buffer_copy(
@@ -254,8 +198,7 @@ read_close(
Buffers const& bs,
error_code& ec)
{
using namespace boost::endian;
auto n = buffer_bytes(bs);
auto const n = buffer_bytes(bs);
BOOST_ASSERT(n <= 125);
if(n == 0)
{
@@ -266,39 +209,32 @@ read_close(
if(n == 1)
{
// invalid payload size == 1
ec = error::bad_close_size;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_size);
return;
}
buffers_suffix<Buffers> cb(bs);
std::uint16_t code_be;
cr.reason.resize(n - 2);
std::array<net::mutable_buffer, 2> out_bufs{{
net::mutable_buffer(&code_be, sizeof(code_be)),
net::mutable_buffer(&cr.reason[0], n - 2)}};
net::buffer_copy(out_bufs, bs);
cr.code = endian::big_to_native(code_be);
if(! is_valid_close_code(cr.code))
{
std::uint8_t b[2];
net::buffer_copy(net::buffer(b), cb);
cr.code = big_uint16_to_native(&b[0]);
cb.consume(2);
n -= 2;
if(! is_valid_close_code(cr.code))
{
// invalid close code
ec = error::bad_close_code;
return;
}
// invalid close code
BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_code);
return;
}
if(n > 0)
if(n > 2 && !check_utf8(
cr.reason.data(), cr.reason.size()))
{
cr.reason.resize(n);
net::buffer_copy(
net::buffer(&cr.reason[0], n), cb);
if(! check_utf8(
cr.reason.data(), cr.reason.size()))
{
// not valid utf-8
ec = error::bad_close_payload;
return;
}
}
else
{
cr.reason = "";
// not valid utf-8
BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_payload);
return;
}
ec = {};
}

View File

@@ -27,18 +27,12 @@ void
make_sec_ws_key(sec_ws_key_type& key)
{
auto g = make_prng(true);
char a[16];
for(int i = 0; i < 16; i += 4)
{
auto const v = g();
a[i ] = v & 0xff;
a[i+1] = (v >> 8) & 0xff;
a[i+2] = (v >> 16) & 0xff;
a[i+3] = (v >> 24) & 0xff;
}
std::uint32_t a[4];
for (auto& v : a)
v = g();
key.resize(key.max_size());
key.resize(beast::detail::base64::encode(
key.data(), &a[0], 16));
key.data(), &a[0], sizeof(a)));
}
void
@@ -46,12 +40,13 @@ make_sec_ws_accept(
sec_ws_accept_type& accept,
string_view key)
{
BOOST_ASSERT(key.size() <= sec_ws_key_type::max_size_n);
static_string<sec_ws_key_type::max_size_n + 36> m(key);
m.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
BOOST_ASSERT(key.size() <= sec_ws_key_type::static_capacity);
using namespace beast::detail::string_literals;
auto const guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"_sv;
beast::detail::sha1_context ctx;
beast::detail::init(ctx);
beast::detail::update(ctx, m.data(), m.size());
beast::detail::update(ctx, key.data(), key.size());
beast::detail::update(ctx, guid.data(), guid.size());
char digest[beast::detail::sha1_context::digest_size];
beast::detail::finish(ctx, &digest[0]);
accept.resize(accept.max_size());

View File

@@ -137,7 +137,7 @@ struct impl_base<true>
return false;
if(zs.avail_out >= 6)
{
zo.write(zs, zlib::Flush::full, ec);
zo.write(zs, zlib::Flush::sync, ec);
BOOST_ASSERT(! ec);
// remove flush marker
zs.total_out -= 4;
@@ -302,6 +302,11 @@ struct impl_base<true>
return pmd_ != nullptr;
}
bool should_compress(std::size_t n_bytes) const
{
return n_bytes >= pmd_opts_.msg_size_threshold;
}
std::size_t
read_size_hint_pmd(
std::size_t initial_size,
@@ -447,6 +452,11 @@ struct impl_base<false>
return false;
}
bool should_compress(std::size_t) const
{
return false;
}
std::size_t
read_size_hint_pmd(
std::size_t initial_size,

View File

@@ -26,62 +26,27 @@ namespace detail {
using prepared_key = std::array<unsigned char, 4>;
inline
BOOST_BEAST_DECL
void
prepare_key(prepared_key& prepared, std::uint32_t key)
{
prepared[0] = (key >> 0) & 0xff;
prepared[1] = (key >> 8) & 0xff;
prepared[2] = (key >> 16) & 0xff;
prepared[3] = (key >> 24) & 0xff;
}
template<std::size_t N>
void
rol(std::array<unsigned char, N>& v, std::size_t n)
{
auto v0 = v;
for(std::size_t i = 0; i < v.size(); ++i )
v[i] = v0[(i + n) % v.size()];
}
prepare_key(prepared_key& prepared, std::uint32_t key);
// Apply mask in place
//
inline
BOOST_BEAST_DECL
void
mask_inplace(net::mutable_buffer& b, prepared_key& key)
{
auto n = b.size();
auto mask = key; // avoid aliasing
auto p = static_cast<unsigned char*>(b.data());
while(n >= 4)
{
for(int i = 0; i < 4; ++i)
p[i] ^= mask[i];
p += 4;
n -= 4;
}
if(n > 0)
{
for(std::size_t i = 0; i < n; ++i)
p[i] ^= mask[i];
rol(key, n);
}
}
mask_inplace(net::mutable_buffer const& b, prepared_key& key);
// Apply mask in place
//
template<
class MutableBufferSequence,
class KeyType>
template<class MutableBufferSequence>
void
mask_inplace(
MutableBufferSequence const& buffers,
KeyType& key)
prepared_key& key)
{
for(net::mutable_buffer b :
beast::buffers_range_ref(buffers))
mask_inplace(b, key);
detail::mask_inplace(b, key);
}
} // detail
@@ -89,4 +54,10 @@ mask_inplace(
} // beast
} // boost
#if BOOST_BEAST_HEADER_ONLY
#include <boost/beast/websocket/detail/mask.ipp>
#endif
#endif

View File

@@ -0,0 +1,66 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_MASK_IPP
#define BOOST_BEAST_WEBSOCKET_DETAIL_MASK_IPP
#include <boost/beast/websocket/detail/mask.hpp>
namespace boost {
namespace beast {
namespace websocket {
namespace detail {
void
prepare_key(prepared_key& prepared, std::uint32_t key)
{
prepared[0] = (key >> 0) & 0xff;
prepared[1] = (key >> 8) & 0xff;
prepared[2] = (key >> 16) & 0xff;
prepared[3] = (key >> 24) & 0xff;
}
inline
void
rol(prepared_key& v, std::size_t n)
{
auto v0 = v;
for(std::size_t i = 0; i < v.size(); ++i )
v[i] = v0[(i + n) % v.size()];
}
// Apply mask in place
//
void
mask_inplace(net::mutable_buffer const& b, prepared_key& key)
{
auto n = b.size();
auto const mask = key; // avoid aliasing
auto p = static_cast<unsigned char*>(b.data());
while(n >= 4)
{
for(int i = 0; i < 4; ++i)
p[i] ^= mask[i];
p += 4;
n -= 4;
}
if(n > 0)
{
for(std::size_t i = 0; i < n; ++i)
p[i] ^= mask[i];
rol(key, n);
}
}
} // detail
} // websocket
} // beast
} // boost
#endif

View File

@@ -82,7 +82,7 @@ pmd_write(http::basic_fields<Allocator>& fields,
pmd_offer const& offer)
{
auto s = detail::pmd_write_impl(offer);
fields.set(http::field::sec_websocket_extensions, s);
fields.set(http::field::sec_websocket_extensions, to_string_view(s));
}
// Negotiate a permessage-deflate client offer
@@ -104,7 +104,7 @@ pmd_negotiate(
auto s = detail::pmd_negotiate_impl(config, offer, o);
if(config.accept)
fields.set(http::field::sec_websocket_extensions, s);
fields.set(http::field::sec_websocket_extensions, to_string_view(s));
}
// Normalize the server's response

View File

@@ -52,11 +52,11 @@ pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
for(auto const& ext : list)
{
if(iequals(ext.first, "permessage-deflate"))
if(beast::iequals(ext.first, "permessage-deflate"))
{
for(auto const& param : ext.second)
{
if(iequals(param.first,
if(beast::iequals(param.first,
"server_max_window_bits"))
{
if(offer.server_max_window_bits != 0)
@@ -84,7 +84,7 @@ pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
return; // MUST decline
}
}
else if(iequals(param.first,
else if(beast::iequals(param.first,
"client_max_window_bits"))
{
if(offer.client_max_window_bits != 0)
@@ -112,7 +112,7 @@ pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
offer.client_max_window_bits = -1;
}
}
else if(iequals(param.first,
else if(beast::iequals(param.first,
"server_no_context_takeover"))
{
if(offer.server_no_context_takeover)
@@ -131,7 +131,7 @@ pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
}
offer.server_no_context_takeover = true;
}
else if(iequals(param.first,
else if(beast::iequals(param.first,
"client_no_context_takeover"))
{
if(offer.client_no_context_takeover)

View File

@@ -11,8 +11,8 @@
#define BOOST_BEAST_WEBSOCKET_DETAIL_PRNG_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/config.hpp>
#include <cstdint>
#include <limits>
#include <random>
namespace boost {
@@ -20,66 +20,7 @@ namespace beast {
namespace websocket {
namespace detail {
// Type-erased UniformRandomBitGenerator
// with 32-bit unsigned integer value_type
//
class prng
{
protected:
virtual ~prng() = default;
virtual prng& acquire() noexcept = 0;
virtual void release() noexcept = 0;
virtual std::uint32_t operator()() noexcept = 0;
public:
using value_type = std::uint32_t;
class ref
{
prng& p_;
public:
ref& operator=(ref const&) = delete;
~ref()
{
p_.release();
}
explicit
ref(prng& p) noexcept
: p_(p.acquire())
{
}
ref(ref const& other) noexcept
: p_(other.p_.acquire())
{
}
value_type
operator()() noexcept
{
return p_();
}
static
value_type constexpr
min() noexcept
{
return (std::numeric_limits<
value_type>::min)();
}
static
value_type constexpr
max() noexcept
{
return (std::numeric_limits<
value_type>::max)();
}
};
};
using generator = std::uint32_t(*)();
//------------------------------------------------------------------------------
@@ -90,25 +31,11 @@ BOOST_BEAST_DECL
std::uint32_t const*
prng_seed(std::seed_seq* ss = nullptr);
// Acquire a PRNG using the no-TLS implementation
//
BOOST_BEAST_DECL
prng::ref
make_prng_no_tls(bool secure);
// Acquire a PRNG using the TLS implementation
//
#ifndef BOOST_NO_CXX11_THREAD_LOCAL
BOOST_BEAST_DECL
prng::ref
make_prng_tls(bool secure);
#endif
// Acquire a PRNG using the TLS implementation if it
// is available, otherwise using the no-TLS implementation.
//
BOOST_BEAST_DECL
prng::ref
generator
make_prng(bool secure);
} // detail

View File

@@ -13,14 +13,10 @@
#include <boost/beast/websocket/detail/prng.hpp>
#include <boost/beast/core/detail/chacha.hpp>
#include <boost/beast/core/detail/pcg.hpp>
#include <boost/align/aligned_alloc.hpp>
#include <boost/throw_exception.hpp>
#include <atomic>
#include <cstdlib>
#include <mutex>
#include <new>
#include <random>
#include <stdexcept>
namespace boost {
namespace beast {
@@ -59,264 +55,92 @@ prng_seed(std::seed_seq* ss)
//------------------------------------------------------------------------------
template<class T>
class prng_pool
inline
std::uint32_t
make_nonce()
{
std::mutex m_;
T* head_ = nullptr;
public:
static
prng_pool&
instance()
{
static prng_pool p;
return p;
}
~prng_pool()
{
for(auto p = head_; p;)
{
auto next = p->next;
p->~T();
boost::alignment::aligned_free(p);
p = next;
}
}
prng::ref
acquire()
{
{
std::lock_guard<
std::mutex> g(m_);
if(head_)
{
auto p = head_;
head_ = head_->next;
return prng::ref(*p);
}
}
auto p = boost::alignment::aligned_alloc(
16, sizeof(T));
if(! p)
BOOST_THROW_EXCEPTION(std::bad_alloc{});
return prng::ref(*(::new(p) T()));
}
void
release(T& t)
{
std::lock_guard<
std::mutex> g(m_);
t.next = head_;
head_ = &t;
}
};
prng::ref
make_prng_no_tls(bool secure)
{
class fast_prng final : public prng
{
int refs_ = 0;
beast::detail::pcg r_;
public:
fast_prng* next = nullptr;
fast_prng()
: r_(
[]{
auto const pv = prng_seed();
return
((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
}(),
[]{
static std::atomic<
std::uint32_t> nonce{0};
return ++nonce;
}())
{
}
protected:
prng&
acquire() noexcept override
{
++refs_;
return *this;
}
void
release() noexcept override
{
if(--refs_ == 0)
prng_pool<fast_prng>::instance().release(*this);
}
value_type
operator()() noexcept override
{
return r_();
}
};
class secure_prng final : public prng
{
int refs_ = 0;
beast::detail::chacha<20> r_;
public:
secure_prng* next = nullptr;
secure_prng()
: r_(prng_seed(), []
{
static std::atomic<
std::uint64_t> nonce{0};
return ++nonce;
}())
{
}
protected:
prng&
acquire() noexcept override
{
++refs_;
return *this;
}
void
release() noexcept override
{
if(--refs_ == 0)
prng_pool<secure_prng>::instance().release(*this);
}
value_type
operator()() noexcept override
{
return r_();
}
};
if(secure)
return prng_pool<secure_prng>::instance().acquire();
return prng_pool<fast_prng>::instance().acquire();
static std::atomic<std::uint32_t> nonce{0};
return ++nonce;
}
//------------------------------------------------------------------------------
#ifndef BOOST_NO_CXX11_THREAD_LOCAL
prng::ref
make_prng_tls(bool secure)
inline
beast::detail::pcg make_pcg()
{
class fast_prng final : public prng
auto const pv = prng_seed();
return beast::detail::pcg{
((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]), make_nonce()};
}
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
inline
std::uint32_t
secure_generate()
{
struct generator
{
beast::detail::pcg r_;
public:
fast_prng()
: r_(
[]{
auto const pv = prng_seed();
return
((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
}(),
[]{
static std::atomic<
std::uint32_t> nonce{0};
return ++nonce;
}())
std::uint32_t operator()()
{
std::lock_guard<std::mutex> guard{mtx};
return gen();
}
protected:
prng&
acquire() noexcept override
{
return *this;
}
void
release() noexcept override
{
}
value_type
operator()() noexcept override
{
return r_();
}
beast::detail::chacha<20> gen;
std::mutex mtx;
};
static generator gen{beast::detail::chacha<20>{prng_seed(), make_nonce()}};
return gen();
}
class secure_prng final : public prng
inline
std::uint32_t
fast_generate()
{
struct generator
{
beast::detail::chacha<20> r_;
public:
secure_prng()
: r_(prng_seed(), []
{
static std::atomic<
std::uint64_t> nonce{0};
return ++nonce;
}())
std::uint32_t operator()()
{
std::lock_guard<std::mutex> guard{mtx};
return gen();
}
protected:
prng&
acquire() noexcept override
{
return *this;
}
void
release() noexcept override
{
}
value_type
operator()() noexcept override
{
return r_();
}
beast::detail::pcg gen;
std::mutex mtx;
};
static generator gen{make_pcg()};
return gen();
}
if(secure)
{
thread_local secure_prng sp;
return prng::ref(sp);
}
#else
thread_local fast_prng fp;
return prng::ref(fp);
inline
std::uint32_t
secure_generate()
{
thread_local static beast::detail::chacha<20> gen{prng_seed(), make_nonce()};
return gen();
}
inline
std::uint32_t
fast_generate()
{
thread_local static beast::detail::pcg gen{make_pcg()};
return gen();
}
#endif
//------------------------------------------------------------------------------
prng::ref
generator
make_prng(bool secure)
{
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
return make_prng_no_tls(secure);
#else
return make_prng_tls(secure);
#endif
if (secure)
return &secure_generate;
else
return &fast_generate;
}
} // detail

View File

@@ -17,7 +17,7 @@ namespace boost {
namespace beast {
namespace websocket {
/// Error codes returned from @ref beast::websocket::stream operations.
/// Error codes returned from @ref boost::beast::websocket::stream operations.
enum class error
{
/** The WebSocket stream was gracefully closed at both endpoints

View File

@@ -21,7 +21,6 @@
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/buffer.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp>
@@ -80,13 +79,8 @@ build_response(
decorator_opt(res);
decorator(res);
if(! res.count(http::field::server))
{
// VFALCO this is weird..
BOOST_STATIC_ASSERT(sizeof(
BOOST_BEAST_VERSION_STRING) < 20);
static_string<20> s(BOOST_BEAST_VERSION_STRING);
res.set(http::field::server, s);
}
res.set(http::field::server,
string_view(BOOST_BEAST_VERSION_STRING));
};
auto err =
[&](error e)
@@ -126,7 +120,7 @@ build_response(
if(it == req.end())
return err(error::no_sec_key);
key = it->value();
if(key.size() > detail::sec_ws_key_type::max_size_n)
if(key.size() > detail::sec_ws_key_type::static_capacity)
return err(error::bad_sec_key);
}
{
@@ -155,7 +149,7 @@ build_response(
{
detail::sec_ws_accept_type acc;
detail::make_sec_ws_accept(acc, key);
res.set(http::field::sec_websocket_accept, acc);
res.set(http::field::sec_websocket_accept, to_string_view(acc));
}
this->build_response_pmd(res, req);
decorate(res);
@@ -172,11 +166,13 @@ template<class Handler>
class stream<NextLayer, deflateSupported>::response_op
: public beast::stable_async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
error_code result_; // must come before res_
response_type& res_;
http::response<http::empty_body> res_100_;
bool needs_res_100_{false};
public:
template<
@@ -198,6 +194,15 @@ public:
, res_(beast::allocate_stable<response_type>(*this,
sp->build_response(req, decorator, result_)))
{
auto itr = req.find(http::field::expect);
if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
{
res_100_.version(res_.version());
res_100_.set(http::field::server, res_[http::field::server]);
res_100_.result(http::status::continue_);
res_100_.prepare_payload();
needs_res_100_ = true;
}
(*this)({}, 0, cont);
}
@@ -210,7 +215,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return this->complete(cont, ec);
}
auto& impl = *sp;
@@ -219,14 +224,33 @@ public:
impl.change_status(status::handshake);
impl.update_timer(this->get_executor());
if (needs_res_100_)
{
BOOST_ASIO_CORO_YIELD
{
BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "websocket::async_accept"));
http::async_write(
impl.stream(), res_100_, std::move(*this));
}
}
// Send response
BOOST_ASIO_CORO_YIELD
http::async_write(
impl.stream(), res_, std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_accept"));
http::async_write(
impl.stream(), res_, std::move(*this));
}
if(impl.check_stop_now(ec))
goto upcall;
if(! ec)
ec = result_;
{
BOOST_BEAST_ASSIGN_EC(ec, result_);
BOOST_BEAST_ASSIGN_EC(ec, result_);
}
if(! ec)
{
impl.do_pmd_config(res_);
@@ -242,12 +266,15 @@ public:
// read and respond to an upgrade request
//
// Cancellation: the async_accept cancellation can be terminal
// because it will just interrupt the reading of the header.
//
template<class NextLayer, bool deflateSupported>
template<class Handler, class Decorator>
class stream<NextLayer, deflateSupported>::accept_op
: public beast::stable_async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
http::request_parser<http::empty_body>& p_;
@@ -290,7 +317,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return this->complete(cont, ec);
}
auto& impl = *sp;
@@ -304,10 +331,18 @@ public:
goto upcall;
BOOST_ASIO_CORO_YIELD
http::async_read(impl.stream(),
impl.rd_buf, p_, std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_accept"));
http::async_read(impl.stream(),
impl.rd_buf, p_, std::move(*this));
}
if(ec == http::error::end_of_stream)
ec = error::closed;
{
BOOST_BEAST_ASSIGN_EC(ec, error::closed);
}
if(impl.check_stop_now(ec))
goto upcall;
@@ -317,6 +352,7 @@ public:
// the handler.
auto const req = p_.release();
auto const decorator = d_;
response_op<Handler>(
this->release_handler(),
sp, req, decorator, true);
@@ -411,10 +447,24 @@ do_accept(
error_code result;
auto const res = impl_->build_response(req, decorator, result);
auto itr = req.find(http::field::expect);
if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
{
http::response<http::empty_body> res_100;
res_100.version(res.version());
res_100.set(http::field::server, res[http::field::server]);
res_100.result(http::status::continue_);
res_100.prepare_payload();
http::write(impl_->stream(), res_100, ec);
if (ec)
return;
}
http::write(impl_->stream(), res, ec);
if(ec)
return;
ec = result;
BOOST_BEAST_ASSIGN_EC(ec, result);
if(ec)
{
// VFALCO TODO Respect keep alive setting, perform
@@ -446,7 +496,9 @@ do_accept(
http::request_parser<http::empty_body> p;
http::read(next_layer(), impl_->rd_buf, p, ec);
if(ec == http::error::end_of_stream)
ec = error::closed;
{
BOOST_BEAST_ASSIGN_EC(ec, error::closed);
}
if(ec)
return;
do_accept(p.get(), decorator, ec);
@@ -548,7 +600,7 @@ accept(
template<class NextLayer, bool deflateSupported>
template<
class AcceptHandler>
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
stream<NextLayer, deflateSupported>::
async_accept(
@@ -567,43 +619,19 @@ async_accept(
net::const_buffer{});
}
template<class NextLayer, bool deflateSupported>
template<
class ResponseDecorator,
class AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
stream<NextLayer, deflateSupported>::
async_accept_ex(
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
return net::async_initiate<
AcceptHandler,
void(error_code)>(
run_accept_op{},
handler,
impl_,
decorator,
net::const_buffer{});
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class AcceptHandler>
typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)>::type
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
stream<NextLayer, deflateSupported>::
async_accept(
ConstBufferSequence const& buffers,
AcceptHandler&& handler)
AcceptHandler&& handler,
typename std::enable_if<
! http::detail::is_header<
ConstBufferSequence>::value>::type*
)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
@@ -621,43 +649,10 @@ async_accept(
buffers);
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator,
class AcceptHandler>
typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)>::type
stream<NextLayer, deflateSupported>::
async_accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
return net::async_initiate<
AcceptHandler,
void(error_code)>(
run_accept_op{},
handler,
impl_,
decorator,
buffers);
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class AcceptHandler>
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
stream<NextLayer, deflateSupported>::
async_accept(
@@ -677,184 +672,6 @@ async_accept(
&default_decorate_res);
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator,
class AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
stream<NextLayer, deflateSupported>::
async_accept_ex(
http::request<Body, http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
return net::async_initiate<
AcceptHandler,
void(error_code)>(
run_response_op{},
handler,
impl_,
&req,
decorator);
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator, error_code& ec)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
do_accept(
net::const_buffer{},
decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const &decorator)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(buffers, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
error_code& ec)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
do_accept(buffers, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(req, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
error_code& ec)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
do_accept(req, decorator, ec);
}
} // websocket
} // beast
} // boost

View File

@@ -38,7 +38,7 @@ template<class Handler>
class stream<NextLayer, deflateSupported>::close_op
: public beast::stable_async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
error_code ev_;
@@ -76,7 +76,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return this->complete(cont, ec);
}
auto& impl = *sp;
@@ -86,10 +86,28 @@ public:
if(! impl.wr_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_close.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
this->set_allowed_cancellation(net::cancellation_type::all);
impl.op_close.emplace(std::move(*this),
net::cancellation_type::all);
}
// cancel fired before we could do anything.
if (ec == net::error::operation_aborted)
return this->complete(cont, ec);
this->set_allowed_cancellation(net::cancellation_type::terminal);
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
}
if(impl.check_stop_now(ec))
@@ -104,8 +122,14 @@ public:
impl.change_status(status::closing);
impl.update_timer(this->get_executor());
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), fb_.data(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
net::async_write(impl.stream(), fb_.data(),
beast::detail::bind_continuation(std::move(*this)));
}
if(impl.check_stop_now(ec))
goto upcall;
@@ -121,10 +145,30 @@ public:
if(! impl.rd_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_r_close.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
// terminal only, that's the default
impl.op_r_close.emplace(std::move(*this));
}
if (ec == net::error::operation_aborted)
{
// if a cancellation fires here, we do a dirty shutdown
impl.change_status(status::closed);
close_socket(get_lowest_layer(impl.stream()));
return this->complete(cont, ec);
}
impl.rd_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.rd_block.is_locked(this));
if(impl.check_stop_now(ec))
goto upcall;
@@ -144,12 +188,18 @@ public:
if(ev_)
goto teardown;
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
beast::detail::bind_continuation(std::move(*this)));
}
impl.rd_buf.commit(bytes_transferred);
if(impl.check_stop_now(ec))
if(impl.check_stop_now(ec)) //< this catches cancellation
goto upcall;
}
if(detail::is_control(impl.rd_fh.op))
@@ -184,10 +234,16 @@ public:
impl.rd_remain -= impl.rd_buf.size();
impl.rd_buf.consume(impl.rd_buf.size());
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
beast::detail::bind_continuation(std::move(*this)));
}
impl.rd_buf.commit(bytes_transferred);
if(impl.check_stop_now(ec))
goto upcall;
@@ -202,8 +258,14 @@ public:
BOOST_ASSERT(impl.wr_block.is_locked(this));
using beast::websocket::async_teardown;
BOOST_ASIO_CORO_YIELD
async_teardown(impl.role, impl.stream(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_close"));
async_teardown(impl.role, impl.stream(),
beast::detail::bind_continuation(std::move(*this)));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(ec == net::error::eof)
{
@@ -212,7 +274,9 @@ public:
ec = {};
}
if(! ec)
ec = ev_;
{
BOOST_BEAST_ASSIGN_EC(ec, ev_);
}
if(ec)
impl.change_status(status::failed);
else
@@ -382,7 +446,7 @@ close(close_reason const& cr, error_code& ec)
}
template<class NextLayer, bool deflateSupported>
template<class CloseHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 CloseHandler>
BOOST_BEAST_ASYNC_RESULT1(CloseHandler)
stream<NextLayer, deflateSupported>::
async_close(close_reason const& cr, CloseHandler&& handler)

View File

@@ -20,6 +20,9 @@ namespace detail {
class error_codes : public error_category
{
public:
error_codes() : error_category(0x065d7edd7687edafu ) {}
const char*
name() const noexcept override
{
@@ -123,6 +126,9 @@ public:
return "boost.beast.websocket";
}
error_conditions() : error_category(0x7a8de5d61799ce9eu) {}
std::string
message(int cv) const override
{

View File

@@ -37,7 +37,7 @@ template<class Handler>
class stream<NextLayer, deflateSupported>::handshake_op
: public beast::stable_async_base<Handler,
beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
struct data
{
@@ -93,7 +93,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return this->complete(cont, ec);
}
auto& impl = *sp;
@@ -105,16 +105,28 @@ public:
// write HTTP request
impl.do_pmd_config(d_.req);
BOOST_ASIO_CORO_YIELD
http::async_write(impl.stream(),
d_.req, std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_handshake"));
http::async_write(impl.stream(),
d_.req, std::move(*this));
}
if(impl.check_stop_now(ec))
goto upcall;
// read HTTP response
BOOST_ASIO_CORO_YIELD
http::async_read(impl.stream(),
impl.rd_buf, d_.p,
std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_handshake"));
http::async_read(impl.stream(),
impl.rd_buf, d_.p,
std::move(*this));
}
if(ec == http::error::buffer_overflow)
{
// If the response overflows the internal
@@ -127,8 +139,14 @@ public:
impl.rd_buf.clear();
BOOST_ASIO_CORO_YIELD
http::async_read(impl.stream(),
d_.fb, d_.p, std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_handshake"));
http::async_read(impl.stream(),
d_.fb, d_.p, std::move(*this));
}
if(! ec)
{
@@ -144,7 +162,7 @@ public:
}
else
{
ec = http::error::buffer_overflow;
BOOST_BEAST_ASSIGN_EC(ec, http::error::buffer_overflow);
}
}
@@ -207,6 +225,9 @@ do_handshake(
RequestDecorator const& decorator,
error_code& ec)
{
if(res_p)
res_p->result(http::status::internal_server_error);
auto& impl = *impl_;
impl.change_status(status::handshake);
impl.reset();
@@ -250,25 +271,31 @@ do_handshake(
}
else
{
ec = http::error::buffer_overflow;
BOOST_BEAST_ASSIGN_EC(ec, http::error::buffer_overflow);
}
}
}
if(impl.check_stop_now(ec))
return;
impl.on_response(p.get(), key, ec);
if(impl.check_stop_now(ec))
return;
if(res_p)
if (res_p)
{
// If res_p is not null, move parser's response into it.
*res_p = p.release();
}
else
{
// Otherwise point res_p at the response in the parser.
res_p = &p.get();
}
impl.on_response(*res_p, key, ec);
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
template<class HandshakeHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
stream<NextLayer, deflateSupported>::
async_handshake(
@@ -293,7 +320,7 @@ async_handshake(
}
template<class NextLayer, bool deflateSupported>
template<class HandshakeHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
stream<NextLayer, deflateSupported>::
async_handshake(
@@ -307,6 +334,7 @@ async_handshake(
detail::sec_ws_key_type key;
auto req = impl_->build_request(
key, host, target, &default_decorate_req);
res.result(http::status::internal_server_error);
return net::async_initiate<
HandshakeHandler,
void(error_code)>(
@@ -374,165 +402,6 @@ handshake(response_type& res,
host, target, &default_decorate_req, ec);
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(res, host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
error_code& ec)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
do_handshake(nullptr,
host, target, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
error_code& ec)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
do_handshake(&res,
host, target, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
stream<NextLayer, deflateSupported>::
async_handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
detail::sec_ws_key_type key;
auto req = impl_->build_request(
key, host, target, decorator);
return net::async_initiate<
HandshakeHandler,
void(error_code)>(
run_handshake_op{},
handler,
impl_,
std::move(req),
key,
nullptr);
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
stream<NextLayer, deflateSupported>::
async_handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream type requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
detail::sec_ws_key_type key;
auto req = impl_->build_request(
key, host, target, decorator);
return net::async_initiate<
HandshakeHandler,
void(error_code)>(
run_handshake_op{},
handler,
impl_,
std::move(req),
key,
&res);
}
} // websocket
} // beast
} // boost

View File

@@ -35,7 +35,7 @@ template<class Handler>
class stream<NextLayer, deflateSupported>::ping_op
: public beast::stable_async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
detail::frame_buffer& fb_;
@@ -72,7 +72,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return this->complete(cont, ec);
}
auto& impl = *sp;
@@ -82,10 +82,25 @@ public:
if(! impl.wr_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_ping.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
this->set_allowed_cancellation(net::cancellation_type::all);
impl.op_ping.emplace(std::move(*this), net::cancellation_type::all);
}
if (ec)
return this->complete(cont, ec);
this->set_allowed_cancellation(net::cancellation_type::terminal);
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
}
if(impl.check_stop_now(ec))
@@ -93,8 +108,14 @@ public:
// Send ping frame
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), fb_.data(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
net::async_write(impl.stream(), fb_.data(),
beast::detail::bind_continuation(std::move(*this)));
}
if(impl.check_stop_now(ec))
goto upcall;
@@ -115,7 +136,7 @@ public:
template<class NextLayer, bool deflateSupported>
template<class Executor>
class stream<NextLayer, deflateSupported>::idle_ping_op
: public net::coroutine
: public asio::coroutine
, public boost::empty_value<Executor>
{
boost::weak_ptr<impl_type> wp_;
@@ -173,10 +194,22 @@ public:
if(! impl.wr_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_idle_ping.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
impl.op_idle_ping.emplace(std::move(*this));
}
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(this->get(), std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
}
if(impl.check_stop_now(ec))
@@ -184,9 +217,14 @@ public:
// Send ping frame
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), fb_->data(),
//beast::detail::bind_continuation(std::move(*this)));
std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_ping"));
net::async_write(impl.stream(), fb_->data(),
std::move(*this));
}
if(impl.check_stop_now(ec))
goto upcall;
@@ -287,7 +325,7 @@ pong(ping_data const& payload, error_code& ec)
}
template<class NextLayer, bool deflateSupported>
template<class WriteHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 WriteHandler>
BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
stream<NextLayer, deflateSupported>::
async_ping(ping_data const& payload, WriteHandler&& handler)
@@ -305,7 +343,7 @@ async_ping(ping_data const& payload, WriteHandler&& handler)
}
template<class NextLayer, bool deflateSupported>
template<class WriteHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 WriteHandler>
BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
stream<NextLayer, deflateSupported>::
async_pong(ping_data const& payload, WriteHandler&& handler)

View File

@@ -48,7 +48,7 @@ template<class Handler, class MutableBufferSequence>
class stream<NextLayer, deflateSupported>::read_some_op
: public beast::async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
MutableBufferSequence bs_;
@@ -87,7 +87,7 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
bytes_written_ = 0;
return this->complete(cont, ec, bytes_written_);
}
@@ -102,17 +102,38 @@ public:
{
do_suspend:
BOOST_ASIO_CORO_YIELD
impl.op_r_rd.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
this->set_allowed_cancellation(net::cancellation_type::all);
impl.op_r_rd.emplace(std::move(*this), net::cancellation_type::all);
}
if (ec)
return this->complete(cont, ec, bytes_written_);
this->set_allowed_cancellation(net::cancellation_type::terminal);
impl.rd_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.rd_block.is_locked(this));
// VFALCO Is this check correct here?
BOOST_ASSERT(! ec && impl.check_stop_now(ec));
BOOST_ASSERT(!ec);
if(impl.check_stop_now(ec))
{
BOOST_ASSERT(ec == net::error::operation_aborted);
// Issue 2264 - There is no guarantee that the next
// error will be operation_aborted.
// The error could be a result of the peer resetting the
// connection
// BOOST_ASSERT(ec == net::error::operation_aborted);
goto upcall;
}
// VFALCO Should never get here
@@ -121,7 +142,7 @@ public:
// a `close_op` wrote a close frame
BOOST_ASSERT(impl.wr_close);
BOOST_ASSERT(impl.status_ != status::open);
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
goto upcall;
}
else
@@ -130,7 +151,7 @@ public:
if( impl.status_ == status::closed ||
impl.status_ == status::failed)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
goto upcall;
}
}
@@ -163,10 +184,16 @@ public:
}
BOOST_ASSERT(impl.rd_block.is_locked(this));
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
}
BOOST_ASSERT(impl.rd_block.is_locked(this));
impl.rd_buf.commit(bytes_transferred);
if(impl.check_stop_now(ec))
@@ -206,7 +233,13 @@ public:
if(! cont)
{
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(cont);
// VFALCO call check_stop_now() here?
}
@@ -225,7 +258,7 @@ public:
goto loop;
if(impl.ctrl_cb)
impl.ctrl_cb(
frame_type::ping, payload);
frame_type::ping, to_string_view(payload));
impl.rd_fb.clear();
impl.template write_ping<
flat_static_buffer_base>(impl.rd_fb,
@@ -241,10 +274,25 @@ public:
if(! impl.wr_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_rd.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.op_rd.emplace(std::move(*this));
}
if (ec)
return this->complete(cont, ec, bytes_written_);
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec))
goto upcall;
@@ -253,9 +301,15 @@ public:
// Send pong
BOOST_ASSERT(impl.wr_block.is_locked(this));
BOOST_ASIO_CORO_YIELD
net::async_write(
impl.stream(), impl.rd_fb.data(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::async_write(
impl.stream(), net::const_buffer(impl.rd_fb.data()),
beast::detail::bind_continuation(std::move(*this)));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec))
goto upcall;
@@ -276,7 +330,13 @@ public:
if(! cont)
{
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(cont);
}
}
@@ -289,7 +349,7 @@ public:
impl.rd_buf.consume(len);
// Ignore pong when closing
if(! impl.wr_close && impl.ctrl_cb)
impl.ctrl_cb(frame_type::pong, payload);
impl.ctrl_cb(frame_type::pong, to_string_view(payload));
goto loop;
}
@@ -301,7 +361,13 @@ public:
if(! cont)
{
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(cont);
}
}
@@ -323,7 +389,7 @@ public:
impl.rd_buf.consume(len);
if(impl.ctrl_cb)
impl.ctrl_cb(frame_type::close,
impl.cr.reason);
to_string_view(impl.cr.reason));
// See if we are already closing
if(impl.status_ == status::closing)
{
@@ -359,10 +425,16 @@ public:
// Fill the read buffer first, otherwise we
// get fewer bytes at the cost of one I/O.
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
}
impl.rd_buf.commit(bytes_transferred);
if(impl.check_stop_now(ec))
goto upcall;
@@ -405,8 +477,14 @@ public:
BOOST_ASSERT(buffer_bytes(buffers_prefix(
clamp(impl.rd_remain), cb_)) > 0);
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(buffers_prefix(
clamp(impl.rd_remain), cb_), std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.stream().async_read_some(buffers_prefix(
clamp(impl.rd_remain), cb_), std::move(*this));
}
if(impl.check_stop_now(ec))
goto upcall;
impl.reset_idle();
@@ -432,7 +510,9 @@ public:
impl.rd_size += bytes_transferred;
}
}
impl.rd_done = impl.rd_remain == 0 && impl.rd_fh.fin;
BOOST_ASSERT( ! impl.rd_done );
if( impl.rd_remain == 0 && impl.rd_fh.fin )
impl.rd_done = true;
}
else
{
@@ -447,10 +527,16 @@ public:
{
// read new
BOOST_ASIO_CORO_YIELD
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.stream().async_read_some(
impl.rd_buf.prepare(read_size(
impl.rd_buf, impl.rd_buf.max_size())),
std::move(*this));
}
if(impl.check_stop_now(ec))
goto upcall;
impl.reset_idle();
@@ -469,6 +555,8 @@ public:
zs.avail_out = out.size();
BOOST_ASSERT(zs.avail_out > 0);
}
// boolean to track the end of the message.
bool fin = false;
if(impl.rd_remain > 0)
{
if(impl.rd_buf.size() > 0)
@@ -488,22 +576,11 @@ public:
else if(impl.rd_fh.fin)
{
// append the empty block codes
std::uint8_t constexpr
static std::uint8_t constexpr
empty_block[4] = { 0x00, 0x00, 0xff, 0xff };
zs.next_in = empty_block;
zs.avail_in = sizeof(empty_block);
impl.inflate(zs, zlib::Flush::sync, ec);
if(! ec)
{
// https://github.com/madler/zlib/issues/280
if(zs.total_out > 0)
ec = error::partial_deflate_block;
}
if(impl.check_stop_now(ec))
goto upcall;
impl.do_context_takeover_read(impl.role);
impl.rd_done = true;
break;
fin = true;
}
else
{
@@ -512,6 +589,11 @@ public:
impl.inflate(zs, zlib::Flush::sync, ec);
if(impl.check_stop_now(ec))
goto upcall;
if(fin && zs.total_out == 0) {
impl.do_context_takeover_read(impl.role);
impl.rd_done = true;
break;
}
if(impl.rd_msg_max && beast::detail::sum_exceeds(
impl.rd_size, zs.total_out, impl.rd_msg_max))
{
@@ -522,8 +604,10 @@ public:
}
cb_.consume(zs.total_out);
impl.rd_size += zs.total_out;
impl.rd_remain -= zs.total_in;
impl.rd_buf.consume(zs.total_in);
if (! fin) {
impl.rd_remain -= zs.total_in;
impl.rd_buf.consume(zs.total_in);
}
bytes_written_ += zs.total_out;
}
if(impl.rd_op == detail::opcode::text)
@@ -547,10 +631,25 @@ public:
if(! impl.wr_block.try_lock(this))
{
BOOST_ASIO_CORO_YIELD
impl.op_rd.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
impl.op_rd.emplace(std::move(*this));
}
if (ec)
return this->complete(cont, ec, bytes_written_);
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec))
goto upcall;
@@ -571,8 +670,14 @@ public:
// Send close frame
BOOST_ASSERT(impl.wr_block.is_locked(this));
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), impl.rd_fb.data(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
net::async_write(impl.stream(), net::const_buffer(impl.rd_fb.data()),
beast::detail::bind_continuation(std::move(*this)));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec))
goto upcall;
@@ -582,8 +687,14 @@ public:
using beast::websocket::async_teardown;
BOOST_ASSERT(impl.wr_block.is_locked(this));
BOOST_ASIO_CORO_YIELD
async_teardown(impl.role, impl.stream(),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read_some"));
async_teardown(impl.role, impl.stream(),
beast::detail::bind_continuation(std::move(*this)));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
if(ec == net::error::eof)
{
@@ -592,7 +703,9 @@ public:
ec = {};
}
if(! ec)
ec = result_;
{
BOOST_BEAST_ASSIGN_EC(ec, result_);
}
if(ec && ec != error::closed)
impl.change_status(status::failed);
else
@@ -619,7 +732,7 @@ template<class Handler, class DynamicBuffer>
class stream<NextLayer, deflateSupported>::read_op
: public beast::async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
boost::weak_ptr<impl_type> wp_;
DynamicBuffer& b_;
@@ -657,28 +770,34 @@ public:
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
bytes_written_ = 0;
return this->complete(cont, ec, bytes_written_);
}
auto& impl = *sp;
using mutable_buffers_type = typename
DynamicBuffer::mutable_buffers_type;
boost::optional<mutable_buffers_type> mb;
BOOST_ASIO_CORO_REENTER(*this)
{
do
{
mb = beast::detail::dynamic_buffer_prepare(b_,
clamp(impl.read_size_hint_db(b_), limit_),
ec, error::buffer_overflow);
if(impl.check_stop_now(ec))
goto upcall;
// VFALCO TODO use boost::beast::bind_continuation
BOOST_ASIO_CORO_YIELD
read_some_op<read_op, mutable_buffers_type>(
std::move(*this), sp, *mb);
{
auto mb = beast::detail::dynamic_buffer_prepare(b_,
clamp(impl.read_size_hint_db(b_), limit_),
ec, error::buffer_overflow);
if(impl.check_stop_now(ec))
goto upcall;
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::async_read"));
read_some_op<read_op, mutable_buffers_type>(
std::move(*this), sp, *mb);
}
b_.commit(bytes_transferred);
bytes_written_ += bytes_transferred;
if(ec)
@@ -801,7 +920,7 @@ read(DynamicBuffer& buffer, error_code& ec)
}
template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class ReadHandler>
template<class DynamicBuffer, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
stream<NextLayer, deflateSupported>::
async_read(DynamicBuffer& buffer, ReadHandler&& handler)
@@ -875,7 +994,7 @@ read_some(
}
template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class ReadHandler>
template<class DynamicBuffer, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
stream<NextLayer, deflateSupported>::
async_read_some(
@@ -1002,7 +1121,7 @@ loop:
goto loop;
}
if(impl.ctrl_cb)
impl.ctrl_cb(frame_type::ping, payload);
impl.ctrl_cb(frame_type::ping, to_string_view(payload));
detail::frame_buffer fb;
impl.template write_ping<flat_static_buffer_base>(fb,
detail::opcode::pong, payload);
@@ -1018,7 +1137,7 @@ loop:
detail::read_ping(payload, b);
impl.rd_buf.consume(len);
if(impl.ctrl_cb)
impl.ctrl_cb(frame_type::pong, payload);
impl.ctrl_cb(frame_type::pong, to_string_view(payload));
goto loop;
}
// Handle close frame
@@ -1038,7 +1157,7 @@ loop:
impl.cr = cr;
impl.rd_buf.consume(len);
if(impl.ctrl_cb)
impl.ctrl_cb(frame_type::close, impl.cr.reason);
impl.ctrl_cb(frame_type::close, to_string_view(impl.cr.reason));
BOOST_ASSERT(! impl.wr_close);
// _Start the WebSocket Closing Handshake_
do_fail(
@@ -1141,7 +1260,9 @@ loop:
impl.rd_size += bytes_transferred;
}
}
impl.rd_done = impl.rd_remain == 0 && impl.rd_fh.fin;
BOOST_ASSERT( ! impl.rd_done );
if( impl.rd_remain == 0 && impl.rd_fh.fin )
impl.rd_done = true;
}
else
{
@@ -1160,6 +1281,8 @@ loop:
zs.avail_out = out.size();
BOOST_ASSERT(zs.avail_out > 0);
}
// boolean to track the end of the message.
bool fin = false;
if(impl.rd_remain > 0)
{
if(impl.rd_buf.size() > 0)
@@ -1203,22 +1326,10 @@ loop:
{
// append the empty block codes
static std::uint8_t constexpr
empty_block[4] = {
0x00, 0x00, 0xff, 0xff };
empty_block[4] = { 0x00, 0x00, 0xff, 0xff };
zs.next_in = empty_block;
zs.avail_in = sizeof(empty_block);
impl.inflate(zs, zlib::Flush::sync, ec);
if(! ec)
{
// https://github.com/madler/zlib/issues/280
if(zs.total_out > 0)
ec = error::partial_deflate_block;
}
if(impl.check_stop_now(ec))
return bytes_written;
impl.do_context_takeover_read(impl.role);
impl.rd_done = true;
break;
fin = true;
}
else
{
@@ -1227,6 +1338,11 @@ loop:
impl.inflate(zs, zlib::Flush::sync, ec);
if(impl.check_stop_now(ec))
return bytes_written;
if (fin && zs.total_out == 0) {
impl.do_context_takeover_read(impl.role);
impl.rd_done = true;
break;
}
if(impl.rd_msg_max && beast::detail::sum_exceeds(
impl.rd_size, zs.total_out, impl.rd_msg_max))
{
@@ -1236,8 +1352,10 @@ loop:
}
cb.consume(zs.total_out);
impl.rd_size += zs.total_out;
impl.rd_remain -= zs.total_in;
impl.rd_buf.consume(zs.total_in);
if (! fin) {
impl.rd_remain -= zs.total_in;
impl.rd_buf.consume(zs.total_in);
}
bytes_written += zs.total_out;
}
if(impl.rd_op == detail::opcode::text)
@@ -1258,7 +1376,7 @@ loop:
}
template<class NextLayer, bool deflateSupported>
template<class MutableBufferSequence, class ReadHandler>
template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
stream<NextLayer, deflateSupported>::
async_read_some(

View File

@@ -11,6 +11,9 @@
#define BOOST_BEAST_WEBSOCKET_IMPL_SSL_HPP
#include <utility>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp>
namespace boost {
namespace beast {
@@ -33,24 +36,73 @@ namespace beast {
template<class AsyncStream>
void
teardown(
role_type,
net::ssl::stream<AsyncStream>& stream,
role_type role,
boost::asio::ssl::stream<AsyncStream>& stream,
error_code& ec)
{
stream.shutdown(ec);
using boost::beast::websocket::teardown;
error_code ec2;
teardown(role, stream.next_layer(), ec ? ec2 : ec);
}
namespace detail {
template<class AsyncStream>
struct ssl_shutdown_op
: boost::asio::coroutine
{
ssl_shutdown_op(
boost::asio::ssl::stream<AsyncStream>& s,
role_type role)
: s_(s)
, role_(role)
{
}
template<class Self>
void
operator()(Self& self, error_code ec = {}, std::size_t = 0)
{
BOOST_ASIO_CORO_REENTER(*this)
{
self.reset_cancellation_state(net::enable_total_cancellation());
BOOST_ASIO_CORO_YIELD
s_.async_shutdown(std::move(self));
ec_ = ec;
using boost::beast::websocket::async_teardown;
BOOST_ASIO_CORO_YIELD
async_teardown(role_, s_.next_layer(), std::move(self));
if (!ec_)
ec_ = ec;
self.complete(ec_);
}
}
private:
boost::asio::ssl::stream<AsyncStream>& s_;
role_type role_;
error_code ec_;
};
} // detail
template<
class AsyncStream,
class TeardownHandler>
void
async_teardown(
role_type,
net::ssl::stream<AsyncStream>& stream,
role_type role,
boost::asio::ssl::stream<AsyncStream>& stream,
TeardownHandler&& handler)
{
stream.async_shutdown(
std::forward<TeardownHandler>(handler));
return boost::asio::async_compose<TeardownHandler, void(error_code)>(
detail::ssl_shutdown_op<AsyncStream>(stream, role),
handler,
stream);
}
} // beast

View File

@@ -25,11 +25,8 @@
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/detail/clamp.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/assert.hpp>
#include <boost/endian/buffers.hpp>
#include <boost/make_shared.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
@@ -61,10 +58,19 @@ stream(Args&&... args)
max_control_frame_size);
}
template<class NextLayer, bool deflateSupported>
template<class Other>
stream<NextLayer, deflateSupported>::
stream(stream<Other> && other)
: impl_(boost::make_shared<impl_type>(std::move(other.next_layer())))
{
}
template<class NextLayer, bool deflateSupported>
auto
stream<NextLayer, deflateSupported>::
get_executor() const noexcept ->
get_executor() noexcept ->
executor_type
{
return impl_->stream().get_executor();
@@ -140,12 +146,7 @@ read_size_hint(DynamicBuffer& buffer) const
static_assert(
net::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer type requirements not met");
auto const initial_size = (std::min)(
+tcp_frame_size,
buffer.max_size() - buffer.size());
if(initial_size == 0)
return 1; // buffer is full
return read_size_hint(initial_size);
return impl_->read_size_hint_db(buffer);
}
//------------------------------------------------------------------------------
@@ -312,6 +313,22 @@ text() const
return impl_->wr_opcode == detail::opcode::text;
}
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
compress(bool value)
{
impl_->wr_compress_opt = value;
}
template<class NextLayer, bool deflateSupported>
bool
stream<NextLayer, deflateSupported>::
compress() const
{
return impl_->wr_compress_opt;
}
//------------------------------------------------------------------------------
// _Fail the WebSocket Connection_
@@ -344,7 +361,9 @@ do_fail(
ec = {};
}
if(! ec)
ec = ev;
{
BOOST_BEAST_ASSIGN_EC(ec, ev);
}
if(ec && ec != error::closed)
impl_->change_status(status::failed);
else

View File

@@ -30,9 +30,6 @@
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/clamp.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -71,8 +68,9 @@ struct stream<NextLayer, deflateSupported>::impl_type
impl_type>(this->detail::service::
impl_type::shared_from_this());
}
net::steady_timer timer; // used for timeouts
using executor_type = typename std::decay<NextLayer>::type::executor_type;
typename net::steady_timer::rebind_executor<executor_type>::other
timer; // used for timeouts
close_reason cr; // set from received close frame
control_cb_type ctrl_cb; // control callback
@@ -99,7 +97,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
bool wr_cont /* next write is a continuation */ = false;
bool wr_frag /* autofrag the current message */ = false;
bool wr_frag_opt /* autofrag option setting */ = true;
bool wr_compress /* compress current message */ = false;
bool wr_compress; /* compress current message */
bool wr_compress_opt /* compress message setting */ = true;
detail::opcode wr_opcode /* message type */ = detail::opcode::text;
std::unique_ptr<
std::uint8_t[]> wr_buf; // write buffer
@@ -130,7 +129,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
boost::empty_init_t{},
std::forward<Args>(args)...)
, detail::service::impl_type(
this->boost::empty_value<NextLayer>::get().get_executor().context())
this->get_context(
this->boost::empty_value<NextLayer>::get().get_executor()))
, timer(this->boost::empty_value<NextLayer>::get().get_executor())
{
timeout_opt.handshake_timeout = none();
@@ -211,11 +211,24 @@ struct stream<NextLayer, deflateSupported>::impl_type
timer.cancel();
}
// Called before each write frame
void
begin_msg()
time_out()
{
timed_out = true;
change_status(status::closed);
close_socket(get_lowest_layer(stream()));
}
// Called just before sending
// the first frame of each message
void
begin_msg(std::size_t n_bytes)
{
wr_frag = wr_frag_opt;
wr_compress =
this->pmd_enabled() &&
wr_compress_opt &&
this->should_compress(n_bytes);
// Maintain the write buffer
if( this->pmd_enabled() ||
@@ -234,6 +247,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
wr_buf_size = wr_buf_opt;
wr_buf.reset();
}
//
}
//--------------------------------------------------------------------------
@@ -275,13 +290,6 @@ struct stream<NextLayer, deflateSupported>::impl_type
return key;
}
std::size_t
read_size_hint(std::size_t initial_size) const
{
return this->read_size_hint_pmd(
initial_size, rd_done, rd_remain, rd_fh);
}
template<class DynamicBuffer>
std::size_t
read_size_hint_db(DynamicBuffer& buffer) const
@@ -291,7 +299,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
buffer.max_size() - buffer.size());
if(initial_size == 0)
return 1; // buffer is full
return this->read_size_hint(initial_size);
return this->read_size_hint_pmd(
initial_size, rd_done, rd_remain, rd_fh);
}
template<class DynamicBuffer>
@@ -334,7 +343,7 @@ struct stream<NextLayer, deflateSupported>::impl_type
if(timed_out)
{
timed_out = false;
ec = beast::error::timeout;
BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
return true;
}
@@ -343,7 +352,7 @@ struct stream<NextLayer, deflateSupported>::impl_type
status_ == status::failed)
{
//BOOST_ASSERT(ec_delivered);
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return true;
}
@@ -355,7 +364,7 @@ struct stream<NextLayer, deflateSupported>::impl_type
if(ec_delivered)
{
// No, so abort
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
return true;
}
@@ -414,6 +423,12 @@ struct stream<NextLayer, deflateSupported>::impl_type
{
timer.expires_after(
timeout_opt.handshake_timeout);
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::check_stop_now"
));
timer.async_wait(
timeout_handler<Executor>(
ex, this->weak_from_this()));
@@ -430,6 +445,12 @@ struct stream<NextLayer, deflateSupported>::impl_type
else
timer.expires_after(
timeout_opt.idle_timeout);
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::check_stop_now"
));
timer.async_wait(
timeout_handler<Executor>(
ex, this->weak_from_this()));
@@ -447,13 +468,23 @@ struct stream<NextLayer, deflateSupported>::impl_type
idle_counter = 0;
timer.expires_after(
timeout_opt.handshake_timeout);
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::check_stop_now"
));
timer.async_wait(
timeout_handler<Executor>(
ex, this->weak_from_this()));
}
else
{
BOOST_ASSERT(! is_timer_set());
// VFALCO This assert goes off when there's also
// a pending read with the timer set. The bigger
// fix is to give close its own timeout, instead
// of using the handshake timeout.
// BOOST_ASSERT(! is_timer_set());
}
break;
@@ -467,6 +498,22 @@ struct stream<NextLayer, deflateSupported>::impl_type
}
private:
template<class Executor>
static net::execution_context&
get_context(Executor const& ex,
typename std::enable_if< net::execution::is_executor<Executor>::value >::type* = 0)
{
return net::query(ex, net::execution::context);
}
template<class Executor>
static net::execution_context&
get_context(Executor const& ex,
typename std::enable_if< !net::execution::is_executor<Executor>::value >::type* = 0)
{
return ex.context();
}
bool
is_timer_set() const
{
@@ -514,8 +561,7 @@ private:
switch(impl.status_)
{
case status::handshake:
impl.timed_out = true;
close_socket(get_lowest_layer(impl.stream()));
impl.time_out();
return;
case status::open:
@@ -526,23 +572,34 @@ private:
if( impl.timeout_opt.keep_alive_pings &&
impl.idle_counter < 1)
{
idle_ping_op<Executor>(sp, get_executor());
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::timeout_handler"
));
idle_ping_op<Executor>(sp, get_executor());
}
++impl.idle_counter;
impl.timer.expires_after(
impl.timeout_opt.idle_timeout / 2);
impl.timer.async_wait(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::timeout_handler"
));
impl.timer.async_wait(std::move(*this));
}
return;
}
// timeout
impl.timed_out = true;
close_socket(get_lowest_layer(impl.stream()));
impl.time_out();
return;
case status::closing:
impl.timed_out = true;
close_socket(get_lowest_layer(impl.stream()));
impl.time_out();
return;
case status::closed:
@@ -577,14 +634,11 @@ build_request(
req.set(http::field::upgrade, "websocket");
req.set(http::field::connection, "upgrade");
detail::make_sec_ws_key(key);
req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_key, to_string_view(key));
req.set(http::field::sec_websocket_version, "13");
this->build_request_pmd(req);
decorator_opt(req);
decorator(req);
if(! req.count(http::field::user_agent))
req.set(http::field::user_agent,
BOOST_BEAST_VERSION_STRING);
return req;
}
@@ -600,7 +654,7 @@ on_response(
auto const err =
[&](error e)
{
ec = e;
BOOST_BEAST_ASSIGN_EC(ec, e);
};
if(res.result() != http::status::switching_protocols)
return err(error::upgrade_declined);
@@ -626,8 +680,8 @@ on_response(
if(it == res.end())
return err(error::no_sec_accept);
detail::sec_ws_accept_type acc;
detail::make_sec_ws_accept(acc, key);
if(acc.compare(it->value()) != 0)
detail::make_sec_ws_accept(acc, to_string_view(key));
if (to_string_view(acc).compare(it->value()) != 0)
return err(error::bad_sec_accept);
}
@@ -694,14 +748,14 @@ parse_fh(
if(rd_cont)
{
// new data frame when continuation expected
ec = error::bad_data_frame;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_data_frame);
return false;
}
if(fh.rsv2 || fh.rsv3 ||
! this->rd_deflated(fh.rsv1))
{
// reserved bits not cleared
ec = error::bad_reserved_bits;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
return false;
}
break;
@@ -710,13 +764,13 @@ parse_fh(
if(! rd_cont)
{
// continuation without an active message
ec = error::bad_continuation;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_continuation);
return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
ec = error::bad_reserved_bits;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
return false;
}
break;
@@ -725,25 +779,25 @@ parse_fh(
if(detail::is_reserved(fh.op))
{
// reserved opcode
ec = error::bad_opcode;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_opcode);
return false;
}
if(! fh.fin)
{
// fragmented control message
ec = error::bad_control_fragment;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_fragment);
return false;
}
if(fh.len > 125)
{
// invalid length for control message
ec = error::bad_control_size;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_size);
return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
ec = error::bad_reserved_bits;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
return false;
}
break;
@@ -751,13 +805,13 @@ parse_fh(
if(role == role_type::server && ! fh.mask)
{
// unmasked frame from client
ec = error::bad_unmasked_frame;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_unmasked_frame);
return false;
}
if(role == role_type::client && fh.mask)
{
// masked frame from server
ec = error::bad_masked_frame;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_masked_frame);
return false;
}
if(detail::is_control(fh.op) &&
@@ -771,28 +825,31 @@ parse_fh(
{
case 126:
{
std::uint8_t tmp[2];
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(tmp));
cb.consume(net::buffer_copy(net::buffer(tmp), cb));
fh.len = detail::big_uint16_to_native(&tmp[0]);
std::uint16_t len_be;
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
cb.consume(net::buffer_copy(
net::mutable_buffer(&len_be, sizeof(len_be)), cb));
fh.len = endian::big_to_native(len_be);
if(fh.len < 126)
{
// length not canonical
ec = error::bad_size;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
return false;
}
break;
}
case 127:
{
std::uint8_t tmp[8];
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(tmp));
cb.consume(net::buffer_copy(net::buffer(tmp), cb));
fh.len = detail::big_uint64_to_native(&tmp[0]);
std::uint64_t len_be;
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
cb.consume(net::buffer_copy(
net::mutable_buffer(&len_be, sizeof(len_be)), cb));
fh.len = endian::big_to_native(len_be);
if(fh.len < 65536)
{
// length not canonical
ec = error::bad_size;
BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
return false;
}
break;
@@ -800,10 +857,11 @@ parse_fh(
}
if(fh.mask)
{
std::uint8_t tmp[4];
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(tmp));
cb.consume(net::buffer_copy(net::buffer(tmp), cb));
fh.key = detail::little_uint32_to_native(&tmp[0]);
std::uint32_t key_le;
BOOST_ASSERT(buffer_bytes(cb) >= sizeof(key_le));
cb.consume(net::buffer_copy(
net::mutable_buffer(&key_le, sizeof(key_le)), cb));
fh.key = endian::little_to_native(key_le);
detail::prepare_key(rd_key, fh.key);
}
else
@@ -824,7 +882,7 @@ parse_fh(
std::uint64_t>::max)() - fh.len)
{
// message size exceeds configured limit
ec = error::message_too_big;
BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
return false;
}
}
@@ -834,7 +892,7 @@ parse_fh(
rd_size, fh.len, rd_msg_max))
{
// message size exceeds configured limit
ec = error::message_too_big;
BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
return false;
}
}
@@ -909,12 +967,10 @@ write_close(DynamicBuffer& db, close_reason const& cr)
if(fh.mask)
detail::prepare_key(key, fh.key);
{
std::uint8_t tmp[2];
::new(&tmp[0]) big_uint16_buf_t{
(std::uint16_t)cr.code};
auto code_be = endian::native_to_big<std::uint16_t>(cr.code);
auto mb = db.prepare(2);
net::buffer_copy(mb,
net::buffer(tmp));
net::const_buffer(&code_be, sizeof(code_be)));
if(fh.mask)
detail::mask_inplace(mb, key);
db.commit(2);

View File

@@ -14,7 +14,7 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/bind_continuation.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp>
#include <memory>
@@ -33,7 +33,7 @@ class teardown_tcp_op
Handler, beast::executor_type<
net::basic_stream_socket<
Protocol, Executor>>>
, public net::coroutine
, public asio::coroutine
{
using socket_type =
net::basic_stream_socket<Protocol, Executor>;
@@ -56,8 +56,10 @@ public:
s.get_executor())
, s_(s)
, role_(role)
, nb_(false)
{
(*this)({}, 0, false);
this->set_allowed_cancellation(net::cancellation_type::all);
}
void
@@ -85,9 +87,16 @@ public:
if(ec == net::error::would_block)
{
BOOST_ASIO_CORO_YIELD
s_.async_wait(
net::socket_base::wait_read,
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::tcp::async_teardown"
));
s_.async_wait(
net::socket_base::wait_read,
beast::detail::bind_continuation(std::move(*this)));
}
continue;
}
if(ec)
@@ -113,8 +122,15 @@ public:
if(! cont)
{
BOOST_ASIO_CORO_YIELD
net::post(bind_front_handler(
std::move(*this), ec));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"websocket::tcp::async_teardown"
));
net::post(s_.get_executor(), bind_front_handler(
std::move(*this), ec));
}
}
{
error_code ignored;

View File

@@ -41,7 +41,7 @@ template<class Handler, class Buffers>
class stream<NextLayer, deflateSupported>::write_some_op
: public beast::async_base<
Handler, beast::executor_type<stream>>
, public net::coroutine
, public asio::coroutine
{
enum
{
@@ -86,7 +86,7 @@ public:
// Set up the outgoing frame header
if(! impl.wr_cont)
{
impl.begin_msg();
impl.begin_msg(beast::buffer_bytes(bs));
fh_.rsv1 = impl.wr_compress;
}
else
@@ -114,7 +114,7 @@ public:
else
{
BOOST_ASSERT(impl.wr_buf_size != 0);
remain_ = buffer_bytes(cb_);
remain_ = beast::buffer_bytes(cb_);
if(remain_ > impl.wr_buf_size)
how_ = do_nomask_frag;
else
@@ -130,7 +130,7 @@ public:
else
{
BOOST_ASSERT(impl.wr_buf_size != 0);
remain_ = buffer_bytes(cb_);
remain_ = beast::buffer_bytes(cb_);
if(remain_ > impl.wr_buf_size)
how_ = do_mask_frag;
else
@@ -147,10 +147,10 @@ public:
};
template<class NextLayer, bool deflateSupported>
template<class Buffers, class Handler>
template<class Handler, class Buffers>
void
stream<NextLayer, deflateSupported>::
write_some_op<Buffers, Handler>::
write_some_op<Handler, Buffers>::
operator()(
error_code ec,
std::size_t bytes_transferred,
@@ -162,7 +162,7 @@ operator()(
auto sp = wp_.lock();
if(! sp)
{
ec = net::error::operation_aborted;
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
bytes_transferred_ = 0;
return this->complete(cont, ec, bytes_transferred_);
}
@@ -174,10 +174,33 @@ operator()(
{
do_suspend:
BOOST_ASIO_CORO_YIELD
impl.op_wr.emplace(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
this->set_allowed_cancellation(net::cancellation_type::all);
impl.op_wr.emplace(std::move(*this),
net::cancellation_type::all);
}
if (ec)
return this->complete(cont, ec, bytes_transferred_);
this->set_allowed_cancellation(net::cancellation_type::terminal);
impl.wr_block.lock(this);
BOOST_ASIO_CORO_YIELD
net::post(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
net::post(sp->stream().get_executor(), std::move(*this));
}
BOOST_ASSERT(impl.wr_block.is_locked(this));
}
if(impl.check_stop_now(ec))
@@ -189,15 +212,29 @@ operator()(
{
// send a single frame
fh_.fin = fin_;
fh_.len = buffer_bytes(cb_);
fh_.len = beast::buffer_bytes(cb_);
impl.wr_fb.clear();
detail::write<flat_static_buffer_base>(
impl.wr_fb, fh_);
impl.wr_cont = ! fin_;
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(),
buffers_cat(impl.wr_fb.data(), cb_),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(impl.wr_fb.data()),
net::const_buffer(0, 0),
cb_,
buffers_prefix(0, cb_)
),
beast::detail::bind_continuation(std::move(*this)));
}
bytes_transferred_ += clamp(fh_.len);
if(impl.check_stop_now(ec))
goto upcall;
@@ -221,10 +258,26 @@ operator()(
impl.wr_cont = ! fin_;
// Send frame
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), buffers_cat(
impl.wr_fb.data(),
buffers_prefix(clamp(fh_.len), cb_)),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
buffers_suffix<Buffers> empty_cb(cb_);
empty_cb.consume(~std::size_t(0));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(impl.wr_fb.data()),
net::const_buffer(0, 0),
empty_cb,
buffers_prefix(clamp(fh_.len), cb_)
),
beast::detail::bind_continuation(std::move(*this)));
}
n = clamp(fh_.len); // restore `n` on yield
bytes_transferred_ += n;
if(impl.check_stop_now(ec))
@@ -272,10 +325,26 @@ operator()(
impl.wr_cont = ! fin_;
// write frame header and some payload
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), buffers_cat(
impl.wr_fb.data(),
net::buffer(impl.wr_buf.get(), n)),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
buffers_suffix<Buffers> empty_cb(cb_);
empty_cb.consume(~std::size_t(0));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(impl.wr_fb.data()),
net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
empty_cb,
buffers_prefix(0, empty_cb)
),
beast::detail::bind_continuation(std::move(*this)));
}
// VFALCO What about consuming the buffer on error?
bytes_transferred_ +=
bytes_transferred - impl.wr_fb.size();
@@ -292,9 +361,26 @@ operator()(
remain_ -= n;
// write more payload
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(),
net::buffer(impl.wr_buf.get(), n),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
buffers_suffix<Buffers> empty_cb(cb_);
empty_cb.consume(~std::size_t(0));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(0, 0),
net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
empty_cb,
buffers_prefix(0, empty_cb)
),
beast::detail::bind_continuation(std::move(*this)));
}
bytes_transferred_ += bytes_transferred;
if(impl.check_stop_now(ec))
goto upcall;
@@ -325,10 +411,26 @@ operator()(
impl.wr_cont = ! fin_;
// Send frame
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), buffers_cat(
impl.wr_fb.data(),
net::buffer(impl.wr_buf.get(), n)),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
buffers_suffix<Buffers> empty_cb(cb_);
empty_cb.consume(~std::size_t(0));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(impl.wr_fb.data()),
net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
empty_cb,
buffers_prefix(0, empty_cb)
),
beast::detail::bind_continuation(std::move(*this)));
}
n = bytes_transferred - impl.wr_fb.size();
bytes_transferred_ += n;
if(impl.check_stop_now(ec))
@@ -365,13 +467,13 @@ operator()(
more_ = impl.deflate(b, cb_, fin_, in_, ec);
if(impl.check_stop_now(ec))
goto upcall;
n = buffer_bytes(b);
n = beast::buffer_bytes(b);
if(n == 0)
{
// The input was consumed, but there is
// no output due to compression latency.
BOOST_ASSERT(! fin_);
BOOST_ASSERT(buffer_bytes(cb_) == 0);
BOOST_ASSERT(beast::buffer_bytes(cb_) == 0);
goto upcall;
}
if(fh_.mask)
@@ -389,9 +491,26 @@ operator()(
impl.wr_cont = ! fin_;
// Send frame
BOOST_ASIO_CORO_YIELD
net::async_write(impl.stream(), buffers_cat(
impl.wr_fb.data(), b),
beast::detail::bind_continuation(std::move(*this)));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
fin_ ?
"websocket::async_write" :
"websocket::async_write_some"
));
buffers_suffix<Buffers> empty_cb(cb_);
empty_cb.consume(~std::size_t(0));
net::async_write(impl.stream(),
buffers_cat(
net::const_buffer(impl.wr_fb.data()),
net::const_buffer(b),
empty_cb,
buffers_prefix(0, empty_cb)
),
beast::detail::bind_continuation(std::move(*this)));
}
bytes_transferred_ += in_;
if(impl.check_stop_now(ec))
goto upcall;
@@ -508,7 +627,7 @@ write_some(bool fin,
detail::frame_header fh;
if(! impl.wr_cont)
{
impl.begin_msg();
impl.begin_msg(beast::buffer_bytes(buffers));
fh.rsv1 = impl.wr_compress;
}
else
@@ -520,7 +639,7 @@ write_some(bool fin,
fh.op = impl.wr_cont ?
detail::opcode::cont : impl.wr_opcode;
fh.mask = impl.role == role_type::client;
auto remain = buffer_bytes(buffers);
auto remain = beast::buffer_bytes(buffers);
if(impl.wr_compress)
{
@@ -534,14 +653,14 @@ write_some(bool fin,
b, cb, fin, bytes_transferred, ec);
if(impl.check_stop_now(ec))
return bytes_transferred;
auto const n = buffer_bytes(b);
auto const n = beast::buffer_bytes(b);
if(n == 0)
{
// The input was consumed, but there
// is no output due to compression
// latency.
BOOST_ASSERT(! fin);
BOOST_ASSERT(buffer_bytes(cb) == 0);
BOOST_ASSERT(beast::buffer_bytes(cb) == 0);
fh.fin = false;
break;
}
@@ -700,7 +819,7 @@ write_some(bool fin,
}
template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence, class WriteHandler>
template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
stream<NextLayer, deflateSupported>::
async_write_some(bool fin,
@@ -756,7 +875,7 @@ write(ConstBufferSequence const& buffers, error_code& ec)
}
template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence, class WriteHandler>
template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
stream<NextLayer, deflateSupported>::
async_write(

View File

@@ -11,15 +11,6 @@
#define BOOST_BEAST_WEBSOCKET_OPTION_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstdint>
#include <functional>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
@@ -64,6 +55,9 @@ struct permessage_deflate
/// Deflate memory level, 1..9
int memLevel = 4;
/// The minimum size a message should have to be compressed
std::size_t msg_size_threshold = 0;
};
} // websocket

View File

@@ -189,7 +189,7 @@ struct close_reason
/// Construct from a reason string. code is @ref close_code::normal.
close_reason(string_view s)
: code(close_code::normal)
, reason(s)
, reason(s.data(), s.size())
{
}
@@ -203,7 +203,7 @@ struct close_reason
/// Construct from a close code and reason string.
close_reason(close_code code_, string_view s)
: code(code_)
, reason(s)
, reason(s.data(), s.size())
{
}

View File

@@ -1,35 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_WEBSOCKET_ROLE_HPP
#define BOOST_BEAST_WEBSOCKET_ROLE_HPP
#include <boost/beast/core/detail/config.hpp>
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
#error This file is deprecated interface, #define BOOST_BEAST_ALLOW_DEPRECATED to allow it
#else
#include <boost/beast/core/role.hpp>
namespace boost {
namespace beast {
namespace websocket {
using role_type = beast::role_type;
} // websocket
} // beast
} // boost
#endif
#endif

View File

@@ -68,6 +68,18 @@ teardown(
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_teardown
and @c async_shutdown operation.
*/
template<class AsyncStream, class TeardownHandler>
void

View File

@@ -23,7 +23,6 @@
#include <boost/beast/core/role.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/http/detail/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/error.hpp>
@@ -83,7 +82,7 @@ class frame_test;
To declare the @ref stream object with a @ref tcp_stream in a
multi-threaded asynchronous program using a strand, you may write:
@code
websocket::stream<tcp_stream> ws{net::io_context::strand(ioc)};
websocket::stream<tcp_stream> ws{net::make_strand(ioc)};
@endcode
Alternatively, for a single-threaded or synchronous application
you may write:
@@ -140,6 +139,7 @@ class stream
using control_cb_type =
std::function<void(frame_type, string_view)>;
#ifndef BOOST_BEAST_DOXYGEN
friend class close_test;
friend class frame_test;
friend class ping_test;
@@ -154,6 +154,7 @@ class stream
*/
static std::size_t constexpr max_control_frame_size = 2 + 8 + 4 + 125;
static std::size_t constexpr tcp_frame_size = 1536;
#endif
static time_point never() noexcept
{
@@ -161,6 +162,7 @@ class stream
}
public:
/// Indicates if the permessage-deflate extension is supported
using is_deflate_supported =
std::integral_constant<bool, deflateSupported>;
@@ -173,6 +175,16 @@ public:
using executor_type =
beast::executor_type<next_layer_type>;
/// Rebinds the stream type to another executor.
template<class Executor1>
struct rebind_executor
{
/// The stream type when rebound to the specified executor.
using other = stream<
typename next_layer_type::template rebind_executor<Executor1>::other,
deflateSupported>;
};
/** Destructor
Destroys the stream and all associated resources.
@@ -210,6 +222,20 @@ public:
explicit
stream(Args&&... args);
/** Rebinding constructor
*
* This constructor creates a the websocket stream from a
* websocket stream with a different executor.
*
* @throw Any exception thrown by the NextLayer rebind constructor.
*
* @param other The other websocket stream to construct from.
*/
template<class Other>
explicit
stream(stream<Other> && other);
//--------------------------------------------------------------------------
/** Get the executor associated with the object.
@@ -220,7 +246,7 @@ public:
@return A copy of the executor that stream will use to dispatch handlers.
*/
executor_type
get_executor() const noexcept;
get_executor() noexcept;
/** Get a reference to the next layer
@@ -343,21 +369,31 @@ public:
//--------------------------------------------------------------------------
#if BOOST_BEAST_DOXYGEN
/// Get the option value
template<class Option>
void
get_option(Option& opt);
/// Set the option value
template<class Option>
void
set_option(Option opt);
#else
void set_option(decorator opt);
void get_option(timeout& opt);
void set_option(timeout const& opt);
#endif
/** Set the timeout option
@throws system_error on failure to reset the
timer.
*/
void
set_option(timeout const& opt);
/// Get the timeout option
void
get_option(timeout& opt);
/** Set the permessage-deflate extension options
@throws invalid_argument if `deflateSupported == false`, and either
@@ -586,6 +622,42 @@ public:
bool
text() const;
/** Set the compress message write option.
This controls whether or not outgoing messages should be
compressed. The setting is only applied when
@li The template parameter `deflateSupported` is true
@li Compression is enable. This is controlled with `stream::set_option`
@li Client and server have negotiated permessage-deflate settings
@li The message is larger than `permessage_deflate::msg_size_threshold`
This function permits adjusting per-message compression.
Changing the opcode after a message is started will only take effect
after the current message being sent is complete.
The default setting is to compress messages whenever the conditions
above are true.
@param value `true` if outgoing messages should be compressed
@par Example
Disabling compression for a single message.
@code
ws.compress(false);
ws.write(net::buffer(s), ec);
ws.compress(true);
@endcode
*/
void
compress(bool value);
/// Returns `true` if the compress message write option is set.
bool
compress() const;
/*
timer settings
@@ -676,7 +748,11 @@ public:
@param res The HTTP Upgrade response returned by the remote
endpoint. The caller may use the response to access any
additional information sent by the server.
additional information sent by the server. Note that the response object
referenced by this parameter will be updated as long as the stream has
received a valid HTTP response. If not (for example because of a communications
error), the response contents will be undefined except for the result() which
will bet set to 500, Internal Server Error.
@param host The name of the remote host. This is required by
the HTTP protocol to set the "Host" header field.
@@ -876,12 +952,17 @@ public:
@li <a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">request-target (RFC7230)</a>
@li <a href="https://tools.ietf.org/html/rfc7230#section-5.3.1">origin-form (RFC7230)</a>
*/
template<class HandshakeHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
async_handshake(
string_view host,
string_view target,
HandshakeHandler&& handler);
HandshakeHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Perform the WebSocket handshake asynchronously in the client role.
@@ -957,13 +1038,18 @@ public:
@li <a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">request-target (RFC7230)</a>
@li <a href="https://tools.ietf.org/html/rfc7230#section-5.3.1">origin-form (RFC7230)</a>
*/
template<class HandshakeHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
async_handshake(
response_type& res,
string_view host,
string_view target,
HandshakeHandler&& handler);
HandshakeHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
//
@@ -1276,9 +1362,15 @@ public:
@see
@li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a>
*/
template<class AcceptHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
async_accept(AcceptHandler&& handler);
async_accept(
AcceptHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Perform the WebSocket handshake asynchronously in the server role.
@@ -1339,17 +1431,21 @@ public:
*/
template<
class ConstBufferSequence,
class AcceptHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)>::type
#endif
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
async_accept(
ConstBufferSequence const& buffers,
AcceptHandler&& handler);
AcceptHandler&& handler =
net::default_completion_token_t<
executor_type>{}
#ifndef BOOST_BEAST_DOXYGEN
, typename std::enable_if<
! http::detail::is_header<
ConstBufferSequence>::value>::type* = 0
#endif
);
/** Perform the WebSocket handshake asynchronously in the server role.
@@ -1400,12 +1496,16 @@ public:
*/
template<
class Body, class Allocator,
class AcceptHandler>
BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
async_accept(
http::request<Body,
http::basic_fields<Allocator>> const& req,
AcceptHandler&& handler);
AcceptHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
//
@@ -1527,12 +1627,33 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
@note `terminal` cancellation will may close the underlying socket.
@see
@li <a href="https://tools.ietf.org/html/rfc6455#section-7.1.2">Websocket Closing Handshake (RFC6455)</a>
*/
template<class CloseHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 CloseHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(CloseHandler)
async_close(close_reason const& cr, CloseHandler&& handler);
async_close(
close_reason const& cr,
CloseHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
//
@@ -1624,10 +1745,32 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class WriteHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 WriteHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
async_ping(ping_data const& payload, WriteHandler&& handler);
async_ping(
ping_data const& payload,
WriteHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Send a websocket pong control frame.
@@ -1725,10 +1868,32 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class WriteHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 WriteHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
async_pong(ping_data const& payload, WriteHandler&& handler);
async_pong(
ping_data const& payload,
WriteHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
//
@@ -1879,12 +2044,33 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class DynamicBuffer, class ReadHandler>
template<
class DynamicBuffer,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<
executor_type>>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read(
DynamicBuffer& buffer,
ReadHandler&& handler);
ReadHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
@@ -2052,13 +2238,34 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class DynamicBuffer, class ReadHandler>
template<
class DynamicBuffer,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<
executor_type>>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(
DynamicBuffer& buffer,
std::size_t limit,
ReadHandler&& handler);
ReadHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
@@ -2150,6 +2357,21 @@ public:
from the beginning.
@param ec Set to indicate what error occurred, if any.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class MutableBufferSequence>
std::size_t
@@ -2221,12 +2443,34 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class MutableBufferSequence, class ReadHandler>
template<
class MutableBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<
executor_type>>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler);
ReadHandler&& handler =
net::default_completion_token_t<
executor_type>{});
//--------------------------------------------------------------------------
//
@@ -2338,14 +2582,33 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<
class ConstBufferSequence,
class WriteHandler>
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
net::default_completion_token_t<
executor_type>>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write(
ConstBufferSequence const& buffers,
WriteHandler&& handler);
WriteHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Write some message data.
@@ -2372,6 +2635,7 @@ public:
@return The number of bytes sent from the buffers.
@throws system_error Thrown on failure.
*/
template<class ConstBufferSequence>
std::size_t
@@ -2457,138 +2721,34 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::total
`total` cancellation succeeds if the operation is suspended due to ongoing
control operations such as a ping/pong.
`terminal` cancellation succeeds when supported by the underlying stream.
`terminal` cancellation leaves the stream in an undefined state,
so that only closing it is guaranteed to succeed.
*/
template<class ConstBufferSequence, class WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(bool fin,
ConstBufferSequence const& buffers, WriteHandler&& handler);
//
// Deprecated
//
#if ! BOOST_BEAST_DOXYGEN
template<class RequestDecorator>
void
handshake_ex(
string_view host,
string_view target,
RequestDecorator const& decorator);
template<class RequestDecorator>
void
handshake_ex(
response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator);
template<class RequestDecorator>
void
handshake_ex(
string_view host,
string_view target,
RequestDecorator const& decorator,
error_code& ec);
template<class RequestDecorator>
void
handshake_ex(
response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
error_code& ec);
template<class RequestDecorator, class HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
async_handshake_ex(
string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler);
template<class RequestDecorator, class HandshakeHandler>
BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
async_handshake_ex(
response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler);
template<class ResponseDecorator>
void
accept_ex(ResponseDecorator const& decorator);
template<class ResponseDecorator>
void
accept_ex(
ResponseDecorator const& decorator,
error_code& ec);
template<class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator);
template<class ConstBufferSequence, class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
error_code& ec);
template<class Body, class Allocator,
class ResponseDecorator>
void
accept_ex(http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator);
template<class Body, class Allocator,
class ResponseDecorator>
void
accept_ex(http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
error_code& ec);
template<
class ResponseDecorator,
class AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
async_accept_ex(
ResponseDecorator const& decorator,
AcceptHandler&& handler);
template<
class ConstBufferSequence,
class ResponseDecorator,
class AcceptHandler>
typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)>::type
async_accept_ex(
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
net::default_completion_token_t<
executor_type>>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(
bool fin,
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
AcceptHandler&& handler);
template<
class Body, class Allocator,
class ResponseDecorator,
class AcceptHandler>
BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
async_accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
AcceptHandler&& handler);
#endif
WriteHandler&& handler =
net::default_completion_token_t<
executor_type>{});
private:
template<class, class> class accept_op;

View File

@@ -54,8 +54,10 @@ struct stream_base
{
detail::decorator d_;
#ifndef BOOST_BEAST_DOXYGEN
template<class, bool>
friend class stream;
#endif
public:
// Move Constructor

View File

@@ -12,6 +12,8 @@
#include <boost/beast/core/detail/config.hpp>
#ifndef BOOST_BEAST_DOXYGEN
//[code_websocket_1h
namespace boost {
@@ -30,3 +32,5 @@ class stream;
//]
#endif
#endif

View File

@@ -163,6 +163,17 @@ teardown(
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_wait operation.
*/
template<
class Protocol, class Executor,