Skip to content

Commit 6d83768

Browse files
committed
Create body_write_stream
1 parent a456c0f commit 6d83768

File tree

4 files changed

+1334
-0
lines changed

4 files changed

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

0 commit comments

Comments
 (0)