diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd4bedf9..40698038 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
API Changes:
* Provide websocket::stream accept() overloads
+* Refactor websocket decorators
--------------------------------------------------------------------------------
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 94a1a3c3..a1afe585 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -112,7 +112,6 @@
Options
auto_fragment
- decorate
keep_alive
message_type
permessage_deflate
diff --git a/examples/websocket_async_echo_server.hpp b/examples/websocket_async_echo_server.hpp
index bd0c8481..e6ed81ef 100644
--- a/examples/websocket_async_echo_server.hpp
+++ b/examples/websocket_async_echo_server.hpp
@@ -38,25 +38,6 @@ public:
using endpoint_type = boost::asio::ip::tcp::endpoint;
private:
- struct identity
- {
- template
- void
- operator()(beast::http::message<
- true, Body, Fields>& req) const
- {
- req.fields.replace("User-Agent", "async_echo_client");
- }
-
- template
- 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
@@ -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)
diff --git a/examples/websocket_sync_echo_server.hpp b/examples/websocket_sync_echo_server.hpp
index 1f41b52c..ab8bd5d5 100644
--- a/examples/websocket_sync_echo_server.hpp
+++ b/examples/websocket_sync_echo_server.hpp
@@ -38,25 +38,6 @@ public:
using socket_type = boost::asio::ip::tcp::socket;
private:
- struct identity
- {
- template
- void
- operator()(beast::http::message<
- true, Body, Fields>& req) const
- {
- req.fields.replace("User-Agent", "sync_echo_client");
- }
-
- template
- 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
@@ -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);
diff --git a/extras/beast/test/string_ostream.hpp b/extras/beast/test/string_ostream.hpp
index 52a9bf5d..bc5b7896 100644
--- a/extras/beast/test/string_ostream.hpp
+++ b/extras/beast/test/string_ostream.hpp
@@ -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 completion{handler};
ios_.post(bind_handler(completion.handler,
- error_code{}, 0));
+ boost::asio::error::eof, 0));
return completion.result.get();
}
diff --git a/include/beast/websocket/detail/decorator.hpp b/include/beast/websocket/detail/decorator.hpp
deleted file mode 100644
index bb40e58f..00000000
--- a/include/beast/websocket/detail/decorator.hpp
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-
-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 decorator : public abstract_decorator
-{
- F f_;
-
- class call_req_possible
- {
- template().operator()(
- std::declval()),
- std::true_type{})>
- static R check(int);
- template
- static std::false_type check(...);
- public:
- using type = decltype(check(0));
- };
-
- class call_res_possible
- {
- template().operator()(
- std::declval()),
- std::true_type{})>
- static R check(int);
- template
- static std::false_type check(...);
- public:
- using type = decltype(check(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 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::type,
- decorator_type>::value>>
- decorator_type(F&& f)
- : p_(std::make_shared>(
- std::forward(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
diff --git a/include/beast/websocket/detail/stream_base.hpp b/include/beast/websocket/detail/stream_base.hpp
index 5b5aaa99..66ede62e 100644
--- a/include/beast/websocket/detail/stream_base.hpp
+++ b/include/beast/websocket/detail/stream_base.hpp
@@ -11,7 +11,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -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
void
open(role_type role);
diff --git a/include/beast/websocket/detail/type_traits.hpp b/include/beast/websocket/detail/type_traits.hpp
new file mode 100644
index 00000000..58be3caf
--- /dev/null
+++ b/include/beast/websocket/detail/type_traits.hpp
@@ -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
+#include
+
+namespace beast {
+namespace websocket {
+namespace detail {
+
+template
+using is_RequestDecorator =
+ typename beast::detail::is_call_possible::type;
+
+template
+using is_ResponseDecorator =
+ typename beast::detail::is_call_possible::type;
+
+} // detail
+} // websocket
+} // beast
+
+#endif
diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp
index 489440b7..2543d0f7 100644
--- a/include/beast/websocket/impl/accept.ipp
+++ b/include/beast/websocket/impl/accept.ipp
@@ -8,6 +8,7 @@
#ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
#define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
+#include
#include
#include
#include
@@ -38,23 +39,27 @@ class stream::response_op
http::response_header res;
int state = 0;
- template
+ template
data(Handler&, stream& ws_,
http::header const& req,
- bool cont_)
+ Decorator const& decorator,
+ bool cont_)
: cont(cont_)
, ws(ws_)
- , res(ws_.build_response(req))
+ , res(ws_.build_response(req, decorator))
{
}
- template
+ template
data(Handler&, stream& ws_,
http::header 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
-template
+template
class stream::accept_op
{
struct data
{
bool cont;
stream& ws;
+ Decorator decorator;
http::header_parser p;
int state = 0;
- // VFALCO These lines are formatted to work around a codecov defect
- data(Handler& handler, stream& ws_) : cont(beast_asio_helpers::is_continuation(handler))
- , ws(ws_) {}
+ data(Handler& handler, stream& ws_,
+ Decorator const& decorator_)
+ : cont(beast_asio_helpers::is_continuation(handler))
+ , ws(ws_)
+ , decorator(decorator_)
+ {
+ }
template
data(Handler& handler, stream& 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
-template
+template
void
-stream::accept_op::
+stream::accept_op::
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{
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
+template
+void
+stream::
+accept_ex(ResponseDecorator const& decorator)
+{
+ static_assert(is_SyncStream::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
void
stream::
@@ -297,7 +334,22 @@ accept(error_code& ec)
static_assert(is_SyncStream::value,
"SyncStream requirements not met");
reset();
- do_accept(ec);
+ do_accept(&default_decorate_res, ec);
+}
+
+template
+template
+void
+stream::
+accept_ex(ResponseDecorator const& decorator, error_code& ec)
+{
+ static_assert(is_SyncStream::value,
+ "SyncStream requirements not met");
+ static_assert(detail::is_ResponseDecorator<
+ ResponseDecorator>::value,
+ "ResponseDecorator requirements not met");
+ reset();
+ do_accept(decorator, ec);
}
template
@@ -317,6 +369,28 @@ accept(ConstBufferSequence const& buffers)
throw system_error{ec};
}
+template
+template<
+ class ConstBufferSequence, class ResponseDecorator>
+void
+stream::
+accept_ex(ConstBufferSequence const& buffers,
+ ResponseDecorator const &decorator)
+{
+ static_assert(is_SyncStream::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
template
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
+template<
+ class ConstBufferSequence, class ResponseDecorator>
+void
+stream::
+accept_ex(ConstBufferSequence const& buffers,
+ ResponseDecorator const& decorator, error_code& ec)
+{
+ static_assert(is_SyncStream::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
@@ -351,6 +450,24 @@ accept(http::header const& req)
throw system_error{ec};
}
+template
+template
+void
+stream::
+accept_ex(http::header const& req,
+ ResponseDecorator const& decorator)
+{
+ static_assert(is_SyncStream::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
template
void
@@ -361,15 +478,30 @@ accept(http::header const& req,
static_assert(is_SyncStream::value,
"SyncStream requirements not met");
reset();
- do_accept(req, ec);
+ do_accept(req, &default_decorate_res, ec);
+}
+
+template
+template
+void
+stream::
+accept_ex(http::header const& req,
+ ResponseDecorator const& decorator, error_code& ec)
+{
+ static_assert(is_SyncStream::value,
+ "SyncStream requirements not met");
+ static_assert(detail::is_ResponseDecorator<
+ ResponseDecorator>::value,
+ "ResponseDecorator requirements not met");
+ reset();
+ do_accept(req, decorator, ec);
}
template
template
void
stream::
-accept(
- http::header const& req,
+accept(http::header const& req,
ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream::value,
@@ -383,14 +515,35 @@ accept(
throw system_error{ec};
}
+template
+template
+void
+stream::
+accept_ex(http::header const& req,
+ ConstBufferSequence const& buffers,
+ ResponseDecorator const& decorator)
+{
+ static_assert(is_SyncStream::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
template
void
stream::
-accept(
- http::header const& req,
- ConstBufferSequence const& buffers,
- error_code& ec)
+accept(http::header const& req,
+ ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream::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
+template
+void
+stream::
+accept_ex(http::header const& req,
+ ConstBufferSequence const& buffers,
+ ResponseDecorator const& decorator,
+ error_code& ec)
+{
+ static_assert(is_SyncStream::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 completion{handler};
reset();
- accept_op{
- completion.handler, *this};
+ accept_op{completion.handler,
+ *this, &default_decorate_res};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+async_accept_ex(ResponseDecorator const& decorator,
+ AcceptHandler&& handler)
+{
+ static_assert(is_AsyncStream::value,
+ "AsyncStream requirements requirements not met");
+ static_assert(detail::is_ResponseDecorator<
+ ResponseDecorator>::value,
+ "ResponseDecorator requirements not met");
+ beast::async_completion completion{handler};
+ reset();
+ accept_op{
+ completion.handler, *this, decorator};
return completion.result.get();
}
@@ -441,8 +643,35 @@ async_accept(ConstBufferSequence const& buffers,
beast::async_completion completion{handler};
reset();
- accept_op{
- completion.handler, *this, buffers};
+ accept_op{completion.handler,
+ *this, buffers, &default_decorate_res};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+async_accept_ex(ConstBufferSequence const& buffers,
+ ResponseDecorator const& decorator,
+ AcceptHandler&& handler)
+{
+ static_assert(is_AsyncStream::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 completion{handler};
+ reset();
+ accept_op{
+ completion.handler, *this, buffers, decorator};
return completion.result.get();
}
@@ -461,11 +690,35 @@ async_accept(http::header const& req,
reset();
response_op{
completion.handler, *this, req,
- beast_asio_helpers::
+ &default_decorate_res, beast_asio_helpers::
is_continuation(completion.handler)};
return completion.result.get();
}
+template
+template
+typename async_completion::result_type
+stream::
+async_accept_ex(http::header const& req,
+ ResponseDecorator const& decorator, AcceptHandler&& handler)
+{
+ static_assert(is_AsyncStream::value,
+ "AsyncStream requirements requirements not met");
+ static_assert(detail::is_ResponseDecorator<
+ ResponseDecorator>::value,
+ "ResponseDecorator requirements not met");
+ beast::async_completion completion{handler};
+ reset();
+ response_op{
+ completion.handler, *this, req, decorator,
+ beast_asio_helpers::is_continuation(
+ completion.handler)};
+ return completion.result.get();
+}
+
template
template
@@ -486,8 +739,37 @@ async_accept(http::header const& req,
reset();
response_op{
completion.handler, *this, req, buffers,
- beast_asio_helpers::
- is_continuation(completion.handler)};
+ &default_decorate_res, beast_asio_helpers::
+ is_continuation(completion.handler)};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+async_accept_ex(http::header const& req,
+ ConstBufferSequence const& buffers,
+ ResponseDecorator const& decorator,
+ AcceptHandler&& handler)
+{
+ static_assert(is_AsyncStream::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 completion{handler};
+ reset();
+ response_op{
+ completion.handler, *this, req, buffers, decorator,
+ beast_asio_helpers::is_continuation(
+ completion.handler)};
return completion.result.get();
}
diff --git a/include/beast/websocket/impl/handshake.ipp b/include/beast/websocket/impl/handshake.ipp
index b788e4ed..07569b6c 100644
--- a/include/beast/websocket/impl/handshake.ipp
+++ b/include/beast/websocket/impl/handshake.ipp
@@ -8,6 +8,7 @@
#ifndef BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
+#include
#include
#include
#include
@@ -33,18 +34,24 @@ class stream::handshake_op
{
bool cont;
stream& ws;
+ response_type* res_p;
std::string key;
- http::request_header req;
- http::response res;
+ request_type req;
+ response_type res;
int state = 0;
+ template
data(Handler& handler, stream& ws_,
- boost::string_ref const& host,
- boost::string_ref const& resource)
+ response_type* res_p_,
+ boost::string_ref const& host,
+ 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
template
-typename async_completion<
- HandshakeHandler, void(error_code)>::result_type
+typename async_completion::result_type
stream::
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::value,
"AsyncStream requirements not met");
- beast::async_completion<
- HandshakeHandler, void(error_code)
- > completion{handler};
+ beast::async_completion completion{handler};
handshake_op{
- completion.handler, *this, host, resource};
+ completion.handler, *this, nullptr,
+ host, resource, &default_decorate_req};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+async_handshake(response_type& res,
+ boost::string_ref const& host,
+ boost::string_ref const& resource,
+ HandshakeHandler&& handler)
+{
+ static_assert(is_AsyncStream::value,
+ "AsyncStream requirements not met");
+ beast::async_completion completion{handler};
+ handshake_op{
+ completion.handler, *this, &res,
+ host, resource, &default_decorate_req};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+async_handshake_ex(boost::string_ref const& host,
+ boost::string_ref const& resource,
+ RequestDecorator const& decorator,
+ HandshakeHandler&& handler)
+{
+ static_assert(is_AsyncStream::value,
+ "AsyncStream requirements not met");
+ static_assert(detail::is_RequestDecorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ beast::async_completion completion{handler};
+ handshake_op{
+ completion.handler, *this, nullptr,
+ host, resource, decorator};
+ return completion.result.get();
+}
+
+template
+template
+typename async_completion::result_type
+stream::
+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::value,
+ "AsyncStream requirements not met");
+ static_assert(detail::is_RequestDecorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ beast::async_completion completion{handler};
+ handshake_op{
+ 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::value,
"SyncStream requirements not met");
error_code ec;
- handshake(host, resource, ec);
+ handshake(
+ host, resource, ec);
+ if(ec)
+ throw system_error{ec};
+}
+
+template
+void
+stream::
+handshake(response_type& res,
+ boost::string_ref const& host,
+ boost::string_ref const& resource)
+{
+ static_assert(is_SyncStream::value,
+ "SyncStream requirements not met");
+ error_code ec;
+ handshake(res, host, resource, ec);
+ if(ec)
+ throw system_error{ec};
+}
+
+template
+template
+void
+stream::
+handshake_ex(boost::string_ref const& host,
+ boost::string_ref const& resource,
+ RequestDecorator const& decorator)
+{
+ static_assert(is_SyncStream::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
+template
+void
+stream::
+handshake_ex(response_type& res,
+ boost::string_ref const& host,
+ boost::string_ref const& resource,
+ RequestDecorator const& decorator)
+{
+ static_assert(is_SyncStream::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::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 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
+void
+stream::
+handshake(response_type& res,
+ boost::string_ref const& host,
+ boost::string_ref const& resource,
+ error_code& ec)
+{
+ static_assert(is_SyncStream::value,
+ "SyncStream requirements not met");
+ do_handshake(&res,
+ host, resource, &default_decorate_req, ec);
+}
+
+template
+template
+void
+stream::
+handshake_ex(boost::string_ref const& host,
+ boost::string_ref const& resource,
+ RequestDecorator const& decorator,
+ error_code& ec)
+{
+ static_assert(is_SyncStream::value,
+ "SyncStream requirements not met");
+ static_assert(detail::is_RequestDecorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ do_handshake(nullptr,
+ host, resource, decorator, ec);
+}
+
+template
+template
+void
+stream::
+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::value,
+ "SyncStream requirements not met");
+ static_assert(detail::is_RequestDecorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ do_handshake(&res,
+ host, resource, decorator, ec);
}
//------------------------------------------------------------------------------
diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp
index 8bba955d..717e9aef 100644
--- a/include/beast/websocket/impl/stream.ipp
+++ b/include/beast/websocket/impl/stream.ipp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -83,9 +84,11 @@ reset()
}
template
+template
void
stream::
-do_accept(error_code& ec)
+do_accept(
+ Decorator const& decorator, error_code& ec)
{
http::header_parser 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
-template
+template
void
stream::
do_accept(http::header 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 const& req,
}
template
-http::request_header
+template
+void
stream::
-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
+template