1212
1313#include < boost/beast2/write.hpp>
1414
15+ #include < boost/assert.hpp>
1516#include < boost/asio/buffer.hpp>
1617#include < boost/asio/buffers_iterator.hpp>
1718#include < boost/asio/coroutine.hpp>
@@ -24,18 +25,12 @@ namespace detail {
2425template <class AsyncWriteStream >
2526class body_write_stream_close_op : public asio ::coroutine
2627{
27- AsyncWriteStream& stream_;
28- http_proto::serializer& sr_;
29- http_proto::serializer::stream& srs_;
28+ body_write_stream<AsyncWriteStream>& bws_;
3029
3130public:
3231 body_write_stream_close_op (
33- AsyncWriteStream& s,
34- http_proto::serializer& sr,
35- http_proto::serializer::stream& srs) noexcept
36- : stream_(s)
37- , sr_(sr)
38- , srs_(srs)
32+ body_write_stream<AsyncWriteStream>& bws) noexcept
33+ : bws_(bws)
3934 {
4035 }
4136
@@ -50,15 +45,33 @@ class body_write_stream_close_op : public asio::coroutine
5045 {
5146 self.reset_cancellation_state (asio::enable_total_cancellation ());
5247
53- srs_.close ();
48+ // Check for a saved error from a previous async_write_some call.
49+ if (bws_.ec_ .failed ())
50+ {
51+ ec = bws_.ec_ ;
52+ bws_.ec_ = {};
53+ BOOST_ASIO_CORO_YIELD
54+ {
55+ BOOST_ASIO_HANDLER_LOCATION (
56+ (__FILE__, __LINE__, " immediate" ));
57+ auto io_ex = self.get_io_executor ();
58+ asio::async_immediate (
59+ io_ex,
60+ asio::append (std::move (self), ec));
61+ }
62+ goto upcall;
63+ }
64+
65+ bws_.srs_ .close ();
5466
5567 BOOST_ASIO_CORO_YIELD
5668 {
5769 BOOST_ASIO_HANDLER_LOCATION (
5870 (__FILE__, __LINE__, " async_write_some" ));
59- beast2::async_write (stream_, sr_, std::move (self));
71+ beast2::async_write (bws_. stream_ , bws_. sr_ , std::move (self));
6072 }
6173
74+ upcall:
6275 self.complete (ec);
6376 }
6477 }
@@ -67,25 +80,16 @@ class body_write_stream_close_op : public asio::coroutine
6780template <class ConstBufferSequence , class AsyncWriteStream >
6881class body_write_stream_op : public asio ::coroutine
6982{
70- AsyncWriteStream& stream_ ;
83+ body_write_stream< AsyncWriteStream>& bws_ ;
7184 ConstBufferSequence cb_;
72- http_proto::serializer& sr_;
73- http_proto::serializer::stream& srs_;
74- system::error_code& saved_ec_;
7585 std::size_t bytes_;
7686
7787public:
7888 body_write_stream_op (
79- AsyncWriteStream& s,
80- ConstBufferSequence const & cb,
81- http_proto::serializer& sr,
82- http_proto::serializer::stream& srs,
83- system::error_code& saved_ec) noexcept
84- : stream_(s)
89+ body_write_stream<AsyncWriteStream>& bws,
90+ ConstBufferSequence const & cb) noexcept
91+ : bws_(bws)
8592 , cb_(cb)
86- , sr_(sr)
87- , srs_(srs)
88- , saved_ec_(saved_ec)
8993 , bytes_(0 )
9094 {
9195 }
@@ -99,28 +103,19 @@ class body_write_stream_op : public asio::coroutine
99103 {
100104 BOOST_ASIO_CORO_REENTER (*this )
101105 {
102- self.reset_cancellation_state (asio::enable_total_cancellation ());
106+ // Verify preconditions
107+ BOOST_ASSERT (!bws_.sr_ .is_done ());
103108
104- bytes_ = 0 ;
109+ self. reset_cancellation_state ( asio::enable_total_cancellation ()) ;
105110
106- // Check for a saved error from a previous call
107- if (saved_ec_.failed ())
108- {
109- ec = saved_ec_;
110- saved_ec_ = {};
111- }
112- else if (buffers::size (cb_) == 0 )
113- // A zero-sized buffer is a special case, we are required to
114- // complete immediately with no error.
115- ;
116- else if (sr_.is_done () ||
117- !srs_.is_open ())
118- // The serializer and stream are in the wrong state.
119- ec = asio::error::not_connected;
120-
121- if (ec.failed () ||
111+ // A zero-sized buffer is a special case, we are required to
112+ // complete immediately with no error. Also check for a saved
113+ // error from a previous call.
114+ if (bws_.ec_ .failed () ||
122115 buffers::size (cb_) == 0 )
123116 {
117+ ec = bws_.ec_ ;
118+ bws_.ec_ = {};
124119 BOOST_ASIO_CORO_YIELD
125120 {
126121 BOOST_ASIO_HANDLER_LOCATION (
@@ -137,39 +132,36 @@ class body_write_stream_op : public asio::coroutine
137132 // option but to try to write to the stream to clear space.
138133 // This may require multiple attempts as buffer space cannot
139134 // be cleared until the headers have been written.
140- while (!(bytes_ = asio::buffer_copy (srs_. prepare (), cb_)) )
135+ for (;; )
141136 {
137+ bytes_ = asio::buffer_copy (bws_.srs_ .prepare (), cb_);
138+ bws_.srs_ .commit (bytes_);
139+
142140 BOOST_ASIO_CORO_YIELD
143141 {
144142 BOOST_ASIO_HANDLER_LOCATION (
145143 (__FILE__, __LINE__, " async_write_some" ));
146- async_write_some (stream_, sr_, std::move (self));
144+ async_write_some (bws_. stream_ , bws_. sr_ , std::move (self));
147145 }
148146
149- if (sr_.is_done () ||
150- !srs_.is_open ())
151- ec = asio::error::not_connected;
152- else if (!!self.cancelled ())
153- ec = asio::error::operation_aborted;
154-
155147 if (ec.failed ())
156- goto upcall;
157- }
158- srs_.commit (bytes_);
148+ {
149+ if (bytes_ != 0 )
150+ {
151+ bws_.ec_ = ec;
152+ ec = {};
153+ }
154+ break ;
155+ }
159156
160- BOOST_ASIO_CORO_YIELD
161- {
162- BOOST_ASIO_HANDLER_LOCATION (
163- (__FILE__, __LINE__, " async_write_some" ));
164- beast2::async_write_some (stream_, sr_, std::move (self));
165- }
157+ if (bytes_ != 0 )
158+ break ;
166159
167- // Save error/cancellation for next call, but report success with bytes
168- if (ec.failed () ||
169- !!self.cancelled ())
170- {
171- saved_ec_ = ec.failed () ? ec : asio::error::operation_aborted;
172- ec = {};
160+ if (!!self.cancelled ())
161+ {
162+ ec = asio::error::operation_aborted;
163+ break ;
164+ }
173165 }
174166
175167 upcall:
@@ -190,11 +182,13 @@ body_write_stream<AsyncWriteStream>::
190182body_write_stream (
191183 AsyncWriteStream& s,
192184 http_proto::serializer& sr,
193- http_proto::serializer::stream& srs)
185+ http_proto::serializer::stream srs)
194186 : stream_(s)
195187 , sr_(sr)
196- , srs_(srs)
188+ , srs_(std::move( srs) )
197189{
190+ // Verify preconditions
191+ BOOST_ASSERT (srs_.is_open ());
198192}
199193
200194template <class AsyncWriteStream >
@@ -213,7 +207,7 @@ async_write_some(
213207 return asio::
214208 async_compose<CompletionToken, void (system::error_code, std::size_t )>(
215209 detail::body_write_stream_op<ConstBufferSequence, AsyncWriteStream>{
216- stream_ , cb, sr_, srs_, ec_ },
210+ * this , cb },
217211 token,
218212 stream_);
219213}
@@ -231,8 +225,7 @@ async_close(
231225{
232226 return asio::
233227 async_compose<CompletionToken, void (system::error_code)>(
234- detail::body_write_stream_close_op<AsyncWriteStream>{
235- stream_, sr_, srs_ },
228+ detail::body_write_stream_close_op<AsyncWriteStream>{ *this },
236229 token,
237230 stream_);
238231}
0 commit comments