From e56d9955de4094a90356845b2edc44d4f31c87ac Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 25 Jul 2017 08:50:58 -0700 Subject: [PATCH] websocket read returns the number of bytes inserted (API Change): * read and async_read now return the number of bytes inserted into the caller's buffer. Actions Required: * Change the signature of completion handlers used with websocket::stream::async_read to void(error_code, std::size_t) --- CHANGELOG.md | 9 +++ include/boost/beast/websocket/impl/read.ipp | 31 +++++------ include/boost/beast/websocket/stream.hpp | 61 ++++++++++++--------- test/websocket/doc_snippets.cpp | 2 +- test/websocket/stream.cpp | 18 +++--- 5 files changed, 69 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fd149df..ff60611b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,15 @@ Version 86: * Fix Deferred Body Type Example Documentation * Add library metadata +API Changes: + +* websocket read returns the number of bytes inserted + +Actions Required: + +* Change the signature of completion handlers used with + websocket::stream::async_read to void(error_code, std::size_t) + -------------------------------------------------------------------------------- Version 85: diff --git a/include/boost/beast/websocket/impl/read.ipp b/include/boost/beast/websocket/impl/read.ipp index fc7c0671..123c4529 100644 --- a/include/boost/beast/websocket/impl/read.ipp +++ b/include/boost/beast/websocket/impl/read.ipp @@ -804,7 +804,7 @@ operator()( template template -void +std::size_t stream:: read(DynamicBuffer& buffer) { @@ -813,14 +813,15 @@ read(DynamicBuffer& buffer) static_assert(beast::is_dynamic_buffer::value, "DynamicBuffer requirements not met"); error_code ec; - read(buffer, ec); + auto const bytes_written = read(buffer, ec); if(ec) BOOST_THROW_EXCEPTION(system_error{ec}); + return bytes_written; } template template -void +std::size_t stream:: read(DynamicBuffer& buffer, error_code& ec) { @@ -828,18 +829,20 @@ read(DynamicBuffer& buffer, error_code& ec) "SyncStream requirements not met"); static_assert(beast::is_dynamic_buffer::value, "DynamicBuffer requirements not met"); + std::size_t bytes_written = 0; do { - read_some(buffer, 0, ec); + bytes_written += read_some(buffer, 0, ec); if(ec) - return; + return bytes_written; } while(! is_message_done()); + return bytes_written; } template template -async_return_type +async_return_type stream:: async_read(DynamicBuffer& buffer, ReadHandler&& handler) { @@ -848,19 +851,15 @@ async_read(DynamicBuffer& buffer, ReadHandler&& handler) static_assert(beast::is_dynamic_buffer::value, "DynamicBuffer requirements not met"); async_completion< - ReadHandler, void(error_code)> init{handler}; + ReadHandler, void(error_code, std::size_t)> init{handler}; read_op< DynamicBuffer, - beast::detail::bound_handler< - handler_type, - decltype(std::placeholders::_1) &> >{ - beast::bind_handler( + handler_type >{ init.completion_handler, - std::placeholders::_1), - *this, - buffer, - 0, - false}(); + *this, + buffer, + 0, + false}(); return init.result.get(); } diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index 4d9986f7..55500dbf 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -2835,43 +2835,46 @@ public: // //-------------------------------------------------------------------------- - /** Read a message from the stream. + /** Read a complete message - This function is used to synchronously read a message from - the stream. The call blocks until one of the following is true: + This function is used to synchronously read a message from the stream. + The call blocks until one of the following is true: @li A complete message is received. + @li A close frame is received. In this case the error indicated by + the function will be @ref error::closed. + @li An error occurs on the stream. - This call is implemented in terms of one or more calls to the - stream's `read_some` and `write_some` operations. + This operation is implemented in terms of one or more calls to the next + layer's `read_some` and `write_some` functions. - Upon a success, the input area of the stream buffer will - hold the received message payload bytes (which may be zero - in length). The functions @ref got_binary and @ref got_text - may be used to query the stream and determine the type - of the last received message. + Received message data, if any, is appended to the input area of the buffer. + The functions @ref got_binary and @ref got_text may be used to query + the stream and determine the type of the last received message. - During reads, the implementation handles control frames as - follows: + While this operation is active, the implementation will read incoming + control frames and handle them automatically as follows: - @li A pong frame is sent when a ping frame is received. + @li The @ref control_callback will be invoked for each control frame. - @li The @ref control_callback is invoked when a ping frame - or pong frame is received. + @li For each received ping frame, a pong frame will be automatically sent. - @li The WebSocket close procedure is started if a close frame - is received. In this case, the operation will eventually - complete with the error set to @ref error::closed. + @li If a close frame is received, the WebSocket close procedure is + performed. In this case, when the function returns, the error + @ref error::closed will be indicated. - @param buffer A dynamic buffer to hold the message data after - any masking or decompression has been applied. + @return The number of message payload bytes appended to the buffer. - @throws system_error Thrown on failure. + @param buffer A dynamic buffer to hold the message data after any + masking or decompression has been applied. + + @throws system_error Thrown to indicate an error. The corresponding + error code may be retrieved from the exception object for inspection. */ template - void + std::size_t read(DynamicBuffer& buffer); /** Read a message from the stream. @@ -2910,10 +2913,10 @@ public: @param ec Set to indicate what error occurred, if any. */ template - void + std::size_t read(DynamicBuffer& buffer, error_code& ec); - /** Start an asynchronous operation to read a message from the stream. + /** Read a complete message asynchronously This function is used to asynchronously read a message from the stream. The function call always returns immediately. The @@ -2963,7 +2966,8 @@ public: function signature of the handler must be: @code void handler( - error_code const& ec; // Result of operation + error_code const& ec, // Result of operation + std::size_t bytes_ ); @endcode Regardless of whether the asynchronous operation completes @@ -2976,9 +2980,12 @@ public: void_or_deduced #else async_return_type< - ReadHandler, void(error_code)> + ReadHandler, + void(error_code, std::size_t)> #endif - async_read(DynamicBuffer& buffer, ReadHandler&& handler); + async_read( + DynamicBuffer& buffer, + ReadHandler&& handler); //-------------------------------------------------------------------------- diff --git a/test/websocket/doc_snippets.cpp b/test/websocket/doc_snippets.cpp index 82f9a3c0..14406093 100644 --- a/test/websocket/doc_snippets.cpp +++ b/test/websocket/doc_snippets.cpp @@ -209,7 +209,7 @@ boost::asio::ip::tcp::socket sock{ios}; //[ws_snippet_20 multi_buffer buffer; ws.async_read(buffer, - [](error_code) + [](error_code, std::size_t) { // Do something with the buffer }); diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index aa647954..103eb70c 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -270,7 +270,7 @@ public: template< class NextLayer, class DynamicBuffer> - void + std::size_t read(stream& ws, DynamicBuffer& buffer) const { @@ -506,14 +506,16 @@ public: template< class NextLayer, class DynamicBuffer> - void + std::size_t read(stream& ws, DynamicBuffer& buffer) const { error_code ec; - ws.async_read(buffer, yield_[ec]); + auto const bytes_written = + ws.async_read(buffer, yield_[ec]); if(ec) throw system_error{ec}; + return bytes_written; } template< @@ -1342,7 +1344,7 @@ public: // Read text message with bad utf8. // Causes a close to be sent, blocking writes. ws.async_read(db, - [&](error_code ec) + [&](error_code ec, std::size_t) { // Read should fail with protocol error ++count; @@ -1350,7 +1352,7 @@ public: ec == error::failed, ec.message()); // Reads after failure are aborted ws.async_read(db, - [&](error_code ec) + [&](error_code ec, std::size_t) { ++count; BOOST_BEAST_EXPECTS(ec == boost::asio:: @@ -1409,7 +1411,7 @@ public: // Read a close frame. // Sends a close frame, blocking writes. ws.async_read(db, - [&](error_code ec) + [&](error_code ec, std::size_t) { // Read should complete with error::closed ++count; @@ -1472,7 +1474,7 @@ public: multi_buffer db; std::size_t count = 0; ws.async_read(db, - [&](error_code ec) + [&](error_code ec, std::size_t) { ++count; BOOST_BEAST_EXPECTS(ec == error::closed, @@ -1521,7 +1523,7 @@ public: }); multi_buffer db; ws.async_read(db, - [&](error_code ec) + [&](error_code ec, std::size_t) { BOOST_BEAST_EXPECTS(ec == error::closed, ec.message()); });