Skip to content

Commit 32e2162

Browse files
committed
Create body_write_stream
1 parent eebe8ca commit 32e2162

4 files changed

Lines changed: 1103 additions & 0 deletions

File tree

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
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_BEAST2_BODY_WRITE_STREAM_HPP
11+
#define BOOST_BEAST2_BODY_WRITE_STREAM_HPP
12+
13+
#include <boost/asio/async_result.hpp>
14+
#include <boost/http_proto/serializer.hpp>
15+
#include <boost/system/error_code.hpp>
16+
17+
#include <utility>
18+
19+
namespace boost {
20+
namespace beast2 {
21+
22+
/** A body writer for HTTP/1 messages.
23+
24+
This type is modelled on asio's AsyncWriteStream, and is constructed with a
25+
reference to an underlying AsyncWriteStream.
26+
27+
Any call to `async_write_some` initially triggers writes to the underlying
28+
stream until all of the HTTP headers and at least one byte of the body have
29+
been written and processed. Thereafter, each subsequent call to
30+
`async_write_some` processes at least one byte of the body, triggering, where
31+
required, calls to the underlying stream's `async_write_some` method. The
32+
body data is read from the referenced ConstBufferSequence.
33+
34+
All processing depends on a beast2::serializer object owned by the caller and
35+
referenced in the construction of this object.
36+
37+
@par Deviations from AsyncWriteStream
38+
39+
This type deviates from the strict AsyncWriteStream requirements in the
40+
following ways:
41+
42+
@li <b>Deferred error reporting:</b> If an error or cancellation occurs
43+
after data has been successfully committed to the serializer, the
44+
operation completes with success and reports the number of bytes
45+
consumed. The error is saved and reported on the next call to
46+
`async_write_some`. This differs from the AsyncWriteStream requirement
47+
that on error, `bytes_transferred` must be 0. This behaviour ensures
48+
that the caller knows exactly how many bytes were consumed by the
49+
serializer, preventing data loss or duplication.
50+
51+
@see
52+
@ref http_proto::serializer.
53+
*/
54+
template<class AsyncWriteStream>
55+
class body_write_stream
56+
{
57+
58+
public:
59+
/** The type of the executor associated with the stream.
60+
61+
This will be the type of executor used to invoke completion handlers
62+
which do not have an explicit associated executor.
63+
*/
64+
using executor_type =
65+
decltype(std::declval<AsyncWriteStream&>().get_executor());
66+
67+
/** Return the executor associated with the object.
68+
69+
This function may be used to obtain the executor object that the stream
70+
uses to dispatch completion handlers without an associated executor.
71+
72+
@return A copy of the executor that stream will use to dispatch
73+
handlers.
74+
*/
75+
executor_type
76+
get_executor()
77+
{
78+
return stream_.get_executor();
79+
}
80+
81+
/** Constructor
82+
83+
This constructor creates the stream which retains a reference to the
84+
underlying stream. The underlying stream then needs to be open before
85+
data can be written
86+
87+
@param s The underlying stream to which the HTTP message is written.
88+
This object's executor is initialized to that of the
89+
underlying stream.
90+
91+
@param sr A http_proto::serializer object which will perform the serialization of
92+
the HTTP message and extraction of the body. This must be
93+
initialized by the caller and ownership of the serializer is
94+
retained by the caller, which must guarantee that it remains
95+
valid until the handler is called.
96+
97+
@param srs A http_proto::serializer::stream object which must have been
98+
obtained by a call to `start_stream` on `sr`. Ownership of the
99+
serializer::stream is
100+
retained by the caller, which must guarantee that it remains
101+
valid until the handler is called.
102+
*/
103+
explicit body_write_stream(
104+
AsyncWriteStream& s,
105+
http_proto::serializer& sr,
106+
http_proto::serializer::stream& srs);
107+
108+
/** Write some data asynchronously.
109+
110+
This function is used to asynchronously write data to the stream.
111+
112+
This call always returns immediately. The asynchronous operation will
113+
continue until one of the following conditions is true:
114+
115+
@li One or more bytes are written from `cb` to the body stored in the
116+
serializer and one or more bytes are written from the serializer to the
117+
underlying stream.
118+
119+
@li An error occurs.
120+
121+
The algorithm, known as a <em>composed asynchronous operation</em>, is
122+
implemented in terms of calls to the underlying stream's
123+
`async_write_some` function. The program must ensure that no other calls
124+
implemented using the underlying stream's `async_write_some` are
125+
performed until this operation completes.
126+
127+
@param cb The buffer sequence from which the body data will be read. If
128+
the size of the buffer sequence is zero bytes, the operation always
129+
completes immediately with no error. Although the buffers object may be
130+
copied as necessary, ownership of the underlying memory blocks is
131+
retained by the caller, which must guarantee that they remain valid until
132+
the handler is called. Where the internal buffer of the contained
133+
serializer is not of sufficient size to hold the data to be copied from
134+
cb, the remainder may be written by subsequent calls to this function.
135+
136+
@param handler The completion handler to invoke when the operation
137+
completes. The implementation takes ownership of the handler by
138+
performing a decay-copy. The equivalent function signature of the
139+
handler must be:
140+
@code
141+
void handler(
142+
error_code const& error, // result of operation
143+
std::size_t bytes_transferred // the number of bytes consumed from
144+
// cb by the serializer
145+
);
146+
@endcode
147+
Regardless of whether the asynchronous operation
148+
completes immediately or not, the completion handler will not be invoked
149+
from within this function. On immediate completion, invocation of the
150+
handler will be performed in a manner equivalent to using
151+
`asio::async_immediate`.
152+
153+
@note The `async_write_some` operation may not transmit all of the
154+
requested number of bytes. Consider using the function
155+
`asio::async_write` if you need to ensure that the requested amount of
156+
data is written before the asynchronous operation completes.
157+
158+
@note This function does not guarantee that all of the consumed data is
159+
written to the underlying stream. For this reason one or more calls to
160+
`async_write_some` must be followed by a call to `async_close` to put the
161+
serializer into the `done` state and to write all data remaining in the
162+
serializer to the underlying stream.
163+
164+
@par Per-Operation Cancellation
165+
166+
This asynchronous operation supports cancellation for the following
167+
net::cancellation_type values:
168+
169+
@li @c net::cancellation_type::terminal
170+
@li @c net::cancellation_type::partial
171+
@li @c net::cancellation_type::total
172+
173+
if they are also supported by the underlying stream's @c async_write_some
174+
operation.
175+
*/
176+
template<
177+
class ConstBufferSequence,
178+
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(system::error_code, std::size_t))
179+
CompletionToken>
180+
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
181+
CompletionToken,
182+
void(system::error_code, std::size_t))
183+
async_write_some(ConstBufferSequence const& cb, CompletionToken&& handler);
184+
185+
/** Close serializer::stream and flush remaining data to the underlying stream asynchronously.
186+
187+
This function is used to asynchronously call `close` on the
188+
`serializer::stream` object referenced in the construction of this
189+
`body_write_stream` and write all remaining data in the serializer to the
190+
underlying stream.
191+
192+
This call always returns immediately. The asynchronous operation will
193+
continue until one of the following conditions is true:
194+
195+
@li All remaining output bytes of the serializer are written to the
196+
underlying stream and the serializer's `is_done()` method returns true.
197+
198+
@li An error occurs.
199+
200+
The algorithm, known as a <em>composed asynchronous operation</em>, is
201+
implemented in terms of calls to the underlying stream's
202+
`async_write_some` function. The program must ensure that no other calls
203+
implemented using the underlying stream's `async_write_some` are
204+
performed until this operation completes.
205+
206+
@param handler The completion handler to invoke when the operation
207+
completes. The implementation takes ownership of the handler by
208+
performing a decay-copy. The equivalent function signature of the
209+
handler must be:
210+
@code
211+
void handler(
212+
error_code const& error // result of operation
213+
);
214+
@endcode
215+
Regardless of whether the asynchronous operation
216+
completes immediately or not, the completion handler will not be invoked
217+
from within this function. On immediate completion, invocation of the
218+
handler will be performed in a manner equivalent to using
219+
`asio::async_immediate`.
220+
221+
@par Per-Operation Cancellation
222+
223+
This asynchronous operation supports cancellation for the following
224+
net::cancellation_type values:
225+
226+
@li @c net::cancellation_type::terminal
227+
@li @c net::cancellation_type::partial
228+
@li @c net::cancellation_type::total
229+
230+
if they are also supported by the underlying stream's @c async_write_some
231+
operation.
232+
*/
233+
template<
234+
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(system::error_code))
235+
CompletionToken>
236+
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
237+
CompletionToken,
238+
void(system::error_code))
239+
async_close(CompletionToken&& handler);
240+
241+
private:
242+
AsyncWriteStream& stream_;
243+
http_proto::serializer& sr_;
244+
http_proto::serializer::stream& srs_;
245+
system::error_code ec_;
246+
};
247+
248+
} // beast2
249+
} // boost
250+
251+
#include <boost/beast2/impl/body_write_stream.hpp>
252+
253+
#endif // BOOST_BEAST2_BODY_WRITE_STREAM_HPP

0 commit comments

Comments
 (0)