2 // Copyright (c) 2013-2017 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)
8 #ifndef BEAST_DYNABUF_READSTREAM_HPP
9 #define BEAST_DYNABUF_READSTREAM_HPP
11 #include <beast/config.hpp>
12 #include <beast/core/async_completion.hpp>
13 #include <beast/core/buffer_concepts.hpp>
14 #include <beast/core/error.hpp>
15 #include <beast/core/stream_concepts.hpp>
16 #include <beast/core/streambuf.hpp>
17 #include <beast/core/detail/get_lowest_layer.hpp>
18 #include <boost/asio/buffer.hpp>
19 #include <boost/asio/io_service.hpp>
25 /** A @b `Stream` with attached @b `DynamicBuffer` to buffer reads.
27 This wraps a @b `Stream` implementation so that calls to write are
28 passed through to the underlying stream, while calls to read will
29 first consume the input sequence stored in a @b `DynamicBuffer` which
30 is part of the object.
32 The use-case for this class is different than that of the
33 `boost::asio::buffered_readstream`. It is designed to facilitate
34 the use of `boost::asio::read_until`, and to allow buffers
35 acquired during detection of handshakes to be made transparently
36 available to callers. A hypothetical implementation of the
37 buffered version of `boost::asio::ssl::stream::async_handshake`
38 could make use of this wrapper.
42 @li Transparently leave untouched input acquired in calls
43 to `boost::asio::read_until` behind for subsequent callers.
45 @li "Preload" a stream with handshake input data acquired
50 // Process the next HTTP header on the stream,
51 // leaving excess bytes behind for the next call.
53 template<class DynamicBuffer>
54 void process_http_message(
55 dynabuf_readstream<DynamicBuffer>& stream)
57 // Read up to and including the end of the HTTP
58 // header, leaving the sequence in the stream's
59 // buffer. read_until may read past the end of the
60 // headers; the return value will include only the
61 // part up to the end of the delimiter.
63 std::size_t bytes_transferred =
64 boost::asio::read_until(
65 stream.next_layer(), stream.buffer(), "\r\n\r\n");
67 // Use prepare_buffers() to limit the input
68 // sequence to only the data up to and including
69 // the trailing "\r\n\r\n".
71 auto header_buffers = prepare_buffers(
72 bytes_transferred, stream.buffer().data());
76 // Discard the portion of the input corresponding
77 // to the HTTP headers.
79 stream.buffer().consume(bytes_transferred);
81 // Everything we read from the stream
82 // is part of the content-body.
86 @tparam Stream The type of stream to wrap.
88 @tparam DynamicBuffer The type of stream buffer to use.
90 template<class Stream, class DynamicBuffer>
91 class dynabuf_readstream
93 static_assert(is_DynamicBuffer<DynamicBuffer>::value,
94 "DynamicBuffer requirements not met");
96 template<class Buffers, class Handler>
100 std::size_t capacity_ = 0;
104 /// The type of the internal buffer
105 using dynabuf_type = DynamicBuffer;
107 /// The type of the next layer.
108 using next_layer_type =
109 typename std::remove_reference<Stream>::type;
111 /// The type of the lowest layer.
112 using lowest_layer_type =
114 implementation_defined;
116 typename detail::get_lowest_layer<
117 next_layer_type>::type;
120 /** Move constructor.
122 @note The behavior of move assignment on or from streams
123 with active or pending operations is undefined.
125 dynabuf_readstream(dynabuf_readstream&&) = default;
129 @note The behavior of move assignment on or from streams
130 with active or pending operations is undefined.
132 dynabuf_readstream& operator=(dynabuf_readstream&&) = default;
134 /** Construct the wrapping stream.
136 @param args Parameters forwarded to the `Stream` constructor.
138 template<class... Args>
140 dynabuf_readstream(Args&&... args);
142 /// Get a reference to the next layer.
149 /// Get a const reference to the next layer.
150 next_layer_type const&
156 /// Get a reference to the lowest layer.
160 return next_layer_.lowest_layer();
163 /// Get a const reference to the lowest layer.
164 lowest_layer_type const&
167 return next_layer_.lowest_layer();
170 /// Get the io_service associated with the object.
171 boost::asio::io_service&
174 return next_layer_.get_io_service();
177 /** Access the internal buffer.
179 The internal buffer is returned. It is possible for the
180 caller to break invariants with this function. For example,
181 by causing the internal buffer size to increase beyond
182 the caller defined maximum.
190 /// Access the internal buffer
197 /** Set the maximum buffer size.
199 This changes the maximum size of the internal buffer used
200 to hold read data. No bytes are discarded by this call. If
201 the buffer size is set to zero, no more data will be buffered.
204 The caller is responsible for making sure the call is
205 made from the same implicit or explicit strand.
207 @param size The number of bytes in the read buffer.
209 @note This is a soft limit. If the new maximum size is smaller
210 than the amount of data in the buffer, no bytes are discarded.
213 capacity(std::size_t size)
218 /** Read some data from the stream.
220 This function is used to read data from the stream.
221 The function call will block until one or more bytes of
222 data has been read successfully, or until an error occurs.
224 @param buffers One or more buffers into which the data will be read.
226 @return The number of bytes read.
228 @throws system_error Thrown on failure.
230 template<class MutableBufferSequence>
232 read_some(MutableBufferSequence const& buffers);
234 /** Read some data from the stream.
236 This function is used to read data from the stream.
237 The function call will block until one or more bytes of
238 data has been read successfully, or until an error occurs.
240 @param buffers One or more buffers into which the data will be read.
242 @param ec Set to the error, if any occurred.
244 @return The number of bytes read, or 0 on error.
246 template<class MutableBufferSequence>
248 read_some(MutableBufferSequence const& buffers,
251 /** Start an asynchronous read.
253 This function is used to asynchronously read data from
254 the stream. The function call always returns immediately.
256 @param buffers One or more buffers into which the data
257 will be read. Although the buffers object may be copied
258 as necessary, ownership of the underlying memory blocks
259 is retained by the caller, which must guarantee that they
260 remain valid until the handler is called.
262 @param handler The handler to be called when the operation
263 completes. Copies will be made of the handler as required.
264 The equivalent function signature of the handler must be:
266 error_code const& error, // result of operation
267 std::size_t bytes_transferred // number of bytes transferred
269 Regardless of whether the asynchronous operation completes
270 immediately or not, the handler will not be invoked from within
271 this function. Invocation of the handler will be performed in a
272 manner equivalent to using `boost::asio::io_service::post`.
274 template<class MutableBufferSequence, class ReadHandler>
278 typename async_completion<ReadHandler, void(error_code)>::result_type
280 async_read_some(MutableBufferSequence const& buffers,
281 ReadHandler&& handler);
283 /** Write some data to the stream.
285 This function is used to write data to the stream.
286 The function call will block until one or more bytes of the
287 data has been written successfully, or until an error occurs.
289 @param buffers One or more data buffers to be written to the stream.
291 @return The number of bytes written.
293 @throws system_error Thrown on failure.
295 template<class ConstBufferSequence>
297 write_some(ConstBufferSequence const& buffers)
299 static_assert(is_SyncWriteStream<next_layer_type>::value,
300 "SyncWriteStream requirements not met");
301 return next_layer_.write_some(buffers);
304 /** Write some data to the stream.
306 This function is used to write data to the stream.
307 The function call will block until one or more bytes of the
308 data has been written successfully, or until an error occurs.
310 @param buffers One or more data buffers to be written to the stream.
312 @param ec Set to the error, if any occurred.
314 @return The number of bytes written.
316 template<class ConstBufferSequence>
318 write_some(ConstBufferSequence const& buffers,
321 static_assert(is_SyncWriteStream<next_layer_type>::value,
322 "SyncWriteStream requirements not met");
323 return next_layer_.write_some(buffers, ec);
326 /** Start an asynchronous write.
328 This function is used to asynchronously write data from
329 the stream. The function call always returns immediately.
331 @param buffers One or more data buffers to be written to
332 the stream. Although the buffers object may be copied as
333 necessary, ownership of the underlying memory blocks is
334 retained by the caller, which must guarantee that they
335 remain valid until the handler is called.
337 @param handler The handler to be called when the operation
338 completes. Copies will be made of the handler as required.
339 The equivalent function signature of the handler must be:
341 error_code const& error, // result of operation
342 std::size_t bytes_transferred // number of bytes transferred
344 Regardless of whether the asynchronous operation completes
345 immediately or not, the handler will not be invoked from within
346 this function. Invocation of the handler will be performed in a
347 manner equivalent to using `boost::asio::io_service::post`.
349 template<class ConstBufferSequence, class WriteHandler>
353 typename async_completion<WriteHandler, void(error_code)>::result_type
355 async_write_some(ConstBufferSequence const& buffers,
356 WriteHandler&& handler);
361 #include <beast/core/impl/dynabuf_readstream.ipp>