WebSocket ping, fixes, coverage:

* Improve test coverage
* tests for invokable in composed ops

* Update documentation
* Add License badge to README
* Target Windows 7 SDK and later
* Make role_type private
* Remove extra unused masking functions
* Allow stream reuse / reconnect after failure
* Restructure logic of composed operations
* Allow 0 for read_message_max meaning no limit
* Respect keep alive when building HTTP responses
* Check version in upgrade request
* Response with 426 status on unsupported WebSocket version
* Remove unnecessary Sec-WebSocket-Key in HTTP responses
* Rename to mask_buffer_size

* Remove maybe_throw
* Add ping, async_ping, async_on_pong
* Add ping_op
* Add pong_op
* Fix crash in accept_op
* Fix suspend in close_op
* Fix read_frame_op logic
* Fix crash in read_op
* Fix races in echo sync and async echo servers
This commit is contained in:
Vinnie Falco
2016-05-15 16:22:25 -04:00
parent bfb840fe8e
commit 039244cda4
40 changed files with 2757 additions and 1365 deletions

View File

@@ -69,8 +69,8 @@ struct frame_info
@tparam NextLayer The type representing the next layer, to which
data will be read and written during operations. For synchronous
operations, the type must support the @b `SyncStream` concept.
For asynchronous operations, the type must support the @b `AsyncStream`
concept.
For asynchronous operations, the type must support the
@b `AsyncStream` concept.
@note A stream object must not be destroyed while there are
pending asynchronous operations associated with it.
@@ -84,7 +84,7 @@ struct frame_info
template<class NextLayer>
class stream : public detail::stream_base
{
friend class ws_test;
friend class stream_test;
streambuf_readstream<NextLayer, streambuf> stream_;
@@ -124,12 +124,12 @@ public:
/** Construct a WebSocket stream.
This constructor creates a websocket stream and initialises
This constructor creates a websocket stream and initializes
the next layer object.
@throws Any exceptions thrown by the NextLayer constructor.
@param args The arguments to be passed to initialise the
@param args The arguments to be passed to initialize the
next layer object. The arguments are forwarded to the next
layer's constructor.
*/
@@ -198,6 +198,13 @@ public:
wr_opcode_ = o.value;
}
/// Set the pong callback
void
set_option(pong_callback o)
{
pong_cb_ = std::move(o.value);
}
/// Set the read buffer size
void
set_option(read_buffer_size const& o)
@@ -212,11 +219,11 @@ public:
rd_msg_max_ = o.value;
}
/// Set the size of the write buffer
/// Set the size of the mask buffer
void
set_option(write_buffer_size const& o)
set_option(mask_buffer_size const& o)
{
wr_buf_size_ = std::max<std::size_t>(o.value, 1024);
mask_buf_size_ = o.value;
stream_.capacity(o.value);
}
@@ -788,7 +795,7 @@ public:
/** Send a WebSocket close frame.
This function is used to sycnhronously send a close frame on
This function is used to synchronously send a close frame on
the stream. The call blocks until one of the following is true:
@li The close frame finishes sending.
@@ -817,7 +824,7 @@ public:
/** Send a WebSocket close frame.
This function is used to sycnhronously send a close frame on
This function is used to synchronously send a close frame on
the stream. The call blocks until one of the following is true:
@li The close frame finishes sending.
@@ -844,7 +851,7 @@ public:
void
close(close_reason const& cr, error_code& ec);
/** Start an asycnhronous operation to send a WebSocket close frame.
/** Start an asynchronous operation to send a WebSocket close frame.
This function is used to asynchronously send a close frame on
the stream. This function call always returns immediately. The
@@ -858,7 +865,7 @@ public:
This operation is implemented in terms of one or more calls to the
next layer's `async_write_some` functions, and is known as a
<em>composed operation</em>. The program must ensure that the
stream performs no other write operations (such as
stream performs no other write operations (such as @ref async_ping,
@ref stream::async_write, @ref stream::async_write_frame, or
@ref stream::async_close) until this operation completes.
@@ -896,6 +903,84 @@ public:
#endif
async_close(close_reason const& cr, CloseHandler&& handler);
/** Send a WebSocket ping frame.
This function is used to synchronously send a ping frame on
the stream. The call blocks until one of the following is true:
@li The ping frame finishes sending.
@li An error occurs on the stream.
This function is implemented in terms of one or more calls to the
next layer's `write_some` functions.
@param payload The payload of the ping message, which may be empty.
@throws boost::system::system_error Thrown on failure.
*/
void
ping(ping_data const& payload);
/** Send a WebSocket ping frame.
This function is used to synchronously send a ping frame on
the stream. The call blocks until one of the following is true:
@li The ping frame finishes sending.
@li An error occurs on the stream.
This function is implemented in terms of one or more calls to the
next layer's `write_some` functions.
@param payload The payload of the ping message, which may be empty.
@param ec Set to indicate what error occurred, if any.
*/
void
ping(ping_data const& payload, error_code& ec);
/** Start an asynchronous operation to send a WebSocket ping frame.
This function is used to asynchronously send a ping frame to
the stream. The function call always returns immediately. The
asynchronous operation will continue until one of the following
is true:
@li The entire ping frame is sent.
@li An error occurs on the stream.
This operation is implemented in terms of one or more calls to the
next layer's `async_write_some` functions, and is known as a
<em>composed operation</em>. The program must ensure that the
stream performs no other writes until this operation completes.
@param payload The payload of the ping message, which may be empty.
@param handler The handler to be called when the read operation
completes. Copies will be made of the handler as required. The
function signature of the handler must be:
@code
void handler(
error_code const& error // Result of operation
);
@endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class PingHandler>
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<
PingHandler, void(error_code)>::result_type
#endif
async_ping(ping_data const& payload, PingHandler&& handler);
/** Read a message from the stream.
This function is used to synchronously read a message from
@@ -969,7 +1054,7 @@ public:
/** Start an asynchronous operation to read a message from the stream.
This function is used to asychronously read a message from
This function is used to asynchronously read a message from
the stream. The function call always returns immediately. The
asynchronous operation will continue until one of the following
is true:
@@ -981,7 +1066,7 @@ public:
This operation is implemented in terms of one or more calls to the
next layer's `async_read_some` and `async_write_some` functions,
and is known as a <em>composed operation</em>. The program must
ensure that the stream performs no other until this operation
ensure that the stream performs no other reads until this operation
completes.
Upon a success, op is set to either binary or text depending on
@@ -989,15 +1074,14 @@ public:
hold all the message payload bytes (which may be zero in length).
Control frames encountered while reading frame or message data
are handled automatically. Pings are replied to, pongs are noted,
and close frames initiate the WebSocket close procedure. When a
close frame is received, this call will eventually return
@ref error::closed. Because of the need to handle control frames,
read operations can cause writes to take place. These writes are
managed transparently; callers can still have one active
asynchronous read and asynchronous write operation pending
simultaneously (a user initiated call to @ref async_close
counts as a write).
are handled automatically. Pings are replied to, pongs cause
an outstanding call to `async_ping` to complete, and close
frames initiate the WebSocket close procedure. When a close
frame is received, this call will eventually return
@ref error::closed. Because of the need to handle control
frames, these read operations can cause writes to take place.
Despite this, calls to `async_read` and `async_read_frame`
only count as read operations.
@param op A value to receive the message type.
This object must remain valid until the handler is called.
@@ -1104,7 +1188,7 @@ public:
/** Start an asynchronous operation to read a message frame from the stream.
This function is used to asychronously read a single message
This function is used to asynchronously read a single message
frame from the websocket. The function call always returns
immediately. The asynchronous operation will continue until
one of the following conditions is true:
@@ -1116,7 +1200,7 @@ public:
This operation is implemented in terms of one or more calls to the
next layer's `async_read_some` and `async_write_some` functions,
and is known as a <em>composed operation</em>. The program must
ensure that the stream performs no other until this operation
ensure that the stream performs no other reads until this operation
completes.
Upon a successful completion, fi is filled out to reflect the
@@ -1242,7 +1326,7 @@ public:
/** Start an asynchronous operation to write a message to the stream.
This function is used to asychronously write a message to
This function is used to asynchronously write a message to
the stream. The function call always returns immediately.
The asynchronous operation will continue until one of the
following conditions is true:
@@ -1407,11 +1491,15 @@ private:
template<class Handler> class accept_op;
template<class Handler> class close_op;
template<class Handler> class handshake_op;
template<class Handler> class ping_op;
template<class Handler> class response_op;
template<class Streambuf, class Handler> class read_op;
template<class Streambuf, class Handler> class read_frame_op;
template<class Buffers, class Handler> class write_op;
template<class Buffers, class Handler> class write_frame_op;
template<class Streambuf, class Handler> class read_op;
template<class Streambuf, class Handler> class read_frame_op;
void
reset();
http::request_v1<http::empty_body>
build_request(boost::string_ref const& host,