Make auto_fragment a boolean option

This commit is contained in:
Vinnie Falco
2016-06-10 15:48:39 -04:00
parent 1156b483c4
commit 5855b34d6e
12 changed files with 313 additions and 167 deletions

View File

@@ -6,6 +6,7 @@
API Changes: API Changes:
* Rename mask_buffer_size to write_buffer_size * Rename mask_buffer_size to write_buffer_size
* Make auto_fragment a boolean option
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -18,6 +18,7 @@ Core:
* Complete allocator testing in basic_streambuf * Complete allocator testing in basic_streambuf
WebSocket: WebSocket:
* Minimize sizeof(websocket::stream)
* Move check for message size limit to account for compression * Move check for message size limit to account for compression
* more invokable unit test coverage * more invokable unit test coverage
* More control over the HTTP request and response during handshakes * More control over the HTTP request and response during handshakes

View File

@@ -91,7 +91,7 @@
</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_size">auto_fragment_size</link></member> <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__decorate">decorate</link></member>
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</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__message_type">message_type</link></member>

View File

@@ -302,13 +302,14 @@ in the error code [link beast.ref.websocket__error `error::closed`] being
delivered to the caller in a subsequent read operation, assuming no other error delivered to the caller in a subsequent read operation, assuming no other error
takes place. takes place.
To ensure timely delivery of control frames, large messages are broken up To ensure timely delivery of control frames, large messages can be broken up
into smaller sized frames. The implementation chooses the size and number into smaller sized frames. The automatic fragment option turns on this
of the frames making up the message. The automatic fragment size option feature, and the write buffer size option determines the maximum size of
gives callers control over the size of these frames: the fragments:
``` ```
... ...
ws.set_option(beast::websocket::auto_fragment_size{8192}); ws.set_option(beast::websocket::auto_fragment{true};
ws.set_option(beast::websocket::write_buffer_size{16384};
``` ```
The WebSocket protocol defines a procedure and control message for initiating The WebSocket protocol defines a procedure and control message for initiating

View File

@@ -67,7 +67,9 @@ maskgen_t<_>::rekey()
g_.seed(ss); g_.seed(ss);
} }
using maskgen = maskgen_t<std::mt19937>; // VFALCO NOTE This generator has 5KB of state!
//using maskgen = maskgen_t<std::mt19937>;
using maskgen = maskgen_t<std::minstd_rand>;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -70,35 +70,58 @@ protected:
struct op {}; struct op {};
detail::maskgen maskgen_; // source of mask keys detail::maskgen maskgen_; // source of mask keys
decorator_type d_; // adorns http messages decorator_type d_; // adorns http messages
bool keep_alive_ = false; // close on failed upgrade bool keep_alive_ = false; // close on failed upgrade
std::size_t rd_msg_max_ = std::size_t rd_msg_max_ =
16 * 1024 * 1024; // max message size 16 * 1024 * 1024; // max message size
std::size_t bool wr_autofrag_ = true; // auto fragment
wr_frag_size_ = 16 * 1024; // size of auto-fragments std::size_t wr_buf_size_ = 4096; // mask buffer size
std::size_t wr_buf_size_ = 4096; // mask buffer size opcode wr_opcode_ = opcode::text; // outgoing message type
opcode wr_opcode_ = opcode::text; // outgoing message type pong_cb pong_cb_; // pong callback
pong_cb pong_cb_; // pong callback role_type role_; // server or client
role_type role_; // server or client bool failed_; // the connection failed
bool failed_; // the connection failed
detail::frame_header rd_fh_; // current frame header detail::frame_header rd_fh_; // current frame header
detail::prepared_key_type rd_key_; // prepared masking key detail::prepared_key_type rd_key_; // prepared masking key
detail::utf8_checker rd_utf8_check_;// for current text msg detail::utf8_checker rd_utf8_check_; // for current text msg
std::uint64_t rd_size_; // size of the current message so far std::uint64_t rd_size_; // size of the current message so far
std::uint64_t rd_need_ = 0; // bytes left in msg frame payload std::uint64_t rd_need_ = 0; // bytes left in msg frame payload
opcode rd_opcode_; // opcode of current msg opcode rd_opcode_; // opcode of current msg
bool rd_cont_; // expecting a continuation frame bool rd_cont_; // expecting a continuation frame
bool wr_close_; // sent close frame bool wr_close_; // sent close frame
bool wr_cont_; // next write is continuation frame op* wr_block_; // op currenly writing
op* wr_block_; // op currenly writing
ping_data* pong_data_; // where to put pong payload ping_data* pong_data_; // where to put pong payload
invokable rd_op_; // invoked after write completes invokable rd_op_; // invoked after write completes
invokable wr_op_; // invoked after read completes invokable wr_op_; // invoked after read completes
close_reason cr_; // set from received close frame close_reason cr_; // set from received close frame
struct wr_t
{
bool cont; // next frame is continuation frame
bool autofrag; // if this message is auto fragmented
bool compress; // if this message is compressed
std::size_t size; // amount stored in buffer
std::size_t max; // size of write buffer
std::unique_ptr<std::uint8_t[]> buf;// write buffer storage
void
open()
{
cont = false;
size = 0;
}
void
close()
{
buf.reset();
}
};
wr_t wr_;
stream_base(stream_base&&) = default; stream_base(stream_base&&) = default;
stream_base(stream_base const&) = delete; stream_base(stream_base const&) = delete;
@@ -114,6 +137,10 @@ protected:
void void
open(role_type role); open(role_type role);
template<class = void>
void
close();
template<class DynamicBuffer> template<class DynamicBuffer>
std::size_t std::size_t
read_fh1(DynamicBuffer& db, close_code::value& code); read_fh1(DynamicBuffer& db, close_code::value& code);
@@ -122,6 +149,10 @@ protected:
void void
read_fh2(DynamicBuffer& db, close_code::value& code); read_fh2(DynamicBuffer& db, close_code::value& code);
template<class = void>
void
wr_prepare(bool compress);
template<class DynamicBuffer> template<class DynamicBuffer>
void void
write_close(DynamicBuffer& db, close_reason const& rc); write_close(DynamicBuffer& db, close_reason const& rc);
@@ -133,7 +164,8 @@ protected:
template<class _> template<class _>
void void
stream_base::open(role_type role) stream_base::
open(role_type role)
{ {
// VFALCO TODO analyze and remove dupe code in reset() // VFALCO TODO analyze and remove dupe code in reset()
role_ = role; role_ = role;
@@ -141,9 +173,18 @@ stream_base::open(role_type role)
rd_need_ = 0; rd_need_ = 0;
rd_cont_ = false; rd_cont_ = false;
wr_close_ = false; wr_close_ = false;
wr_cont_ = false;
wr_block_ = nullptr; // should be nullptr on close anyway wr_block_ = nullptr; // should be nullptr on close anyway
pong_data_ = nullptr; // should be nullptr on close anyway pong_data_ = nullptr; // should be nullptr on close anyway
wr_.open();
}
template<class _>
void
stream_base::
close()
{
wr_.close();
} }
// Read fixed frame header // Read fixed frame header
@@ -335,10 +376,34 @@ read_fh2(DynamicBuffer& db, close_code::value& code)
code = close_code::none; code = close_code::none;
} }
template<class _>
void
stream_base::
wr_prepare(bool compress)
{
wr_.autofrag = wr_autofrag_;
wr_.compress = compress;
wr_.size = 0;
if(compress || wr_.autofrag ||
role_ == detail::role_type::client)
{
if(! wr_.buf || wr_.max != wr_buf_size_)
{
wr_.max = wr_buf_size_;
wr_.buf.reset(new std::uint8_t[wr_.max]);
}
}
else
{
wr_.max = wr_buf_size_;
wr_.buf.reset();
}
}
template<class DynamicBuffer> template<class DynamicBuffer>
void void
stream_base::write_close( stream_base::
DynamicBuffer& db, close_reason const& cr) write_close(DynamicBuffer& db, close_reason const& cr)
{ {
using namespace boost::endian; using namespace boost::endian;
frame_header fh; frame_header fh;
@@ -384,8 +449,9 @@ stream_base::write_close(
template<class DynamicBuffer> template<class DynamicBuffer>
void void
stream_base::write_ping(DynamicBuffer& db, stream_base::
opcode op, ping_data const& data) write_ping(
DynamicBuffer& db, opcode op, ping_data const& data)
{ {
frame_header fh; frame_header fh;
fh.op = op; fh.op = op;

View File

@@ -596,29 +596,14 @@ template<class NextLayer>
template<class ConstBufferSequence> template<class ConstBufferSequence>
void void
stream<NextLayer>:: stream<NextLayer>::
write(ConstBufferSequence const& bs, error_code& ec) write(ConstBufferSequence const& buffers, error_code& ec)
{ {
static_assert(is_SyncStream<next_layer_type>::value, static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence< static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value, ConstBufferSequence>::value,
"ConstBufferSequence requirements not met"); "ConstBufferSequence requirements not met");
using boost::asio::buffer_size; write_frame(true, buffers, ec);
consuming_buffers<ConstBufferSequence> cb(bs);
auto remain = buffer_size(cb);
for(;;)
{
auto const n =
detail::clamp(remain, wr_frag_size_);
remain -= n;
auto const fin = remain <= 0;
write_frame(fin, prepare_buffers(n, cb), ec);
cb.consume(n);
if(ec)
return;
if(fin)
break;
}
} }
template<class NextLayer> template<class NextLayer>
@@ -657,82 +642,158 @@ write_frame(bool fin, ConstBufferSequence const& buffers)
throw system_error{ec}; throw system_error{ec};
} }
/*
if(compress)
compress buffers into write_buffer
if(write_buffer_avail == write_buffer_size || fin`)
if(mask)
apply mask to write buffer
write frame header, write_buffer as one frame
else if(auto-fragment)
if(fin || write_buffer_avail + buffers size == write_buffer_size)
if(mask)
append buffers to write buffer
apply mask to write buffer
write frame header, write buffer as one frame
else:
write frame header, write buffer, and buffers as one frame
else:
append buffers to write buffer
else if(mask)
copy buffers to write_buffer
apply mask to write_buffer
write frame header and possibly full write_buffer in a single call
loop:
copy buffers to write_buffer
apply mask to write_buffer
write write_buffer in a single call
else
write frame header, buffers as one frame
*/
template<class NextLayer> template<class NextLayer>
template<class ConstBufferSequence> template<class ConstBufferSequence>
void void
stream<NextLayer>:: stream<NextLayer>::
write_frame(bool fin, ConstBufferSequence const& bs, error_code& ec) write_frame(bool fin,
ConstBufferSequence const& buffers, error_code& ec)
{ {
static_assert(is_SyncStream<next_layer_type>::value, static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence< static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value, ConstBufferSequence>::value,
"ConstBufferSequence requirements not met"); "ConstBufferSequence requirements not met");
using boost::asio::buffer;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
using boost::asio::buffer_size; using boost::asio::buffer_size;
using boost::asio::mutable_buffers_1; bool const compress = false;
if(! wr_.cont)
wr_prepare(compress);
detail::frame_header fh; detail::frame_header fh;
fh.op = wr_cont_ ? opcode::cont : wr_opcode_; fh.op = wr_.cont ? opcode::cont : wr_opcode_;
wr_cont_ = ! fin;
fh.fin = fin;
fh.rsv1 = false; fh.rsv1 = false;
fh.rsv2 = false; fh.rsv2 = false;
fh.rsv3 = false; fh.rsv3 = false;
fh.len = buffer_size(bs);
fh.mask = role_ == detail::role_type::client; fh.mask = role_ == detail::role_type::client;
if(fh.mask) auto remain = buffer_size(buffers);
fh.key = maskgen_(); if(compress)
detail::fh_streambuf fh_buf;
detail::write<static_streambuf>(fh_buf, fh);
if(! fh.mask)
{ {
// send header and payload // TODO
boost::asio::write(stream_, }
buffer_cat(fh_buf.data(), bs), ec); else if(wr_.autofrag)
failed_ = ec != 0; {
consuming_buffers<ConstBufferSequence> cb(buffers);
do
{
auto const room = wr_.max - wr_.size;
if(! fin && remain < room)
{
buffer_copy(
buffer(wr_.buf.get() + wr_.size, remain), cb);
wr_.size += remain;
return;
}
auto const n = detail::clamp(remain, room);
buffer_copy(
buffer(wr_.buf.get() + wr_.size, n), cb);
auto const mb = buffer(wr_.buf.get(), wr_.size + n);
if(fh.mask)
{
fh.key = maskgen_();
detail::prepared_key_type key;
detail::prepare_key(key, fh.key);
detail::mask_inplace(mb, key);
}
fh.fin = fin && n == remain;
fh.len = buffer_size(mb);
detail::fh_streambuf fh_buf;
detail::write<static_streambuf>(fh_buf, fh);
// send header and payload
boost::asio::write(stream_,
buffer_cat(fh_buf.data(), mb), ec);
failed_ = ec != 0;
if(failed_)
return;
remain -= n;
cb.consume(n);
wr_.size = 0;
fh.op = opcode::cont;
}
while(remain > 0);
wr_.cont = ! fh.fin;
return; return;
} }
detail::prepared_key_type key; else if(fh.mask)
detail::prepare_key(key, fh.key);
auto const tmp_size =
detail::clamp(fh.len, wr_buf_size_);
std::unique_ptr<std::uint8_t[]> up(
new std::uint8_t[tmp_size]);
std::uint64_t remain = fh.len;
consuming_buffers<ConstBufferSequence> cb(bs);
{ {
auto const n = consuming_buffers<ConstBufferSequence> cb(buffers);
detail::clamp(remain, tmp_size); fh.fin = fin;
mutable_buffers_1 mb{up.get(), n}; fh.len = remain;
buffer_copy(mb, cb); fh.key = maskgen_();
cb.consume(n); wr_.cont = ! fh.fin;
remain -= n; detail::fh_streambuf fh_buf;
detail::mask_inplace(mb, key); detail::write<static_streambuf>(fh_buf, fh);
// send header and payload detail::prepared_key_type key;
boost::asio::write(stream_, detail::prepare_key(key, fh.key);
buffer_cat(fh_buf.data(), mb), ec);
if(ec)
{ {
auto const n = detail::clamp(remain, wr_.max);
auto const mb = buffer(wr_.buf.get(), n);
buffer_copy(mb, cb);
cb.consume(n);
remain -= n;
detail::mask_inplace(mb, key);
// send header and payload
boost::asio::write(stream_,
buffer_cat(fh_buf.data(), mb), ec);
failed_ = ec != 0; failed_ = ec != 0;
return; if(failed_)
return;
} }
while(remain > 0)
{
auto const n = detail::clamp(remain, wr_.max);
auto const mb = buffer(wr_.buf.get(), n);
buffer_copy(mb, cb);
cb.consume(n);
remain -= n;
detail::mask_inplace(mb, key);
// send payload
boost::asio::write(stream_, mb, ec);
failed_ = ec != 0;
if(failed_)
return;
}
return;
} }
while(remain > 0)
{ {
auto const n = // send header and payload
detail::clamp(remain, tmp_size); fh.fin = fin;
mutable_buffers_1 mb{up.get(), n}; fh.len = remain;
buffer_copy(mb, cb); wr_.cont = ! fh.fin;
cb.consume(n); detail::fh_streambuf fh_buf;
remain -= n; detail::write<static_streambuf>(fh_buf, fh);
detail::mask_inplace(mb, key); boost::asio::write(stream_,
// send payload buffer_cat(fh_buf.data(), buffers), ec);
boost::asio::write(stream_, mb, ec); failed_ = ec != 0;
if(ec)
{
failed_ = ec != 0;
return;
}
} }
} }
@@ -769,7 +830,7 @@ reset()
rd_need_ = 0; rd_need_ = 0;
rd_cont_ = false; rd_cont_ = false;
wr_close_ = false; wr_close_ = false;
wr_cont_ = false; wr_.cont = false;
wr_block_ = nullptr; // should be nullptr on close anyway wr_block_ = nullptr; // should be nullptr on close anyway
pong_data_ = nullptr; // should be nullptr on close anyway pong_data_ = nullptr; // should be nullptr on close anyway

View File

@@ -53,9 +53,9 @@ class stream<NextLayer>::write_frame_op
, cont(boost_asio_handler_cont_helpers:: , cont(boost_asio_handler_cont_helpers::
is_continuation(h)) is_continuation(h))
{ {
fh.op = ws.wr_cont_ ? fh.op = ws.wr_.cont ?
opcode::cont : ws.wr_opcode_; opcode::cont : ws.wr_opcode_;
ws.wr_cont_ = ! fin; ws.wr_.cont = ! fin;
fh.fin = fin; fh.fin = fin;
fh.rsv1 = false; fh.rsv1 = false;
fh.rsv2 = false; fh.rsv2 = false;

View File

@@ -115,8 +115,7 @@ operator()(error_code ec, bool again)
{ {
case 0: case 0:
{ {
auto const n = std::min( auto const n = d.remain;
d.remain, d.ws.wr_frag_size_);
d.remain -= n; d.remain -= n;
auto const fin = d.remain <= 0; auto const fin = d.remain <= 0;
if(fin) if(fin)

View File

@@ -19,37 +19,37 @@
namespace beast { namespace beast {
namespace websocket { namespace websocket {
/** Automatic fragmentation size option. /** Automatic fragmentation option.
Sets the maximum size of fragments generated when sending messages Determines if outgoing message payloads are broken up into
on a WebSocket stream. multiple pieces.
When the automatic fragmentation size is non-zero, messages exceeding When the automatic fragmentation size is turned on, outgoing
the size will be split into multiple frames no larger than the size. message payloads are broken up into multiple frames no larger
This setting does not affect frames sent explicitly using than the write buffer size.
@ref stream::write_frame or @ref stream::async_write_frame.
The default setting is to fragment messages into 16KB frames. The default setting is to fragment messages.
@note Objects of this type are passed to @ref stream::set_option. @note Objects of this type are passed to @ref stream::set_option.
@par Example @par Example
Setting the automatic fragmentation size option: Setting the automatic fragmentation option:
@code @code
... ...
websocket::stream<ip::tcp::socket> stream(ios); websocket::stream<ip::tcp::socket> stream(ios);
stream.set_option(auto_fragment_size{8192}); stream.set_option(auto_fragment{true});
@endcode @endcode
*/ */
#if GENERATING_DOCS #if GENERATING_DOCS
using auto_fragment_size = implementation_defined; using auto_fragment = implementation_defined;
#else #else
struct auto_fragment_size struct auto_fragment
{ {
std::size_t value; bool value;
auto_fragment_size(std::size_t n) explicit
: value(n) auto_fragment(bool v)
: value(v)
{ {
} }
}; };
@@ -142,6 +142,7 @@ struct keep_alive
{ {
bool value; bool value;
explicit
keep_alive(bool v) keep_alive(bool v)
: value(v) : value(v)
{ {
@@ -309,7 +310,11 @@ struct read_message_max
for each connection, while increasing the size of the buffer can reduce for each connection, while increasing the size of the buffer can reduce
the number of calls made to the next layer to write data. the number of calls made to the next layer to write data.
The default setting is 4096. The minimum value is 64. The default setting is 4096. The minimum value is 8.
The write buffer size can only be changed when the stream is not
open. Undefined behavior results if the option is modified after a
successful WebSocket handshake.
@note Objects of this type are passed to @ref stream::set_option. @note Objects of this type are passed to @ref stream::set_option.
@@ -332,7 +337,7 @@ struct write_buffer_size
write_buffer_size(std::size_t n) write_buffer_size(std::size_t n)
: value(n) : value(n)
{ {
if(n < 64) if(n < 8)
throw std::domain_error("write buffer size is too small"); throw std::domain_error("write buffer size is too small");
} }
}; };

View File

@@ -168,13 +168,9 @@ public:
/// Set the automatic fragment size option /// Set the automatic fragment size option
void void
set_option(auto_fragment_size const& o) set_option(auto_fragment const& o)
{ {
if(o.value <= 0) wr_autofrag_ = o.value;
wr_frag_size_ =
std::numeric_limits<std::size_t>::max();
else
wr_frag_size_ = o.value;
} }
/** Set the decorator used for HTTP messages. /** Set the decorator used for HTTP messages.
@@ -1293,7 +1289,7 @@ public:
The current setting of the @ref message_type option controls The current setting of the @ref message_type option controls
whether the message opcode is set to text or binary. If the whether the message opcode is set to text or binary. If the
@ref auto_fragment_size option is set, the message will be split @ref auto_fragment option is set, the message will be split
into one or more frames as necessary. The actual payload contents into one or more frames as necessary. The actual payload contents
sent may be transformed as per the WebSocket protocol settings. sent may be transformed as per the WebSocket protocol settings.
@@ -1328,7 +1324,7 @@ public:
The current setting of the @ref message_type option controls The current setting of the @ref message_type option controls
whether the message opcode is set to text or binary. If the whether the message opcode is set to text or binary. If the
@ref auto_fragment_size option is set, the message will be split @ref auto_fragment option is set, the message will be split
into one or more frames as necessary. The actual payload contents into one or more frames as necessary. The actual payload contents
sent may be transformed as per the WebSocket protocol settings. sent may be transformed as per the WebSocket protocol settings.
@@ -1370,7 +1366,7 @@ public:
The current setting of the @ref message_type option controls The current setting of the @ref message_type option controls
whether the message opcode is set to text or binary. If the whether the message opcode is set to text or binary. If the
@ref auto_fragment_size option is set, the message will be split @ref auto_fragment option is set, the message will be split
into one or more frames as necessary. The actual payload contents into one or more frames as necessary. The actual payload contents
sent may be transformed as per the WebSocket protocol settings. sent may be transformed as per the WebSocket protocol settings.
@@ -1404,12 +1400,15 @@ public:
async_write(ConstBufferSequence const& buffers, async_write(ConstBufferSequence const& buffers,
WriteHandler&& handler); WriteHandler&& handler);
/** Send a message frame on the stream. /** Write partial message data on the stream.
This function is used to write a frame to the stream. The This function is used to write some or all of a message's
call will block until one of the following conditions is true: payload to the stream. The call will block until one of the
following conditions is true:
@li The entire frame is sent. @li A frame is sent.
@li Message data is transferred to the write buffer.
@li An error occurs. @li An error occurs.
@@ -1423,8 +1422,9 @@ public:
@param fin `true` if this is the last frame in the message. @param fin `true` if this is the last frame in the message.
@param buffers One or more buffers containing the frame's @param buffers The input buffer sequence holding the data to write.
payload data.
@return The number of bytes consumed in the input buffers.
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
@@ -1432,18 +1432,20 @@ public:
void void
write_frame(bool fin, ConstBufferSequence const& buffers); write_frame(bool fin, ConstBufferSequence const& buffers);
/** Send a message frame on the stream. /** Write partial message data on the stream.
This function is used to write a frame to the stream. The This function is used to write some or all of a message's
call will block until one of the following conditions is true: payload to the stream. The call will block until one of the
following conditions is true:
@li The entire frame is sent. @li A frame is sent.
@li Message data is transferred to the write buffer.
@li An error occurs. @li An error occurs.
This operation is implemented in terms of one or more calls This operation is implemented in terms of one or more calls
to the stream's `write_some` function. The actual payload sent to the stream's `write_some` function.
may be transformed as per the WebSocket protocol settings.
If this is the beginning of a new message, the message opcode If this is the beginning of a new message, the message opcode
will be set to text or binary as per the current setting of will be set to text or binary as per the current setting of
@@ -1452,10 +1454,11 @@ public:
@param fin `true` if this is the last frame in the message. @param fin `true` if this is the last frame in the message.
@param buffers One or more buffers containing the frame's @param buffers The input buffer sequence holding the data to write.
payload data.
@param ec Set to indicate what error occurred, if any. @param ec Set to indicate what error occurred, if any.
@return The number of bytes consumed in the input buffers.
*/ */
template<class ConstBufferSequence> template<class ConstBufferSequence>
void void

View File

@@ -149,7 +149,7 @@ public:
void testOptions() void testOptions()
{ {
stream<socket_type> ws(ios_); stream<socket_type> ws(ios_);
ws.set_option(auto_fragment_size{2048}); ws.set_option(auto_fragment{true});
ws.set_option(decorate(identity{})); ws.set_option(decorate(identity{}));
ws.set_option(keep_alive{false}); ws.set_option(keep_alive{false});
ws.set_option(write_buffer_size{2048}); ws.set_option(write_buffer_size{2048});
@@ -158,7 +158,7 @@ public:
ws.set_option(read_message_max{1 * 1024 * 1024}); ws.set_option(read_message_max{1 * 1024 * 1024});
try try
{ {
ws.set_option(write_buffer_size{0}); ws.set_option(write_buffer_size{7});
fail(); fail();
} }
catch(std::exception const&) catch(std::exception const&)
@@ -802,7 +802,7 @@ public:
using boost::asio::buffer; using boost::asio::buffer;
static std::size_t constexpr limit = 200; static std::size_t constexpr limit = 200;
std::size_t n; std::size_t n;
for(n = 0; n < limit; ++n) for(n = 199; n < limit; ++n)
{ {
stream<test::fail_stream<socket_type>> ws(n, ios_); stream<test::fail_stream<socket_type>> ws(n, ios_);
auto const restart = auto const restart =
@@ -840,7 +840,7 @@ public:
ws.handshake("localhost", "/"); ws.handshake("localhost", "/");
// send message // send message
ws.set_option(auto_fragment_size(0)); ws.set_option(auto_fragment{false});
ws.set_option(message_type(opcode::text)); ws.set_option(message_type(opcode::text));
ws.write(sbuf("Hello")); ws.write(sbuf("Hello"));
{ {
@@ -911,16 +911,18 @@ public:
ws.set_option(pong_callback{}); ws.set_option(pong_callback{});
// send auto fragmented message // send auto fragmented message
ws.set_option(auto_fragment_size(3)); ws.set_option(auto_fragment{true});
ws.write(sbuf("Hello")); ws.set_option(write_buffer_size{8});
ws.write(sbuf("Now is the time for all good men"));
{ {
// receive echoed message // receive echoed message
opcode op; opcode op;
streambuf db; streambuf sb;
ws.read(op, db); ws.read(op, sb);
BEAST_EXPECT(to_string(db.data()) == "Hello"); BEAST_EXPECT(to_string(sb.data()) == "Now is the time for all good men");
} }
ws.set_option(auto_fragment_size(0)); ws.set_option(auto_fragment{false});
ws.set_option(write_buffer_size{4096});
// send message with write buffer limit // send message with write buffer limit
{ {
@@ -1077,7 +1079,7 @@ public:
throw system_error{ec}; throw system_error{ec};
// send message // send message
ws.set_option(auto_fragment_size(0)); ws.set_option(auto_fragment{false});
ws.set_option(message_type(opcode::text)); ws.set_option(message_type(opcode::text));
ws.async_write(sbuf("Hello"), do_yield[ec]); ws.async_write(sbuf("Hello"), do_yield[ec]);
if(ec) if(ec)
@@ -1171,8 +1173,9 @@ public:
} }
// send auto fragmented message // send auto fragmented message
ws.set_option(auto_fragment_size(3)); ws.set_option(auto_fragment{true});
ws.async_write(sbuf("Hello"), do_yield[ec]); ws.set_option(write_buffer_size{8});
ws.async_write(sbuf("Now is the time for all good men"), do_yield[ec]);
{ {
// receive echoed message // receive echoed message
opcode op; opcode op;
@@ -1180,9 +1183,10 @@ public:
ws.async_read(op, db, do_yield[ec]); ws.async_read(op, db, do_yield[ec]);
if(ec) if(ec)
throw system_error{ec}; throw system_error{ec};
BEAST_EXPECT(to_string(db.data()) == "Hello"); BEAST_EXPECT(to_string(db.data()) == "Now is the time for all good men");
} }
ws.set_option(auto_fragment_size(0)); ws.set_option(auto_fragment{false});
ws.set_option(write_buffer_size{4096});
// send message with mask buffer limit // send message with mask buffer limit
{ {
@@ -1379,6 +1383,9 @@ public:
static_assert(! std::is_move_assignable< static_assert(! std::is_move_assignable<
stream<socket_type&>>::value, ""); stream<socket_type&>>::value, "");
log << "sizeof(websocket::stream) == " <<
sizeof(websocket::stream<boost::asio::ip::tcp::socket&>) << std::endl;
auto const any = endpoint_type{ auto const any = endpoint_type{
address_type::from_string("127.0.0.1"), 0}; address_type::from_string("127.0.0.1"), 0};