|
| 1 | +// |
| 2 | +// Copyright (c) 2025 Mungo Gill |
| 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/cppalliance/beast2 |
| 8 | +// |
| 9 | + |
| 10 | +#ifndef BOOST_HTTP_IO_BODY_READ_STREAM_HPP |
| 11 | +#define BOOST_HTTP_IO_BODY_READ_STREAM_HPP |
| 12 | + |
| 13 | +#include <boost/asio/async_result.hpp> |
| 14 | +#include <boost/http_proto/parser.hpp> |
| 15 | +#include <boost/system/error_code.hpp> |
| 16 | + |
| 17 | +namespace boost { |
| 18 | +namespace beast2 { |
| 19 | + |
| 20 | + /** A body reader for HTTP/1 messages. |
| 21 | +
|
| 22 | + This type meets the requirements of asio's |
| 23 | + AsyncReadStream, and is constructed with a reference to an |
| 24 | + underlying AsyncReadStream. |
| 25 | +
|
| 26 | + Any call to `async_read_some` initially triggers reads |
| 27 | + from the underlying stream until all of the HTTP headers |
| 28 | + and at least one byte of the body |
| 29 | + have been read and processed. Thereafter, each subsequent |
| 30 | + call to `async_read_some` processes at least one byte of |
| 31 | + the body, triggering, where required, calls to the underlying |
| 32 | + stream's `async_read_some` method. The resulting body |
| 33 | + data is stored in the referenced MutableBufferSequence. |
| 34 | +
|
| 35 | + All processing depends on a http_io::parser object owned |
| 36 | + by the caller and referenced in the construction of this |
| 37 | + object. |
| 38 | +
|
| 39 | + @see |
| 40 | + @ref http_proto::parser. |
| 41 | + */ |
| 42 | +template<class AsyncReadStream> |
| 43 | +class body_read_stream { |
| 44 | + |
| 45 | +public: |
| 46 | + |
| 47 | + /** The type of the executor associated with the stream. |
| 48 | +
|
| 49 | + This will be the type of executor used to invoke completion |
| 50 | + handlers which do not have an explicit associated executor. |
| 51 | + */ |
| 52 | + typedef typename AsyncReadStream::executor_type executor_type; |
| 53 | + |
| 54 | + /** Get the executor associated with the object. |
| 55 | +
|
| 56 | + This function may be used to obtain the executor object that the |
| 57 | + stream uses to dispatch completion handlers without an assocaited |
| 58 | + executor. |
| 59 | +
|
| 60 | + @return A copy of the executor that stream will use to dispatch |
| 61 | + handlers. |
| 62 | + */ |
| 63 | + executor_type get_executor() { |
| 64 | + return us_.get_executor(); |
| 65 | + } |
| 66 | + |
| 67 | + /** Constructor |
| 68 | +
|
| 69 | + This constructor creates the stream by forwarding all arguments |
| 70 | + to the underlying socket. The socket then needs to be open and |
| 71 | + connected or accepted before data can be sent or received on it. |
| 72 | +
|
| 73 | + @param us The underlying stream from which the HTTP message is read. |
| 74 | + This object's executor is initialized to that of the |
| 75 | + underlying stream. |
| 76 | +
|
| 77 | + @param pr A http_proto::parser object which will perform the parsing |
| 78 | + of the HTTP message and extraction of the body. This must |
| 79 | + be initialized by the caller and ownership of the parser is |
| 80 | + retained by the caller, which must guarantee that it remains |
| 81 | + valid until the handler is called. |
| 82 | + */ |
| 83 | + explicit |
| 84 | + body_read_stream( |
| 85 | + AsyncReadStream& us, |
| 86 | + http_proto::parser& pr); |
| 87 | + |
| 88 | + /** Read some data asynchronously. |
| 89 | +
|
| 90 | + This function is used to asynchronously read data from the stream. |
| 91 | +
|
| 92 | + This call always returns immediately. The asynchronous operation |
| 93 | + will continue until one of the following conditions is true: |
| 94 | +
|
| 95 | + @li The HTTP headers are read in full from the underlying stream |
| 96 | + and one or more bytes of the body are read from the stream and |
| 97 | + stored in the buffer `mb`. |
| 98 | +
|
| 99 | + @li An error occurs. |
| 100 | +
|
| 101 | + The algorithm, known as a <em>composed asynchronous operation</em>, |
| 102 | + is implemented in terms of calls to the underlying stream's `async_read_some` |
| 103 | + function. The program must ensure that no other calls to |
| 104 | + `async_read_some` are performed until this operation completes. |
| 105 | +
|
| 106 | + @param mb The buffers into which the body data will be read. If the size |
| 107 | + of the buffers is zero bytes, the operation always completes immediately |
| 108 | + with no error. |
| 109 | + Although the buffers object may be copied as necessary, ownership of the |
| 110 | + underlying memory blocks is retained by the caller, which must guarantee |
| 111 | + that they remain valid until the handler is called. |
| 112 | + Where the mb buffer is not of sufficient size to hold the read data, the |
| 113 | + remainder may be read by subsequent calls to this function. |
| 114 | +
|
| 115 | + @param handler The completion handler to invoke when the operation |
| 116 | + completes. The implementation takes ownership of the handler by |
| 117 | + performing a decay-copy. The equivalent function signature of |
| 118 | + the handler must be: |
| 119 | + `void handler(error_code error, std::size_t bytes_transferred)` |
| 120 | + If the handler has an associated immediate executor, |
| 121 | + an immediate completion will be dispatched to it. |
| 122 | + Otherwise, the handler will not be invoked from within |
| 123 | + this function. Invocation of the handler will be performed |
| 124 | + by dispatching to the immediate executor. If no |
| 125 | + immediate executor is specified, this is equivalent |
| 126 | + to using `net::post`. |
| 127 | +
|
| 128 | + @note The `async_read_some` operation may not receive all of the requested |
| 129 | + number of bytes. Consider using the function `net::async_read` if you need |
| 130 | + to ensure that the requested amount of data is read before the asynchronous |
| 131 | + operation completes. |
| 132 | +
|
| 133 | + @par Per-Operation Cancellation |
| 134 | +
|
| 135 | + This asynchronous operation supports cancellation for the following |
| 136 | + net::cancellation_type values: |
| 137 | +
|
| 138 | + @li @c net::cancellation_type::terminal |
| 139 | + @li @c net::cancellation_type::partial |
| 140 | + @li @c net::cancellation_type::total |
| 141 | +
|
| 142 | + if they are also supported by the underlying stream's @c async_read_some |
| 143 | + operation. |
| 144 | + */ |
| 145 | + template< |
| 146 | + class MutableBufferSequence, |
| 147 | + BOOST_ASIO_COMPLETION_TOKEN_FOR( |
| 148 | + void(system::error_code, std::size_t)) CompletionToken> |
| 149 | + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, |
| 150 | + void(system::error_code, std::size_t)) |
| 151 | + async_read_some( |
| 152 | + MutableBufferSequence mb, |
| 153 | + CompletionToken&& handler); |
| 154 | + |
| 155 | +private: |
| 156 | + AsyncReadStream& us_; |
| 157 | + http_proto::parser& pr_; |
| 158 | +}; |
| 159 | + |
| 160 | +} // beast2 |
| 161 | +} // boost |
| 162 | + |
| 163 | +#include <boost/beast2/impl/body_read_stream.hpp> |
| 164 | + |
| 165 | +#endif |
0 commit comments