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