@@ -25,19 +25,22 @@ namespace http_io {
2525namespace detail {
2626
2727template <class AsyncStream >
28- class read_header_op
28+ class read_until_op
2929 : public asio::coroutine
3030{
3131 AsyncStream& stream_;
3232 http_proto::parser& pr_;
3333 std::size_t total_bytes_ = 0 ;
34+ bool (&condition_)(http_proto::parser&);
3435
3536public:
36- read_header_op (
37+ read_until_op (
3738 AsyncStream& s,
38- http_proto::parser& pr) noexcept
39+ http_proto::parser& pr,
40+ bool (&condition)(http_proto::parser&)) noexcept
3941 : stream_(s)
4042 , pr_(pr)
43+ , condition_(condition)
4144 {
4245 }
4346
@@ -50,20 +53,34 @@ class read_header_op
5053 {
5154 BOOST_ASIO_CORO_REENTER (*this )
5255 {
53- if (pr_.got_header ())
56+ self.reset_cancellation_state (
57+ asio::enable_total_cancellation ());
58+
59+ for (;;)
5460 {
55- BOOST_ASIO_CORO_YIELD
61+ for (;;)
5662 {
57- BOOST_ASIO_HANDLER_LOCATION ((
58- __FILE__, __LINE__,
59- " immediate" ));
60- asio::async_immediate (
61- self.get_io_executor (), std::move (self));
63+ pr_.parse (ec);
64+ if (ec == http_proto::condition::need_more_input)
65+ break ;
66+ if (ec.failed () || condition_ (pr_))
67+ {
68+ if (total_bytes_ == 0 )
69+ {
70+ BOOST_ASIO_CORO_YIELD
71+ {
72+ BOOST_ASIO_HANDLER_LOCATION ((
73+ __FILE__, __LINE__,
74+ " immediate" ));
75+ auto io_ex = self.get_io_executor ();
76+ asio::async_immediate (
77+ io_ex,
78+ asio::append (std::move (self), ec));
79+ }
80+ }
81+ goto upcall;
82+ }
6283 }
63- goto upcall;
64- }
65- for (;;)
66- {
6784 BOOST_ASIO_CORO_YIELD
6885 {
6986 BOOST_ASIO_HANDLER_LOCATION ((
@@ -86,14 +103,6 @@ class read_header_op
86103 {
87104 goto upcall;
88105 }
89- pr_.parse (ec);
90- if (ec != http_proto::condition::need_more_input)
91- break ;
92- if (pr_.got_header ())
93- {
94- ec = {}; // override possible need_more_input
95- break ;
96- }
97106 }
98107
99108 upcall:
@@ -102,97 +111,19 @@ class read_header_op
102111 }
103112};
104113
105- // ------------------------------------------------
106-
107- template <class AsyncStream >
108- class read_body_op
109- : public asio::coroutine
114+ inline
115+ bool
116+ got_header_condition (http_proto::parser& pr)
110117{
111- AsyncStream& stream_;
112- http_proto::parser& pr_;
113- std::size_t total_bytes_ = 0 ;
114- bool some_;
115-
116- public:
117- read_body_op (
118- AsyncStream& s,
119- http_proto::parser& pr,
120- bool some)
121- : stream_(s)
122- , pr_(pr)
123- , some_(some)
124- {
125- }
126-
127- template <class Self >
128- void
129- operator ()(
130- Self& self,
131- system::error_code ec = {},
132- std::size_t bytes_transferred = 0 )
133- {
134- BOOST_ASIO_CORO_REENTER (*this )
135- {
136- pr_.parse (ec);
137- if (ec != http_proto::condition::need_more_input)
138- {
139- BOOST_ASIO_CORO_YIELD
140- {
141- BOOST_ASIO_HANDLER_LOCATION ((
142- __FILE__, __LINE__,
143- " immediate" ));
144- auto io_ex = self.get_io_executor ();
145- asio::async_immediate (
146- io_ex,
147- asio::append (std::move (self), ec));
148- }
149- goto upcall;
150- }
151- for (;;)
152- {
153- BOOST_ASIO_CORO_YIELD
154- {
155- BOOST_ASIO_HANDLER_LOCATION ((
156- __FILE__, __LINE__,
157- " async_read_some" ));
158- stream_.async_read_some (
159- pr_.prepare (),
160- std::move (self));
161- }
162- pr_.commit (bytes_transferred);
163- total_bytes_ += bytes_transferred;
164- if (ec == asio::error::eof)
165- {
166- BOOST_ASSERT (
167- bytes_transferred == 0 );
168- pr_.commit_eof ();
169- ec = {};
170- }
171- else if (ec.failed ())
172- {
173- goto upcall;
174- }
175- pr_.parse (ec);
176- if (! ec.failed ())
177- {
178- BOOST_ASSERT (
179- pr_.is_complete ());
180- break ;
181- }
182- if (ec != http_proto::condition::need_more_input)
183- break ;
184- if (some_)
185- {
186- ec = {};
187- break ;
188- }
189- }
118+ return pr.got_header ();
119+ }
190120
191- upcall:
192- self.complete (ec, total_bytes_);
193- }
194- }
195- };
121+ inline
122+ bool
123+ is_complete_condition (http_proto::parser& pr)
124+ {
125+ return pr.is_complete ();
126+ }
196127
197128} // detail
198129
@@ -204,16 +135,16 @@ template<
204135 void (system::error_code, std::size_t )) CompletionToken>
205136BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
206137 void (system::error_code, std::size_t ))
207- async_read_header (
138+ async_read_some (
208139 AsyncReadStream& s,
209140 http_proto::parser& pr,
210141 CompletionToken&& token)
211142{
212143 return asio::async_compose<
213144 CompletionToken,
214145 void (system::error_code, std::size_t )>(
215- detail::read_header_op<
216- AsyncReadStream> {s, pr},
146+ detail::read_until_op<AsyncReadStream>
147+ {s, pr, detail::got_header_condition },
217148 token,
218149 s);
219150}
@@ -224,22 +155,12 @@ template<
224155 void (system::error_code, std::size_t )) CompletionToken>
225156BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
226157 void (system::error_code, std::size_t ))
227- async_read_some (
158+ async_read_header (
228159 AsyncReadStream& s,
229160 http_proto::parser& pr,
230161 CompletionToken&& token)
231162{
232- // header must be read first!
233- if (! pr.got_header ())
234- detail::throw_logic_error ();
235-
236- return asio::async_compose<
237- CompletionToken,
238- void (system::error_code, std::size_t )>(
239- detail::read_body_op<
240- AsyncReadStream>{s, pr, true },
241- token,
242- s);
163+ return async_read_some (s, pr, std::move (token));
243164}
244165
245166template <
@@ -253,15 +174,11 @@ async_read(
253174 http_proto::parser& pr,
254175 CompletionToken&& token)
255176{
256- // header must be read first!
257- if (! pr.got_header ())
258- detail::throw_logic_error ();
259-
260177 return asio::async_compose<
261178 CompletionToken,
262179 void (system::error_code, std::size_t )>(
263- detail::read_body_op<
264- AsyncReadStream> {s, pr, false },
180+ detail::read_until_op<AsyncReadStream>
181+ {s, pr, detail::is_complete_condition },
265182 token,
266183 s);
267184}
0 commit comments