auto_fragment is a member of stream (API Change):

fix #374, fix #446

* auto_fragment option struct is removed

Actions Required:

* Change call sites which use auto_fragment with set_option
  to call stream::auto_fragment instead.
This commit is contained in:
Vinnie Falco
2017-06-08 17:36:31 -07:00
parent 669b1feae1
commit f22895224b
9 changed files with 99 additions and 230 deletions

View File

@ -1,3 +1,16 @@
Version 52:
API Changes:
* auto_fragment is a member of stream
Actions Required:
* Change call sites which use auto_fragment with set_option
to call stream::auto_fragment instead.
--------------------------------------------------------------------------------
Version 51 Version 51
* Fix operator<< for header * Fix operator<< for header

View File

@ -123,7 +123,6 @@
</simplelist> </simplelist>
<bridgehead renderas="sect3">Options</bridgehead> <bridgehead renderas="sect3">Options</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
<member><link linkend="beast.ref.websocket__message_type">message_type</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> <member><link linkend="beast.ref.websocket__permessage_deflate">permessage_deflate</link></member>
<member><link linkend="beast.ref.websocket__ping_callback">ping_callback</link></member> <member><link linkend="beast.ref.websocket__ping_callback">ping_callback</link></member>

View File

@ -20,8 +20,6 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <type_traits> #include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <utility> #include <utility>
namespace websocket { namespace websocket {
@ -37,81 +35,6 @@ public:
using endpoint_type = boost::asio::ip::tcp::endpoint; using endpoint_type = boost::asio::ip::tcp::endpoint;
private: private:
/** A container of type-erased option setters.
*/
template<class NextLayer>
class options_set
{
// workaround for std::function bug in msvc
struct callable
{
virtual ~callable() = default;
virtual void operator()(
beast::websocket::stream<NextLayer>&) = 0;
};
template<class T>
class callable_impl : public callable
{
T t_;
public:
template<class U>
callable_impl(U&& u)
: t_(std::forward<U>(u))
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws)
{
t_(ws);
}
};
template<class Opt>
class lambda
{
Opt opt_;
public:
lambda(lambda&&) = default;
lambda(lambda const&) = default;
lambda(Opt const& opt)
: opt_(opt)
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws) const
{
ws.set_option(opt_);
}
};
std::unordered_map<std::type_index,
std::unique_ptr<callable>> list_;
public:
template<class Opt>
void
set_option(Opt const& opt)
{
std::unique_ptr<callable> p;
p.reset(new callable_impl<lambda<Opt>>{opt});
list_[std::type_index{
typeid(Opt)}] = std::move(p);
}
void
set_options(beast::websocket::stream<NextLayer>& ws)
{
for(auto const& op : list_)
(*op.second)(ws);
}
};
std::ostream* log_; std::ostream* log_;
boost::asio::io_service ios_; boost::asio::io_service ios_;
socket_type sock_; socket_type sock_;
@ -119,7 +42,7 @@ private:
boost::asio::ip::tcp::acceptor acceptor_; boost::asio::ip::tcp::acceptor acceptor_;
std::vector<std::thread> thread_; std::vector<std::thread> thread_;
boost::optional<boost::asio::io_service::work> work_; boost::optional<boost::asio::io_service::work> work_;
options_set<socket_type> opts_; std::function<void(beast::websocket::stream<socket_type>&)> mod_;
public: public:
async_echo_server(async_echo_server const&) = delete; async_echo_server(async_echo_server const&) = delete;
@ -150,9 +73,12 @@ public:
~async_echo_server() ~async_echo_server()
{ {
work_ = boost::none; work_ = boost::none;
error_code ec;
ios_.dispatch( ios_.dispatch(
[&]{ acceptor_.close(ec); }); [&]
{
error_code ec;
acceptor_.close(ec);
});
for(auto& t : thread_) for(auto& t : thread_)
t.join(); t.join();
} }
@ -165,17 +91,16 @@ public:
return acceptor_.local_endpoint(); return acceptor_.local_endpoint();
} }
/** Set a websocket option. /** Set a handler called for new streams.
The option will be applied to all new connections. This function is called for each new stream.
It is used to set options for every connection.
@param opt The option to apply.
*/ */
template<class Opt> template<class F>
void void
set_option(Opt const& opt) on_new_stream(F const& f)
{ {
opts_.set_option(opt); mod_ = f;
} }
/** Open a listening port. /** Open a listening port.
@ -253,7 +178,7 @@ private:
std::forward<Args>(args)...)) std::forward<Args>(args)...))
{ {
auto& d = *d_; auto& d = *d_;
d.server.opts_.set_options(d.ws); d.server.mod_(d.ws);
run(); run();
} }

View File

@ -25,6 +25,29 @@ sig_wait()
ios.run(); ios.run();
} }
class set_stream_options
{
beast::websocket::permessage_deflate pmd_;
public:
set_stream_options(set_stream_options const&) = default;
set_stream_options(
beast::websocket::permessage_deflate const& pmd)
: pmd_(pmd)
{
}
template<class NextLayer>
void
operator()(beast::websocket::stream<NextLayer>& ws) const
{
ws.auto_fragment(false);
ws.set_option(pmd_);
ws.set_option(beast::websocket::read_message_max{64 * 1024 * 1024});
}
};
int main() int main()
{ {
using namespace beast::websocket; using namespace beast::websocket;
@ -39,16 +62,12 @@ int main()
pmd.compLevel = 3; pmd.compLevel = 3;
websocket::async_echo_server s1{&std::cout, 1}; websocket::async_echo_server s1{&std::cout, 1};
s1.set_option(read_message_max{64 * 1024 * 1024}); s1.on_new_stream(set_stream_options{pmd});
s1.set_option(auto_fragment{false});
s1.set_option(pmd);
s1.open(endpoint_type{ s1.open(endpoint_type{
address_type::from_string("127.0.0.1"), 6000 }, ec); address_type::from_string("127.0.0.1"), 6000 }, ec);
websocket::sync_echo_server s2{&std::cout}; websocket::sync_echo_server s2{&std::cout};
s2.set_option(read_message_max{64 * 1024 * 1024}); s2.on_new_stream(set_stream_options{pmd});
s2.set_option(auto_fragment{false});
s2.set_option(pmd);
s2.open(endpoint_type{ s2.open(endpoint_type{
address_type::from_string("127.0.0.1"), 6001 }, ec); address_type::from_string("127.0.0.1"), 6001 }, ec);

View File

@ -20,8 +20,6 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <type_traits> #include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <utility> #include <utility>
namespace websocket { namespace websocket {
@ -37,88 +35,13 @@ public:
using socket_type = boost::asio::ip::tcp::socket; using socket_type = boost::asio::ip::tcp::socket;
private: private:
/** A container of type-erased option setters.
*/
template<class NextLayer>
class options_set
{
// workaround for std::function bug in msvc
struct callable
{
virtual ~callable() = default;
virtual void operator()(
beast::websocket::stream<NextLayer>&) = 0;
};
template<class T>
class callable_impl : public callable
{
T t_;
public:
template<class U>
callable_impl(U&& u)
: t_(std::forward<U>(u))
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws)
{
t_(ws);
}
};
template<class Opt>
class lambda
{
Opt opt_;
public:
lambda(lambda&&) = default;
lambda(lambda const&) = default;
lambda(Opt const& opt)
: opt_(opt)
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws) const
{
ws.set_option(opt_);
}
};
std::unordered_map<std::type_index,
std::unique_ptr<callable>> list_;
public:
template<class Opt>
void
set_option(Opt const& opt)
{
std::unique_ptr<callable> p;
p.reset(new callable_impl<lambda<Opt>>{opt});
list_[std::type_index{
typeid(Opt)}] = std::move(p);
}
void
set_options(beast::websocket::stream<NextLayer>& ws)
{
for(auto const& op : list_)
(*op.second)(ws);
}
};
std::ostream* log_; std::ostream* log_;
boost::asio::io_service ios_; boost::asio::io_service ios_;
socket_type sock_; socket_type sock_;
endpoint_type ep_; endpoint_type ep_;
boost::asio::ip::tcp::acceptor acceptor_; boost::asio::ip::tcp::acceptor acceptor_;
std::thread thread_; std::thread thread_;
options_set<socket_type> opts_; std::function<void(beast::websocket::stream<socket_type>&)> mod_;
public: public:
/** Constructor. /** Constructor.
@ -154,17 +77,16 @@ public:
return acceptor_.local_endpoint(); return acceptor_.local_endpoint();
} }
/** Set a websocket option. /** Set a handler called for new streams.
The option will be applied to all new connections. This function is called for each new stream.
It is used to set options for every connection.
@param opt The option to apply.
*/ */
template<class Opt> template<class F>
void void
set_option(Opt const& opt) on_new_stream(F const& f)
{ {
opts_.set_option(opt); mod_ = f;
} }
/** Open a listening port. /** Open a listening port.
@ -269,7 +191,7 @@ private:
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
beast::websocket::stream< beast::websocket::stream<
socket_type> ws{std::move(sock)}; socket_type> ws{std::move(sock)};
opts_.set_options(ws); mod_(ws);
error_code ec; error_code ec;
ws.accept_ex( ws.accept_ex(
[](beast::websocket::response_type& res) [](beast::websocket::response_type& res)

View File

@ -22,43 +22,6 @@
namespace beast { namespace beast {
namespace websocket { namespace websocket {
/** Automatic fragmentation option.
Determines if outgoing message payloads are broken up into
multiple pieces.
When the automatic fragmentation size is turned on, outgoing
message payloads are broken up into multiple frames no larger
than the write buffer size.
The default setting is to fragment messages.
@note Objects of this type are used with
@ref beast::websocket::stream::set_option.
@par Example
Setting the automatic fragmentation option:
@code
...
websocket::stream<ip::tcp::socket> stream(ios);
stream.set_option(auto_fragment{true});
@endcode
*/
#if BEAST_DOXYGEN
using auto_fragment = implementation_defined;
#else
struct auto_fragment
{
bool value;
explicit
auto_fragment(bool v)
: value(v)
{
}
};
#endif
/** Message type option. /** Message type option.
This controls the opcode set for outgoing messages. Valid This controls the opcode set for outgoing messages. Valid

View File

@ -151,6 +151,41 @@ public:
*/ */
~stream() = default; ~stream() = default;
/** Set the automatic fragmentation option.
Determines if outgoing message payloads are broken up into
multiple pieces.
When the automatic fragmentation size is turned on, outgoing
message payloads are broken up into multiple frames no larger
than the write buffer size.
The default setting is to fragment messages.
@note Objects of this type are used with
@ref beast::websocket::stream::set_option.
@par Example
Setting the automatic fragmentation option:
@code
...
websocket::stream<ip::tcp::socket> stream{ios};
stream.auto_fragment(true);
@endcode
*/
void
auto_fragment(bool v)
{
wr_autofrag_ = v;
}
/// Returns `true` if the automatic fragmentation option is set.
bool
auto_fragment() const
{
return wr_autofrag_;
}
/** Set options on the stream. /** Set options on the stream.
The application must ensure that calls to set options The application must ensure that calls to set options
@ -173,13 +208,6 @@ public:
std::forward<An>(an)...); std::forward<An>(an)...);
} }
/// Set the automatic fragment size option
void
set_option(auto_fragment const& o)
{
wr_autofrag_ = o.value;
}
/// Set the outgoing message type /// Set the outgoing message type
void void
set_option(message_type const& o) set_option(message_type const& o)

View File

@ -205,7 +205,7 @@ boost::asio::ip::tcp::socket sock{ios};
//] //]
//[ws_snippet_19 //[ws_snippet_19
ws.set_option(auto_fragment{true}); ws.auto_fragment(true);
ws.set_option(write_buffer_size{16384}); ws.set_option(write_buffer_size{16384});
//] //]

View File

@ -553,7 +553,7 @@ public:
testOptions() testOptions()
{ {
stream<socket_type> ws(ios_); stream<socket_type> ws(ios_);
ws.set_option(auto_fragment{true}); ws.auto_fragment(true);
ws.set_option(write_buffer_size{2048}); ws.set_option(write_buffer_size{2048});
ws.set_option(message_type{opcode::text}); ws.set_option(message_type{opcode::text});
ws.set_option(read_buffer_size{8192}); ws.set_option(read_buffer_size{8192});
@ -1655,7 +1655,7 @@ public:
c.handshake(ws, "localhost", "/"); c.handshake(ws, "localhost", "/");
// send message // send message
ws.set_option(auto_fragment{false}); ws.auto_fragment(false);
ws.set_option(message_type(opcode::text)); ws.set_option(message_type(opcode::text));
c.write(ws, sbuf("Hello")); c.write(ws, sbuf("Hello"));
{ {
@ -1728,7 +1728,7 @@ public:
c.pong(ws, ""); c.pong(ws, "");
// send auto fragmented message // send auto fragmented message
ws.set_option(auto_fragment{true}); ws.auto_fragment(true);
ws.set_option(write_buffer_size{8}); ws.set_option(write_buffer_size{8});
c.write(ws, sbuf("Now is the time for all good men")); c.write(ws, sbuf("Now is the time for all good men"));
{ {
@ -1738,7 +1738,7 @@ public:
c.read(ws, op, b); c.read(ws, op, b);
BEAST_EXPECT(to_string(b.data()) == "Now is the time for all good men"); BEAST_EXPECT(to_string(b.data()) == "Now is the time for all good men");
} }
ws.set_option(auto_fragment{false}); ws.auto_fragment(false);
ws.set_option(write_buffer_size{4096}); ws.set_option(write_buffer_size{4096});
// send message with write buffer limit // send message with write buffer limit