1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 #ifndef BOOST_BEAST_BUFFERED_READ_STREAM_HPP 11 #define BOOST_BEAST_BUFFERED_READ_STREAM_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/error.hpp> 15 #include <boost/beast/core/multi_buffer.hpp> 16 #include <boost/beast/core/stream_traits.hpp> 17 #include <boost/asio/async_result.hpp> 18 #include <boost/asio/buffer.hpp> 19 #include <boost/asio/io_context.hpp> 20 #include <cstdint> 21 #include <utility> 22 23 namespace boost { 24 namespace beast { 25 26 /** A <em>Stream</em> with attached <em>DynamicBuffer</em> to buffer reads. 27 28 This wraps a <em>Stream</em> implementation so that calls to write are 29 passed through to the underlying stream, while calls to read will 30 first consume the input sequence stored in a <em>DynamicBuffer</em> which 31 is part of the object. 32 33 The use-case for this class is different than that of the 34 `net::buffered_read_stream`. It is designed to facilitate 35 the use of `net::read_until`, and to allow buffers 36 acquired during detection of handshakes to be made transparently 37 available to callers. A hypothetical implementation of the 38 buffered version of `net::ssl::stream::async_handshake` 39 could make use of this wrapper. 40 41 Uses: 42 43 @li Transparently leave untouched input acquired in calls 44 to `net::read_until` behind for subsequent callers. 45 46 @li "Preload" a stream with handshake input data acquired 47 from other sources. 48 49 Example: 50 @code 51 // Process the next HTTP header on the stream, 52 // leaving excess bytes behind for the next call. 53 // 54 template<class Stream, class DynamicBuffer> 55 void process_http_message( 56 buffered_read_stream<Stream, DynamicBuffer>& stream) 57 { 58 // Read up to and including the end of the HTTP 59 // header, leaving the sequence in the stream's 60 // buffer. read_until may read past the end of the 61 // headers; the return value will include only the 62 // part up to the end of the delimiter. 63 // 64 std::size_t bytes_transferred = 65 net::read_until( 66 stream.next_layer(), stream.buffer(), "\r\n\r\n"); 67 68 // Use buffers_prefix() to limit the input 69 // sequence to only the data up to and including 70 // the trailing "\r\n\r\n". 71 // 72 auto header_buffers = buffers_prefix( 73 bytes_transferred, stream.buffer().data()); 74 75 ... 76 77 // Discard the portion of the input corresponding 78 // to the HTTP headers. 79 // 80 stream.buffer().consume(bytes_transferred); 81 82 // Everything we read from the stream 83 // is part of the content-body. 84 } 85 @endcode 86 87 @tparam Stream The type of stream to wrap. 88 89 @tparam DynamicBuffer The type of stream buffer to use. 90 */ 91 template<class Stream, class DynamicBuffer> 92 class buffered_read_stream 93 { 94 static_assert( 95 net::is_dynamic_buffer<DynamicBuffer>::value, 96 "DynamicBuffer type requirements not met"); 97 98 struct ops; 99 100 DynamicBuffer buffer_; 101 std::size_t capacity_ = 0; 102 Stream next_layer_; 103 104 public: 105 /// The type of the internal buffer 106 using buffer_type = DynamicBuffer; 107 108 /// The type of the next layer. 109 using next_layer_type = 110 typename std::remove_reference<Stream>::type; 111 112 /** Move constructor. 113 114 @note The behavior of move assignment on or from streams 115 with active or pending operations is undefined. 116 */ 117 buffered_read_stream(buffered_read_stream&&) = default; 118 119 /** Move assignment. 120 121 @note The behavior of move assignment on or from streams 122 with active or pending operations is undefined. 123 */ 124 buffered_read_stream& operator=(buffered_read_stream&&) = default; 125 126 /** Construct the wrapping stream. 127 128 @param args Parameters forwarded to the `Stream` constructor. 129 */ 130 template<class... Args> 131 explicit 132 buffered_read_stream(Args&&... args); 133 134 /// Get a reference to the next layer. 135 next_layer_type& next_layer()136 next_layer() noexcept 137 { 138 return next_layer_; 139 } 140 141 /// Get a const reference to the next layer. 142 next_layer_type const& next_layer() const143 next_layer() const noexcept 144 { 145 return next_layer_; 146 } 147 148 using executor_type = 149 beast::executor_type<next_layer_type>; 150 151 /** Get the executor associated with the object. 152 153 This function may be used to obtain the executor object that the stream 154 uses to dispatch handlers for asynchronous operations. 155 156 @return A copy of the executor that stream will use to dispatch handlers. 157 */ 158 executor_type get_executor()159 get_executor() noexcept 160 { 161 return next_layer_.get_executor(); 162 } 163 164 /** Access the internal buffer. 165 166 The internal buffer is returned. It is possible for the 167 caller to break invariants with this function. For example, 168 by causing the internal buffer size to increase beyond 169 the caller defined maximum. 170 */ 171 DynamicBuffer& buffer()172 buffer() noexcept 173 { 174 return buffer_; 175 } 176 177 /// Access the internal buffer 178 DynamicBuffer const& buffer() const179 buffer() const noexcept 180 { 181 return buffer_; 182 } 183 184 /** Set the maximum buffer size. 185 186 This changes the maximum size of the internal buffer used 187 to hold read data. No bytes are discarded by this call. If 188 the buffer size is set to zero, no more data will be buffered. 189 190 Thread safety: 191 The caller is responsible for making sure the call is 192 made from the same implicit or explicit strand. 193 194 @param size The number of bytes in the read buffer. 195 196 @note This is a soft limit. If the new maximum size is smaller 197 than the amount of data in the buffer, no bytes are discarded. 198 */ 199 void capacity(std::size_t size)200 capacity(std::size_t size) noexcept 201 { 202 capacity_ = size; 203 } 204 205 /** Read some data from the stream. 206 207 This function is used to read data from the stream. 208 The function call will block until one or more bytes of 209 data has been read successfully, or until an error occurs. 210 211 @param buffers One or more buffers into which the data will be read. 212 213 @return The number of bytes read. 214 215 @throws system_error Thrown on failure. 216 */ 217 template<class MutableBufferSequence> 218 std::size_t 219 read_some(MutableBufferSequence const& buffers); 220 221 /** Read some data from the stream. 222 223 This function is used to read data from the stream. 224 The function call will block until one or more bytes of 225 data has been read successfully, or until an error occurs. 226 227 @param buffers One or more buffers into which the data will be read. 228 229 @param ec Set to the error, if any occurred. 230 231 @return The number of bytes read, or 0 on error. 232 */ 233 template<class MutableBufferSequence> 234 std::size_t 235 read_some(MutableBufferSequence const& buffers, 236 error_code& ec); 237 238 /** Start an asynchronous read. 239 240 This function is used to asynchronously read data from 241 the stream. The function call always returns immediately. 242 243 @param buffers One or more buffers into which the data 244 will be read. Although the buffers object may be copied 245 as necessary, ownership of the underlying memory blocks 246 is retained by the caller, which must guarantee that they 247 remain valid until the handler is called. 248 249 @param handler The completion handler to invoke when the operation 250 completes. The implementation takes ownership of the handler by 251 performing a decay-copy. The equivalent function signature of 252 the handler must be: 253 @code 254 void handler( 255 error_code const& error, // result of operation 256 std::size_t bytes_transferred // number of bytes transferred 257 ); 258 @endcode 259 Regardless of whether the asynchronous operation completes 260 immediately or not, the handler will not be invoked from within 261 this function. Invocation of the handler will be performed in a 262 manner equivalent to using `net::post`. 263 */ 264 template< 265 class MutableBufferSequence, 266 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = 267 net::default_completion_token_t<executor_type>> 268 BOOST_BEAST_ASYNC_RESULT2(ReadHandler) 269 async_read_some( 270 MutableBufferSequence const& buffers, 271 ReadHandler&& handler = 272 net::default_completion_token_t<executor_type>{}); 273 274 /** Write some data to the stream. 275 276 This function is used to write data to the stream. 277 The function call will block until one or more bytes of the 278 data has been written successfully, or until an error occurs. 279 280 @param buffers One or more data buffers to be written to the stream. 281 282 @return The number of bytes written. 283 284 @throws system_error Thrown on failure. 285 */ 286 template<class ConstBufferSequence> 287 std::size_t write_some(ConstBufferSequence const & buffers)288 write_some(ConstBufferSequence const& buffers) 289 { 290 static_assert(is_sync_write_stream<next_layer_type>::value, 291 "SyncWriteStream type requirements not met"); 292 return next_layer_.write_some(buffers); 293 } 294 295 /** Write some data to the stream. 296 297 This function is used to write data to the stream. 298 The function call will block until one or more bytes of the 299 data has been written successfully, or until an error occurs. 300 301 @param buffers One or more data buffers to be written to the stream. 302 303 @param ec Set to the error, if any occurred. 304 305 @return The number of bytes written. 306 */ 307 template<class ConstBufferSequence> 308 std::size_t write_some(ConstBufferSequence const & buffers,error_code & ec)309 write_some(ConstBufferSequence const& buffers, 310 error_code& ec) 311 { 312 static_assert(is_sync_write_stream<next_layer_type>::value, 313 "SyncWriteStream type requirements not met"); 314 return next_layer_.write_some(buffers, ec); 315 } 316 317 /** Start an asynchronous write. 318 319 This function is used to asynchronously write data from 320 the stream. The function call always returns immediately. 321 322 @param buffers One or more data buffers to be written to 323 the stream. Although the buffers object may be copied as 324 necessary, ownership of the underlying memory blocks is 325 retained by the caller, which must guarantee that they 326 remain valid until the handler is called. 327 328 @param handler The completion handler to invoke when the operation 329 completes. The implementation takes ownership of the handler by 330 performing a decay-copy. The equivalent function signature of 331 the handler must be: 332 @code 333 void handler( 334 error_code const& error, // result of operation 335 std::size_t bytes_transferred // number of bytes transferred 336 ); 337 @endcode 338 Regardless of whether the asynchronous operation completes 339 immediately or not, the handler will not be invoked from within 340 this function. Invocation of the handler will be performed in a 341 manner equivalent to using `net::post`. 342 */ 343 template< 344 class ConstBufferSequence, 345 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = 346 net::default_completion_token_t<executor_type>> 347 BOOST_BEAST_ASYNC_RESULT2(WriteHandler) 348 async_write_some( 349 ConstBufferSequence const& buffers, 350 WriteHandler&& handler = 351 net::default_completion_token_t<executor_type>{}); 352 }; 353 354 } // beast 355 } // boost 356 357 #include <boost/beast/core/impl/buffered_read_stream.hpp> 358 359 #endif 360