2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_BUFFERED_READ_STREAM_HPP
11 #define BOOST_BEAST_BUFFERED_READ_STREAM_HPP
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>
26 /** A <em>Stream</em> with attached <em>DynamicBuffer</em> to buffer reads.
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.
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.
43 @li Transparently leave untouched input acquired in calls
44 to `net::read_until` behind for subsequent callers.
46 @li "Preload" a stream with handshake input data acquired
51 // Process the next HTTP header on the stream,
52 // leaving excess bytes behind for the next call.
54 template<class Stream, class DynamicBuffer>
55 void process_http_message(
56 buffered_read_stream<Stream, DynamicBuffer>& stream)
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.
64 std::size_t bytes_transferred =
66 stream.next_layer(), stream.buffer(), "\r\n\r\n");
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".
72 auto header_buffers = buffers_prefix(
73 bytes_transferred, stream.buffer().data());
77 // Discard the portion of the input corresponding
78 // to the HTTP headers.
80 stream.buffer().consume(bytes_transferred);
82 // Everything we read from the stream
83 // is part of the content-body.
87 @tparam Stream The type of stream to wrap.
89 @tparam DynamicBuffer The type of stream buffer to use.
91 template<class Stream, class DynamicBuffer>
92 class buffered_read_stream
95 net::is_dynamic_buffer<DynamicBuffer>::value,
96 "DynamicBuffer type requirements not met");
100 DynamicBuffer buffer_;
101 std::size_t capacity_ = 0;
105 /// The type of the internal buffer
106 using buffer_type = DynamicBuffer;
108 /// The type of the next layer.
109 using next_layer_type =
110 typename std::remove_reference<Stream>::type;
112 /** Move constructor.
114 @note The behavior of move assignment on or from streams
115 with active or pending operations is undefined.
117 buffered_read_stream(buffered_read_stream&&) = default;
121 @note The behavior of move assignment on or from streams
122 with active or pending operations is undefined.
124 buffered_read_stream& operator=(buffered_read_stream&&) = default;
126 /** Construct the wrapping stream.
128 @param args Parameters forwarded to the `Stream` constructor.
130 template<class... Args>
132 buffered_read_stream(Args&&... args);
134 /// Get a reference to the next layer.
136 next_layer() noexcept
141 /// Get a const reference to the next layer.
142 next_layer_type const&
143 next_layer() const noexcept
148 using executor_type =
149 beast::executor_type<next_layer_type>;
151 /** Get the executor associated with the object.
153 This function may be used to obtain the executor object that the stream
154 uses to dispatch handlers for asynchronous operations.
156 @return A copy of the executor that stream will use to dispatch handlers.
159 get_executor() noexcept
161 return next_layer_.get_executor();
164 /** Access the internal buffer.
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.
177 /// Access the internal buffer
179 buffer() const noexcept
184 /** Set the maximum buffer size.
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.
191 The caller is responsible for making sure the call is
192 made from the same implicit or explicit strand.
194 @param size The number of bytes in the read buffer.
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.
200 capacity(std::size_t size) noexcept
205 /** Read some data from the stream.
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.
211 @param buffers One or more buffers into which the data will be read.
213 @return The number of bytes read.
215 @throws system_error Thrown on failure.
217 template<class MutableBufferSequence>
219 read_some(MutableBufferSequence const& buffers);
221 /** Read some data from the stream.
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.
227 @param buffers One or more buffers into which the data will be read.
229 @param ec Set to the error, if any occurred.
231 @return The number of bytes read, or 0 on error.
233 template<class MutableBufferSequence>
235 read_some(MutableBufferSequence const& buffers,
238 /** Start an asynchronous read.
240 This function is used to asynchronously read data from
241 the stream. The function call always returns immediately.
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.
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
255 error_code const& error, // result of operation
256 std::size_t bytes_transferred // number of bytes transferred
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`.
265 class MutableBufferSequence,
266 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
267 net::default_completion_token_t<executor_type>>
268 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
270 MutableBufferSequence const& buffers,
271 ReadHandler&& handler =
272 net::default_completion_token_t<executor_type>{});
274 /** Write some data to the stream.
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.
280 @param buffers One or more data buffers to be written to the stream.
282 @return The number of bytes written.
284 @throws system_error Thrown on failure.
286 template<class ConstBufferSequence>
288 write_some(ConstBufferSequence const& buffers)
290 static_assert(is_sync_write_stream<next_layer_type>::value,
291 "SyncWriteStream type requirements not met");
292 return next_layer_.write_some(buffers);
295 /** Write some data to the stream.
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.
301 @param buffers One or more data buffers to be written to the stream.
303 @param ec Set to the error, if any occurred.
305 @return The number of bytes written.
307 template<class ConstBufferSequence>
309 write_some(ConstBufferSequence const& buffers,
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);
317 /** Start an asynchronous write.
319 This function is used to asynchronously write data from
320 the stream. The function call always returns immediately.
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.
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
334 error_code const& error, // result of operation
335 std::size_t bytes_transferred // number of bytes transferred
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`.
344 class ConstBufferSequence,
345 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
346 net::default_completion_token_t<executor_type>>
347 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
349 ConstBufferSequence const& buffers,
350 WriteHandler&& handler =
351 net::default_completion_token_t<executor_type>{});
357 #include <boost/beast/core/impl/buffered_read_stream.hpp>