mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317 websocket::stream now provides the following families of functions for performing handshakes: When operating in the server role: * stream::accept * stream::accept_ex * stream::async_accept * stream::async_accept_ex When operating in the client role: * stream::handshake * stream::handshake_ex * stream::async_handshake * stream::async_handshake_ex Member functions ending with "_ex" allow an additional RequestDecorator parameter (for the accept family of functions) or ResponseDecorator parameter (for the handshake family of functions). The decorator is called to optionally modify the contents of the HTTP request or HTTP response object generated by the implementation, before the message is sent. This permits callers to set the User-Agent or Server fields, add or modify HTTP fields related to subprotocols, or perform any required transformation of the HTTP message for application-specific needs. The handshake() family of functions now have an additional set of overloads accepting a parameter of type response_type&, allowing the caller to receive the HTTP Response to the Upgrade handshake. This permits inspection of the response to handle things like subprotocols, authentication, or other application-specific needs. The new implementation does not require any state to be stored in the stream object. Therefore, websocket::stream objects are now smaller in size. The overload of set_option for setting a decorator on the stream is removed. The only way to set decorators now is with a suitable overload of accept or handshake.
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
API Changes:
|
||||
|
||||
* Provide websocket::stream accept() overloads
|
||||
* Refactor websocket decorators
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -112,7 +112,6 @@
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__permessage_deflate">permessage_deflate</link></member>
|
||||
|
@ -38,25 +38,6 @@ public:
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "async_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "async_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
@ -159,8 +140,6 @@ public:
|
||||
, acceptor_(ios_)
|
||||
, work_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
thread_.reserve(threads);
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
thread_.emplace_back(
|
||||
@ -282,7 +261,13 @@ private:
|
||||
void run()
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.ws.async_accept(std::move(*this));
|
||||
d.ws.async_accept_ex(
|
||||
[](beast::websocket::response_type& res)
|
||||
{
|
||||
res.fields.insert(
|
||||
"Server", "async_echo_server");
|
||||
},
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
void operator()(error_code ec, std::size_t)
|
||||
|
@ -38,25 +38,6 @@ public:
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "sync_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "sync_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
@ -151,8 +132,6 @@ public:
|
||||
, sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
@ -293,7 +272,13 @@ private:
|
||||
socket_type> ws{std::move(sock)};
|
||||
opts_.set_options(ws);
|
||||
error_code ec;
|
||||
ws.accept(ec);
|
||||
ws.accept_ex(
|
||||
[](beast::websocket::response_type& res)
|
||||
{
|
||||
res.fields.insert(
|
||||
"Server", "sync_echo_server");
|
||||
},
|
||||
ec);
|
||||
if(ec)
|
||||
{
|
||||
fail("accept", ec, id, ep);
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
read_some(MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
ec = boost::asio::error::eof;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -66,7 +67,7 @@ public:
|
||||
async_completion<ReadHandler,
|
||||
void(error_code, std::size_t)> completion{handler};
|
||||
ios_.post(bind_handler(completion.handler,
|
||||
error_code{}, 0));
|
||||
boost::asio::error::eof, 0));
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
|
@ -1,166 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2013-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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
|
||||
#define BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
|
||||
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/version.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
using request_type = http::request_header;
|
||||
|
||||
using response_type = http::response_header;
|
||||
|
||||
struct abstract_decorator
|
||||
{
|
||||
virtual
|
||||
~abstract_decorator() = default;
|
||||
|
||||
virtual
|
||||
void
|
||||
operator()(request_type& req) const = 0;
|
||||
|
||||
virtual
|
||||
void
|
||||
operator()(response_type& res) const = 0;
|
||||
};
|
||||
|
||||
template<class F>
|
||||
class decorator : public abstract_decorator
|
||||
{
|
||||
F f_;
|
||||
|
||||
class call_req_possible
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U const>().operator()(
|
||||
std::declval<request_type&>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check<F>(0));
|
||||
};
|
||||
|
||||
class call_res_possible
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U const>().operator()(
|
||||
std::declval<response_type&>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check<F>(0));
|
||||
};
|
||||
|
||||
public:
|
||||
decorator(F&& t)
|
||||
: f_(std::move(t))
|
||||
{
|
||||
}
|
||||
|
||||
decorator(F const& t)
|
||||
: f_(t)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type& req) const override
|
||||
{
|
||||
(*this)(req, typename call_req_possible::type{});
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type& res) const override
|
||||
{
|
||||
(*this)(res, typename call_res_possible::type{});
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
operator()(request_type& req, std::true_type) const
|
||||
{
|
||||
f_(req);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type& req, std::false_type) const
|
||||
{
|
||||
req.fields.replace("User-Agent",
|
||||
std::string{"Beast/"} + BEAST_VERSION_STRING);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type& res, std::true_type) const
|
||||
{
|
||||
f_(res);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type& res, std::false_type) const
|
||||
{
|
||||
res.fields.replace("Server",
|
||||
std::string{"Beast/"} + BEAST_VERSION_STRING);
|
||||
}
|
||||
};
|
||||
|
||||
class decorator_type
|
||||
{
|
||||
std::shared_ptr<abstract_decorator> p_;
|
||||
|
||||
public:
|
||||
decorator_type() = delete;
|
||||
decorator_type(decorator_type&&) = default;
|
||||
decorator_type(decorator_type const&) = default;
|
||||
decorator_type& operator=(decorator_type&&) = default;
|
||||
decorator_type& operator=(decorator_type const&) = default;
|
||||
|
||||
template<class F, class =
|
||||
typename std::enable_if<! std::is_same<
|
||||
typename std::decay<F>::type,
|
||||
decorator_type>::value>>
|
||||
decorator_type(F&& f)
|
||||
: p_(std::make_shared<decorator<F>>(
|
||||
std::forward<F>(f)))
|
||||
{
|
||||
BOOST_ASSERT(p_);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type& req)
|
||||
{
|
||||
(*p_)(req);
|
||||
BOOST_ASSERT(p_);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type& res)
|
||||
{
|
||||
(*p_)(res);
|
||||
BOOST_ASSERT(p_);
|
||||
}
|
||||
};
|
||||
|
||||
struct default_decorator
|
||||
{
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -11,7 +11,6 @@
|
||||
#include <beast/websocket/error.hpp>
|
||||
#include <beast/websocket/option.hpp>
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/detail/decorator.hpp>
|
||||
#include <beast/websocket/detail/frame.hpp>
|
||||
#include <beast/websocket/detail/invokable.hpp>
|
||||
#include <beast/websocket/detail/mask.hpp>
|
||||
@ -50,7 +49,6 @@ protected:
|
||||
struct op {};
|
||||
|
||||
detail::maskgen maskgen_; // source of mask keys
|
||||
decorator_type d_; // adorns http messages
|
||||
bool keep_alive_ = false; // close on failed upgrade
|
||||
std::size_t rd_msg_max_ =
|
||||
16 * 1024 * 1024; // max message size
|
||||
@ -153,16 +151,12 @@ protected:
|
||||
// Offer for clients, negotiated result for servers
|
||||
pmd_offer pmd_config_;
|
||||
|
||||
stream_base() = default;
|
||||
stream_base(stream_base&&) = default;
|
||||
stream_base(stream_base const&) = delete;
|
||||
stream_base& operator=(stream_base&&) = default;
|
||||
stream_base& operator=(stream_base const&) = delete;
|
||||
|
||||
stream_base()
|
||||
: d_(detail::default_decorator{})
|
||||
{
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
open(role_type role);
|
||||
|
32
include/beast/websocket/detail/type_traits.hpp
Normal file
32
include/beast/websocket/detail/type_traits.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright (c) 2013-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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WEBSOCKET_DETAIL_TYPE_TRAITS_HPP
|
||||
#define BEAST_WEBSOCKET_DETAIL_TYPE_TRAITS_HPP
|
||||
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/core/detail/is_call_possible.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
template<class F>
|
||||
using is_RequestDecorator =
|
||||
typename beast::detail::is_call_possible<F,
|
||||
void(request_type&)>::type;
|
||||
|
||||
template<class F>
|
||||
using is_ResponseDecorator =
|
||||
typename beast::detail::is_call_possible<F,
|
||||
void(response_type&)>::type;
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
||||
#define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
||||
|
||||
#include <beast/websocket/detail/type_traits.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/header_parser.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
@ -38,23 +39,27 @@ class stream<NextLayer>::response_op
|
||||
http::response_header res;
|
||||
int state = 0;
|
||||
|
||||
template<class Fields>
|
||||
template<class Fields, class Decorator>
|
||||
data(Handler&, stream<NextLayer>& ws_,
|
||||
http::header<true, Fields> const& req,
|
||||
Decorator const& decorator,
|
||||
bool cont_)
|
||||
: cont(cont_)
|
||||
, ws(ws_)
|
||||
, res(ws_.build_response(req))
|
||||
, res(ws_.build_response(req, decorator))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Fields, class Buffers>
|
||||
template<class Fields,
|
||||
class Buffers, class Decorator>
|
||||
data(Handler&, stream<NextLayer>& ws_,
|
||||
http::header<true, Fields> const& req,
|
||||
Buffers const& buffers, bool cont_)
|
||||
Buffers const& buffers,
|
||||
Decorator const& decorator,
|
||||
bool cont_)
|
||||
: cont(cont_)
|
||||
, ws(ws_)
|
||||
, res(ws_.build_response(req))
|
||||
, res(ws_.build_response(req, decorator))
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
@ -155,26 +160,32 @@ operator()(error_code ec, bool again)
|
||||
// read and respond to an upgrade request
|
||||
//
|
||||
template<class NextLayer>
|
||||
template<class Handler>
|
||||
template<class Decorator, class Handler>
|
||||
class stream<NextLayer>::accept_op
|
||||
{
|
||||
struct data
|
||||
{
|
||||
bool cont;
|
||||
stream<NextLayer>& ws;
|
||||
Decorator decorator;
|
||||
http::header_parser<true, http::fields> p;
|
||||
int state = 0;
|
||||
|
||||
// VFALCO These lines are formatted to work around a codecov defect
|
||||
data(Handler& handler, stream<NextLayer>& ws_) : cont(beast_asio_helpers::is_continuation(handler))
|
||||
, ws(ws_) {}
|
||||
data(Handler& handler, stream<NextLayer>& ws_,
|
||||
Decorator const& decorator_)
|
||||
: cont(beast_asio_helpers::is_continuation(handler))
|
||||
, ws(ws_)
|
||||
, decorator(decorator_)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
data(Handler& handler, stream<NextLayer>& ws_,
|
||||
Buffers const& buffers)
|
||||
: cont(beast_asio_helpers::
|
||||
is_continuation(handler))
|
||||
Buffers const& buffers,
|
||||
Decorator const& decorator_)
|
||||
: cont(beast_asio_helpers::is_continuation(handler))
|
||||
, ws(ws_)
|
||||
, decorator(decorator_)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
@ -235,9 +246,9 @@ public:
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Handler>
|
||||
template<class Decorator, class Handler>
|
||||
void
|
||||
stream<NextLayer>::accept_op<Handler>::
|
||||
stream<NextLayer>::accept_op<Decorator, Handler>::
|
||||
operator()(error_code ec,
|
||||
std::size_t bytes_used, bool again)
|
||||
{
|
||||
@ -263,10 +274,19 @@ operator()(error_code ec,
|
||||
// moved to the stack before releasing
|
||||
// the handler.
|
||||
auto& ws = d.ws;
|
||||
auto m = d.p.release();
|
||||
auto const req = d.p.release();
|
||||
auto const decorator = d.decorator;
|
||||
#if 1
|
||||
response_op<Handler>{
|
||||
d_.release_handler(),
|
||||
ws, std::move(m), true};
|
||||
ws, req, decorator, true};
|
||||
#else
|
||||
// VFALCO This *should* work but breaks
|
||||
// coroutine invariants in the unit test.
|
||||
// Also it calls reset() when it shouldn't.
|
||||
ws.async_accept_ex(
|
||||
req, decorator, d_.release_handler());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -289,6 +309,23 @@ accept()
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
@ -297,7 +334,22 @@ accept(error_code& ec)
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
reset();
|
||||
do_accept(ec);
|
||||
do_accept(&default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
reset();
|
||||
do_accept(decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
@ -317,6 +369,28 @@ accept(ConstBufferSequence const& buffers)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const &decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(buffers, decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
@ -334,7 +408,32 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||
stream_.buffer().commit(buffer_copy(
|
||||
stream_.buffer().prepare(
|
||||
buffer_size(buffers)), buffers));
|
||||
do_accept(ec);
|
||||
do_accept(&default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
reset();
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
stream_.buffer().commit(buffer_copy(
|
||||
stream_.buffer().prepare(
|
||||
buffer_size(buffers)), buffers));
|
||||
do_accept(decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
@ -351,6 +450,24 @@ accept(http::header<true, Fields> const& req)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(http::header<true, Fields> const& req,
|
||||
ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(req, decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields>
|
||||
void
|
||||
@ -361,15 +478,30 @@ accept(http::header<true, Fields> const& req,
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
reset();
|
||||
do_accept(req, ec);
|
||||
do_accept(req, &default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(http::header<true, Fields> const& req,
|
||||
ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
reset();
|
||||
do_accept(req, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields, class ConstBufferSequence>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept(
|
||||
http::header<true, Fields> const& req,
|
||||
accept(http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
@ -383,14 +515,35 @@ accept(
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields,
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(req, buffers, decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields, class ConstBufferSequence>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept(
|
||||
http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
accept(http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
@ -403,7 +556,34 @@ accept(
|
||||
stream_.buffer().commit(buffer_copy(
|
||||
stream_.buffer().prepare(
|
||||
buffer_size(buffers)), buffers));
|
||||
do_accept(req, ec);
|
||||
do_accept(req, &default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields,
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
accept_ex(http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
reset();
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
stream_.buffer().commit(buffer_copy(
|
||||
stream_.buffer().prepare(
|
||||
buffer_size(buffers)), buffers));
|
||||
do_accept(req, decorator, ec);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -420,8 +600,30 @@ async_accept(AcceptHandler&& handler)
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
accept_op<decltype(completion.handler)>{
|
||||
completion.handler, *this};
|
||||
accept_op<decltype(&default_decorate_res),
|
||||
decltype(completion.handler)>{completion.handler,
|
||||
*this, &default_decorate_res};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ResponseDecorator, class AcceptHandler>
|
||||
typename async_completion<AcceptHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_accept_ex(ResponseDecorator const& decorator,
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
accept_op<ResponseDecorator, decltype(completion.handler)>{
|
||||
completion.handler, *this, decorator};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
@ -441,8 +643,35 @@ async_accept(ConstBufferSequence const& buffers,
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
accept_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, buffers};
|
||||
accept_op<decltype(&default_decorate_res),
|
||||
decltype(completion.handler)>{completion.handler,
|
||||
*this, buffers, &default_decorate_res};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence,
|
||||
class ResponseDecorator, class AcceptHandler>
|
||||
typename async_completion<AcceptHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
accept_op<ResponseDecorator, decltype(completion.handler)>{
|
||||
completion.handler, *this, buffers, decorator};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
@ -461,11 +690,35 @@ async_accept(http::header<true, Fields> const& req,
|
||||
reset();
|
||||
response_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, req,
|
||||
beast_asio_helpers::
|
||||
&default_decorate_res, beast_asio_helpers::
|
||||
is_continuation(completion.handler)};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields,
|
||||
class ResponseDecorator, class AcceptHandler>
|
||||
typename async_completion<AcceptHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_accept_ex(http::header<true, Fields> const& req,
|
||||
ResponseDecorator const& decorator, AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
response_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, req, decorator,
|
||||
beast_asio_helpers::is_continuation(
|
||||
completion.handler)};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields,
|
||||
class ConstBufferSequence, class AcceptHandler>
|
||||
@ -486,11 +739,40 @@ async_accept(http::header<true, Fields> const& req,
|
||||
reset();
|
||||
response_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, req, buffers,
|
||||
beast_asio_helpers::
|
||||
&default_decorate_res, beast_asio_helpers::
|
||||
is_continuation(completion.handler)};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields, class ConstBufferSequence,
|
||||
class ResponseDecorator, class AcceptHandler>
|
||||
typename async_completion<AcceptHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_accept_ex(http::header<true, Fields> const& req,
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_ResponseDecorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
beast::async_completion<AcceptHandler,
|
||||
void(error_code)> completion{handler};
|
||||
reset();
|
||||
response_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, req, buffers, decorator,
|
||||
beast_asio_helpers::is_continuation(
|
||||
completion.handler)};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
|
||||
#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
|
||||
|
||||
#include <beast/websocket/detail/type_traits.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/streambuf_body.hpp>
|
||||
@ -33,18 +34,24 @@ class stream<NextLayer>::handshake_op
|
||||
{
|
||||
bool cont;
|
||||
stream<NextLayer>& ws;
|
||||
response_type* res_p;
|
||||
std::string key;
|
||||
http::request_header req;
|
||||
http::response<http::streambuf_body> res;
|
||||
request_type req;
|
||||
response_type res;
|
||||
int state = 0;
|
||||
|
||||
template<class Decorator>
|
||||
data(Handler& handler, stream<NextLayer>& ws_,
|
||||
response_type* res_p_,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource)
|
||||
boost::string_ref const& resource,
|
||||
Decorator const& decorator)
|
||||
: cont(beast_asio_helpers::
|
||||
is_continuation(handler))
|
||||
, ws(ws_)
|
||||
, req(ws.build_request(host, resource, key))
|
||||
, res_p(res_p_)
|
||||
, req(ws.build_request(key,
|
||||
host, resource, decorator))
|
||||
{
|
||||
ws.reset();
|
||||
}
|
||||
@ -117,10 +124,14 @@ operator()(error_code ec, bool again)
|
||||
d.state = 1;
|
||||
// VFALCO Do we need the ability to move
|
||||
// a message on the async_write?
|
||||
//
|
||||
pmd_read(
|
||||
d.ws.pmd_config_, d.req.fields);
|
||||
http::async_write(d.ws.stream_,
|
||||
d.req, std::move(*this));
|
||||
// TODO We don't need d.req now. Figure
|
||||
// out a way to make it a parameter instead
|
||||
// of a state variable to reduce footprint.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -143,24 +154,94 @@ operator()(error_code ec, bool again)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(d.res_p)
|
||||
swap(d.res, *d.res_p);
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class HandshakeHandler>
|
||||
typename async_completion<
|
||||
HandshakeHandler, void(error_code)>::result_type
|
||||
typename async_completion<HandshakeHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_handshake(boost::string_ref const& host,
|
||||
boost::string_ref const& resource, HandshakeHandler&& handler)
|
||||
boost::string_ref const& resource,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
beast::async_completion<
|
||||
HandshakeHandler, void(error_code)
|
||||
> completion{handler};
|
||||
beast::async_completion<HandshakeHandler,
|
||||
void(error_code)> completion{handler};
|
||||
handshake_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, host, resource};
|
||||
completion.handler, *this, nullptr,
|
||||
host, resource, &default_decorate_req};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class HandshakeHandler>
|
||||
typename async_completion<HandshakeHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_handshake(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
beast::async_completion<HandshakeHandler,
|
||||
void(error_code)> completion{handler};
|
||||
handshake_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, &res,
|
||||
host, resource, &default_decorate_req};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
typename async_completion<HandshakeHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_handshake_ex(boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
beast::async_completion<HandshakeHandler,
|
||||
void(error_code)> completion{handler};
|
||||
handshake_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, nullptr,
|
||||
host, resource, decorator};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
typename async_completion<HandshakeHandler,
|
||||
void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_handshake_ex(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
beast::async_completion<HandshakeHandler,
|
||||
void(error_code)> completion{handler};
|
||||
handshake_op<decltype(completion.handler)>{
|
||||
completion.handler, *this, &res,
|
||||
host, resource, decorator};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
@ -173,7 +254,62 @@ handshake(boost::string_ref const& host,
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
error_code ec;
|
||||
handshake(host, resource, ec);
|
||||
handshake(
|
||||
host, resource, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
error_code ec;
|
||||
handshake(res, host, resource, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake_ex(boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(host, resource, decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake_ex(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(res, host, resource, decorator, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
@ -186,21 +322,59 @@ handshake(boost::string_ref const& host,
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
reset();
|
||||
std::string key;
|
||||
{
|
||||
auto const req =
|
||||
build_request(host, resource, key);
|
||||
pmd_read(pmd_config_, req.fields);
|
||||
http::write(stream_, req, ec);
|
||||
}
|
||||
if(ec)
|
||||
return;
|
||||
http::response<http::streambuf_body> res;
|
||||
http::read(next_layer(), stream_.buffer(), res, ec);
|
||||
if(ec)
|
||||
return;
|
||||
do_response(res, key, ec);
|
||||
do_handshake(nullptr,
|
||||
host, resource, &default_decorate_req, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
do_handshake(&res,
|
||||
host, resource, &default_decorate_req, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake_ex(boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
do_handshake(nullptr,
|
||||
host, resource, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake_ex(response_type& res,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_RequestDecorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
do_handshake(&res,
|
||||
host, resource, decorator, ec);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
#include <beast/websocket/detail/hybi13.hpp>
|
||||
#include <beast/websocket/detail/pmd_extension.hpp>
|
||||
#include <beast/version.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
#include <beast/http/reason.hpp>
|
||||
@ -83,9 +84,11 @@ reset()
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Decorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
do_accept(error_code& ec)
|
||||
do_accept(
|
||||
Decorator const& decorator, error_code& ec)
|
||||
{
|
||||
http::header_parser<true, http::fields> p;
|
||||
auto const bytes_used = http::read_some(
|
||||
@ -94,17 +97,17 @@ do_accept(error_code& ec)
|
||||
return;
|
||||
BOOST_ASSERT(p.got_header());
|
||||
stream_.buffer().consume(bytes_used);
|
||||
do_accept(p.get(), ec);
|
||||
do_accept(p.get(), decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Fields>
|
||||
template<class Fields, class Decorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
do_accept(http::header<true, Fields> const& req,
|
||||
error_code& ec)
|
||||
Decorator const& decorator, error_code& ec)
|
||||
{
|
||||
auto const res = build_response(req);
|
||||
auto const res = build_response(req, decorator);
|
||||
http::write(stream_, res, ec);
|
||||
if(ec)
|
||||
return;
|
||||
@ -120,12 +123,44 @@ do_accept(http::header<true, Fields> const& req,
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
http::request_header
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
build_request(boost::string_ref const& host,
|
||||
boost::string_ref const& resource, std::string& key)
|
||||
do_handshake(response_type* res_p,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
http::request_header req;
|
||||
response_type res;
|
||||
reset();
|
||||
std::string key;
|
||||
{
|
||||
auto const req = build_request(
|
||||
key, host, resource, decorator);
|
||||
pmd_read(pmd_config_, req.fields);
|
||||
http::write(stream_, req, ec);
|
||||
}
|
||||
if(ec)
|
||||
return;
|
||||
http::read(next_layer(), stream_.buffer(), res, ec);
|
||||
if(ec)
|
||||
return;
|
||||
do_response(res, key, ec);
|
||||
if(res_p)
|
||||
swap(res, *res_p);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Decorator>
|
||||
request_type
|
||||
stream<NextLayer>::
|
||||
build_request(std::string& key,
|
||||
boost::string_ref const& host,
|
||||
boost::string_ref const& resource,
|
||||
Decorator const& decorator)
|
||||
{
|
||||
request_type req;
|
||||
req.url = { resource.data(), resource.size() };
|
||||
req.version = 11;
|
||||
req.method = "GET";
|
||||
@ -150,28 +185,42 @@ build_request(boost::string_ref const& host,
|
||||
detail::pmd_write(
|
||||
req.fields, config);
|
||||
}
|
||||
d_(req);
|
||||
decorator(req);
|
||||
if(! req.fields.exists("User-Agent"))
|
||||
req.fields.insert("User-Agent",
|
||||
std::string("Beast/") + BEAST_VERSION_STRING);
|
||||
return req;
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
http::response_header
|
||||
template<class Decorator>
|
||||
response_type
|
||||
stream<NextLayer>::
|
||||
build_response(http::request_header const& req)
|
||||
build_response(request_type const& req,
|
||||
Decorator const& decorator)
|
||||
{
|
||||
auto const decorate =
|
||||
[&decorator](response_type& res)
|
||||
{
|
||||
decorator(res);
|
||||
if(! res.fields.exists("Server"))
|
||||
res.fields.insert("Server",
|
||||
std::string("Beast/") +
|
||||
BEAST_VERSION_STRING);
|
||||
};
|
||||
auto err =
|
||||
[&](std::string const& text)
|
||||
{
|
||||
http::response<http::string_body> res;
|
||||
response_type res;
|
||||
res.status = 400;
|
||||
res.reason = http::reason_string(res.status);
|
||||
res.version = req.version;
|
||||
res.body = text;
|
||||
d_(res);
|
||||
prepare(res,
|
||||
(is_keep_alive(req) && keep_alive_) ?
|
||||
http::connection::keep_alive :
|
||||
http::connection::close);
|
||||
decorate(res);
|
||||
return res;
|
||||
};
|
||||
if(req.version < 11)
|
||||
@ -193,20 +242,20 @@ build_response(http::request_header const& req)
|
||||
return err("Missing Sec-WebSocket-Version");
|
||||
if(version != "13")
|
||||
{
|
||||
http::response<http::string_body> res;
|
||||
response_type res;
|
||||
res.status = 426;
|
||||
res.reason = http::reason_string(res.status);
|
||||
res.version = req.version;
|
||||
res.fields.insert("Sec-WebSocket-Version", "13");
|
||||
d_(res);
|
||||
prepare(res,
|
||||
(is_keep_alive(req) && keep_alive_) ?
|
||||
http::connection::keep_alive :
|
||||
http::connection::close);
|
||||
decorate(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
http::response_header res;
|
||||
response_type res;
|
||||
{
|
||||
detail::pmd_offer offer;
|
||||
detail::pmd_offer unused;
|
||||
@ -225,8 +274,7 @@ build_response(http::request_header const& req)
|
||||
res.fields.insert("Sec-WebSocket-Accept",
|
||||
detail::make_sec_ws_accept(key));
|
||||
}
|
||||
res.fields.replace("Server", "Beast.WebSocket");
|
||||
d_(res);
|
||||
decorate(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/detail/decorator.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@ -59,56 +58,6 @@ struct auto_fragment
|
||||
};
|
||||
#endif
|
||||
|
||||
/** HTTP decorator option.
|
||||
|
||||
The decorator transforms the HTTP requests and responses used
|
||||
when requesting or responding to the WebSocket Upgrade. This may
|
||||
be used to set or change header fields. For example to set the
|
||||
Server or User-Agent fields. The default setting applies no
|
||||
transformation to the HTTP message.
|
||||
|
||||
The context in which the decorator is called depends on the
|
||||
type of operation performed:
|
||||
|
||||
@li For synchronous operations, the implementation will call the
|
||||
decorator before the operation unblocks.
|
||||
|
||||
@li For asynchronous operations, the implementation guarantees
|
||||
that calls to the decorator will be made from the same implicit
|
||||
or explicit strand used to call the asynchronous initiation
|
||||
function.
|
||||
|
||||
The default setting is no decorator.
|
||||
|
||||
@note Objects of this type are used with
|
||||
@ref beast::websocket::stream::set_option.
|
||||
|
||||
@par Example
|
||||
Setting the decorator.
|
||||
@code
|
||||
struct identity
|
||||
{
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
void
|
||||
operator()(http::message<isRequest, Body, Fields>& m)
|
||||
{
|
||||
if(isRequest)
|
||||
m.fields.replace("User-Agent", "MyClient");
|
||||
else
|
||||
m.fields.replace("Server", "MyServer");
|
||||
}
|
||||
};
|
||||
...
|
||||
websocket::stream<ip::tcp::socket> ws(ios);
|
||||
ws.set_option(decorate(identity{}));
|
||||
@endcode
|
||||
*/
|
||||
#if BEAST_DOXYGEN
|
||||
using decorate = implementation_defined;
|
||||
#else
|
||||
using decorate = detail::decorator_type;
|
||||
#endif
|
||||
|
||||
/** Keep-alive option.
|
||||
|
||||
Determines if the connection is closed after a failed upgrade
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -111,33 +111,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct test_decorator
|
||||
{
|
||||
int& what;
|
||||
|
||||
test_decorator(test_decorator const&) = default;
|
||||
|
||||
test_decorator(int& what_)
|
||||
: what(what_)
|
||||
{
|
||||
what = 0;
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
void
|
||||
operator()(http::header<true, Fields>&) const
|
||||
{
|
||||
what |= 1;
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
void
|
||||
operator()(http::header<false, Fields>&) const
|
||||
{
|
||||
what |= 2;
|
||||
}
|
||||
};
|
||||
|
||||
struct SyncClient
|
||||
{
|
||||
template<class NextLayer>
|
||||
@ -173,6 +146,46 @@ public:
|
||||
ws.accept(req, buffers);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(d);
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Buffers, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(buffers, d);
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Fields, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
http::header<true, Fields> const& req,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(req, d);
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Fields, class Buffers,
|
||||
class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
http::header<true, Fields> const& req,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.accept_ex(req, buffers, d);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
@ -182,6 +195,37 @@ public:
|
||||
ws.handshake(uri, path);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
response_type& res,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path) const
|
||||
{
|
||||
ws.handshake(res, uri, path);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.handshake_ex(uri, path, d);
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
response_type& res,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path,
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.handshake_ex(res, uri, path, d);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
ping(stream<NextLayer>& ws,
|
||||
@ -301,14 +345,56 @@ public:
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Fields, class Buffers>
|
||||
class Decorator>
|
||||
void
|
||||
accept(stream<NextLayer>& ws,
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Buffers, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
Buffers const& buffers,
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(buffers, d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer,
|
||||
class Fields, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
http::header<true, Fields> const& req,
|
||||
Decorator const& d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_accept_ex(req, d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Fields,
|
||||
class Buffers, class Decorator>
|
||||
void
|
||||
accept_ex(stream<NextLayer>& ws,
|
||||
http::header<true, Fields> const& req,
|
||||
Buffers const& buffers,
|
||||
error_code& ec) const
|
||||
Decorator const& d) const
|
||||
{
|
||||
ws.async_accept(req, buffers, yield_[ec]);
|
||||
error_code ec;
|
||||
ws.async_accept_ex(
|
||||
req, buffers, d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
@ -318,7 +404,51 @@ public:
|
||||
boost::string_ref const& path) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake(uri, path, yield_[ec]);
|
||||
ws.async_handshake(
|
||||
uri, path, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
handshake(stream<NextLayer>& ws,
|
||||
response_type& res,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake(
|
||||
res, uri, path, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path,
|
||||
Decorator const &d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake_ex(
|
||||
uri, path, d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer, class Decorator>
|
||||
void
|
||||
handshake_ex(stream<NextLayer>& ws,
|
||||
response_type& res,
|
||||
boost::string_ref const& uri,
|
||||
boost::string_ref const& path,
|
||||
Decorator const &d) const
|
||||
{
|
||||
error_code ec;
|
||||
ws.async_handshake_ex(
|
||||
res, uri, path, d, yield_[ec]);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
@ -436,6 +566,28 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class res_decorator
|
||||
{
|
||||
bool& b_;
|
||||
|
||||
public:
|
||||
res_decorator(res_decorator const&) = default;
|
||||
|
||||
explicit
|
||||
res_decorator(bool& b)
|
||||
: b_(b)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type&) const
|
||||
{
|
||||
b_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Client>
|
||||
void
|
||||
testAccept(Client const& c)
|
||||
@ -460,7 +612,22 @@ public:
|
||||
"\r\n"
|
||||
, 20};
|
||||
c.accept(ws);
|
||||
//log << ws.next_layer().str << std::endl;
|
||||
// VFALCO validate contents of ws.next_layer().str?
|
||||
}
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
test::string_iostream>> ws{fc, ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n"
|
||||
, 20};
|
||||
bool called = false;
|
||||
c.accept_ex(ws, res_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
// request in buffers
|
||||
{
|
||||
@ -476,6 +643,21 @@ public:
|
||||
"\r\n"
|
||||
));
|
||||
}
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
test::string_ostream>> ws{fc, ios_};
|
||||
bool called = false;
|
||||
c.accept_ex(ws, sbuf(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n"),
|
||||
res_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
// request in buffers and stream
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
@ -491,9 +673,25 @@ public:
|
||||
"Upgrade: websocket\r\n"
|
||||
));
|
||||
}
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
test::string_iostream>> ws{fc, ios_,
|
||||
"Connection: upgrade\r\n"
|
||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"\r\n"
|
||||
, 16};
|
||||
bool called = false;
|
||||
c.accept_ex(ws, sbuf(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"Upgrade: websocket\r\n"),
|
||||
res_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
// request in message
|
||||
{
|
||||
http::request_header req;
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
@ -506,9 +704,26 @@ public:
|
||||
test::string_ostream>> ws{fc, ios_};
|
||||
c.accept(ws, req);
|
||||
}
|
||||
{
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.fields.insert("Host", "localhost");
|
||||
req.fields.insert("Upgrade", "websocket");
|
||||
req.fields.insert("Connection", "upgrade");
|
||||
req.fields.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
|
||||
req.fields.insert("Sec-WebSocket-Version", "13");
|
||||
stream<test::fail_stream<
|
||||
test::string_ostream>> ws{fc, ios_};
|
||||
bool called = false;
|
||||
c.accept_ex(ws, req,
|
||||
res_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
// request in message, close frame in buffers
|
||||
{
|
||||
http::request_header req;
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
@ -534,9 +749,39 @@ public:
|
||||
throw;
|
||||
}
|
||||
}
|
||||
{
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.fields.insert("Host", "localhost");
|
||||
req.fields.insert("Upgrade", "websocket");
|
||||
req.fields.insert("Connection", "upgrade");
|
||||
req.fields.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
|
||||
req.fields.insert("Sec-WebSocket-Version", "13");
|
||||
stream<test::fail_stream<
|
||||
test::string_ostream>> ws{fc, ios_};
|
||||
bool called = false;
|
||||
c.accept_ex(ws, req,
|
||||
cbuf(0x88, 0x82, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x17),
|
||||
res_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
try
|
||||
{
|
||||
opcode op;
|
||||
streambuf sb;
|
||||
c.read(ws, op, sb);
|
||||
fail("success", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& e)
|
||||
{
|
||||
if(e.code() != websocket::error::closed)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// request in message, close frame in stream
|
||||
{
|
||||
http::request_header req;
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
@ -564,7 +809,7 @@ public:
|
||||
}
|
||||
// request in message, close frame in stream and buffers
|
||||
{
|
||||
http::request_header req;
|
||||
request_type req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
@ -609,8 +854,10 @@ public:
|
||||
}
|
||||
catch(system_error const& e)
|
||||
{
|
||||
if(e.code() !=
|
||||
websocket::error::handshake_failed)
|
||||
if( e.code() !=
|
||||
websocket::error::handshake_failed &&
|
||||
e.code() !=
|
||||
boost::asio::error::eof)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -635,6 +882,107 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class req_decorator
|
||||
{
|
||||
bool& b_;
|
||||
|
||||
public:
|
||||
req_decorator(req_decorator const&) = default;
|
||||
|
||||
explicit
|
||||
req_decorator(bool& b)
|
||||
: b_(b)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type&) const
|
||||
{
|
||||
b_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Client>
|
||||
void
|
||||
testHandshake(endpoint_type const& ep, Client const& c)
|
||||
{
|
||||
static std::size_t constexpr limit = 200;
|
||||
std::size_t n;
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc{n};
|
||||
try
|
||||
{
|
||||
// handshake
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
boost::asio::ip::tcp::socket>> ws{fc, ios_};
|
||||
ws.next_layer().next_layer().connect(ep);
|
||||
c.handshake(ws, "localhost", "/");
|
||||
}
|
||||
// handshake, response
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
boost::asio::ip::tcp::socket>> ws{fc, ios_};
|
||||
ws.next_layer().next_layer().connect(ep);
|
||||
response_type res;
|
||||
c.handshake(ws, res, "localhost", "/");
|
||||
// VFALCO validate res?
|
||||
}
|
||||
// handshake_ex
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
boost::asio::ip::tcp::socket>> ws{fc, ios_};
|
||||
ws.next_layer().next_layer().connect(ep);
|
||||
bool called = false;
|
||||
c.handshake_ex(ws, "localhost", "/",
|
||||
req_decorator{called});
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
// handshake_ex, response
|
||||
{
|
||||
stream<test::fail_stream<
|
||||
boost::asio::ip::tcp::socket>> ws{fc, ios_};
|
||||
ws.next_layer().next_layer().connect(ep);
|
||||
bool called = false;
|
||||
response_type res;
|
||||
c.handshake_ex(ws, res, "localhost", "/",
|
||||
req_decorator{called});
|
||||
// VFALCO validate res?
|
||||
BEAST_EXPECT(called);
|
||||
}
|
||||
}
|
||||
catch(system_error const&)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
BEAST_EXPECT(n < limit);
|
||||
}
|
||||
|
||||
void
|
||||
testHandshake()
|
||||
{
|
||||
error_code ec;
|
||||
::websocket::async_echo_server server{nullptr, 1};
|
||||
auto const any = endpoint_type{
|
||||
address_type::from_string("127.0.0.1"), 0};
|
||||
server.open(any, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
auto const ep = server.local_endpoint();
|
||||
testHandshake(ep, SyncClient{});
|
||||
yield_to(
|
||||
[&](yield_context yield)
|
||||
{
|
||||
testHandshake(ep, AsyncClient{yield});
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testBadHandshakes()
|
||||
{
|
||||
auto const check =
|
||||
@ -823,24 +1171,6 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
testDecorator(endpoint_type const& ep)
|
||||
{
|
||||
error_code ec;
|
||||
socket_type sock{ios_};
|
||||
sock.connect(ep, ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
return;
|
||||
stream<socket_type&> ws{sock};
|
||||
int what;
|
||||
ws.set_option(decorate(test_decorator{what}));
|
||||
BEAST_EXPECT(what == 0);
|
||||
ws.handshake("localhost", "/", ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
return;
|
||||
BEAST_EXPECT(what == 1);
|
||||
}
|
||||
|
||||
void testMask(endpoint_type const& ep,
|
||||
yield_context do_yield)
|
||||
{
|
||||
@ -1525,6 +1855,7 @@ public:
|
||||
|
||||
testOptions();
|
||||
testAccept();
|
||||
testHandshake();
|
||||
testBadHandshakes();
|
||||
testBadResponses();
|
||||
|
||||
@ -1539,7 +1870,6 @@ public:
|
||||
server.open(any, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
auto const ep = server.local_endpoint();
|
||||
testDecorator(ep);
|
||||
//testInvokable1(ep);
|
||||
testInvokable2(ep);
|
||||
testInvokable3(ep);
|
||||
|
@ -38,25 +38,6 @@ public:
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "async_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "async_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
@ -159,8 +140,6 @@ public:
|
||||
, acceptor_(ios_)
|
||||
, work_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
thread_.reserve(threads);
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
thread_.emplace_back(
|
||||
@ -282,7 +261,13 @@ private:
|
||||
void run()
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.ws.async_accept(std::move(*this));
|
||||
d.ws.async_accept_ex(
|
||||
[](beast::websocket::response_type& res)
|
||||
{
|
||||
res.fields.insert(
|
||||
"Server", "async_echo_server");
|
||||
},
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
template<class DynamicBuffer, std::size_t N>
|
||||
|
@ -38,25 +38,6 @@ public:
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "sync_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "sync_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
@ -151,8 +132,6 @@ public:
|
||||
, sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
@ -312,7 +291,13 @@ private:
|
||||
socket_type> ws{std::move(sock)};
|
||||
opts_.set_options(ws);
|
||||
error_code ec;
|
||||
ws.accept(ec);
|
||||
ws.accept_ex(
|
||||
[](beast::websocket::response_type& res)
|
||||
{
|
||||
res.fields.insert(
|
||||
"Server", "sync_echo_server");
|
||||
},
|
||||
ec);
|
||||
if(ec)
|
||||
{
|
||||
fail("accept", ec, id, ep);
|
||||
|
Reference in New Issue
Block a user