Skip to content

Commit e14d19e

Browse files
committed
Create body_write_stream (initial wip)
1 parent b64bc65 commit e14d19e

4 files changed

Lines changed: 1016 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)