WebSocket Decorator is a socket option (API Change):

This changes the interface used to apply a decorator to the HTTP
request or response messages used to perform the WebSocket handshake
as follows:

* Add the `stream_base::decorator` option object

* Add `stream::set_option` overload to set the decorator from
  the option

* The decorator applies to all client and server handshakes
  performed on the stream after the option is set.

* Overloads of the following functions which accept a Decorator
  are deprecated:
  - accept, accept_ex
  - handshake, handshake_ex
  - async_accept, async_accept_ex
  - async_handshake, async_handshake_ex

Actions Required:

* Code which passes decorator to any `websocket::stream` member
  function should call `stream::set_option` instead with a newly
  constructed `stream_base::decorator` object containing the
  decorator. Alternatively, the macro `BOOST_BEAST_ALLOW_DEPRECATED`
  may be defined to 1.
This commit is contained in:
Vinnie Falco committed 2019-02-19 16:23:30 -08:00
1 parent 085fb66b26
commit 3f50efa138
41 files changed
+1097 -1391

No files matched your search

@@ -104,7 +104,7 @@ public:
void
reset() noexcept
{
static_assert(sizeof(I) != 0,
static_assert(I != 0,
BOOST_BEAST_DEPRECATION_STRING);
}
#endif
@@ -19,6 +19,7 @@
#include <functional>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
namespace boost {
@@ -37,14 +38,12 @@ class decorator
void(*)(),
void(incomplete::*)(),
decltype(std::bind(
std::declval<void(incomplete::*)()>(),
std::declval<std::shared_ptr<incomplete>>()))
std::declval<
void(incomplete::*)(request_type&)>(),
std::shared_ptr<incomplete>{},
std::placeholders::_1))
>();
struct none
{
};
struct base
{
virtual ~base() = default;
@@ -62,6 +61,16 @@ class decorator
invoke(response_type&) = 0;
};
using type = typename
std::aligned_storage<Bytes>::type;
type buf_;
base* base_;
struct none
{
};
template<class T, class = void>
struct is_req_op : std::false_type
{
@@ -143,13 +152,42 @@ class decorator
}
};
using type = typename
std::aligned_storage<Bytes>::type;
void
destroy()
{
if(is_inline())
base_->~base();
else if(base_)
delete base_;
}
type buf_;
base* base_;
template<class F>
base*
construct(F&& f, std::true_type)
{
return ::new(&buf_) impl<
typename std::decay<F>::type>(
std::forward<F>(f));
}
template<class F>
base*
construct(F&& f, std::false_type)
{
return new impl<
typename std::decay<F>::type>(
std::forward<F>(f));
}
public:
decorator(decorator const&) = delete;
decorator& operator=(decorator const&) = delete;
~decorator()
{
destroy();
}
decorator()
: decorator(none{})
{
@@ -171,25 +209,34 @@ public:
impl<none>(none{});
}
template<class F>
template<class F,
class = typename std::enable_if<
! std::is_convertible<F, decorator>::value>::type>
explicit
decorator(F&& f)
: base_(sizeof(F) <= sizeof(buf_) ?
::new(&buf_) impl<
typename std::decay<F>::type>(
std::forward<F>(f)) :
new impl<
typename std::decay<F>::type>(
std::forward<F>(f)))
: base_(construct(std::forward<F>(f),
std::integral_constant<bool,
sizeof(F) <= sizeof(buf_)>{}))
{
}
~decorator()
decorator&
operator=(decorator&& other)
{
if(is_inline())
base_->~base();
this->destroy();
base_ = nullptr;
if(other.is_inline())
{
base_ = other.base_->move(&buf_);
other.base_->~base();
}
else
delete base_;
{
base_ = other.base_;
}
other.base_ = ::new(&other.buf_)
impl<none>(none{});
return *this;
}
bool
+155 -126
View File
@@ -75,12 +75,15 @@ build_response(
error_code& result)
{
auto const decorate =
[&decorator](response_type& res)
[this, &decorator](response_type& res)
{
decorator_opt(res);
decorator(res);
if(! res.count(http::field::server))
{
BOOST_STATIC_ASSERT(sizeof(BOOST_BEAST_VERSION_STRING) < 20);
// VFALCO this is weird..
BOOST_STATIC_ASSERT(sizeof(
BOOST_BEAST_VERSION_STRING) < 20);
static_string<20> s(BOOST_BEAST_VERSION_STRING);
res.set(http::field::server, s);
}
@@ -395,23 +398,6 @@ accept()
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
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_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
@@ -424,22 +410,6 @@ accept(error_code& ec)
&default_decorate_res, ec);
}
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
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_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
do_accept(
net::const_buffer{},
decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
typename std::enable_if<! http::detail::is_header<
@@ -457,32 +427,6 @@ accept(ConstBufferSequence const& buffers)
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const &decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(buffers, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
typename std::enable_if<! http::detail::is_header<
@@ -499,28 +443,6 @@ accept(
do_accept(buffers, &default_decorate_res, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
do_accept(buffers, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator>
@@ -538,28 +460,6 @@ accept(
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(req, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator>
void
@@ -575,27 +475,6 @@ accept(
do_accept(req, &default_decorate_res, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
do_accept(req, decorator, ec);
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
@@ -769,6 +648,156 @@ async_accept_ex(
return init.result.get();
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator, error_code& ec)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
do_accept(
net::const_buffer{},
decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const &decorator)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(buffers, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
error_code& ec)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
do_accept(buffers, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
accept_ex(req, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
error_code& ec)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(ResponseDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
impl_->reset();
do_accept(req, decorator, ec);
}
} // websocket
} // beast
} // boost
+119 -90
View File
@@ -195,57 +195,6 @@ async_handshake(response_type& res,
return init.result.get();
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
stream<NextLayer, deflateSupported>::
async_handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
BOOST_BEAST_HANDLER_INIT(
HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>(
std::move(init.completion_handler),
impl_, nullptr, host, target,
decorator)();
return init.result.get();
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
stream<NextLayer, deflateSupported>::
async_handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
BOOST_BEAST_HANDLER_INIT(
HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>(
std::move(init.completion_handler),
impl_, &res, host, target,
decorator)();
return init.result.get();
}
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
@@ -276,45 +225,6 @@ handshake(response_type& res,
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(res, host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
@@ -341,6 +251,55 @@ handshake(response_type& res,
host, target, &default_decorate_req, ec);
}
//------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
handshake_ex(res, host, target, decorator, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
@@ -350,6 +309,10 @@ handshake_ex(string_view host,
RequestDecorator const& decorator,
error_code& ec)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
@@ -369,6 +332,10 @@ handshake_ex(response_type& res,
RequestDecorator const& decorator,
error_code& ec)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_request_decorator<
@@ -378,6 +345,68 @@ handshake_ex(response_type& res,
host, target, decorator, ec);
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
stream<NextLayer, deflateSupported>::
async_handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
BOOST_BEAST_HANDLER_INIT(
HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>(
std::move(init.completion_handler),
impl_, nullptr, host, target,
decorator)();
return init.result.get();
}
template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
stream<NextLayer, deflateSupported>::
async_handshake_ex(response_type& res,
string_view host,
string_view target,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
#if ! BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(RequestDecorator) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
BOOST_BEAST_HANDLER_INIT(
HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>(
std::move(init.completion_handler),
impl_, &res, host, target,
decorator)();
return init.result.get();
}
} // websocket
} // beast
} // boost
@@ -147,6 +147,16 @@ read_size_hint(DynamicBuffer& buffer) const
//
//------------------------------------------------------------------------------
// decorator
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
set_option(decorator opt)
{
impl_->decorator_opt = std::move(opt.d_);
}
// timeout
template<class NextLayer, bool deflateSupported>
@@ -96,7 +96,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
bool timed_out = false;
int idle_counter = 0;
timeout timeout_opt;
detail::decorator decorator_opt; // Decorator for HTTP messages
timeout timeout_opt; // Timeout/idle settings
template<class... Args>
@@ -532,6 +533,7 @@ build_request(
req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_version, "13");
this->build_request_pmd(req);
decorator_opt(req);
decorator(req);
if(! req.count(http::field::user_agent))
req.set(http::field::user_agent,
File diff suppressed because it is too large. Load diff
@@ -12,6 +12,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/websocket/role.hpp>
#include <boost/beast/websocket/detail/decorator.hpp>
#include <chrono>
namespace boost {
@@ -48,6 +49,25 @@ struct stream_base
return (duration::max)();
}
/** Stream option used to adjust HTTP fields of WebSocket upgrade request and responses.
*/
class decorator
{
detail::decorator d_;
template<class, bool>
friend class stream;
public:
decorator(decorator&&) = default;
template<class Decorator>
decorator(Decorator&& f)
: d_(f)
{
}
};
/** Stream option to control the behavior of websocket timeouts.
Timeout features are available for asynchronous operations only.