]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
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/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP | |
11 | #define BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP | |
12 | ||
13 | #include <boost/beast/http/type_traits.hpp> | |
14 | #include <boost/beast/http/error.hpp> | |
15 | #include <boost/beast/http/parser.hpp> | |
16 | #include <boost/beast/http/read.hpp> | |
17 | #include <boost/beast/core/bind_handler.hpp> | |
18 | #include <boost/beast/core/handler_ptr.hpp> | |
19 | #include <boost/beast/core/read_size.hpp> | |
20 | #include <boost/beast/core/type_traits.hpp> | |
21 | #include <boost/asio/associated_allocator.hpp> | |
22 | #include <boost/asio/associated_executor.hpp> | |
11fdf7f2 | 23 | #include <boost/asio/coroutine.hpp> |
b32b8144 | 24 | #include <boost/asio/handler_continuation_hook.hpp> |
11fdf7f2 | 25 | #include <boost/asio/handler_invoke_hook.hpp> |
b32b8144 FG |
26 | #include <boost/asio/post.hpp> |
27 | #include <boost/assert.hpp> | |
28 | #include <boost/config.hpp> | |
29 | #include <boost/optional.hpp> | |
30 | #include <boost/throw_exception.hpp> | |
31 | ||
32 | namespace boost { | |
33 | namespace beast { | |
34 | namespace http { | |
35 | ||
36 | namespace detail { | |
37 | ||
38 | //------------------------------------------------------------------------------ | |
39 | ||
40 | template<class Stream, class DynamicBuffer, | |
41 | bool isRequest, class Derived, class Handler> | |
42 | class read_some_op | |
11fdf7f2 | 43 | : public boost::asio::coroutine |
b32b8144 | 44 | { |
b32b8144 FG |
45 | Stream& s_; |
46 | DynamicBuffer& b_; | |
47 | basic_parser<isRequest, Derived>& p_; | |
b32b8144 FG |
48 | std::size_t bytes_transferred_ = 0; |
49 | Handler h_; | |
11fdf7f2 | 50 | bool cont_ = false; |
b32b8144 FG |
51 | |
52 | public: | |
53 | read_some_op(read_some_op&&) = default; | |
11fdf7f2 | 54 | read_some_op(read_some_op const&) = delete; |
b32b8144 FG |
55 | |
56 | template<class DeducedHandler> | |
57 | read_some_op(DeducedHandler&& h, Stream& s, | |
58 | DynamicBuffer& b, basic_parser<isRequest, Derived>& p) | |
59 | : s_(s) | |
60 | , b_(b) | |
61 | , p_(p) | |
62 | , h_(std::forward<DeducedHandler>(h)) | |
63 | { | |
64 | } | |
65 | ||
66 | using allocator_type = | |
67 | boost::asio::associated_allocator_t<Handler>; | |
68 | ||
69 | allocator_type | |
70 | get_allocator() const noexcept | |
71 | { | |
11fdf7f2 | 72 | return (boost::asio::get_associated_allocator)(h_); |
b32b8144 FG |
73 | } |
74 | ||
75 | using executor_type = boost::asio::associated_executor_t< | |
76 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
77 | ||
78 | executor_type | |
79 | get_executor() const noexcept | |
80 | { | |
11fdf7f2 | 81 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
82 | h_, s_.get_executor()); |
83 | } | |
84 | ||
85 | void | |
86 | operator()( | |
11fdf7f2 TL |
87 | error_code ec, |
88 | std::size_t bytes_transferred = 0, | |
89 | bool cont = true); | |
b32b8144 FG |
90 | |
91 | friend | |
92 | bool asio_handler_is_continuation(read_some_op* op) | |
93 | { | |
94 | using boost::asio::asio_handler_is_continuation; | |
11fdf7f2 | 95 | return op->cont_ ? true : |
b32b8144 FG |
96 | asio_handler_is_continuation( |
97 | std::addressof(op->h_)); | |
98 | } | |
11fdf7f2 TL |
99 | |
100 | template<class Function> | |
101 | friend | |
102 | void asio_handler_invoke(Function&& f, read_some_op* op) | |
103 | { | |
104 | using boost::asio::asio_handler_invoke; | |
105 | asio_handler_invoke(f, std::addressof(op->h_)); | |
106 | } | |
b32b8144 FG |
107 | }; |
108 | ||
109 | template<class Stream, class DynamicBuffer, | |
110 | bool isRequest, class Derived, class Handler> | |
111 | void | |
112 | read_some_op<Stream, DynamicBuffer, | |
113 | isRequest, Derived, Handler>:: | |
114 | operator()( | |
115 | error_code ec, | |
11fdf7f2 TL |
116 | std::size_t bytes_transferred, |
117 | bool cont) | |
b32b8144 | 118 | { |
11fdf7f2 TL |
119 | cont_ = cont; |
120 | boost::optional<typename | |
121 | DynamicBuffer::mutable_buffers_type> mb; | |
122 | BOOST_ASIO_CORO_REENTER(*this) | |
b32b8144 | 123 | { |
b32b8144 FG |
124 | if(b_.size() == 0) |
125 | goto do_read; | |
11fdf7f2 | 126 | for(;;) |
b32b8144 | 127 | { |
11fdf7f2 | 128 | // parse |
b32b8144 | 129 | { |
11fdf7f2 TL |
130 | auto const used = p_.put(b_.data(), ec); |
131 | bytes_transferred_ += used; | |
132 | b_.consume(used); | |
b32b8144 | 133 | } |
11fdf7f2 TL |
134 | if(ec != http::error::need_more) |
135 | break; | |
b32b8144 | 136 | |
11fdf7f2 TL |
137 | do_read: |
138 | try | |
139 | { | |
140 | mb.emplace(b_.prepare( | |
141 | read_size_or_throw(b_, 65536))); | |
142 | } | |
143 | catch(std::length_error const&) | |
144 | { | |
145 | ec = error::buffer_overflow; | |
146 | break; | |
147 | } | |
148 | BOOST_ASIO_CORO_YIELD | |
149 | s_.async_read_some(*mb, std::move(*this)); | |
150 | if(ec == boost::asio::error::eof) | |
151 | { | |
152 | BOOST_ASSERT(bytes_transferred == 0); | |
153 | if(p_.got_some()) | |
154 | { | |
155 | // caller sees EOF on next read | |
156 | ec.assign(0, ec.category()); | |
157 | p_.put_eof(ec); | |
158 | if(ec) | |
159 | goto upcall; | |
160 | BOOST_ASSERT(p_.is_done()); | |
161 | goto upcall; | |
162 | } | |
163 | ec = error::end_of_stream; | |
164 | break; | |
165 | } | |
166 | if(ec) | |
167 | break; | |
168 | b_.commit(bytes_transferred); | |
b32b8144 | 169 | } |
b32b8144 | 170 | |
11fdf7f2 TL |
171 | upcall: |
172 | if(! cont_) | |
173 | return boost::asio::post( | |
174 | s_.get_executor(), | |
175 | bind_handler(std::move(h_), | |
176 | ec, bytes_transferred_)); | |
177 | h_(ec, bytes_transferred_); | |
b32b8144 | 178 | } |
b32b8144 FG |
179 | } |
180 | ||
181 | //------------------------------------------------------------------------------ | |
182 | ||
183 | struct parser_is_done | |
184 | { | |
185 | template<bool isRequest, class Derived> | |
186 | bool | |
187 | operator()(basic_parser< | |
188 | isRequest, Derived> const& p) const | |
189 | { | |
190 | return p.is_done(); | |
191 | } | |
192 | }; | |
193 | ||
194 | struct parser_is_header_done | |
195 | { | |
196 | template<bool isRequest, class Derived> | |
197 | bool | |
198 | operator()(basic_parser< | |
199 | isRequest, Derived> const& p) const | |
200 | { | |
201 | return p.is_header_done(); | |
202 | } | |
203 | }; | |
204 | ||
205 | template<class Stream, class DynamicBuffer, | |
206 | bool isRequest, class Derived, class Condition, | |
207 | class Handler> | |
208 | class read_op | |
11fdf7f2 | 209 | : public boost::asio::coroutine |
b32b8144 | 210 | { |
b32b8144 FG |
211 | Stream& s_; |
212 | DynamicBuffer& b_; | |
213 | basic_parser<isRequest, Derived>& p_; | |
214 | std::size_t bytes_transferred_ = 0; | |
215 | Handler h_; | |
11fdf7f2 | 216 | bool cont_ = false; |
b32b8144 FG |
217 | |
218 | public: | |
219 | read_op(read_op&&) = default; | |
11fdf7f2 | 220 | read_op(read_op const&) = delete; |
b32b8144 FG |
221 | |
222 | template<class DeducedHandler> | |
223 | read_op(DeducedHandler&& h, Stream& s, | |
224 | DynamicBuffer& b, basic_parser<isRequest, | |
225 | Derived>& p) | |
226 | : s_(s) | |
227 | , b_(b) | |
228 | , p_(p) | |
229 | , h_(std::forward<DeducedHandler>(h)) | |
230 | { | |
231 | } | |
232 | ||
233 | using allocator_type = | |
234 | boost::asio::associated_allocator_t<Handler>; | |
235 | ||
236 | allocator_type | |
237 | get_allocator() const noexcept | |
238 | { | |
11fdf7f2 | 239 | return (boost::asio::get_associated_allocator)(h_); |
b32b8144 FG |
240 | } |
241 | ||
242 | using executor_type = boost::asio::associated_executor_t< | |
243 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
244 | ||
245 | executor_type | |
246 | get_executor() const noexcept | |
247 | { | |
11fdf7f2 | 248 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
249 | h_, s_.get_executor()); |
250 | } | |
251 | ||
252 | void | |
253 | operator()( | |
11fdf7f2 TL |
254 | error_code ec, |
255 | std::size_t bytes_transferred = 0, | |
256 | bool cont = true); | |
b32b8144 FG |
257 | |
258 | friend | |
259 | bool asio_handler_is_continuation(read_op* op) | |
260 | { | |
261 | using boost::asio::asio_handler_is_continuation; | |
11fdf7f2 | 262 | return op->cont_ ? true : |
b32b8144 FG |
263 | asio_handler_is_continuation( |
264 | std::addressof(op->h_)); | |
265 | } | |
11fdf7f2 TL |
266 | |
267 | template<class Function> | |
268 | friend | |
269 | void asio_handler_invoke(Function&& f, read_op* op) | |
270 | { | |
271 | using boost::asio::asio_handler_invoke; | |
272 | asio_handler_invoke(f, std::addressof(op->h_)); | |
273 | } | |
b32b8144 FG |
274 | }; |
275 | ||
276 | template<class Stream, class DynamicBuffer, | |
277 | bool isRequest, class Derived, class Condition, | |
278 | class Handler> | |
279 | void | |
280 | read_op<Stream, DynamicBuffer, | |
281 | isRequest, Derived, Condition, Handler>:: | |
282 | operator()( | |
283 | error_code ec, | |
11fdf7f2 TL |
284 | std::size_t bytes_transferred, |
285 | bool cont) | |
b32b8144 | 286 | { |
11fdf7f2 TL |
287 | cont_ = cont; |
288 | BOOST_ASIO_CORO_REENTER(*this) | |
b32b8144 | 289 | { |
b32b8144 FG |
290 | if(Condition{}(p_)) |
291 | { | |
11fdf7f2 TL |
292 | BOOST_ASIO_CORO_YIELD |
293 | boost::asio::post(s_.get_executor(), | |
b32b8144 | 294 | bind_handler(std::move(*this), ec)); |
b32b8144 | 295 | goto upcall; |
11fdf7f2 TL |
296 | } |
297 | for(;;) | |
298 | { | |
299 | BOOST_ASIO_CORO_YIELD | |
300 | async_read_some( | |
301 | s_, b_, p_, std::move(*this)); | |
302 | if(ec) | |
303 | goto upcall; | |
304 | bytes_transferred_ += bytes_transferred; | |
305 | if(Condition{}(p_)) | |
306 | goto upcall; | |
307 | } | |
308 | upcall: | |
309 | h_(ec, bytes_transferred_); | |
b32b8144 | 310 | } |
b32b8144 FG |
311 | } |
312 | ||
313 | //------------------------------------------------------------------------------ | |
314 | ||
315 | template<class Stream, class DynamicBuffer, | |
316 | bool isRequest, class Body, class Allocator, | |
317 | class Handler> | |
318 | class read_msg_op | |
11fdf7f2 | 319 | : public boost::asio::coroutine |
b32b8144 FG |
320 | { |
321 | using parser_type = | |
322 | parser<isRequest, Body, Allocator>; | |
323 | ||
324 | using message_type = | |
325 | typename parser_type::value_type; | |
326 | ||
327 | struct data | |
328 | { | |
b32b8144 FG |
329 | Stream& s; |
330 | DynamicBuffer& b; | |
331 | message_type& m; | |
332 | parser_type p; | |
333 | std::size_t bytes_transferred = 0; | |
11fdf7f2 | 334 | bool cont = false; |
b32b8144 | 335 | |
11fdf7f2 | 336 | data(Handler const&, Stream& s_, |
b32b8144 FG |
337 | DynamicBuffer& b_, message_type& m_) |
338 | : s(s_) | |
339 | , b(b_) | |
340 | , m(m_) | |
341 | , p(std::move(m)) | |
342 | { | |
343 | p.eager(true); | |
344 | } | |
345 | }; | |
346 | ||
347 | handler_ptr<data, Handler> d_; | |
348 | ||
349 | public: | |
350 | read_msg_op(read_msg_op&&) = default; | |
11fdf7f2 | 351 | read_msg_op(read_msg_op const&) = delete; |
b32b8144 FG |
352 | |
353 | template<class DeducedHandler, class... Args> | |
354 | read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) | |
355 | : d_(std::forward<DeducedHandler>(h), | |
356 | s, std::forward<Args>(args)...) | |
357 | { | |
358 | } | |
359 | ||
360 | using allocator_type = | |
361 | boost::asio::associated_allocator_t<Handler>; | |
362 | ||
363 | allocator_type | |
364 | get_allocator() const noexcept | |
365 | { | |
11fdf7f2 | 366 | return (boost::asio::get_associated_allocator)(d_.handler()); |
b32b8144 FG |
367 | } |
368 | ||
369 | using executor_type = boost::asio::associated_executor_t< | |
370 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
371 | ||
372 | executor_type | |
373 | get_executor() const noexcept | |
374 | { | |
11fdf7f2 | 375 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
376 | d_.handler(), d_->s.get_executor()); |
377 | } | |
378 | ||
379 | void | |
380 | operator()( | |
11fdf7f2 TL |
381 | error_code ec, |
382 | std::size_t bytes_transferred = 0, | |
383 | bool cont = true); | |
b32b8144 FG |
384 | |
385 | friend | |
386 | bool asio_handler_is_continuation(read_msg_op* op) | |
387 | { | |
388 | using boost::asio::asio_handler_is_continuation; | |
11fdf7f2 | 389 | return op->d_->cont ? true : |
b32b8144 FG |
390 | asio_handler_is_continuation( |
391 | std::addressof(op->d_.handler())); | |
392 | } | |
11fdf7f2 TL |
393 | |
394 | template<class Function> | |
395 | friend | |
396 | void asio_handler_invoke(Function&& f, read_msg_op* op) | |
397 | { | |
398 | using boost::asio::asio_handler_invoke; | |
399 | asio_handler_invoke(f, std::addressof(op->d_.handler())); | |
400 | } | |
b32b8144 FG |
401 | }; |
402 | ||
403 | template<class Stream, class DynamicBuffer, | |
404 | bool isRequest, class Body, class Allocator, | |
405 | class Handler> | |
406 | void | |
407 | read_msg_op<Stream, DynamicBuffer, | |
408 | isRequest, Body, Allocator, Handler>:: | |
409 | operator()( | |
410 | error_code ec, | |
11fdf7f2 TL |
411 | std::size_t bytes_transferred, |
412 | bool cont) | |
b32b8144 FG |
413 | { |
414 | auto& d = *d_; | |
11fdf7f2 TL |
415 | d.cont = cont; |
416 | BOOST_ASIO_CORO_REENTER(*this) | |
b32b8144 | 417 | { |
11fdf7f2 | 418 | for(;;) |
b32b8144 | 419 | { |
11fdf7f2 TL |
420 | BOOST_ASIO_CORO_YIELD |
421 | async_read_some( | |
422 | d.s, d.b, d.p, std::move(*this)); | |
423 | if(ec) | |
424 | goto upcall; | |
425 | d.bytes_transferred += | |
426 | bytes_transferred; | |
427 | if(d.p.is_done()) | |
428 | { | |
429 | d.m = d.p.release(); | |
430 | goto upcall; | |
431 | } | |
b32b8144 | 432 | } |
11fdf7f2 TL |
433 | upcall: |
434 | bytes_transferred = d.bytes_transferred; | |
435 | d_.invoke(ec, bytes_transferred); | |
b32b8144 | 436 | } |
b32b8144 FG |
437 | } |
438 | ||
439 | } // detail | |
440 | ||
441 | //------------------------------------------------------------------------------ | |
442 | ||
443 | template< | |
444 | class SyncReadStream, | |
445 | class DynamicBuffer, | |
446 | bool isRequest, class Derived> | |
447 | std::size_t | |
448 | read_some( | |
449 | SyncReadStream& stream, | |
450 | DynamicBuffer& buffer, | |
451 | basic_parser<isRequest, Derived>& parser) | |
452 | { | |
453 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
454 | "SyncReadStream requirements not met"); | |
455 | static_assert( | |
456 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
457 | "DynamicBuffer requirements not met"); | |
458 | BOOST_ASSERT(! parser.is_done()); | |
459 | error_code ec; | |
460 | auto const bytes_transferred = | |
461 | read_some(stream, buffer, parser, ec); | |
462 | if(ec) | |
463 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
464 | return bytes_transferred; | |
465 | } | |
466 | ||
467 | template< | |
468 | class SyncReadStream, | |
469 | class DynamicBuffer, | |
470 | bool isRequest, class Derived> | |
471 | std::size_t | |
472 | read_some( | |
473 | SyncReadStream& stream, | |
474 | DynamicBuffer& buffer, | |
475 | basic_parser<isRequest, Derived>& parser, | |
476 | error_code& ec) | |
477 | { | |
478 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
479 | "SyncReadStream requirements not met"); | |
480 | static_assert( | |
481 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
482 | "DynamicBuffer requirements not met"); | |
483 | BOOST_ASSERT(! parser.is_done()); | |
484 | std::size_t bytes_transferred = 0; | |
485 | if(buffer.size() == 0) | |
486 | goto do_read; | |
487 | for(;;) | |
488 | { | |
489 | // invoke parser | |
490 | { | |
491 | auto const n = parser.put(buffer.data(), ec); | |
492 | bytes_transferred += n; | |
493 | buffer.consume(n); | |
494 | if(! ec) | |
495 | break; | |
496 | if(ec != http::error::need_more) | |
497 | break; | |
498 | } | |
499 | do_read: | |
500 | boost::optional<typename | |
501 | DynamicBuffer::mutable_buffers_type> b; | |
502 | try | |
503 | { | |
504 | b.emplace(buffer.prepare( | |
505 | read_size_or_throw(buffer, 65536))); | |
506 | } | |
507 | catch(std::length_error const&) | |
508 | { | |
509 | ec = error::buffer_overflow; | |
510 | return bytes_transferred; | |
511 | } | |
512 | auto const n = stream.read_some(*b, ec); | |
513 | if(ec == boost::asio::error::eof) | |
514 | { | |
515 | BOOST_ASSERT(n == 0); | |
516 | if(parser.got_some()) | |
517 | { | |
518 | // caller sees EOF on next read | |
519 | parser.put_eof(ec); | |
520 | if(ec) | |
521 | break; | |
522 | BOOST_ASSERT(parser.is_done()); | |
523 | break; | |
524 | } | |
525 | ec = error::end_of_stream; | |
526 | break; | |
527 | } | |
528 | if(ec) | |
529 | break; | |
530 | buffer.commit(n); | |
531 | } | |
532 | return bytes_transferred; | |
533 | } | |
534 | ||
535 | template< | |
536 | class AsyncReadStream, | |
537 | class DynamicBuffer, | |
538 | bool isRequest, class Derived, | |
539 | class ReadHandler> | |
540 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
541 | ReadHandler, void(error_code, std::size_t)) | |
542 | async_read_some( | |
543 | AsyncReadStream& stream, | |
544 | DynamicBuffer& buffer, | |
545 | basic_parser<isRequest, Derived>& parser, | |
546 | ReadHandler&& handler) | |
547 | { | |
548 | static_assert(is_async_read_stream<AsyncReadStream>::value, | |
549 | "AsyncReadStream requirements not met"); | |
550 | static_assert( | |
551 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
552 | "DynamicBuffer requirements not met"); | |
553 | BOOST_ASSERT(! parser.is_done()); | |
11fdf7f2 TL |
554 | BOOST_BEAST_HANDLER_INIT( |
555 | ReadHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
556 | detail::read_some_op<AsyncReadStream, |
557 | DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE( | |
558 | ReadHandler, void(error_code, std::size_t))>{ | |
11fdf7f2 TL |
559 | std::move(init.completion_handler), stream, buffer, parser}( |
560 | {}, 0, false); | |
b32b8144 FG |
561 | return init.result.get(); |
562 | } | |
563 | ||
564 | //------------------------------------------------------------------------------ | |
565 | ||
566 | template< | |
567 | class SyncReadStream, | |
568 | class DynamicBuffer, | |
569 | bool isRequest, class Derived> | |
570 | std::size_t | |
571 | read_header( | |
572 | SyncReadStream& stream, | |
573 | DynamicBuffer& buffer, | |
574 | basic_parser<isRequest, Derived>& parser) | |
575 | { | |
576 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
577 | "SyncReadStream requirements not met"); | |
578 | static_assert( | |
579 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
580 | "DynamicBuffer requirements not met"); | |
581 | error_code ec; | |
582 | auto const bytes_transferred = | |
583 | read_header(stream, buffer, parser, ec); | |
584 | if(ec) | |
585 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
586 | return bytes_transferred; | |
587 | } | |
588 | ||
589 | template< | |
590 | class SyncReadStream, | |
591 | class DynamicBuffer, | |
592 | bool isRequest, class Derived> | |
593 | std::size_t | |
594 | read_header( | |
595 | SyncReadStream& stream, | |
596 | DynamicBuffer& buffer, | |
597 | basic_parser<isRequest, Derived>& parser, | |
598 | error_code& ec) | |
599 | { | |
600 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
601 | "SyncReadStream requirements not met"); | |
602 | static_assert( | |
603 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
604 | "DynamicBuffer requirements not met"); | |
605 | parser.eager(false); | |
606 | if(parser.is_header_done()) | |
607 | { | |
608 | ec.assign(0, ec.category()); | |
609 | return 0; | |
610 | } | |
611 | std::size_t bytes_transferred = 0; | |
612 | do | |
613 | { | |
614 | bytes_transferred += read_some( | |
615 | stream, buffer, parser, ec); | |
616 | if(ec) | |
617 | return bytes_transferred; | |
618 | } | |
619 | while(! parser.is_header_done()); | |
620 | return bytes_transferred; | |
621 | } | |
622 | ||
623 | template< | |
624 | class AsyncReadStream, | |
625 | class DynamicBuffer, | |
626 | bool isRequest, class Derived, | |
627 | class ReadHandler> | |
628 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
629 | ReadHandler, void(error_code, std::size_t)) | |
630 | async_read_header( | |
631 | AsyncReadStream& stream, | |
632 | DynamicBuffer& buffer, | |
633 | basic_parser<isRequest, Derived>& parser, | |
634 | ReadHandler&& handler) | |
635 | { | |
636 | static_assert(is_async_read_stream<AsyncReadStream>::value, | |
637 | "AsyncReadStream requirements not met"); | |
638 | static_assert( | |
639 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
640 | "DynamicBuffer requirements not met"); | |
641 | parser.eager(false); | |
11fdf7f2 TL |
642 | BOOST_BEAST_HANDLER_INIT( |
643 | ReadHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
644 | detail::read_op<AsyncReadStream, DynamicBuffer, |
645 | isRequest, Derived, detail::parser_is_header_done, | |
646 | BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{ | |
11fdf7f2 TL |
647 | std::move(init.completion_handler), stream, |
648 | buffer, parser}({}, 0, false); | |
b32b8144 FG |
649 | return init.result.get(); |
650 | } | |
651 | ||
652 | //------------------------------------------------------------------------------ | |
653 | ||
654 | template< | |
655 | class SyncReadStream, | |
656 | class DynamicBuffer, | |
657 | bool isRequest, class Derived> | |
658 | std::size_t | |
659 | read( | |
660 | SyncReadStream& stream, | |
661 | DynamicBuffer& buffer, | |
662 | basic_parser<isRequest, Derived>& parser) | |
663 | { | |
664 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
665 | "SyncReadStream requirements not met"); | |
666 | static_assert( | |
667 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
668 | "DynamicBuffer requirements not met"); | |
669 | error_code ec; | |
670 | auto const bytes_transferred = | |
671 | read(stream, buffer, parser, ec); | |
672 | if(ec) | |
673 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
674 | return bytes_transferred; | |
675 | } | |
676 | ||
677 | template< | |
678 | class SyncReadStream, | |
679 | class DynamicBuffer, | |
680 | bool isRequest, class Derived> | |
681 | std::size_t | |
682 | read( | |
683 | SyncReadStream& stream, | |
684 | DynamicBuffer& buffer, | |
685 | basic_parser<isRequest, Derived>& parser, | |
686 | error_code& ec) | |
687 | { | |
688 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
689 | "SyncReadStream requirements not met"); | |
690 | static_assert( | |
691 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
692 | "DynamicBuffer requirements not met"); | |
693 | parser.eager(true); | |
694 | if(parser.is_done()) | |
695 | { | |
696 | ec.assign(0, ec.category()); | |
697 | return 0; | |
698 | } | |
699 | std::size_t bytes_transferred = 0; | |
700 | do | |
701 | { | |
702 | bytes_transferred += read_some( | |
703 | stream, buffer, parser, ec); | |
704 | if(ec) | |
705 | return bytes_transferred; | |
706 | } | |
707 | while(! parser.is_done()); | |
708 | return bytes_transferred; | |
709 | } | |
710 | ||
711 | template< | |
712 | class AsyncReadStream, | |
713 | class DynamicBuffer, | |
714 | bool isRequest, class Derived, | |
715 | class ReadHandler> | |
716 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
717 | ReadHandler, void(error_code, std::size_t)) | |
718 | async_read( | |
719 | AsyncReadStream& stream, | |
720 | DynamicBuffer& buffer, | |
721 | basic_parser<isRequest, Derived>& parser, | |
722 | ReadHandler&& handler) | |
723 | { | |
724 | static_assert(is_async_read_stream<AsyncReadStream>::value, | |
725 | "AsyncReadStream requirements not met"); | |
726 | static_assert( | |
727 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
728 | "DynamicBuffer requirements not met"); | |
729 | parser.eager(true); | |
11fdf7f2 TL |
730 | BOOST_BEAST_HANDLER_INIT( |
731 | ReadHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
732 | detail::read_op<AsyncReadStream, DynamicBuffer, |
733 | isRequest, Derived, detail::parser_is_done, | |
734 | BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{ | |
11fdf7f2 TL |
735 | std::move(init.completion_handler), stream, buffer, parser}( |
736 | {}, 0, false); | |
b32b8144 FG |
737 | return init.result.get(); |
738 | } | |
739 | ||
740 | //------------------------------------------------------------------------------ | |
741 | ||
742 | template< | |
743 | class SyncReadStream, | |
744 | class DynamicBuffer, | |
745 | bool isRequest, class Body, class Allocator> | |
746 | std::size_t | |
747 | read( | |
748 | SyncReadStream& stream, | |
749 | DynamicBuffer& buffer, | |
750 | message<isRequest, Body, basic_fields<Allocator>>& msg) | |
751 | { | |
752 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
753 | "SyncReadStream requirements not met"); | |
754 | static_assert( | |
755 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
756 | "DynamicBuffer requirements not met"); | |
757 | static_assert(is_body<Body>::value, | |
758 | "Body requirements not met"); | |
759 | static_assert(is_body_reader<Body>::value, | |
760 | "BodyReader requirements not met"); | |
761 | error_code ec; | |
762 | auto const bytes_transferred = | |
763 | read(stream, buffer, msg, ec); | |
764 | if(ec) | |
765 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
766 | return bytes_transferred; | |
767 | } | |
768 | ||
769 | template< | |
770 | class SyncReadStream, | |
771 | class DynamicBuffer, | |
772 | bool isRequest, class Body, class Allocator> | |
773 | std::size_t | |
774 | read( | |
775 | SyncReadStream& stream, | |
776 | DynamicBuffer& buffer, | |
777 | message<isRequest, Body, basic_fields<Allocator>>& msg, | |
778 | error_code& ec) | |
779 | { | |
780 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
781 | "SyncReadStream requirements not met"); | |
782 | static_assert( | |
783 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
784 | "DynamicBuffer requirements not met"); | |
785 | static_assert(is_body<Body>::value, | |
786 | "Body requirements not met"); | |
787 | static_assert(is_body_reader<Body>::value, | |
788 | "BodyReader requirements not met"); | |
789 | parser<isRequest, Body, Allocator> p{std::move(msg)}; | |
790 | p.eager(true); | |
791 | auto const bytes_transferred = | |
792 | read(stream, buffer, p.base(), ec); | |
793 | if(ec) | |
794 | return bytes_transferred; | |
795 | msg = p.release(); | |
796 | return bytes_transferred; | |
797 | } | |
798 | ||
799 | template< | |
800 | class AsyncReadStream, | |
801 | class DynamicBuffer, | |
802 | bool isRequest, class Body, class Allocator, | |
803 | class ReadHandler> | |
804 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
805 | ReadHandler, void(error_code, std::size_t)) | |
806 | async_read( | |
807 | AsyncReadStream& stream, | |
808 | DynamicBuffer& buffer, | |
809 | message<isRequest, Body, basic_fields<Allocator>>& msg, | |
810 | ReadHandler&& handler) | |
811 | { | |
812 | static_assert(is_async_read_stream<AsyncReadStream>::value, | |
813 | "AsyncReadStream requirements not met"); | |
814 | static_assert( | |
815 | boost::asio::is_dynamic_buffer<DynamicBuffer>::value, | |
816 | "DynamicBuffer requirements not met"); | |
817 | static_assert(is_body<Body>::value, | |
818 | "Body requirements not met"); | |
819 | static_assert(is_body_reader<Body>::value, | |
820 | "BodyReader requirements not met"); | |
11fdf7f2 TL |
821 | BOOST_BEAST_HANDLER_INIT( |
822 | ReadHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
823 | detail::read_msg_op< |
824 | AsyncReadStream, | |
825 | DynamicBuffer, | |
826 | isRequest, Body, Allocator, | |
827 | BOOST_ASIO_HANDLER_TYPE( | |
828 | ReadHandler, void(error_code, std::size_t))>{ | |
11fdf7f2 TL |
829 | std::move(init.completion_handler), stream, buffer, msg}( |
830 | {}, 0, false); | |
b32b8144 FG |
831 | return init.result.get(); |
832 | } | |
833 | ||
834 | } // http | |
835 | } // beast | |
836 | } // boost | |
837 | ||
838 | #endif |