Enable explicit instantiation of websocket::stream:

fix #1279, close #1319

This enables users to improve compilation performance by explicitly
instantiating the stream template in another TU.

Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>
This commit is contained in:
Damian Jarek
2018-11-24 00:41:53 +01:00
committed by Vinnie Falco
parent 650ddd07c1
commit 8930d437b5
10 changed files with 292 additions and 354 deletions

View File

@ -3,6 +3,7 @@ Version 193:
* Update ssl_stream signatures for networking changes * Update ssl_stream signatures for networking changes
* Fix test::stream async_result transformation * Fix test::stream async_result transformation
* Tidy up test::stream * Tidy up test::stream
* Enable explicit instantiation of websocket::stream
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -291,7 +291,6 @@ async_read_some(
{ {
lock.unlock(); lock.unlock();
++in_->nread; ++in_->nread;
error_code ec;
if(in_->code == status::eof) if(in_->code == status::eof)
ec = boost::asio::error::eof; ec = boost::asio::error::eof;
else if(in_->code == status::reset) else if(in_->code == status::reset)

View File

@ -10,6 +10,9 @@
#ifndef BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP #ifndef BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
#define BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP #define BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
#include <boost/beast/http/empty_body.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/websocket/option.hpp> #include <boost/beast/websocket/option.hpp>
#include <boost/beast/websocket/detail/pmd_extension.hpp> #include <boost/beast/websocket/detail/pmd_extension.hpp>
#include <boost/beast/zlib/deflate_stream.hpp> #include <boost/beast/zlib/deflate_stream.hpp>
@ -17,6 +20,7 @@
#include <boost/beast/core/buffers_suffix.hpp> #include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/detail/chacha.hpp> #include <boost/beast/core/detail/chacha.hpp>
#include <boost/beast/core/detail/clamp.hpp>
#include <boost/align/aligned_alloc.hpp> #include <boost/align/aligned_alloc.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/core/exchange.hpp> #include <boost/core/exchange.hpp>
@ -353,6 +357,165 @@ struct stream_base : stream_prng
void void
do_context_takeover_read(role_type role); do_context_takeover_read(role_type role);
template<class Body, class Allocator>
void
build_response_pmd(
http::response<http::string_body>& res,
http::request<Body,
http::basic_fields<Allocator>> const& req)
{
detail::pmd_offer offer;
detail::pmd_offer unused;
detail::pmd_read(offer, req);
detail::pmd_negotiate(res, unused, offer, pmd_opts_);
}
void
on_response_pmd(http::response<http::string_body> const& res)
{
detail::pmd_offer offer;
detail::pmd_read(offer, res);
// VFALCO see if offer satisfies pmd_config_,
// return an error if not.
pmd_config_ = offer; // overwrite for now
}
template<class Allocator>
void
do_pmd_config(
http::basic_fields<Allocator> const& h)
{
detail::pmd_read(pmd_config_, h);
}
void
set_option_pmd(permessage_deflate const& o)
{
if( o.server_max_window_bits > 15 ||
o.server_max_window_bits < 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid server_max_window_bits"});
if( o.client_max_window_bits > 15 ||
o.client_max_window_bits < 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid client_max_window_bits"});
if( o.compLevel < 0 ||
o.compLevel > 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid compLevel"});
if( o.memLevel < 1 ||
o.memLevel > 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid memLevel"});
pmd_opts_ = o;
}
void
get_option_pmd(permessage_deflate& o)
{
o = pmd_opts_;
}
void
build_request_pmd(http::request<http::empty_body>& req)
{
if(pmd_opts_.client_enable)
{
detail::pmd_offer config;
config.accept = true;
config.server_max_window_bits =
pmd_opts_.server_max_window_bits;
config.client_max_window_bits =
pmd_opts_.client_max_window_bits;
config.server_no_context_takeover =
pmd_opts_.server_no_context_takeover;
config.client_no_context_takeover =
pmd_opts_.client_no_context_takeover;
detail::pmd_write(req, config);
}
}
void
open_pmd(role_type role)
{
if(((role == role_type::client &&
pmd_opts_.client_enable) ||
(role == role_type::server &&
pmd_opts_.server_enable)) &&
pmd_config_.accept)
{
detail::pmd_normalize(pmd_config_);
pmd_.reset(new typename
detail::stream_base<deflateSupported>::pmd_type);
if(role == role_type::client)
{
pmd_->zi.reset(
pmd_config_.server_max_window_bits);
pmd_->zo.reset(
pmd_opts_.compLevel,
pmd_config_.client_max_window_bits,
pmd_opts_.memLevel,
zlib::Strategy::normal);
}
else
{
pmd_->zi.reset(
pmd_config_.client_max_window_bits);
pmd_->zo.reset(
pmd_opts_.compLevel,
pmd_config_.server_max_window_bits,
pmd_opts_.memLevel,
zlib::Strategy::normal);
}
}
}
void close_pmd()
{
pmd_.reset();
}
bool pmd_enabled() const
{
return pmd_ != nullptr;
}
std::size_t
read_size_hint_pmd(
std::size_t initial_size,
bool rd_done,
std::uint64_t rd_remain,
detail::frame_header const& rd_fh) const
{
using beast::detail::clamp;
std::size_t result;
BOOST_ASSERT(initial_size > 0);
if(! pmd_ || (! rd_done && ! pmd_->rd_set))
{
// current message is uncompressed
if(rd_done)
{
// first message frame
result = initial_size;
goto done;
}
else if(rd_fh.fin)
{
// last message frame
BOOST_ASSERT(rd_remain > 0);
result = clamp(rd_remain);
goto done;
}
}
result = (std::max)(
initial_size, clamp(rd_remain));
done:
BOOST_ASSERT(result != 0);
return result;
}
}; };
template<> template<>
@ -402,6 +565,98 @@ struct stream_base<false> : stream_prng
do_context_takeover_read(role_type) do_context_takeover_read(role_type)
{ {
} }
template<class Body, class Allocator>
void
build_response_pmd(
http::response<http::string_body>&,
http::request<Body,
http::basic_fields<Allocator>> const&)
{
}
void
on_response_pmd(
http::response<http::string_body> const&)
{
}
template<class Allocator>
void
do_pmd_config(http::basic_fields<Allocator> const&)
{
}
void
set_option_pmd(permessage_deflate const& o)
{
if(o.client_enable || o.server_enable)
{
// Can't enable permessage-deflate
// when deflateSupported == false.
//
BOOST_THROW_EXCEPTION(std::invalid_argument{
"deflateSupported == false"});
}
}
void
get_option_pmd(permessage_deflate& o)
{
o = {};
o.client_enable = false;
o.server_enable = false;
}
void
build_request_pmd(
http::request<http::empty_body>&)
{
}
void open_pmd(role_type)
{
}
void close_pmd()
{
}
bool pmd_enabled() const
{
return false;
}
std::size_t
read_size_hint_pmd(
std::size_t initial_size,
bool rd_done,
std::uint64_t rd_remain,
detail::frame_header const& rd_fh) const
{
using beast::detail::clamp;
std::size_t result;
BOOST_ASSERT(initial_size > 0);
// compression is not supported
if(rd_done)
{
// first message frame
result = initial_size;
}
else if(rd_fh.fin)
{
// last message frame
BOOST_ASSERT(rd_remain > 0);
result = clamp(rd_remain);
}
else
{
result = (std::max)(
initial_size, clamp(rd_remain));
}
BOOST_ASSERT(result != 0);
return result;
}
}; };
} // detail } // detail

View File

@ -139,7 +139,7 @@ operator()(
ec = d.result; ec = d.result;
if(! ec) if(! ec)
{ {
d.ws.do_pmd_config(d.res, is_deflate_supported{}); d.ws.do_pmd_config(d.res);
d.ws.open(role_type::server); d.ws.open(role_type::server);
} }
{ {
@ -763,7 +763,7 @@ do_accept(
// teardown if Connection: close. // teardown if Connection: close.
return; return;
} }
do_pmd_config(res, is_deflate_supported{}); this->do_pmd_config(res);
open(role_type::server); open(role_type::server);
} }

View File

@ -135,7 +135,7 @@ operator()(error_code ec, std::size_t)
BOOST_ASIO_CORO_REENTER(*this) BOOST_ASIO_CORO_REENTER(*this)
{ {
// Send HTTP Upgrade // Send HTTP Upgrade
d.ws.do_pmd_config(d.req, is_deflate_supported{}); d.ws.do_pmd_config(d.req);
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
http::async_write(d.ws.stream_, http::async_write(d.ws.stream_,
d.req, std::move(*this)); d.req, std::move(*this));
@ -407,7 +407,7 @@ do_handshake(
{ {
auto const req = build_request( auto const req = build_request(
key, host, target, decorator); key, host, target, decorator);
do_pmd_config(req, is_deflate_supported{}); this->do_pmd_config(req);
http::write(stream_, req, ec); http::write(stream_, req, ec);
} }
if(ec) if(ec)

View File

@ -69,45 +69,6 @@ read_size_hint(DynamicBuffer& buffer) const
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
set_option(permessage_deflate const& o, std::true_type)
{
if( o.server_max_window_bits > 15 ||
o.server_max_window_bits < 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid server_max_window_bits"});
if( o.client_max_window_bits > 15 ||
o.client_max_window_bits < 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid client_max_window_bits"});
if( o.compLevel < 0 ||
o.compLevel > 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid compLevel"});
if( o.memLevel < 1 ||
o.memLevel > 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid memLevel"});
this->pmd_opts_ = o;
}
template<class NextLayer, bool deflateSupported>
void
stream<NextLayer, deflateSupported>::
set_option(permessage_deflate const& o, std::false_type)
{
if(o.client_enable || o.server_enable)
{
// Can't enable permessage-deflate
// when deflateSupported == false.
//
BOOST_THROW_EXCEPTION(std::invalid_argument{
"deflateSupported == false"});
}
}
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
void void
stream<NextLayer, deflateSupported>:: stream<NextLayer, deflateSupported>::
@ -134,45 +95,7 @@ open(role_type role)
wr_cont_ = false; wr_cont_ = false;
wr_buf_size_ = 0; wr_buf_size_ = 0;
open_pmd(is_deflate_supported{}); this->open_pmd(role_);
}
template<class NextLayer, bool deflateSupported>
inline
void
stream<NextLayer, deflateSupported>::
open_pmd(std::true_type)
{
if(((role_ == role_type::client &&
this->pmd_opts_.client_enable) ||
(role_ == role_type::server &&
this->pmd_opts_.server_enable)) &&
this->pmd_config_.accept)
{
pmd_normalize(this->pmd_config_);
this->pmd_.reset(new typename
detail::stream_base<deflateSupported>::pmd_type);
if(role_ == role_type::client)
{
this->pmd_->zi.reset(
this->pmd_config_.server_max_window_bits);
this->pmd_->zo.reset(
this->pmd_opts_.compLevel,
this->pmd_config_.client_max_window_bits,
this->pmd_opts_.memLevel,
zlib::Strategy::normal);
}
else
{
this->pmd_->zi.reset(
this->pmd_config_.client_max_window_bits);
this->pmd_->zo.reset(
this->pmd_opts_.compLevel,
this->pmd_config_.server_max_window_bits,
this->pmd_opts_.memLevel,
zlib::Strategy::normal);
}
}
} }
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
@ -181,7 +104,7 @@ stream<NextLayer, deflateSupported>::
close() close()
{ {
wr_buf_.reset(); wr_buf_.reset();
close_pmd(is_deflate_supported{}); this->close_pmd();
} }
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
@ -211,13 +134,12 @@ template<class NextLayer, bool deflateSupported>
inline inline
void void
stream<NextLayer, deflateSupported>:: stream<NextLayer, deflateSupported>::
begin_msg(std::true_type) begin_msg()
{ {
wr_frag_ = wr_frag_opt_; wr_frag_ = wr_frag_opt_;
wr_compress_ = static_cast<bool>(this->pmd_);
// Maintain the write buffer // Maintain the write buffer
if( wr_compress_ || if( this->pmd_enabled() ||
role_ == role_type::client) role_ == role_type::client)
{ {
if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_) if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
@ -234,98 +156,6 @@ begin_msg(std::true_type)
} }
} }
// Called before each write frame
template<class NextLayer, bool deflateSupported>
inline
void
stream<NextLayer, deflateSupported>::
begin_msg(std::false_type)
{
wr_frag_ = wr_frag_opt_;
// Maintain the write buffer
if(role_ == role_type::client)
{
if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
{
wr_buf_size_ = wr_buf_opt_;
wr_buf_ = boost::make_unique_noinit<
std::uint8_t[]>(wr_buf_size_);
}
}
else
{
wr_buf_size_ = wr_buf_opt_;
wr_buf_.reset();
}
}
template<class NextLayer, bool deflateSupported>
std::size_t
stream<NextLayer, deflateSupported>::
read_size_hint(
std::size_t initial_size,
std::true_type) const
{
using beast::detail::clamp;
std::size_t result;
BOOST_ASSERT(initial_size > 0);
if(! this->pmd_ || (! rd_done_ && ! this->pmd_->rd_set))
{
// current message is uncompressed
if(rd_done_)
{
// first message frame
result = initial_size;
goto done;
}
else if(rd_fh_.fin)
{
// last message frame
BOOST_ASSERT(rd_remain_ > 0);
result = clamp(rd_remain_);
goto done;
}
}
result = (std::max)(
initial_size, clamp(rd_remain_));
done:
BOOST_ASSERT(result != 0);
return result;
}
template<class NextLayer, bool deflateSupported>
std::size_t
stream<NextLayer, deflateSupported>::
read_size_hint(
std::size_t initial_size,
std::false_type) const
{
using beast::detail::clamp;
std::size_t result;
BOOST_ASSERT(initial_size > 0);
// compression is not supported
if(rd_done_)
{
// first message frame
result = initial_size;
}
else if(rd_fh_.fin)
{
// last message frame
BOOST_ASSERT(rd_remain_ > 0);
result = clamp(rd_remain_);
}
else
{
result = (std::max)(
initial_size, clamp(rd_remain_));
}
BOOST_ASSERT(result != 0);
return result;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Attempt to read a complete frame header. // Attempt to read a complete frame header.
@ -644,7 +474,7 @@ build_request(detail::sec_ws_key_type& key,
detail::make_sec_ws_key(key); detail::make_sec_ws_key(key);
req.set(http::field::sec_websocket_key, key); req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_version, "13"); req.set(http::field::sec_websocket_version, "13");
build_request_pmd(req, is_deflate_supported{}); this->build_request_pmd(req);
decorator(req); decorator(req);
if(! req.count(http::field::user_agent)) if(! req.count(http::field::user_agent))
req.set(http::field::user_agent, req.set(http::field::user_agent,
@ -652,28 +482,6 @@ build_request(detail::sec_ws_key_type& key,
return req; return req;
} }
template<class NextLayer, bool deflateSupported>
inline
void
stream<NextLayer, deflateSupported>::
build_request_pmd(request_type& req, std::true_type)
{
if(this->pmd_opts_.client_enable)
{
detail::pmd_offer config;
config.accept = true;
config.server_max_window_bits =
this->pmd_opts_.server_max_window_bits;
config.client_max_window_bits =
this->pmd_opts_.client_max_window_bits;
config.server_no_context_takeover =
this->pmd_opts_.server_no_context_takeover;
config.client_no_context_takeover =
this->pmd_opts_.client_no_context_takeover;
detail::pmd_write(req, config);
}
}
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator, class Decorator> template<class Body, class Allocator, class Decorator>
response_type response_type
@ -764,29 +572,12 @@ build_response(
detail::make_sec_ws_accept(acc, key); detail::make_sec_ws_accept(acc, key);
res.set(http::field::sec_websocket_accept, acc); res.set(http::field::sec_websocket_accept, acc);
} }
build_response_pmd(res, req, is_deflate_supported{}); this->build_response_pmd(res, req);
decorate(res); decorate(res);
result = {}; result = {};
return res; return res;
} }
template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator>
inline
void
stream<NextLayer, deflateSupported>::
build_response_pmd(
response_type& res,
http::request<Body,
http::basic_fields<Allocator>> const& req,
std::true_type)
{
detail::pmd_offer offer;
detail::pmd_offer unused;
pmd_read(offer, req);
pmd_negotiate(res, unused, offer, this->pmd_opts_);
}
// Called when the WebSocket Upgrade response is received // Called when the WebSocket Upgrade response is received
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
void void
@ -830,25 +621,10 @@ on_response(
} }
ec.assign(0, ec.category()); ec.assign(0, ec.category());
on_response_pmd(res, is_deflate_supported{}); this->on_response_pmd(res);
open(role_type::client); open(role_type::client);
} }
template<class NextLayer, bool deflateSupported>
inline
void
stream<NextLayer, deflateSupported>::
on_response_pmd(
response_type const& res,
std::true_type)
{
detail::pmd_offer offer;
pmd_read(offer, res);
// VFALCO see if offer satisfies pmd_config_,
// return an error if not.
this->pmd_config_ = offer; // overwrite for now
}
// _Fail the WebSocket Connection_ // _Fail the WebSocket Connection_
template<class NextLayer, bool deflateSupported> template<class NextLayer, bool deflateSupported>
void void

View File

@ -26,9 +26,6 @@
#include <boost/beast/core/static_buffer.hpp> #include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/type_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/http/empty_body.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/detail/type_traits.hpp> #include <boost/beast/http/detail/type_traits.hpp>
#include <boost/asio/async_result.hpp> #include <boost/asio/async_result.hpp>
#include <boost/asio/error.hpp> #include <boost/asio/error.hpp>
@ -76,7 +73,7 @@ class frame_test;
The @ref stream class template provides asynchronous and blocking The @ref stream class template provides asynchronous and blocking
message-oriented functionality necessary for clients and servers message-oriented functionality necessary for clients and servers
to utilize the WebSocket protocol. to utilize the WebSocket protocol.
For asynchronous operations, the application must ensure For asynchronous operations, the application must ensure
that they are are all performed within the same implicit that they are are all performed within the same implicit
or explicit strand. or explicit strand.
@ -136,7 +133,7 @@ class stream
friend class read2_test; friend class read2_test;
friend class stream_test; friend class stream_test;
friend class write_test; friend class write_test;
/* The read buffer has to be at least as large /* The read buffer has to be at least as large
as the largest possible control frame including as the largest possible control frame including
the frame header. the frame header.
@ -276,7 +273,7 @@ public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** Get the executor associated with the object. /** Get the executor associated with the object.
This function may be used to obtain the executor object that the This function may be used to obtain the executor object that the
stream uses to dispatch handlers for asynchronous operations. stream uses to dispatch handlers for asynchronous operations.
@ -425,8 +422,8 @@ public:
read_size_hint( read_size_hint(
std::size_t initial_size = +tcp_frame_size) const std::size_t initial_size = +tcp_frame_size) const
{ {
return read_size_hint(initial_size, return this->read_size_hint_pmd(
is_deflate_supported{}); initial_size, rd_done_, rd_remain_, rd_fh_);
} }
/** Returns a suggested maximum buffer size for the next call to read. /** Returns a suggested maximum buffer size for the next call to read.
@ -466,14 +463,14 @@ public:
void void
set_option(permessage_deflate const& o) set_option(permessage_deflate const& o)
{ {
set_option(o, is_deflate_supported{}); this->set_option_pmd(o);
} }
/// Get the permessage-deflate extension options /// Get the permessage-deflate extension options
void void
get_option(permessage_deflate& o) get_option(permessage_deflate& o)
{ {
get_option(o, is_deflate_supported{}); this->get_option_pmd(o);
} }
/** Set the automatic fragmentation option. /** Set the automatic fragmentation option.
@ -3374,65 +3371,13 @@ private:
static void default_decorate_req(request_type&) {} static void default_decorate_req(request_type&) {}
static void default_decorate_res(response_type&) {} static void default_decorate_res(response_type&) {}
void
set_option(permessage_deflate const& o, std::true_type);
void
set_option(permessage_deflate const&, std::false_type);
void
get_option(permessage_deflate& o, std::true_type)
{
o = this->pmd_opts_;
}
void
get_option(permessage_deflate& o, std::false_type)
{
o = {};
o.client_enable = false;
o.server_enable = false;
}
void open(role_type role); void open(role_type role);
void open_pmd(std::true_type);
void open_pmd(std::false_type)
{
}
void close(); void close();
void close_pmd(std::true_type)
{
this->pmd_.reset();
}
void close_pmd(std::false_type)
{
}
void reset(); void reset();
void begin_msg() void begin_msg();
{
begin_msg(is_deflate_supported{});
}
void begin_msg(std::true_type);
void begin_msg(std::false_type);
std::size_t
read_size_hint(
std::size_t initial_size,
std::true_type) const;
std::size_t
read_size_hint(
std::size_t initial_size,
std::false_type) const;
bool bool
check_open(error_code& ec) check_open(error_code& ec)
@ -3485,14 +3430,6 @@ private:
string_view target, string_view target,
Decorator const& decorator); Decorator const& decorator);
void
build_request_pmd(request_type& req, std::true_type);
void
build_request_pmd(request_type&, std::false_type)
{
}
template< template<
class Body, class Allocator, class Decorator> class Body, class Allocator, class Decorator>
response_type response_type
@ -3502,63 +3439,16 @@ private:
Decorator const& decorator, Decorator const& decorator,
error_code& ec); error_code& ec);
template<class Body, class Allocator>
void
build_response_pmd(
response_type& res,
http::request<Body,
http::basic_fields<Allocator>> const& req,
std::true_type);
template<class Body, class Allocator>
void
build_response_pmd(
response_type&,
http::request<Body,
http::basic_fields<Allocator>> const&,
std::false_type)
{
}
void void
on_response( on_response(
response_type const& res, response_type const& res,
detail::sec_ws_key_type const& key, detail::sec_ws_key_type const& key,
error_code& ec); error_code& ec);
void
on_response_pmd(
response_type const& res,
std::true_type);
void
on_response_pmd(
response_type const&,
std::false_type)
{
}
// //
// accept / handshake // accept / handshake
// //
template<class Allocator>
void
do_pmd_config(
http::basic_fields<Allocator> const& h,
std::true_type)
{
pmd_read(this->pmd_config_, h);
}
template<class Allocator>
void
do_pmd_config(
http::basic_fields<Allocator> const&,
std::false_type)
{
}
template<class Decorator> template<class Decorator>
void void
do_accept( do_accept(

View File

@ -29,6 +29,7 @@ add_executable (tests-beast-websocket
rfc6455.cpp rfc6455.cpp
role.cpp role.cpp
stream.cpp stream.cpp
stream_explicit.cpp
stream_fwd.cpp stream_fwd.cpp
teardown.cpp teardown.cpp
utf8_checker.cpp utf8_checker.cpp

View File

@ -20,6 +20,7 @@ local SOURCES =
rfc6455.cpp rfc6455.cpp
role.cpp role.cpp
stream.cpp stream.cpp
stream_explicit.cpp
stream_fwd.cpp stream_fwd.cpp
teardown.cpp teardown.cpp
utf8_checker.cpp utf8_checker.cpp

View File

@ -0,0 +1,15 @@
//
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
// Test that header file is self-contained.
#include <boost/beast/websocket/stream.hpp>
#include <boost/asio/ip/tcp.hpp>
template class boost::beast::websocket::stream<boost::asio::ip::tcp::socket, false>;
template class boost::beast::websocket::stream<boost::asio::ip::tcp::socket, true>;