mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
permessage-deflate is a compile-time feature (API Change):
fix #849 This adds an additional `bool` template parameter to `websocket::stream`: * When deflateSupported is `true`, the stream will be capable of negotiating the permessage-deflate websocket extension per the configured run-time settings. * When deflateSupported is `false`, the stream will never negotiate the permessage-deflate websocket extension. Furthermore, all of the code necessary for implementing the permessage-deflate extension will be excluded from function instantiations. The resulting emitted object code should be smaller.
This commit is contained in:
@ -1,3 +1,5 @@
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Version 151:
|
||||
|
||||
* Sanitizer failures are errors
|
||||
@ -13,6 +15,7 @@ WebSocket:
|
||||
API Changes:
|
||||
|
||||
* http::parser is not MoveConstructible
|
||||
* permessage-deflate is a compile-time feature
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -10,13 +10,27 @@
|
||||
[section Creating Streams]
|
||||
|
||||
The interface to the WebSocket implementation is a single template class
|
||||
[link beast.ref.boost__beast__websocket__stream `stream`]
|
||||
which wraps an existing network transport object or other type of
|
||||
octet oriented stream. The wrapped object is called the "next layer"
|
||||
and must meet the requirements of __SyncStream__ if synchronous
|
||||
operations are performed, __AsyncStream__ if asynchronous operations
|
||||
are performed, or both. Any arguments supplied during construction of
|
||||
the stream wrapper are passed to next layer's constructor.
|
||||
[link beast.ref.boost__beast__websocket__stream `stream`]:
|
||||
|
||||
[ws_snippet_26]
|
||||
|
||||
An instance of the stream wraps an existing network transport object
|
||||
or other type of octet oriented stream. The wrapped object is called
|
||||
the "next layer" and must meet the requirements of __SyncStream__ if
|
||||
synchronous operations are performed, __AsyncStream__ if asynchronous
|
||||
operations are performed, or both. Any arguments supplied during
|
||||
construction of the stream wrapper are passed to next layer's constructor.
|
||||
|
||||
The value of `deflateSupported` determines if the stream will support
|
||||
(but not require) the permessage-deflate extension
|
||||
([@https://tools.ietf.org/html/rfc7692 rfc7692])
|
||||
negotiation during handshaking. This extension allows messages to be
|
||||
optionally automatically compressed using the deflate algorithm prior
|
||||
to transmission. When this boolean value is `false`, the extension is
|
||||
disabled. Applications which do not intend to use the permessage-deflate
|
||||
extension may set the value to `false` to enjoy a reduction in the size
|
||||
of the compiled output, as the necessary compression code (included with
|
||||
Beast) will not be compiled in.
|
||||
|
||||
Here we declare a websocket stream over a TCP/IP socket with ownership
|
||||
of the socket. The `io_context` argument is forwarded to the wrapped
|
||||
|
@ -75,7 +75,7 @@ native_to_little_uint32(std::uint32_t v, void* buf)
|
||||
p[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/** WebSocket frame header opcodes. */
|
||||
// frame header opcodes
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
cont = 0,
|
||||
@ -110,8 +110,7 @@ struct frame_header
|
||||
};
|
||||
|
||||
// holds the largest possible frame header
|
||||
using fh_buffer =
|
||||
flat_static_buffer<14>;
|
||||
using fh_buffer = flat_static_buffer<14>;
|
||||
|
||||
// holds the largest possible control frame
|
||||
using frame_buffer =
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <boost/beast/http/rfc7230.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
@ -355,85 +356,6 @@ pmd_normalize(pmd_offer& offer)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Compress a buffer sequence
|
||||
// Returns: `true` if more calls are needed
|
||||
//
|
||||
template<class DeflateStream, class ConstBufferSequence>
|
||||
bool
|
||||
deflate(
|
||||
DeflateStream& zo,
|
||||
boost::asio::mutable_buffer& out,
|
||||
buffers_suffix<ConstBufferSequence>& cb,
|
||||
bool fin,
|
||||
std::size_t& total_in,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
BOOST_ASSERT(out.size() >= 6);
|
||||
zlib::z_params zs;
|
||||
zs.avail_in = 0;
|
||||
zs.next_in = nullptr;
|
||||
zs.avail_out = out.size();
|
||||
zs.next_out = out.data();
|
||||
for(auto in : beast::detail::buffers_range(cb))
|
||||
{
|
||||
zs.avail_in = in.size();
|
||||
if(zs.avail_in == 0)
|
||||
continue;
|
||||
zs.next_in = in.data();
|
||||
zo.write(zs, zlib::Flush::none, ec);
|
||||
if(ec)
|
||||
{
|
||||
if(ec != zlib::error::need_buffers)
|
||||
return false;
|
||||
BOOST_ASSERT(zs.avail_out == 0);
|
||||
BOOST_ASSERT(zs.total_out == out.size());
|
||||
ec.assign(0, ec.category());
|
||||
break;
|
||||
}
|
||||
if(zs.avail_out == 0)
|
||||
{
|
||||
BOOST_ASSERT(zs.total_out == out.size());
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(zs.avail_in == 0);
|
||||
}
|
||||
total_in = zs.total_in;
|
||||
cb.consume(zs.total_in);
|
||||
if(zs.avail_out > 0 && fin)
|
||||
{
|
||||
auto const remain = boost::asio::buffer_size(cb);
|
||||
if(remain == 0)
|
||||
{
|
||||
// Inspired by Mark Adler
|
||||
// https://github.com/madler/zlib/issues/149
|
||||
//
|
||||
// VFALCO We could do this flush twice depending
|
||||
// on how much space is in the output.
|
||||
zo.write(zs, zlib::Flush::block, ec);
|
||||
BOOST_ASSERT(! ec || ec == zlib::error::need_buffers);
|
||||
if(ec == zlib::error::need_buffers)
|
||||
ec.assign(0, ec.category());
|
||||
if(ec)
|
||||
return false;
|
||||
if(zs.avail_out >= 6)
|
||||
{
|
||||
zo.write(zs, zlib::Flush::full, ec);
|
||||
BOOST_ASSERT(! ec);
|
||||
// remove flush marker
|
||||
zs.total_out -= 4;
|
||||
out = buffer(out.data(), zs.total_out);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
out = buffer(out.data(), zs.total_out);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
|
141
include/boost/beast/websocket/detail/stream_base.hpp
Normal file
141
include/boost/beast/websocket/detail/stream_base.hpp
Normal file
@ -0,0 +1,141 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 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_STREAM_BASE_HPP
|
||||
#define BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
|
||||
|
||||
#include <boost/beast/websocket/option.hpp>
|
||||
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
||||
#include <boost/beast/zlib/deflate_stream.hpp>
|
||||
#include <boost/beast/zlib/inflate_stream.hpp>
|
||||
#include <boost/beast/core/buffers_suffix.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
template<bool deflateSupported>
|
||||
struct stream_base
|
||||
{
|
||||
// State information for the permessage-deflate extension
|
||||
struct pmd_type
|
||||
{
|
||||
// `true` if current read message is compressed
|
||||
bool rd_set = false;
|
||||
|
||||
zlib::deflate_stream zo;
|
||||
zlib::inflate_stream zi;
|
||||
};
|
||||
|
||||
std::unique_ptr<pmd_type> pmd_; // pmd settings or nullptr
|
||||
permessage_deflate pmd_opts_; // local pmd options
|
||||
detail::pmd_offer pmd_config_; // offer (client) or negotiation (server)
|
||||
|
||||
// return `true` if current message is deflated
|
||||
bool
|
||||
rd_deflated() const
|
||||
{
|
||||
return pmd_ && pmd_->rd_set;
|
||||
}
|
||||
|
||||
// set whether current message is deflated
|
||||
// returns `false` on protocol violation
|
||||
bool
|
||||
rd_deflated(bool rsv1)
|
||||
{
|
||||
if(pmd_)
|
||||
{
|
||||
pmd_->rd_set = rsv1;
|
||||
return true;
|
||||
}
|
||||
return ! rsv1; // pmd not negotiated
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
bool
|
||||
deflate(
|
||||
boost::asio::mutable_buffer& out,
|
||||
buffers_suffix<ConstBufferSequence>& cb,
|
||||
bool fin,
|
||||
std::size_t& total_in,
|
||||
error_code& ec);
|
||||
|
||||
void
|
||||
do_context_takeover_write(role_type role);
|
||||
|
||||
void
|
||||
inflate(
|
||||
zlib::z_params& zs,
|
||||
zlib::Flush flush,
|
||||
error_code& ec);
|
||||
|
||||
void
|
||||
do_context_takeover_read(role_type role);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct stream_base<false>
|
||||
{
|
||||
// These stubs are for avoiding linking in the zlib
|
||||
// code when permessage-deflate is not enabled.
|
||||
|
||||
bool
|
||||
rd_deflated() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
rd_deflated(bool rsv1)
|
||||
{
|
||||
return ! rsv1;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
bool
|
||||
deflate(
|
||||
boost::asio::mutable_buffer&,
|
||||
buffers_suffix<ConstBufferSequence>&,
|
||||
bool,
|
||||
std::size_t&,
|
||||
error_code&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
do_context_takeover_write(role_type)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
inflate(
|
||||
zlib::z_params&,
|
||||
zlib::Flush,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
do_context_takeover_read(role_type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -19,12 +19,12 @@ namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
template<class F>
|
||||
using is_RequestDecorator =
|
||||
using is_request_decorator =
|
||||
typename beast::detail::is_invocable<F,
|
||||
void(request_type&)>::type;
|
||||
|
||||
template<class F>
|
||||
using is_ResponseDecorator =
|
||||
using is_response_decorator =
|
||||
typename beast::detail::is_invocable<F,
|
||||
void(response_type&)>::type;
|
||||
|
||||
|
@ -34,20 +34,23 @@ namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
// Respond to an upgrade HTTP request
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
class stream<NextLayer>::response_op
|
||||
class stream<NextLayer, deflateSupported>::response_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
stream<NextLayer, deflateSupported>& ws;
|
||||
response_type res;
|
||||
|
||||
template<class Body, class Allocator, class Decorator>
|
||||
data(Handler const&, stream<NextLayer>& ws_, http::request<
|
||||
Body, http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator)
|
||||
data(
|
||||
Handler const&,
|
||||
stream<NextLayer, deflateSupported>& ws_,
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator)
|
||||
: ws(ws_)
|
||||
, res(ws_.build_response(req, decorator))
|
||||
{
|
||||
@ -62,7 +65,7 @@ public:
|
||||
|
||||
template<class DeducedHandler, class... Args>
|
||||
response_op(DeducedHandler&& h,
|
||||
stream<NextLayer>& ws, Args&&... args)
|
||||
stream<NextLayer, deflateSupported>& ws, Args&&... args)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
ws, std::forward<Args>(args)...)
|
||||
{
|
||||
@ -78,7 +81,8 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<
|
||||
stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -100,10 +104,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
response_op<Handler>::
|
||||
operator()(
|
||||
error_code ec,
|
||||
@ -121,7 +125,7 @@ operator()(
|
||||
ec = error::handshake_failed;
|
||||
if(! ec)
|
||||
{
|
||||
pmd_read(d.ws.pmd_config_, d.res);
|
||||
d.ws.do_pmd_config(d.res, is_deflate_supported{});
|
||||
d.ws.open(role_type::server);
|
||||
}
|
||||
d_.invoke(ec);
|
||||
@ -132,18 +136,20 @@ operator()(
|
||||
|
||||
// read and respond to an upgrade request
|
||||
//
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Decorator, class Handler>
|
||||
class stream<NextLayer>::accept_op
|
||||
class stream<NextLayer, deflateSupported>::accept_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
stream<NextLayer, deflateSupported>& ws;
|
||||
Decorator decorator;
|
||||
http::request_parser<http::empty_body> p;
|
||||
data(Handler const&, stream<NextLayer>& ws_,
|
||||
Decorator const& decorator_)
|
||||
data(
|
||||
Handler const&,
|
||||
stream<NextLayer, deflateSupported>& ws_,
|
||||
Decorator const& decorator_)
|
||||
: ws(ws_)
|
||||
, decorator(decorator_)
|
||||
{
|
||||
@ -158,7 +164,7 @@ public:
|
||||
|
||||
template<class DeducedHandler, class... Args>
|
||||
accept_op(DeducedHandler&& h,
|
||||
stream<NextLayer>& ws, Args&&... args)
|
||||
stream<NextLayer, deflateSupported>& ws, Args&&... args)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
ws, std::forward<Args>(args)...)
|
||||
{
|
||||
@ -174,7 +180,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -199,11 +205,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Decorator, class Handler>
|
||||
template<class Buffers>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_op<Decorator, Handler>::
|
||||
run(Buffers const& buffers)
|
||||
{
|
||||
@ -228,10 +234,10 @@ run(Buffers const& buffers)
|
||||
(*this)(ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Decorator, class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_op<Decorator, Handler>::
|
||||
operator()(error_code ec, std::size_t)
|
||||
{
|
||||
@ -280,9 +286,9 @@ operator()(error_code ec, std::size_t)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept()
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -293,15 +299,15 @@ accept()
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
@ -310,9 +316,9 @@ accept_ex(ResponseDecorator const& decorator)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept(error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -321,26 +327,26 @@ accept(error_code& ec)
|
||||
do_accept(&default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
reset();
|
||||
do_accept(decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -354,13 +360,13 @@ accept(ConstBufferSequence const& buffers)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const &decorator)
|
||||
@ -370,7 +376,7 @@ accept_ex(
|
||||
static_assert(boost::asio::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
@ -379,11 +385,11 @@ accept_ex(
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept(
|
||||
ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
@ -412,13 +418,13 @@ accept(
|
||||
do_accept(&default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
@ -451,10 +457,10 @@ accept_ex(
|
||||
do_accept(decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req)
|
||||
@ -467,12 +473,12 @@ accept(
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
@ -480,7 +486,7 @@ accept_ex(
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
@ -489,10 +495,10 @@ accept_ex(
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
@ -504,12 +510,12 @@ accept(
|
||||
do_accept(req, &default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
@ -518,7 +524,7 @@ accept_ex(
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
reset();
|
||||
@ -527,12 +533,12 @@ accept_ex(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class AcceptHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept(
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
@ -551,20 +557,20 @@ async_accept(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ResponseDecorator,
|
||||
class AcceptHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept_ex(
|
||||
ResponseDecorator const& decorator,
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
boost::asio::async_completion<AcceptHandler,
|
||||
@ -580,7 +586,7 @@ async_accept_ex(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class AcceptHandler>
|
||||
@ -588,7 +594,7 @@ typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept(
|
||||
ConstBufferSequence const& buffers,
|
||||
AcceptHandler&& handler)
|
||||
@ -611,7 +617,7 @@ async_accept(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator,
|
||||
@ -620,7 +626,7 @@ typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))>::type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
@ -631,7 +637,7 @@ async_accept_ex(
|
||||
static_assert(boost::asio::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
boost::asio::async_completion<AcceptHandler,
|
||||
@ -647,13 +653,13 @@ async_accept_ex(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class AcceptHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept(
|
||||
http::request<Body, http::basic_fields<Allocator>> const& req,
|
||||
AcceptHandler&& handler)
|
||||
@ -674,14 +680,14 @@ async_accept(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator,
|
||||
class AcceptHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
AcceptHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_accept_ex(
|
||||
http::request<Body, http::basic_fields<Allocator>> const& req,
|
||||
ResponseDecorator const& decorator,
|
||||
@ -689,7 +695,7 @@ async_accept_ex(
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
boost::asio::async_completion<AcceptHandler,
|
||||
@ -708,10 +714,10 @@ async_accept_ex(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Decorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
do_accept(
|
||||
Decorator const& decorator,
|
||||
error_code& ec)
|
||||
@ -725,13 +731,14 @@ do_accept(
|
||||
do_accept(p.get(), decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator,
|
||||
class Decorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
do_accept(
|
||||
http::request<Body,http::basic_fields<Allocator>> const& req,
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
@ -746,7 +753,7 @@ do_accept(
|
||||
// teardown if Connection: close.
|
||||
return;
|
||||
}
|
||||
pmd_read(pmd_config_, res);
|
||||
do_pmd_config(res, is_deflate_supported{});
|
||||
open(role_type::server);
|
||||
}
|
||||
|
||||
|
@ -34,14 +34,14 @@ namespace websocket {
|
||||
frame. Finally it invokes the teardown operation to shut down the
|
||||
underlying connection.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
class stream<NextLayer>::close_op
|
||||
class stream<NextLayer, deflateSupported>::close_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
struct state
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
stream<NextLayer, deflateSupported>& ws;
|
||||
detail::frame_buffer fb;
|
||||
error_code ev;
|
||||
token tok;
|
||||
@ -49,7 +49,7 @@ class stream<NextLayer>::close_op
|
||||
|
||||
state(
|
||||
Handler const&,
|
||||
stream<NextLayer>& ws_,
|
||||
stream<NextLayer, deflateSupported>& ws_,
|
||||
close_reason const& cr)
|
||||
: ws(ws_)
|
||||
, tok(ws.tok_.unique())
|
||||
@ -69,7 +69,7 @@ public:
|
||||
template<class DeducedHandler>
|
||||
close_op(
|
||||
DeducedHandler&& h,
|
||||
stream<NextLayer>& ws,
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
close_reason const& cr)
|
||||
: d_(std::forward<DeducedHandler>(h), ws, cr)
|
||||
{
|
||||
@ -85,7 +85,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -109,10 +109,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
close_op<Handler>::
|
||||
operator()(
|
||||
error_code ec,
|
||||
@ -327,9 +327,9 @@ operator()(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
close(close_reason const& cr)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -340,9 +340,9 @@ close(close_reason const& cr)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
close(close_reason const& cr, error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -434,11 +434,11 @@ close(close_reason const& cr, error_code& ec)
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class CloseHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CloseHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_close(close_reason const& cr, CloseHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
|
@ -33,25 +33,27 @@ namespace websocket {
|
||||
|
||||
// send the upgrade request and process the response
|
||||
//
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
class stream<NextLayer>::handshake_op
|
||||
class stream<NextLayer, deflateSupported>::handshake_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
stream<NextLayer, deflateSupported>& ws;
|
||||
response_type* res_p;
|
||||
detail::sec_ws_key_type key;
|
||||
http::request<http::empty_body> req;
|
||||
response_type res;
|
||||
|
||||
template<class Decorator>
|
||||
data(Handler const&, stream<NextLayer>& ws_,
|
||||
data(
|
||||
Handler const&,
|
||||
stream<NextLayer, deflateSupported>& ws_,
|
||||
response_type* res_p_,
|
||||
string_view host,
|
||||
string_view target,
|
||||
Decorator const& decorator)
|
||||
string_view host,
|
||||
string_view target,
|
||||
Decorator const& decorator)
|
||||
: ws(ws_)
|
||||
, res_p(res_p_)
|
||||
, req(ws.build_request(key,
|
||||
@ -69,7 +71,7 @@ public:
|
||||
|
||||
template<class DeducedHandler, class... Args>
|
||||
handshake_op(DeducedHandler&& h,
|
||||
stream<NextLayer>& ws, Args&&... args)
|
||||
stream<NextLayer, deflateSupported>& ws, Args&&... args)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
ws, std::forward<Args>(args)...)
|
||||
{
|
||||
@ -85,7 +87,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -108,17 +110,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
void
|
||||
stream<NextLayer>::handshake_op<Handler>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_op<Handler>::
|
||||
operator()(error_code ec, std::size_t)
|
||||
{
|
||||
auto& d = *d_;
|
||||
BOOST_ASIO_CORO_REENTER(*this)
|
||||
{
|
||||
// Send HTTP Upgrade
|
||||
pmd_read(d.ws.pmd_config_, d.req);
|
||||
d.ws.do_pmd_config(d.req, is_deflate_supported{});
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
http::async_write(d.ws.stream_,
|
||||
d.req, std::move(*this));
|
||||
@ -146,11 +149,11 @@ operator()(error_code ec, std::size_t)
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake(string_view host,
|
||||
string_view target,
|
||||
HandshakeHandler&& handler)
|
||||
@ -166,11 +169,11 @@ async_handshake(string_view host,
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
@ -187,11 +190,11 @@ async_handshake(response_type& res,
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
@ -199,7 +202,7 @@ async_handshake_ex(string_view host,
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
boost::asio::async_completion<HandshakeHandler,
|
||||
@ -211,11 +214,11 @@ async_handshake_ex(string_view host,
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
@ -224,7 +227,7 @@ async_handshake_ex(response_type& res,
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
boost::asio::async_completion<HandshakeHandler,
|
||||
@ -236,9 +239,9 @@ async_handshake_ex(response_type& res,
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake(string_view host,
|
||||
string_view target)
|
||||
{
|
||||
@ -251,9 +254,9 @@ handshake(string_view host,
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake(response_type& res,
|
||||
string_view host,
|
||||
string_view target)
|
||||
@ -266,17 +269,17 @@ handshake(response_type& res,
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
@ -285,10 +288,10 @@ handshake_ex(string_view host,
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
@ -296,7 +299,7 @@ handshake_ex(response_type& res,
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
@ -305,9 +308,9 @@ handshake_ex(response_type& res,
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake(string_view host,
|
||||
string_view target, error_code& ec)
|
||||
{
|
||||
@ -317,9 +320,9 @@ handshake(string_view host,
|
||||
host, target, &default_decorate_req, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
@ -331,10 +334,10 @@ handshake(response_type& res,
|
||||
host, target, &default_decorate_req, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
@ -342,17 +345,17 @@ handshake_ex(string_view host,
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
do_handshake(nullptr,
|
||||
host, target, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
@ -361,7 +364,7 @@ handshake_ex(response_type& res,
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
do_handshake(&res,
|
||||
@ -370,10 +373,10 @@ handshake_ex(response_type& res,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
do_handshake(
|
||||
response_type* res_p,
|
||||
string_view host,
|
||||
@ -387,7 +390,7 @@ do_handshake(
|
||||
{
|
||||
auto const req = build_request(
|
||||
key, host, target, decorator);
|
||||
pmd_read(pmd_config_, req);
|
||||
do_pmd_config(req, is_deflate_supported{});
|
||||
http::write(stream_, req, ec);
|
||||
}
|
||||
if(ec)
|
||||
|
@ -32,20 +32,20 @@ namespace websocket {
|
||||
It only sends the frames it does not make attempts to read
|
||||
any frame data.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
class stream<NextLayer>::ping_op
|
||||
class stream<NextLayer, deflateSupported>::ping_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
struct state
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
stream<NextLayer, deflateSupported>& ws;
|
||||
detail::frame_buffer fb;
|
||||
token tok;
|
||||
|
||||
state(
|
||||
Handler const&,
|
||||
stream<NextLayer>& ws_,
|
||||
stream<NextLayer, deflateSupported>& ws_,
|
||||
detail::opcode op,
|
||||
ping_data const& payload)
|
||||
: ws(ws_)
|
||||
@ -67,7 +67,7 @@ public:
|
||||
template<class DeducedHandler>
|
||||
ping_op(
|
||||
DeducedHandler&& h,
|
||||
stream<NextLayer>& ws,
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
detail::opcode op,
|
||||
ping_data const& payload)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
@ -85,7 +85,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -107,10 +107,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
ping_op<Handler>::
|
||||
operator()(error_code ec, std::size_t)
|
||||
{
|
||||
@ -174,9 +174,9 @@ operator()(error_code ec, std::size_t)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
ping(ping_data const& payload)
|
||||
{
|
||||
error_code ec;
|
||||
@ -185,9 +185,9 @@ ping(ping_data const& payload)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
ping(ping_data const& payload, error_code& ec)
|
||||
{
|
||||
// Make sure the stream is open
|
||||
@ -201,9 +201,9 @@ ping(ping_data const& payload, error_code& ec)
|
||||
return;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
pong(ping_data const& payload)
|
||||
{
|
||||
error_code ec;
|
||||
@ -212,9 +212,9 @@ pong(ping_data const& payload)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
pong(ping_data const& payload, error_code& ec)
|
||||
{
|
||||
// Make sure the stream is open
|
||||
@ -228,11 +228,11 @@ pong(ping_data const& payload, error_code& ec)
|
||||
return;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_ping(ping_data const& payload, WriteHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
@ -246,11 +246,11 @@ async_ping(ping_data const& payload, WriteHandler&& handler)
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(error_code))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_pong(ping_data const& payload, WriteHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
|
@ -35,19 +35,52 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<>
|
||||
inline
|
||||
void
|
||||
stream_base<true>::
|
||||
inflate(
|
||||
zlib::z_params& zs,
|
||||
zlib::Flush flush,
|
||||
error_code& ec)
|
||||
{
|
||||
this->pmd_->zi.write(zs, flush, ec);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
void
|
||||
stream_base<true>::
|
||||
do_context_takeover_read(role_type role)
|
||||
{
|
||||
if((role == role_type::client &&
|
||||
pmd_config_.server_no_context_takeover) ||
|
||||
(role == role_type::server &&
|
||||
pmd_config_.client_no_context_takeover))
|
||||
{
|
||||
pmd_->zi.reset();
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* Read some message frame data.
|
||||
|
||||
Also reads and handles control frames.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class MutableBufferSequence,
|
||||
class Handler>
|
||||
class stream<NextLayer>::read_some_op
|
||||
class stream<NextLayer, deflateSupported>::read_some_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
Handler h_;
|
||||
stream<NextLayer>& ws_;
|
||||
stream<NextLayer, deflateSupported>& ws_;
|
||||
MutableBufferSequence bs_;
|
||||
buffers_suffix<MutableBufferSequence> cb_;
|
||||
std::size_t bytes_written_ = 0;
|
||||
@ -64,7 +97,7 @@ public:
|
||||
template<class DeducedHandler>
|
||||
read_some_op(
|
||||
DeducedHandler&& h,
|
||||
stream<NextLayer>& ws,
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
MutableBufferSequence const& bs)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, ws_(ws)
|
||||
@ -85,7 +118,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -114,10 +147,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class MutableBufferSequence, class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_some_op<MutableBufferSequence, Handler>::
|
||||
operator()(
|
||||
error_code ec,
|
||||
@ -404,7 +437,7 @@ operator()(
|
||||
}
|
||||
ws_.rd_done_ = false;
|
||||
}
|
||||
if(! ws_.pmd_ || ! ws_.pmd_->rd_set)
|
||||
if(! ws_.rd_deflated())
|
||||
{
|
||||
if(ws_.rd_remain_ > 0)
|
||||
{
|
||||
@ -546,7 +579,7 @@ operator()(
|
||||
0x00, 0x00, 0xff, 0xff };
|
||||
zs.next_in = empty_block;
|
||||
zs.avail_in = sizeof(empty_block);
|
||||
ws_.pmd_->zi.write(zs, zlib::Flush::sync, ec);
|
||||
ws_.inflate(zs, zlib::Flush::sync, ec);
|
||||
if(! ec)
|
||||
{
|
||||
// https://github.com/madler/zlib/issues/280
|
||||
@ -555,12 +588,7 @@ operator()(
|
||||
}
|
||||
if(! ws_.check_ok(ec))
|
||||
goto upcall;
|
||||
if(
|
||||
(ws_.role_ == role_type::client &&
|
||||
ws_.pmd_config_.server_no_context_takeover) ||
|
||||
(ws_.role_ == role_type::server &&
|
||||
ws_.pmd_config_.client_no_context_takeover))
|
||||
ws_.pmd_->zi.reset();
|
||||
ws_.do_context_takeover_read(ws_.role_);
|
||||
ws_.rd_done_ = true;
|
||||
break;
|
||||
}
|
||||
@ -568,7 +596,7 @@ operator()(
|
||||
{
|
||||
break;
|
||||
}
|
||||
ws_.pmd_->zi.write(zs, zlib::Flush::sync, ec);
|
||||
ws_.inflate(zs, zlib::Flush::sync, ec);
|
||||
if(! ws_.check_ok(ec))
|
||||
goto upcall;
|
||||
if(ws_.rd_msg_max_ && beast::detail::sum_exceeds(
|
||||
@ -699,15 +727,15 @@ operator()(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class DynamicBuffer,
|
||||
class Handler>
|
||||
class stream<NextLayer>::read_op
|
||||
class stream<NextLayer, deflateSupported>::read_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
Handler h_;
|
||||
stream<NextLayer>& ws_;
|
||||
stream<NextLayer, deflateSupported>& ws_;
|
||||
DynamicBuffer& b_;
|
||||
std::size_t limit_;
|
||||
std::size_t bytes_written_ = 0;
|
||||
@ -723,7 +751,7 @@ public:
|
||||
template<class DeducedHandler>
|
||||
read_op(
|
||||
DeducedHandler&& h,
|
||||
stream<NextLayer>& ws,
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
DynamicBuffer& b,
|
||||
std::size_t limit,
|
||||
bool some)
|
||||
@ -743,7 +771,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -765,10 +793,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_op<DynamicBuffer, Handler>::
|
||||
operator()(
|
||||
error_code ec,
|
||||
@ -816,10 +844,10 @@ operator()(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read(DynamicBuffer& buffer)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -834,10 +862,10 @@ read(DynamicBuffer& buffer)
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read(DynamicBuffer& buffer, error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -856,11 +884,11 @@ read(DynamicBuffer& buffer, error_code& ec)
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(error_code, std::size_t))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_read(DynamicBuffer& buffer, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
@ -884,10 +912,10 @@ async_read(DynamicBuffer& buffer, ReadHandler&& handler)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_some(
|
||||
DynamicBuffer& buffer,
|
||||
std::size_t limit)
|
||||
@ -905,10 +933,10 @@ read_some(
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_some(
|
||||
DynamicBuffer& buffer,
|
||||
std::size_t limit,
|
||||
@ -941,11 +969,11 @@ read_some(
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(error_code, std::size_t))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_read_some(
|
||||
DynamicBuffer& buffer,
|
||||
std::size_t limit,
|
||||
@ -972,10 +1000,10 @@ async_read_some(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_some(
|
||||
MutableBufferSequence const& buffers)
|
||||
{
|
||||
@ -991,10 +1019,10 @@ read_some(
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
@ -1125,7 +1153,7 @@ loop:
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
if(! pmd_ || ! pmd_->rd_set)
|
||||
if(! this->rd_deflated())
|
||||
{
|
||||
if(rd_remain_ > 0)
|
||||
{
|
||||
@ -1273,7 +1301,7 @@ loop:
|
||||
0x00, 0x00, 0xff, 0xff };
|
||||
zs.next_in = empty_block;
|
||||
zs.avail_in = sizeof(empty_block);
|
||||
pmd_->zi.write(zs, zlib::Flush::sync, ec);
|
||||
this->inflate(zs, zlib::Flush::sync, ec);
|
||||
if(! ec)
|
||||
{
|
||||
// https://github.com/madler/zlib/issues/280
|
||||
@ -1282,12 +1310,7 @@ loop:
|
||||
}
|
||||
if(! check_ok(ec))
|
||||
return bytes_written;
|
||||
if(
|
||||
(role_ == role_type::client &&
|
||||
pmd_config_.server_no_context_takeover) ||
|
||||
(role_ == role_type::server &&
|
||||
pmd_config_.client_no_context_takeover))
|
||||
pmd_->zi.reset();
|
||||
this->do_context_takeover_read(role_);
|
||||
rd_done_ = true;
|
||||
break;
|
||||
}
|
||||
@ -1295,7 +1318,7 @@ loop:
|
||||
{
|
||||
break;
|
||||
}
|
||||
pmd_->zi.write(zs, zlib::Flush::sync, ec);
|
||||
this->inflate(zs, zlib::Flush::sync, ec);
|
||||
if(! check_ok(ec))
|
||||
return bytes_written;
|
||||
if(rd_msg_max_ && beast::detail::sum_exceeds(
|
||||
@ -1328,11 +1351,11 @@ loop:
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(error_code, std::size_t))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
|
@ -40,9 +40,9 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class... Args>
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
stream(Args&&... args)
|
||||
: stream_(std::forward<Args>(args)...)
|
||||
, tok_(1)
|
||||
@ -51,16 +51,221 @@ stream(Args&&... args)
|
||||
max_control_frame_size);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer, class>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_size_hint(DynamicBuffer& buffer) const
|
||||
{
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer 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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
set_option(permessage_deflate const& o, std::true_type)
|
||||
{
|
||||
if( o.server_max_window_bits > 15 ||
|
||||
o.server_max_window_bits < 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid server_max_window_bits"});
|
||||
if( o.client_max_window_bits > 15 ||
|
||||
o.client_max_window_bits < 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid client_max_window_bits"});
|
||||
if( o.compLevel < 0 ||
|
||||
o.compLevel > 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid compLevel"});
|
||||
if( o.memLevel < 1 ||
|
||||
o.memLevel > 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid memLevel"});
|
||||
this->pmd_opts_ = o;
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
set_option(permessage_deflate const& o, std::false_type)
|
||||
{
|
||||
if(o.client_enable || o.server_enable)
|
||||
{
|
||||
// Can't enable permessage-deflate
|
||||
// when deflateSupported == false.
|
||||
//
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"deflateSupported == false"});
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
open(role_type role)
|
||||
{
|
||||
// VFALCO TODO analyze and remove dupe code in reset()
|
||||
role_ = role;
|
||||
status_ = status::open;
|
||||
rd_remain_ = 0;
|
||||
rd_cont_ = false;
|
||||
rd_done_ = true;
|
||||
// Can't clear this because accept uses it
|
||||
//rd_buf_.reset();
|
||||
rd_fh_.fin = false;
|
||||
rd_close_ = false;
|
||||
wr_close_ = false;
|
||||
wr_block_.reset();
|
||||
rd_block_.reset();
|
||||
cr_.code = close_code::none;
|
||||
|
||||
wr_cont_ = false;
|
||||
wr_buf_size_ = 0;
|
||||
|
||||
open_pmd(is_deflate_supported{});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
open_pmd(std::true_type)
|
||||
{
|
||||
if(((role_ == role_type::client &&
|
||||
this->pmd_opts_.client_enable) ||
|
||||
(role_ == role_type::server &&
|
||||
this->pmd_opts_.server_enable)) &&
|
||||
this->pmd_config_.accept)
|
||||
{
|
||||
pmd_normalize(this->pmd_config_);
|
||||
this->pmd_.reset(new typename
|
||||
detail::stream_base<deflateSupported>::pmd_type);
|
||||
if(role_ == role_type::client)
|
||||
{
|
||||
this->pmd_->zi.reset(
|
||||
this->pmd_config_.server_max_window_bits);
|
||||
this->pmd_->zo.reset(
|
||||
this->pmd_opts_.compLevel,
|
||||
this->pmd_config_.client_max_window_bits,
|
||||
this->pmd_opts_.memLevel,
|
||||
zlib::Strategy::normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->pmd_->zi.reset(
|
||||
this->pmd_config_.client_max_window_bits);
|
||||
this->pmd_->zo.reset(
|
||||
this->pmd_opts_.compLevel,
|
||||
this->pmd_config_.server_max_window_bits,
|
||||
this->pmd_opts_.memLevel,
|
||||
zlib::Strategy::normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
close()
|
||||
{
|
||||
wr_buf_.reset();
|
||||
close_pmd(is_deflate_supported{});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
reset()
|
||||
{
|
||||
BOOST_ASSERT(status_ != status::open);
|
||||
rd_remain_ = 0;
|
||||
rd_cont_ = false;
|
||||
rd_done_ = true;
|
||||
rd_buf_.consume(rd_buf_.size());
|
||||
rd_fh_.fin = false;
|
||||
rd_close_ = false;
|
||||
wr_close_ = false;
|
||||
wr_cont_ = false;
|
||||
wr_block_.reset();
|
||||
rd_block_.reset();
|
||||
cr_.code = close_code::none;
|
||||
}
|
||||
|
||||
// Called before each write frame
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
begin_msg(std::true_type)
|
||||
{
|
||||
wr_frag_ = wr_frag_opt_;
|
||||
wr_compress_ = static_cast<bool>(this->pmd_);
|
||||
|
||||
// Maintain the write buffer
|
||||
if( wr_compress_ ||
|
||||
role_ == role_type::client)
|
||||
{
|
||||
if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_ = boost::make_unique_noinit<
|
||||
std::uint8_t[]>(wr_buf_size_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Called before each write frame
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
begin_msg(std::false_type)
|
||||
{
|
||||
wr_frag_ = wr_frag_opt_;
|
||||
|
||||
// Maintain the write buffer
|
||||
if(role_ == role_type::client)
|
||||
{
|
||||
if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_ = boost::make_unique_noinit<
|
||||
std::uint8_t[]>(wr_buf_size_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
std::size_t
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_size_hint(
|
||||
std::size_t initial_size) const
|
||||
std::size_t initial_size,
|
||||
std::true_type) const
|
||||
{
|
||||
using beast::detail::clamp;
|
||||
std::size_t result;
|
||||
BOOST_ASSERT(initial_size > 0);
|
||||
if(! pmd_ || (! rd_done_ && ! pmd_->rd_set))
|
||||
if(! this->pmd_ || (! rd_done_ && ! this->pmd_->rd_set))
|
||||
{
|
||||
// current message is uncompressed
|
||||
|
||||
@ -85,164 +290,45 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class DynamicBuffer, class>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
read_size_hint(DynamicBuffer& buffer) const
|
||||
stream<NextLayer, deflateSupported>::
|
||||
read_size_hint(
|
||||
std::size_t initial_size,
|
||||
std::false_type) const
|
||||
{
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer 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);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
set_option(permessage_deflate const& o)
|
||||
{
|
||||
if( o.server_max_window_bits > 15 ||
|
||||
o.server_max_window_bits < 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid server_max_window_bits"});
|
||||
if( o.client_max_window_bits > 15 ||
|
||||
o.client_max_window_bits < 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid client_max_window_bits"});
|
||||
if( o.compLevel < 0 ||
|
||||
o.compLevel > 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid compLevel"});
|
||||
if( o.memLevel < 1 ||
|
||||
o.memLevel > 9)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||
"invalid memLevel"});
|
||||
pmd_opts_ = o;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
open(role_type role)
|
||||
{
|
||||
// VFALCO TODO analyze and remove dupe code in reset()
|
||||
role_ = role;
|
||||
status_ = status::open;
|
||||
rd_remain_ = 0;
|
||||
rd_cont_ = false;
|
||||
rd_done_ = true;
|
||||
// Can't clear this because accept uses it
|
||||
//rd_buf_.reset();
|
||||
rd_fh_.fin = false;
|
||||
rd_close_ = false;
|
||||
wr_close_ = false;
|
||||
wr_block_.reset();
|
||||
rd_block_.reset();
|
||||
cr_.code = close_code::none;
|
||||
|
||||
wr_cont_ = false;
|
||||
wr_buf_size_ = 0;
|
||||
|
||||
if(((role_ == role_type::client && pmd_opts_.client_enable) ||
|
||||
(role_ == role_type::server && pmd_opts_.server_enable)) &&
|
||||
pmd_config_.accept)
|
||||
using beast::detail::clamp;
|
||||
std::size_t result;
|
||||
BOOST_ASSERT(initial_size > 0);
|
||||
// compression is not supported
|
||||
if(rd_done_)
|
||||
{
|
||||
pmd_normalize(pmd_config_);
|
||||
pmd_.reset(new pmd_t);
|
||||
if(role_ == role_type::client)
|
||||
{
|
||||
pmd_->zi.reset(
|
||||
pmd_config_.server_max_window_bits);
|
||||
pmd_->zo.reset(
|
||||
pmd_opts_.compLevel,
|
||||
pmd_config_.client_max_window_bits,
|
||||
pmd_opts_.memLevel,
|
||||
zlib::Strategy::normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmd_->zi.reset(
|
||||
pmd_config_.client_max_window_bits);
|
||||
pmd_->zo.reset(
|
||||
pmd_opts_.compLevel,
|
||||
pmd_config_.server_max_window_bits,
|
||||
pmd_opts_.memLevel,
|
||||
zlib::Strategy::normal);
|
||||
}
|
||||
// first message frame
|
||||
result = initial_size;
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
close()
|
||||
{
|
||||
wr_buf_.reset();
|
||||
pmd_.reset();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
reset()
|
||||
{
|
||||
BOOST_ASSERT(status_ != status::open);
|
||||
rd_remain_ = 0;
|
||||
rd_cont_ = false;
|
||||
rd_done_ = true;
|
||||
rd_buf_.consume(rd_buf_.size());
|
||||
rd_fh_.fin = false;
|
||||
rd_close_ = false;
|
||||
wr_close_ = false;
|
||||
wr_cont_ = false;
|
||||
wr_block_.reset();
|
||||
rd_block_.reset();
|
||||
cr_.code = close_code::none;
|
||||
}
|
||||
|
||||
// Called before each write frame
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
begin_msg()
|
||||
{
|
||||
wr_frag_ = wr_frag_opt_;
|
||||
wr_compress_ = static_cast<bool>(pmd_);
|
||||
|
||||
// Maintain the write buffer
|
||||
if( wr_compress_ ||
|
||||
role_ == role_type::client)
|
||||
else if(rd_fh_.fin)
|
||||
{
|
||||
if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_ = boost::make_unique_noinit<
|
||||
std::uint8_t[]>(wr_buf_size_);
|
||||
}
|
||||
// last message frame
|
||||
BOOST_ASSERT(rd_remain_ > 0);
|
||||
result = clamp(rd_remain_);
|
||||
}
|
||||
else
|
||||
{
|
||||
wr_buf_size_ = wr_buf_opt_;
|
||||
wr_buf_.reset();
|
||||
result = (std::max)(
|
||||
initial_size, clamp(rd_remain_));
|
||||
}
|
||||
BOOST_ASSERT(result != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Attempt to read a complete frame header.
|
||||
// Returns `false` if more bytes are needed
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
bool
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
parse_fh(
|
||||
detail::frame_header& fh,
|
||||
DynamicBuffer& b,
|
||||
@ -301,14 +387,12 @@ parse_fh(
|
||||
// new data frame when continuation expected
|
||||
return err(close_code::protocol_error);
|
||||
}
|
||||
if((fh.rsv1 && ! pmd_) ||
|
||||
fh.rsv2 || fh.rsv3)
|
||||
if(fh.rsv2 || fh.rsv3 ||
|
||||
! this->rd_deflated(fh.rsv1))
|
||||
{
|
||||
// reserved bits not cleared
|
||||
return err(close_code::protocol_error);
|
||||
}
|
||||
if(pmd_)
|
||||
pmd_->rd_set = fh.rsv1;
|
||||
break;
|
||||
|
||||
case detail::opcode::cont:
|
||||
@ -411,7 +495,7 @@ parse_fh(
|
||||
std::uint64_t>::max)() - fh.len)
|
||||
return err(close_code::too_big);
|
||||
}
|
||||
if(! pmd_ || ! pmd_->rd_set)
|
||||
if(! this->rd_deflated())
|
||||
{
|
||||
if(rd_msg_max_ && beast::detail::sum_exceeds(
|
||||
rd_size_, fh.len, rd_msg_max_))
|
||||
@ -425,10 +509,10 @@ parse_fh(
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write_close(DynamicBuffer& db, close_reason const& cr)
|
||||
{
|
||||
using namespace boost::endian;
|
||||
@ -479,10 +563,10 @@ write_close(DynamicBuffer& db, close_reason const& cr)
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write_ping(DynamicBuffer& db,
|
||||
detail::opcode code, ping_data const& data)
|
||||
{
|
||||
@ -513,14 +597,13 @@ write_ping(DynamicBuffer& db,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Decorator>
|
||||
request_type
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
build_request(detail::sec_ws_key_type& key,
|
||||
string_view host,
|
||||
string_view target,
|
||||
Decorator const& decorator)
|
||||
string_view host, string_view target,
|
||||
Decorator const& decorator)
|
||||
{
|
||||
request_type req;
|
||||
req.target(target);
|
||||
@ -532,20 +615,7 @@ build_request(detail::sec_ws_key_type& key,
|
||||
detail::make_sec_ws_key(key, wr_gen_);
|
||||
req.set(http::field::sec_websocket_key, key);
|
||||
req.set(http::field::sec_websocket_version, "13");
|
||||
if(pmd_opts_.client_enable)
|
||||
{
|
||||
detail::pmd_offer config;
|
||||
config.accept = true;
|
||||
config.server_max_window_bits =
|
||||
pmd_opts_.server_max_window_bits;
|
||||
config.client_max_window_bits =
|
||||
pmd_opts_.client_max_window_bits;
|
||||
config.server_no_context_takeover =
|
||||
pmd_opts_.server_no_context_takeover;
|
||||
config.client_no_context_takeover =
|
||||
pmd_opts_.client_no_context_takeover;
|
||||
detail::pmd_write(req, config);
|
||||
}
|
||||
build_request_pmd(req, is_deflate_supported{});
|
||||
decorator(req);
|
||||
if(! req.count(http::field::user_agent))
|
||||
req.set(http::field::user_agent,
|
||||
@ -553,13 +623,36 @@ build_request(detail::sec_ws_key_type& key,
|
||||
return req;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
build_request_pmd(request_type& req, std::true_type)
|
||||
{
|
||||
if(this->pmd_opts_.client_enable)
|
||||
{
|
||||
detail::pmd_offer config;
|
||||
config.accept = true;
|
||||
config.server_max_window_bits =
|
||||
this->pmd_opts_.server_max_window_bits;
|
||||
config.client_max_window_bits =
|
||||
this->pmd_opts_.client_max_window_bits;
|
||||
config.server_no_context_takeover =
|
||||
this->pmd_opts_.server_no_context_takeover;
|
||||
config.client_no_context_takeover =
|
||||
this->pmd_opts_.client_no_context_takeover;
|
||||
detail::pmd_write(req, config);
|
||||
}
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator, class Decorator>
|
||||
response_type
|
||||
stream<NextLayer>::
|
||||
build_response(http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator)
|
||||
stream<NextLayer, deflateSupported>::
|
||||
build_response(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator)
|
||||
{
|
||||
auto const decorate =
|
||||
[&decorator](response_type& res)
|
||||
@ -614,12 +707,7 @@ build_response(http::request<Body,
|
||||
}
|
||||
|
||||
response_type res;
|
||||
{
|
||||
detail::pmd_offer offer;
|
||||
detail::pmd_offer unused;
|
||||
pmd_read(offer, req);
|
||||
pmd_negotiate(res, unused, offer, pmd_opts_);
|
||||
}
|
||||
build_response_pmd(res, req, is_deflate_supported{});
|
||||
res.result(http::status::switching_protocols);
|
||||
res.version(req.version());
|
||||
res.set(http::field::upgrade, "websocket");
|
||||
@ -633,11 +721,31 @@ build_response(http::request<Body,
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer>::
|
||||
on_response(response_type const& res,
|
||||
detail::sec_ws_key_type const& key, error_code& ec)
|
||||
stream<NextLayer, deflateSupported>::
|
||||
build_response_pmd(
|
||||
response_type& res,
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
std::true_type)
|
||||
{
|
||||
detail::pmd_offer offer;
|
||||
detail::pmd_offer unused;
|
||||
pmd_read(offer, req);
|
||||
pmd_negotiate(res, unused, offer, this->pmd_opts_);
|
||||
}
|
||||
|
||||
// Called when the WebSocket Upgrade response is received
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
on_response(
|
||||
response_type const& res,
|
||||
detail::sec_ws_key_type const& key,
|
||||
error_code& ec)
|
||||
{
|
||||
bool const success = [&]()
|
||||
{
|
||||
@ -664,18 +772,29 @@ on_response(response_type const& res,
|
||||
return;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
on_response_pmd(res, is_deflate_supported{});
|
||||
open(role_type::client);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
inline
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
on_response_pmd(
|
||||
response_type const& res,
|
||||
std::true_type)
|
||||
{
|
||||
detail::pmd_offer offer;
|
||||
pmd_read(offer, res);
|
||||
// VFALCO see if offer satisfies pmd_config_,
|
||||
// return an error if not.
|
||||
pmd_config_ = offer; // overwrite for now
|
||||
open(role_type::client);
|
||||
this->pmd_config_ = offer; // overwrite for now
|
||||
}
|
||||
|
||||
// _Fail the WebSocket Connection_
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
do_fail(
|
||||
std::uint16_t code, // if set, send a close frame first
|
||||
error_code ev, // error code to use upon success
|
||||
|
@ -33,13 +33,113 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
template<class NextLayer>
|
||||
namespace detail {
|
||||
|
||||
// Compress a buffer sequence
|
||||
// Returns: `true` if more calls are needed
|
||||
//
|
||||
template<>
|
||||
template<class ConstBufferSequence>
|
||||
bool
|
||||
stream_base<true>::
|
||||
deflate(
|
||||
boost::asio::mutable_buffer& out,
|
||||
buffers_suffix<ConstBufferSequence>& cb,
|
||||
bool fin,
|
||||
std::size_t& total_in,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
BOOST_ASSERT(out.size() >= 6);
|
||||
auto& zo = this->pmd_->zo;
|
||||
zlib::z_params zs;
|
||||
zs.avail_in = 0;
|
||||
zs.next_in = nullptr;
|
||||
zs.avail_out = out.size();
|
||||
zs.next_out = out.data();
|
||||
for(auto in : beast::detail::buffers_range(cb))
|
||||
{
|
||||
zs.avail_in = in.size();
|
||||
if(zs.avail_in == 0)
|
||||
continue;
|
||||
zs.next_in = in.data();
|
||||
zo.write(zs, zlib::Flush::none, ec);
|
||||
if(ec)
|
||||
{
|
||||
if(ec != zlib::error::need_buffers)
|
||||
return false;
|
||||
BOOST_ASSERT(zs.avail_out == 0);
|
||||
BOOST_ASSERT(zs.total_out == out.size());
|
||||
ec.assign(0, ec.category());
|
||||
break;
|
||||
}
|
||||
if(zs.avail_out == 0)
|
||||
{
|
||||
BOOST_ASSERT(zs.total_out == out.size());
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(zs.avail_in == 0);
|
||||
}
|
||||
total_in = zs.total_in;
|
||||
cb.consume(zs.total_in);
|
||||
if(zs.avail_out > 0 && fin)
|
||||
{
|
||||
auto const remain = boost::asio::buffer_size(cb);
|
||||
if(remain == 0)
|
||||
{
|
||||
// Inspired by Mark Adler
|
||||
// https://github.com/madler/zlib/issues/149
|
||||
//
|
||||
// VFALCO We could do this flush twice depending
|
||||
// on how much space is in the output.
|
||||
zo.write(zs, zlib::Flush::block, ec);
|
||||
BOOST_ASSERT(! ec || ec == zlib::error::need_buffers);
|
||||
if(ec == zlib::error::need_buffers)
|
||||
ec.assign(0, ec.category());
|
||||
if(ec)
|
||||
return false;
|
||||
if(zs.avail_out >= 6)
|
||||
{
|
||||
zo.write(zs, zlib::Flush::full, ec);
|
||||
BOOST_ASSERT(! ec);
|
||||
// remove flush marker
|
||||
zs.total_out -= 4;
|
||||
out = buffer(out.data(), zs.total_out);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
out = buffer(out.data(), zs.total_out);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
void
|
||||
stream_base<true>::
|
||||
do_context_takeover_write(role_type role)
|
||||
{
|
||||
if((role == role_type::client &&
|
||||
this->pmd_config_.client_no_context_takeover) ||
|
||||
(role == role_type::server &&
|
||||
this->pmd_config_.server_no_context_takeover))
|
||||
{
|
||||
this->pmd_->zo.reset();
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Buffers, class Handler>
|
||||
class stream<NextLayer>::write_some_op
|
||||
class stream<NextLayer, deflateSupported>::write_some_op
|
||||
: public boost::asio::coroutine
|
||||
{
|
||||
Handler h_;
|
||||
stream<NextLayer>& ws_;
|
||||
stream<NextLayer, deflateSupported>& ws_;
|
||||
buffers_suffix<Buffers> cb_;
|
||||
detail::frame_header fh_;
|
||||
detail::prepared_key key_;
|
||||
@ -59,7 +159,7 @@ public:
|
||||
template<class DeducedHandler>
|
||||
write_some_op(
|
||||
DeducedHandler&& h,
|
||||
stream<NextLayer>& ws,
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
bool fin,
|
||||
Buffers const& bs)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
@ -80,7 +180,7 @@ public:
|
||||
}
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
|
||||
Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
@ -109,10 +209,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Buffers, class Handler>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write_some_op<Buffers, Handler>::
|
||||
operator()(
|
||||
error_code ec,
|
||||
@ -397,8 +497,7 @@ operator()(
|
||||
{
|
||||
b = buffer(ws_.wr_buf_.get(),
|
||||
ws_.wr_buf_size_);
|
||||
more_ = detail::deflate(ws_.pmd_->zo,
|
||||
b, cb_, fin_, in_, ec);
|
||||
more_ = ws_.deflate(b, cb_, fin_, in_, ec);
|
||||
if(! ws_.check_ok(ec))
|
||||
goto upcall;
|
||||
n = buffer_size(b);
|
||||
@ -450,12 +549,8 @@ operator()(
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fh_.fin && (
|
||||
(ws_.role_ == role_type::client &&
|
||||
ws_.pmd_config_.client_no_context_takeover) ||
|
||||
(ws_.role_ == role_type::server &&
|
||||
ws_.pmd_config_.server_no_context_takeover)))
|
||||
ws_.pmd_->zo.reset();
|
||||
if(fh_.fin)
|
||||
ws_.do_context_takeover_write(ws_.role_);
|
||||
goto upcall;
|
||||
}
|
||||
}
|
||||
@ -479,10 +574,10 @@ operator()(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write_some(bool fin, ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -498,10 +593,10 @@ write_some(bool fin, ConstBufferSequence const& buffers)
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write_some(bool fin,
|
||||
ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
@ -543,9 +638,8 @@ write_some(bool fin,
|
||||
{
|
||||
auto b = buffer(
|
||||
wr_buf_.get(), wr_buf_size_);
|
||||
auto const more = detail::deflate(
|
||||
pmd_->zo, b, cb, fin,
|
||||
bytes_transferred, ec);
|
||||
auto const more = this->deflate(
|
||||
b, cb, fin, bytes_transferred, ec);
|
||||
if(! check_ok(ec))
|
||||
return bytes_transferred;
|
||||
auto const n = buffer_size(b);
|
||||
@ -581,12 +675,8 @@ write_some(bool fin,
|
||||
fh.op = detail::opcode::cont;
|
||||
fh.rsv1 = false;
|
||||
}
|
||||
if(fh.fin && (
|
||||
(role_ == role_type::client &&
|
||||
pmd_config_.client_no_context_takeover) ||
|
||||
(role_ == role_type::server &&
|
||||
pmd_config_.server_no_context_takeover)))
|
||||
pmd_->zo.reset();
|
||||
if(fh.fin)
|
||||
this->do_context_takeover_write(role_);
|
||||
}
|
||||
else if(! fh.mask)
|
||||
{
|
||||
@ -711,11 +801,11 @@ write_some(bool fin,
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(error_code, std::size_t))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_write_some(bool fin,
|
||||
ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||
{
|
||||
@ -735,10 +825,10 @@ async_write_some(bool fin,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -753,10 +843,10 @@ write(ConstBufferSequence const& buffers)
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
write(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
@ -767,11 +857,11 @@ write(ConstBufferSequence const& buffers, error_code& ec)
|
||||
return write_some(true, buffers, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(error_code, std::size_t))
|
||||
stream<NextLayer>::
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_write(
|
||||
ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <boost/beast/websocket/detail/mask.hpp>
|
||||
#include <boost/beast/websocket/detail/pausation.hpp>
|
||||
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
||||
#include <boost/beast/websocket/detail/stream_base.hpp>
|
||||
#include <boost/beast/websocket/detail/utf8_checker.hpp>
|
||||
#include <boost/beast/core/static_buffer.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
@ -29,8 +30,6 @@
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/http/string_body.hpp>
|
||||
#include <boost/beast/http/detail/type_traits.hpp>
|
||||
#include <boost/beast/zlib/deflate_stream.hpp>
|
||||
#include <boost/beast/zlib/inflate_stream.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <algorithm>
|
||||
@ -108,6 +107,12 @@ class frame_test;
|
||||
For asynchronous operations, the type must support the
|
||||
@b AsyncStream concept.
|
||||
|
||||
@tparam deflateSupported A `bool` indicating whether or not the
|
||||
stream will be capable of negotiating the permessage-deflate websocket
|
||||
extension. Note that even if this is set to `true`, the permessage
|
||||
deflate options (set by the caller at runtime) must still have the
|
||||
feature enabled for a successful negotiation to occur.
|
||||
|
||||
@note A stream object must not be moved or destroyed while there
|
||||
are pending asynchronous operations associated with it.
|
||||
|
||||
@ -116,8 +121,13 @@ class frame_test;
|
||||
@b DynamicBuffer,
|
||||
@b SyncStream
|
||||
*/
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class NextLayer,
|
||||
bool deflateSupported>
|
||||
class stream
|
||||
#ifndef BOOST_BEAST_DOXYGEN
|
||||
: private detail::stream_base<deflateSupported>
|
||||
#endif
|
||||
{
|
||||
friend class close_test;
|
||||
friend class frame_test;
|
||||
@ -126,7 +136,7 @@ class stream
|
||||
friend class read2_test;
|
||||
friend class stream_test;
|
||||
friend class write_test;
|
||||
|
||||
|
||||
/* The read buffer has to be at least as large
|
||||
as the largest possible control frame including
|
||||
the frame header.
|
||||
@ -134,8 +144,6 @@ class stream
|
||||
static std::size_t constexpr max_control_frame_size = 2 + 8 + 4 + 125;
|
||||
static std::size_t constexpr tcp_frame_size = 1536;
|
||||
|
||||
struct op {};
|
||||
|
||||
using control_cb_type =
|
||||
std::function<void(frame_type, string_view)>;
|
||||
|
||||
@ -154,16 +162,6 @@ class stream
|
||||
void reset() { id_ = 0; }
|
||||
};
|
||||
|
||||
// State information for the permessage-deflate extension
|
||||
struct pmd_t
|
||||
{
|
||||
// `true` if current read message is compressed
|
||||
bool rd_set = false;
|
||||
|
||||
zlib::deflate_stream zo;
|
||||
zlib::inflate_stream zi;
|
||||
};
|
||||
|
||||
enum class status
|
||||
{
|
||||
open,
|
||||
@ -231,14 +229,14 @@ class stream
|
||||
detail::pausation paused_wr_; // paused write op
|
||||
detail::pausation paused_ping_; // paused ping op
|
||||
detail::pausation paused_close_; // paused close op
|
||||
detail::pausation paused_r_rd_; // paused read op (read)
|
||||
detail::pausation paused_r_close_;// paused close op (read)
|
||||
|
||||
std::unique_ptr<pmd_t> pmd_; // pmd settings or nullptr
|
||||
permessage_deflate pmd_opts_; // local pmd options
|
||||
detail::pmd_offer pmd_config_; // offer (client) or negotiation (server)
|
||||
detail::pausation paused_r_rd_; // paused read op (async read)
|
||||
detail::pausation paused_r_close_;// paused close op (async read)
|
||||
|
||||
public:
|
||||
/// Indicates if the permessage-deflate extension is supported
|
||||
using is_deflate_supported =
|
||||
std::integral_constant<bool, deflateSupported>;
|
||||
|
||||
/// The type of the next layer.
|
||||
using next_layer_type =
|
||||
typename std::remove_reference<NextLayer>::type;
|
||||
@ -444,7 +442,11 @@ public:
|
||||
*/
|
||||
std::size_t
|
||||
read_size_hint(
|
||||
std::size_t initial_size = +tcp_frame_size) const;
|
||||
std::size_t initial_size = +tcp_frame_size) const
|
||||
{
|
||||
return read_size_hint(initial_size,
|
||||
is_deflate_supported{});
|
||||
}
|
||||
|
||||
/** Returns a suggested maximum buffer size for the next call to read.
|
||||
|
||||
@ -475,15 +477,22 @@ public:
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Set the permessage-deflate extension options
|
||||
/** Set the permessage-deflate extension options
|
||||
|
||||
@throws invalid_argument if `deflateSupported == false`, and either
|
||||
`client_enable` or `server_enable` is `true`.
|
||||
*/
|
||||
void
|
||||
set_option(permessage_deflate const& o);
|
||||
set_option(permessage_deflate const& o)
|
||||
{
|
||||
set_option(o, is_deflate_supported{});
|
||||
}
|
||||
|
||||
/// Get the permessage-deflate extension options
|
||||
void
|
||||
get_option(permessage_deflate& o)
|
||||
{
|
||||
o = pmd_opts_;
|
||||
get_option(o, is_deflate_supported{});
|
||||
}
|
||||
|
||||
/** Set the automatic fragmentation option.
|
||||
@ -2353,8 +2362,8 @@ public:
|
||||
next layer's `async_write_some` functions, and is known as a
|
||||
<em>composed operation</em>. The program must ensure that the
|
||||
stream performs no other write operations (such as @ref async_ping,
|
||||
@ref stream::async_write, @ref stream::async_write_some, or
|
||||
@ref stream::async_close) until this operation completes.
|
||||
@ref async_write, @ref async_write_some, or @ref async_close)
|
||||
until this operation completes.
|
||||
|
||||
If the close reason specifies a close code other than
|
||||
@ref beast::websocket::close_code::none, the close frame is
|
||||
@ -3172,8 +3181,8 @@ public:
|
||||
to the next layer's `async_write_some` functions, and is known
|
||||
as a <em>composed operation</em>. The program must ensure that
|
||||
the stream performs no other write operations (such as
|
||||
stream::async_write, stream::async_write_some, or
|
||||
stream::async_close).
|
||||
@ref async_write, @ref async_write_some, or
|
||||
@ref async_close).
|
||||
|
||||
The current setting of the @ref binary option controls
|
||||
whether the message opcode is set to text or binary. If the
|
||||
@ -3301,8 +3310,8 @@ public:
|
||||
as a <em>composed operation</em>. The actual payload sent
|
||||
may be transformed as per the WebSocket protocol settings. The
|
||||
program must ensure that the stream performs no other write
|
||||
operations (such as stream::async_write, stream::async_write_some,
|
||||
or stream::async_close).
|
||||
operations (such as @ref async_write, @ref async_write_some,
|
||||
or @ref async_close).
|
||||
|
||||
If this is the beginning of a new message, the message opcode
|
||||
will be set to text or binary as per the current setting of
|
||||
@ -3351,10 +3360,65 @@ private:
|
||||
static void default_decorate_req(request_type&) {}
|
||||
static void default_decorate_res(response_type&) {}
|
||||
|
||||
void
|
||||
set_option(permessage_deflate const& o, std::true_type);
|
||||
|
||||
void
|
||||
set_option(permessage_deflate const&, std::false_type);
|
||||
|
||||
void
|
||||
get_option(permessage_deflate& o, std::true_type)
|
||||
{
|
||||
o = this->pmd_opts_;
|
||||
}
|
||||
|
||||
void
|
||||
get_option(permessage_deflate& o, std::false_type)
|
||||
{
|
||||
o = {};
|
||||
o.client_enable = false;
|
||||
o.server_enable = false;
|
||||
}
|
||||
|
||||
void open(role_type role);
|
||||
|
||||
void open_pmd(std::true_type);
|
||||
|
||||
void open_pmd(std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
void close_pmd(std::true_type)
|
||||
{
|
||||
this->pmd_.reset();
|
||||
}
|
||||
|
||||
void close_pmd(std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
void reset();
|
||||
void begin_msg();
|
||||
|
||||
void begin_msg()
|
||||
{
|
||||
begin_msg(is_deflate_supported{});
|
||||
}
|
||||
|
||||
void begin_msg(std::true_type);
|
||||
|
||||
void begin_msg(std::false_type);
|
||||
|
||||
std::size_t
|
||||
read_size_hint(
|
||||
std::size_t initial_size,
|
||||
std::true_type) const;
|
||||
|
||||
std::size_t
|
||||
read_size_hint(
|
||||
std::size_t initial_size,
|
||||
std::false_type) const;
|
||||
|
||||
bool
|
||||
check_open(error_code& ec)
|
||||
@ -3394,6 +3458,10 @@ private:
|
||||
write_ping(DynamicBuffer& b,
|
||||
detail::opcode op, ping_data const& data);
|
||||
|
||||
//
|
||||
// upgrade
|
||||
//
|
||||
|
||||
template<class Decorator>
|
||||
request_type
|
||||
build_request(detail::sec_ws_key_type& key,
|
||||
@ -3401,28 +3469,94 @@ private:
|
||||
string_view target,
|
||||
Decorator const& decorator);
|
||||
|
||||
template<class Body,
|
||||
class Allocator, class Decorator>
|
||||
response_type
|
||||
build_response(http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator);
|
||||
void
|
||||
build_request_pmd(request_type& req, std::true_type);
|
||||
|
||||
void
|
||||
on_response(response_type const& resp,
|
||||
detail::sec_ws_key_type const& key, error_code& ec);
|
||||
build_request_pmd(request_type&, std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
template<
|
||||
class Body, class Allocator, class Decorator>
|
||||
response_type
|
||||
build_response(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator);
|
||||
|
||||
template<class Body, class Allocator>
|
||||
void
|
||||
build_response_pmd(
|
||||
response_type& res,
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
std::true_type);
|
||||
|
||||
template<class Body, class Allocator>
|
||||
void
|
||||
build_response_pmd(
|
||||
response_type&,
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const&,
|
||||
std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_response(
|
||||
response_type const& res,
|
||||
detail::sec_ws_key_type const& key,
|
||||
error_code& ec);
|
||||
|
||||
void
|
||||
on_response_pmd(
|
||||
response_type const& res,
|
||||
std::true_type);
|
||||
|
||||
void
|
||||
on_response_pmd(
|
||||
response_type const&,
|
||||
std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// accept / handshake
|
||||
//
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
do_pmd_config(
|
||||
http::basic_fields<Allocator> const& h,
|
||||
std::true_type)
|
||||
{
|
||||
pmd_read(this->pmd_config_, h);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
do_pmd_config(
|
||||
http::basic_fields<Allocator> const&,
|
||||
std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Decorator>
|
||||
void
|
||||
do_accept(Decorator const& decorator,
|
||||
do_accept(
|
||||
Decorator const& decorator,
|
||||
error_code& ec);
|
||||
|
||||
template<class Body, class Allocator,
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class Decorator>
|
||||
void
|
||||
do_accept(http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator, error_code& ec);
|
||||
do_accept(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator,
|
||||
error_code& ec);
|
||||
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
@ -3431,6 +3565,10 @@ private:
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec);
|
||||
|
||||
//
|
||||
// fail
|
||||
//
|
||||
|
||||
void
|
||||
do_fail(
|
||||
std::uint16_t code,
|
||||
|
@ -17,7 +17,8 @@ namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
template<
|
||||
class NextLayer>
|
||||
class NextLayer,
|
||||
bool deflateSupported = true>
|
||||
class stream;
|
||||
|
||||
} // websocket
|
||||
|
@ -23,11 +23,11 @@ namespace websocket {
|
||||
class read1_test : public websocket_test_suite
|
||||
{
|
||||
public:
|
||||
template<class Wrap>
|
||||
template<class Wrap, bool deflateSupported>
|
||||
void
|
||||
doReadTest(
|
||||
Wrap const& w,
|
||||
ws_type& ws,
|
||||
ws_type_t<deflateSupported>& ws,
|
||||
close_code code)
|
||||
{
|
||||
try
|
||||
@ -45,11 +45,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<class Wrap>
|
||||
template<class Wrap, bool deflateSupported>
|
||||
void
|
||||
doFailTest(
|
||||
Wrap const& w,
|
||||
ws_type& ws,
|
||||
ws_type_t<deflateSupported>& ws,
|
||||
error_code ev)
|
||||
{
|
||||
try
|
||||
@ -65,7 +65,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<class Wrap>
|
||||
template<bool deflateSupported = true, class Wrap>
|
||||
void
|
||||
doTestRead(Wrap const& w)
|
||||
{
|
||||
@ -78,7 +78,7 @@ public:
|
||||
// already closed
|
||||
{
|
||||
echo_server es{log};
|
||||
stream<test::stream> ws{ioc_};
|
||||
stream<test::stream, deflateSupported> ws{ioc_};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.close({});
|
||||
@ -97,7 +97,8 @@ public:
|
||||
}
|
||||
|
||||
// empty, fragmented message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.next_layer().append(
|
||||
string_view(
|
||||
@ -109,7 +110,8 @@ public:
|
||||
|
||||
// two part message
|
||||
// triggers "fill the read buffer first"
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_raw(ws, sbuf(
|
||||
"\x01\x81\xff\xff\xff\xff"));
|
||||
@ -123,7 +125,8 @@ public:
|
||||
});
|
||||
|
||||
// ping
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x89, 0x00));
|
||||
@ -144,7 +147,8 @@ public:
|
||||
});
|
||||
|
||||
// ping
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x88, 0x00));
|
||||
@ -161,7 +165,8 @@ public:
|
||||
});
|
||||
|
||||
// ping then message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
bool once = false;
|
||||
ws.control_callback(
|
||||
@ -183,7 +188,8 @@ public:
|
||||
});
|
||||
|
||||
// ping then fragmented message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
bool once = false;
|
||||
ws.control_callback(
|
||||
@ -208,7 +214,7 @@ public:
|
||||
doStreamLoop([&](test::stream& ts)
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
ws_type ws{ts};
|
||||
ws_type_t<deflateSupported> ws{ts};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.set_option(pmd);
|
||||
es.async_handshake();
|
||||
@ -237,7 +243,7 @@ public:
|
||||
{
|
||||
echo_server es{log, kind::async};
|
||||
boost::asio::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
stream<test::stream, deflateSupported> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// Cause close to be received
|
||||
@ -257,7 +263,8 @@ public:
|
||||
});
|
||||
|
||||
// already closed
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.close(ws, {});
|
||||
multi_buffer b;
|
||||
@ -266,7 +273,8 @@ public:
|
||||
});
|
||||
|
||||
// buffer overflow
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s = "Hello, world!";
|
||||
ws.auto_fragment(false);
|
||||
@ -286,7 +294,8 @@ public:
|
||||
});
|
||||
|
||||
// bad utf8, big
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
auto const s = std::string(2000, '*') +
|
||||
random_string();
|
||||
@ -296,7 +305,8 @@ public:
|
||||
});
|
||||
|
||||
// invalid fixed frame header
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_raw(ws, cbuf(
|
||||
0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
|
||||
@ -304,7 +314,8 @@ public:
|
||||
});
|
||||
|
||||
// bad close
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x88, 0x02, 0x03, 0xed));
|
||||
@ -312,7 +323,8 @@ public:
|
||||
});
|
||||
|
||||
// message size above 2^64
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_some(ws, false, sbuf("*"));
|
||||
w.write_raw(ws, cbuf(
|
||||
@ -322,7 +334,8 @@ public:
|
||||
});
|
||||
|
||||
// message size exceeds max
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.read_message_max(1);
|
||||
w.write(ws, sbuf("**"));
|
||||
@ -330,7 +343,8 @@ public:
|
||||
});
|
||||
|
||||
// bad utf8
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
||||
@ -338,7 +352,8 @@ public:
|
||||
});
|
||||
|
||||
// incomplete utf8
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s =
|
||||
"Hello, world!" "\xc0";
|
||||
@ -347,7 +362,8 @@ public:
|
||||
});
|
||||
|
||||
// incomplete utf8, big
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s =
|
||||
"\x81\x7e\x0f\xa1" +
|
||||
@ -375,7 +391,7 @@ public:
|
||||
[&](error_code ev, string_view s)
|
||||
{
|
||||
echo_server es{log};
|
||||
stream<test::stream> ws{ioc_};
|
||||
stream<test::stream, deflateSupported> ws{ioc_};
|
||||
ws.next_layer().connect(es.stream());
|
||||
w.handshake(ws, "localhost", "/");
|
||||
ws.next_layer().append(s);
|
||||
@ -410,11 +426,15 @@ public:
|
||||
check(error::closed,
|
||||
"\x88\x06\xfc\x15utf8");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// permessage-deflate
|
||||
//
|
||||
template<class Wrap>
|
||||
void
|
||||
doTestReadDeflate(Wrap const& w)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.client_max_window_bits = 9;
|
||||
@ -422,7 +442,8 @@ public:
|
||||
pmd.compLevel = 1;
|
||||
|
||||
// message size limit
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
std::string const s = std::string(128, '*');
|
||||
w.write(ws, buffer(s));
|
||||
@ -431,7 +452,8 @@ public:
|
||||
});
|
||||
|
||||
// invalid inflate block
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
auto const& s = random_string();
|
||||
ws.binary(true);
|
||||
@ -458,7 +480,8 @@ public:
|
||||
|
||||
// no_context_takeover
|
||||
pmd.server_no_context_takeover = true;
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
auto const& s = random_string();
|
||||
ws.binary(true);
|
||||
@ -587,10 +610,14 @@ public:
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
|
||||
doTestRead(SyncClient{});
|
||||
doTestRead<false>(SyncClient{});
|
||||
doTestRead<true>(SyncClient{});
|
||||
doTestReadDeflate(SyncClient{});
|
||||
yield_to([&](yield_context yield)
|
||||
{
|
||||
doTestRead(AsyncClient{yield});
|
||||
doTestRead<false>(AsyncClient{yield});
|
||||
doTestRead<true>(AsyncClient{yield});
|
||||
doTestReadDeflate(AsyncClient{yield});
|
||||
});
|
||||
|
||||
permessage_deflate pmd;
|
||||
|
@ -122,6 +122,8 @@ public:
|
||||
BOOST_STATIC_ASSERT(! std::is_move_assignable<
|
||||
stream<test::stream&>>::value);
|
||||
|
||||
log << "sizeof(websocket::stream_base<true>) == " <<
|
||||
sizeof(websocket::detail::stream_base<true>) << std::endl;
|
||||
log << "sizeof(websocket::stream) == " <<
|
||||
sizeof(websocket::stream<test::stream&>) << std::endl;
|
||||
|
||||
|
@ -35,6 +35,10 @@ class websocket_test_suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
template<bool deflateSupported>
|
||||
using ws_type_t =
|
||||
websocket::stream<test::stream&, deflateSupported>;
|
||||
|
||||
using ws_type =
|
||||
websocket::stream<test::stream&>;
|
||||
|
||||
@ -303,7 +307,7 @@ public:
|
||||
, limit);
|
||||
}
|
||||
|
||||
template<class Test>
|
||||
template<bool deflateSupported = true, class Test>
|
||||
void
|
||||
doTest(
|
||||
permessage_deflate const& pmd,
|
||||
@ -320,7 +324,7 @@ public:
|
||||
{
|
||||
test::fail_counter fc{n};
|
||||
test::stream ts{ioc_, fc};
|
||||
ws_type ws{ts};
|
||||
ws_type_t<deflateSupported> ws{ts};
|
||||
ws.set_option(pmd);
|
||||
|
||||
echo_server es{log, i==1 ?
|
||||
@ -481,146 +485,171 @@ public:
|
||||
|
||||
struct SyncClient
|
||||
{
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
accept(stream<NextLayer>& ws) const
|
||||
accept(
|
||||
stream<NextLayer, deflateSupported>& ws) const
|
||||
{
|
||||
ws.accept();
|
||||
}
|
||||
|
||||
template<class NextLayer, class Buffers>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<Buffers>::value>::type
|
||||
accept(stream<NextLayer>& ws,
|
||||
accept(stream<NextLayer, deflateSupported>& ws,
|
||||
Buffers const& buffers) const
|
||||
{
|
||||
ws.accept(buffers);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
accept(stream<NextLayer>& ws,
|
||||
accept(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req) const
|
||||
{
|
||||
ws.accept(req);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(d);
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers, class Decorator>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<Buffers>::value>::type
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(buffers, d);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req,
|
||||
Decorator const& d) const
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(req, d);
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(req, buffers, d);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
handshake(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
string_view path) const
|
||||
{
|
||||
ws.handshake(uri, path);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
handshake(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
response_type& res,
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
{
|
||||
ws.handshake(res, uri, path);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
handshake_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const& d) const
|
||||
string_view path,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.handshake_ex(uri, path, d);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
handshake_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
response_type& res,
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const& d) const
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.handshake_ex(res, uri, path, d);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
ping(stream<NextLayer>& ws,
|
||||
ping(stream<NextLayer, deflateSupported>& ws,
|
||||
ping_data const& payload) const
|
||||
{
|
||||
ws.ping(payload);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
pong(stream<NextLayer>& ws,
|
||||
pong(stream<NextLayer, deflateSupported>& ws,
|
||||
ping_data const& payload) const
|
||||
{
|
||||
ws.pong(payload);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
close(stream<NextLayer>& ws,
|
||||
close(stream<NextLayer, deflateSupported>& ws,
|
||||
close_reason const& cr) const
|
||||
{
|
||||
ws.close(cr);
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class DynamicBuffer>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class DynamicBuffer>
|
||||
std::size_t
|
||||
read(stream<NextLayer>& ws,
|
||||
read(stream<NextLayer, deflateSupported>& ws,
|
||||
DynamicBuffer& buffer) const
|
||||
{
|
||||
return ws.read(buffer);
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class DynamicBuffer>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class DynamicBuffer>
|
||||
std::size_t
|
||||
read_some(stream<NextLayer>& ws,
|
||||
read_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
std::size_t limit,
|
||||
DynamicBuffer& buffer) const
|
||||
{
|
||||
@ -628,36 +657,45 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class MutableBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(stream<NextLayer>& ws,
|
||||
read_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
MutableBufferSequence const& buffers) const
|
||||
{
|
||||
return ws.read_some(buffers);
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write(stream<NextLayer>& ws,
|
||||
write(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
return ws.write(buffers);
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(stream<NextLayer>& ws, bool fin,
|
||||
write_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
bool fin,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
return ws.write_some(fin, buffers);
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_raw(stream<NextLayer>& ws,
|
||||
write_raw(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
return boost::asio::write(
|
||||
@ -678,9 +716,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
accept(stream<NextLayer>& ws) const
|
||||
accept(stream<NextLayer, deflateSupported>& ws) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept(yield_[ec]);
|
||||
@ -688,10 +726,13 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Buffers>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<Buffers>::value>::type
|
||||
accept(stream<NextLayer>& ws,
|
||||
accept(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
Buffers const& buffers) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -700,9 +741,10 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
accept(stream<NextLayer>& ws,
|
||||
accept(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -711,10 +753,12 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -723,13 +767,15 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers, class Decorator>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<Buffers>::value>::type
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(buffers, d, yield_[ec]);
|
||||
@ -737,11 +783,14 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req,
|
||||
Decorator const& d) const
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(req, d, yield_[ec]);
|
||||
@ -749,13 +798,15 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Buffers, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
accept_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
http::request<http::empty_body> const& req,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(
|
||||
@ -764,11 +815,13 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
handshake(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
string_view path) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake(
|
||||
@ -777,12 +830,13 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
handshake(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
response_type& res,
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
string_view uri,
|
||||
string_view path) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake(
|
||||
@ -791,12 +845,15 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
handshake_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const &d) const
|
||||
string_view path,
|
||||
Decorator const &d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake_ex(
|
||||
@ -805,13 +862,16 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
template<
|
||||
class NextLayer, bool deflateSupported,
|
||||
class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
handshake_ex(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
response_type& res,
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const &d) const
|
||||
string_view uri,
|
||||
string_view path,
|
||||
Decorator const &d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake_ex(
|
||||
@ -820,9 +880,10 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
ping(stream<NextLayer>& ws,
|
||||
ping(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ping_data const& payload) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -831,9 +892,10 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
pong(stream<NextLayer>& ws,
|
||||
pong(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ping_data const& payload) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -842,9 +904,10 @@ public:
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
close(stream<NextLayer>& ws,
|
||||
close(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
close_reason const& cr) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -854,9 +917,11 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class DynamicBuffer>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class DynamicBuffer>
|
||||
std::size_t
|
||||
read(stream<NextLayer>& ws,
|
||||
read(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
DynamicBuffer& buffer) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -868,9 +933,11 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class DynamicBuffer>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class DynamicBuffer>
|
||||
std::size_t
|
||||
read_some(stream<NextLayer>& ws,
|
||||
read_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
std::size_t limit,
|
||||
DynamicBuffer& buffer) const
|
||||
{
|
||||
@ -883,9 +950,11 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class MutableBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(stream<NextLayer>& ws,
|
||||
read_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
MutableBufferSequence const& buffers) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -897,9 +966,11 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write(stream<NextLayer>& ws,
|
||||
write(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -911,9 +982,12 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(stream<NextLayer>& ws, bool fin,
|
||||
write_some(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
bool fin,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
error_code ec;
|
||||
@ -925,9 +999,11 @@ public:
|
||||
}
|
||||
|
||||
template<
|
||||
class NextLayer, class ConstBufferSequence>
|
||||
class NextLayer, bool deflateSupported,
|
||||
class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_raw(stream<NextLayer>& ws,
|
||||
write_raw(
|
||||
stream<NextLayer, deflateSupported>& ws,
|
||||
ConstBufferSequence const& buffers) const
|
||||
{
|
||||
error_code ec;
|
||||
|
@ -19,7 +19,7 @@ namespace websocket {
|
||||
class write_test : public websocket_test_suite
|
||||
{
|
||||
public:
|
||||
template<class Wrap>
|
||||
template<bool deflateSupported, class Wrap>
|
||||
void
|
||||
doTestWrite(Wrap const& w)
|
||||
{
|
||||
@ -50,7 +50,8 @@ public:
|
||||
}
|
||||
|
||||
// message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
@ -63,7 +64,8 @@ public:
|
||||
});
|
||||
|
||||
// empty message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.text(true);
|
||||
w.write(ws, boost::asio::const_buffer{});
|
||||
@ -74,7 +76,8 @@ public:
|
||||
});
|
||||
|
||||
// fragmented message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
@ -88,7 +91,8 @@ public:
|
||||
});
|
||||
|
||||
// continuation
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s = "Hello";
|
||||
std::size_t const chop = 3;
|
||||
@ -103,7 +107,8 @@ public:
|
||||
});
|
||||
|
||||
// mask
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.auto_fragment(false);
|
||||
std::string const s = "Hello";
|
||||
@ -114,7 +119,8 @@ public:
|
||||
});
|
||||
|
||||
// mask (large)
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.auto_fragment(false);
|
||||
ws.write_buffer_size(16);
|
||||
@ -126,7 +132,8 @@ public:
|
||||
});
|
||||
|
||||
// mask, autofrag
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.auto_fragment(true);
|
||||
std::string const s(16384, '*');
|
||||
@ -140,7 +147,7 @@ public:
|
||||
doStreamLoop([&](test::stream& ts)
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
ws_type ws{ts};
|
||||
ws_type_t<deflateSupported> ws{ts};
|
||||
ws.next_layer().connect(es.stream());
|
||||
try
|
||||
{
|
||||
@ -166,7 +173,7 @@ public:
|
||||
doStreamLoop([&](test::stream& ts)
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
ws_type ws{ts};
|
||||
ws_type_t<deflateSupported> ws{ts};
|
||||
ws.next_layer().connect(es.stream());
|
||||
try
|
||||
{
|
||||
@ -187,7 +194,15 @@ public:
|
||||
}
|
||||
ts.close();
|
||||
});
|
||||
}
|
||||
|
||||
template<class Wrap>
|
||||
void
|
||||
doTestWriteDeflate(Wrap const& w)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.compLevel = 1;
|
||||
@ -238,11 +253,15 @@ public:
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
|
||||
doTestWrite(SyncClient{});
|
||||
doTestWrite<false>(SyncClient{});
|
||||
doTestWrite<true>(SyncClient{});
|
||||
doTestWriteDeflate(SyncClient{});
|
||||
|
||||
yield_to([&](yield_context yield)
|
||||
{
|
||||
doTestWrite(AsyncClient{yield});
|
||||
doTestWrite<false>(AsyncClient{yield});
|
||||
doTestWrite<true>(AsyncClient{yield});
|
||||
doTestWriteDeflate(AsyncClient{yield});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ boost::asio::ip::tcp::socket sock{ioc};
|
||||
|
||||
{
|
||||
//[ws_snippet_6
|
||||
std::string const host = "mywebapp.com";
|
||||
std::string const host = "example.com";
|
||||
boost::asio::ip::tcp::resolver r{ioc};
|
||||
stream<boost::asio::ip::tcp::socket> ws{ioc};
|
||||
auto const results = r.resolve(host, "ws");
|
||||
@ -310,6 +310,16 @@ struct custom_wrapper
|
||||
|
||||
//]
|
||||
|
||||
//[ws_snippet_26
|
||||
|
||||
// A WebSocket stream
|
||||
template<
|
||||
class NextLayer,
|
||||
bool deflateSupported = true>
|
||||
class stream;
|
||||
|
||||
//]
|
||||
|
||||
} // doc_ws_snippets
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user