1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3// Copyright (c) 2020 Richard Hodges (hodges.r@gmail.com)
4//
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7//
8// Official repository: https://github.com/boostorg/beast
9//
10
11#ifndef BOOST_BEAST_HTTP_IMPL_READ_HPP
12#define BOOST_BEAST_HTTP_IMPL_READ_HPP
13
14#include <boost/beast/http/type_traits.hpp>
15#include <boost/beast/http/error.hpp>
16#include <boost/beast/http/parser.hpp>
17#include <boost/beast/http/read.hpp>
18#include <boost/beast/core/async_base.hpp>
19#include <boost/beast/core/stream_traits.hpp>
20#include <boost/beast/core/detail/buffer.hpp>
21#include <boost/beast/core/detail/read.hpp>
22#include <boost/asio/error.hpp>
23#include <boost/asio/compose.hpp>
24#include <boost/asio/coroutine.hpp>
25#include <boost/asio/prepend.hpp>
26
27namespace boost {
28namespace beast {
29namespace http {
30
31namespace detail {
32
33struct parser_is_done
34{
35 template<bool isRequest>
36 bool
37 operator()(basic_parser<isRequest> const& p) const
38 {
39 return p.is_done();
40 }
41};
42
43struct parser_is_header_done
44{
45 template<bool isRequest>
46 bool
47 operator()(basic_parser<isRequest> const& p) const
48 {
49 return p.is_header_done();
50 }
51};
52
53//------------------------------------------------------------------------------
54
55template<
56 class Stream, class DynamicBuffer,
57 bool isRequest, class Body, class Allocator,
58 class Handler>
59class read_msg_op
60 : public beast::stable_async_base<
61 Handler, beast::executor_type<Stream>>
62 , public asio::coroutine
63{
64 using parser_type =
65 parser<isRequest, Body, Allocator>;
66
67 using message_type =
68 typename parser_type::value_type;
69
70 struct data
71 {
72 Stream& s;
73 message_type& m;
74 parser_type p;
75
76 data(
77 Stream& s_,
78 message_type& m_)
79 : s(s_)
80 , m(m_)
81 , p(std::move(m))
82 {
83 }
84 };
85
86 data& d_;
87
88public:
89 template<class Handler_>
90 read_msg_op(
91 Handler_&& h,
92 Stream& s,
93 DynamicBuffer& b,
94 message_type& m)
95 : stable_async_base<
96 Handler, beast::executor_type<Stream>>(
97 std::forward<Handler_>(h), s.get_executor())
98 , d_(beast::allocate_stable<data>(
99 *this, s, m))
100 {
101 BOOST_ASIO_HANDLER_LOCATION((
102 __FILE__, __LINE__,
103 "http::async_read(msg)"));
104
105 http::async_read(d_.s, b, d_.p, std::move(*this));
106 }
107
108 void
109 operator()(
110 error_code ec,
111 std::size_t bytes_transferred)
112 {
113 if(! ec)
114 d_.m = d_.p.release();
115 this->complete_now(ec, bytes_transferred);
116 }
117};
118
119struct run_read_msg_op
120{
121 template<
122 class ReadHandler,
123 class AsyncReadStream,
124 class DynamicBuffer,
125 bool isRequest, class Body, class Allocator>
126 void
127 operator()(
128 ReadHandler&& h,
129 AsyncReadStream* s,
130 DynamicBuffer* b,
131 message<isRequest, Body,
132 basic_fields<Allocator>>* m)
133 {
134 // If you get an error on the following line it means
135 // that your handler does not meet the documented type
136 // requirements for the handler.
137
138 static_assert(
139 beast::detail::is_invocable<ReadHandler,
140 void(error_code, std::size_t)>::value,
141 "ReadHandler type requirements not met");
142
143 read_msg_op<
144 AsyncReadStream,
145 DynamicBuffer,
146 isRequest, Body, Allocator,
147 typename std::decay<ReadHandler>::type>(
148 std::forward<ReadHandler>(h), *s, *b, *m);
149 }
150};
151
152template<class AsyncReadStream, class DynamicBuffer, bool isRequest>
153class read_some_op : asio::coroutine
154{
155 AsyncReadStream& s_;
156 DynamicBuffer& b_;
157 basic_parser<isRequest>& p_;
158 std::size_t bytes_transferred_;
159 bool cont_;
160
161public:
162 read_some_op(
163 AsyncReadStream& s,
164 DynamicBuffer& b,
165 basic_parser<isRequest>& p)
166 : s_(s)
167 , b_(b)
168 , p_(p)
169 , bytes_transferred_(0)
170 , cont_(false)
171 {
172 }
173
174 template<class Self>
175 void operator()(
176 Self& self,
177 error_code ec = {},
178 std::size_t bytes_transferred = 0)
179 {
180 BOOST_ASIO_CORO_REENTER(*this)
181 {
182 if(b_.size() == 0)
183 goto do_read;
184 for(;;)
185 {
186 // parse
187 {
188 auto const used = p_.put(b_.data(), ec);
189 bytes_transferred_ += used;
190 b_.consume(used);
191 }
192 if(ec != http::error::need_more)
193 break;
194
195 do_read:
196 BOOST_ASIO_CORO_YIELD
197 {
198 cont_ = true;
199 // VFALCO This was read_size_or_throw
200 auto const size = read_size(b_, 65536);
201 if(size == 0)
202 {
203 BOOST_BEAST_ASSIGN_EC(ec, error::buffer_overflow);
204 goto upcall;
205 }
206 auto const mb =
207 beast::detail::dynamic_buffer_prepare(
208 b_, size, ec, error::buffer_overflow);
209 if(ec)
210 goto upcall;
211
212 BOOST_ASIO_HANDLER_LOCATION((
213 __FILE__, __LINE__,
214 "http::async_read_some"));
215
216 s_.async_read_some(*mb, std::move(self));
217 }
218 b_.commit(bytes_transferred);
219 if(ec == net::error::eof)
220 {
221 BOOST_ASSERT(bytes_transferred == 0);
222 if(p_.got_some())
223 {
224 // caller sees EOF on next read
225 ec.assign(val: 0, cat: ec.category());
226 p_.put_eof(ec);
227 if(ec)
228 goto upcall;
229 BOOST_ASSERT(p_.is_done());
230 goto upcall;
231 }
232 BOOST_BEAST_ASSIGN_EC(ec, error::end_of_stream);
233 break;
234 }
235 if(ec)
236 break;
237 }
238
239 upcall:
240 if(! cont_)
241 {
242 BOOST_ASIO_CORO_YIELD
243 {
244 BOOST_ASIO_HANDLER_LOCATION((
245 __FILE__, __LINE__,
246 "http::async_read_some"));
247
248
249 const auto ex =
250 asio::get_associated_immediate_executor(
251 self, s_.get_executor());
252
253 net::dispatch(ex, net::prepend(std::move(self), ec));
254 }
255 }
256 self.complete(ec, bytes_transferred_);
257 }
258 }
259};
260
261template<class Stream, class DynamicBuffer, bool isRequest, class Condition>
262class read_op
263 : asio::coroutine
264{
265 Stream& s_;
266 DynamicBuffer& b_;
267 basic_parser<isRequest>& p_;
268 std::size_t bytes_transferred_;
269
270public:
271 read_op(Stream& s, DynamicBuffer& b, basic_parser<isRequest>& p)
272 : s_(s)
273 , b_(b)
274 , p_(p)
275 , bytes_transferred_(0)
276 {
277 }
278
279 template<class Self>
280 void operator()(Self& self, error_code ec = {}, std::size_t bytes_transferred = 0)
281 {
282 BOOST_ASIO_CORO_REENTER(*this)
283 {
284 if (Condition{}(p_))
285 {
286 BOOST_ASIO_CORO_YIELD
287 {
288 BOOST_ASIO_HANDLER_LOCATION((
289 __FILE__, __LINE__,
290 "http::async_read"));
291
292 const auto ex =
293 asio::get_associated_immediate_executor(
294 self, s_.get_executor());
295
296 net::dispatch(ex, std::move(self));
297 }
298 }
299 else
300 {
301 do
302 {
303 BOOST_ASIO_CORO_YIELD
304 {
305 BOOST_ASIO_HANDLER_LOCATION((
306 __FILE__, __LINE__,
307 "http::async_read"));
308
309 async_read_some(
310 s_, b_, p_, std::move(self));
311 }
312 bytes_transferred_ += bytes_transferred;
313 } while (!ec &&
314 !Condition{}(p_));
315 }
316 self.complete(ec, bytes_transferred_);
317 }
318 }
319};
320
321
322template<
323 class SyncReadStream,
324 class DynamicBuffer,
325 bool isRequest>
326std::size_t
327read_some(SyncReadStream& s, DynamicBuffer& b, basic_parser<isRequest>& p, error_code& ec)
328{
329 std::size_t total = 0;
330 ec.clear();
331 if(b.size() == 0)
332 goto do_read;
333 for(;;)
334 {
335 // parse
336 {
337 auto const used = p.put(b.data(), ec);
338 total += used;
339 b.consume(used);
340 }
341 if(ec != http::error::need_more)
342 break;
343
344 do_read:
345 // VFALCO This was read_size_or_throw
346 auto const size = read_size(b, 65536);
347 if(size == 0)
348 {
349 BOOST_BEAST_ASSIGN_EC(ec, error::buffer_overflow);
350 return total;
351 }
352 auto const mb =
353 beast::detail::dynamic_buffer_prepare(
354 b, size, ec, error::buffer_overflow);
355 if(ec)
356 return total;
357 std::size_t
358 bytes_transferred =
359 s.read_some(*mb, ec);
360 b.commit(bytes_transferred);
361 if(ec == net::error::eof)
362 {
363 BOOST_ASSERT(bytes_transferred == 0);
364 if(p.got_some())
365 {
366 // caller sees EOF on next read
367 ec.assign(val: 0, cat: ec.category());
368 p.put_eof(ec);
369 if(ec)
370 return total;
371 BOOST_ASSERT(p.is_done());
372 return total;
373 }
374 BOOST_BEAST_ASSIGN_EC(ec, error::end_of_stream);
375 break;
376 }
377 if(ec)
378 break;
379 }
380
381 return total;
382}
383
384template<class Condition, class Stream, class DynamicBuffer, bool isRequest>
385std::size_t sync_read_op(Stream& s, DynamicBuffer& b, basic_parser<isRequest>& p, error_code& ec)
386{
387 std::size_t total = 0;
388 ec.clear();
389
390 if (!Condition{}(p))
391 {
392 do
393 {
394 total +=
395 detail::read_some(s, b, p, ec);
396 } while (!ec &&
397 !Condition{}(p));
398 }
399 return total;
400}
401
402} // detail
403
404//------------------------------------------------------------------------------
405
406template<
407 class SyncReadStream,
408 class DynamicBuffer,
409 bool isRequest>
410std::size_t
411read_some(
412 SyncReadStream& stream,
413 DynamicBuffer& buffer,
414 basic_parser<isRequest>& parser)
415{
416 static_assert(
417 is_sync_read_stream<SyncReadStream>::value,
418 "SyncReadStream type requirements not met");
419 static_assert(
420 net::is_dynamic_buffer<DynamicBuffer>::value,
421 "DynamicBuffer type requirements not met");
422 error_code ec;
423 auto const bytes_transferred =
424 http::read_some(stream, buffer, parser, ec);
425 if(ec)
426 BOOST_THROW_EXCEPTION(system_error{ec});
427 return bytes_transferred;
428}
429
430template<
431 class SyncReadStream,
432 class DynamicBuffer,
433 bool isRequest>
434std::size_t
435read_some(
436 SyncReadStream& stream,
437 DynamicBuffer& buffer,
438 basic_parser<isRequest>& parser,
439 error_code& ec)
440{
441 static_assert(
442 is_sync_read_stream<SyncReadStream>::value,
443 "SyncReadStream type requirements not met");
444 static_assert(
445 net::is_dynamic_buffer<DynamicBuffer>::value,
446 "DynamicBuffer type requirements not met");
447 return detail::read_some(stream, buffer, parser, ec);
448}
449
450template<
451 class AsyncReadStream,
452 class DynamicBuffer,
453 bool isRequest,
454 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
455BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
456async_read_some(
457 AsyncReadStream& stream,
458 DynamicBuffer& buffer,
459 basic_parser<isRequest>& parser,
460 ReadHandler&& handler)
461{
462 return net::async_compose<ReadHandler,
463 void(beast::error_code, std::size_t)>(
464 detail::read_some_op<AsyncReadStream, DynamicBuffer, isRequest> {
465 stream,
466 buffer,
467 parser
468 },
469 handler,
470 stream);
471}
472
473//------------------------------------------------------------------------------
474
475template<
476 class SyncReadStream,
477 class DynamicBuffer,
478 bool isRequest>
479std::size_t
480read_header(
481 SyncReadStream& stream,
482 DynamicBuffer& buffer,
483 basic_parser<isRequest>& parser)
484{
485 static_assert(
486 is_sync_read_stream<SyncReadStream>::value,
487 "SyncReadStream type requirements not met");
488 static_assert(
489 net::is_dynamic_buffer<DynamicBuffer>::value,
490 "DynamicBuffer type requirements not met");
491 error_code ec;
492 auto const bytes_transferred =
493 http::read_header(stream, buffer, parser, ec);
494 if(ec)
495 BOOST_THROW_EXCEPTION(system_error{ec});
496 return bytes_transferred;
497}
498
499template<
500 class SyncReadStream,
501 class DynamicBuffer,
502 bool isRequest>
503std::size_t
504read_header(
505 SyncReadStream& stream,
506 DynamicBuffer& buffer,
507 basic_parser<isRequest>& parser,
508 error_code& ec)
509{
510 static_assert(
511 is_sync_read_stream<SyncReadStream>::value,
512 "SyncReadStream type requirements not met");
513 static_assert(
514 net::is_dynamic_buffer<DynamicBuffer>::value,
515 "DynamicBuffer type requirements not met");
516 parser.eager(false);
517 return detail::sync_read_op<
518 detail::parser_is_header_done>(
519 stream, buffer, parser, ec);
520}
521
522template<
523 class AsyncReadStream,
524 class DynamicBuffer,
525 bool isRequest,
526 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
527BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
528async_read_header(
529 AsyncReadStream& stream,
530 DynamicBuffer& buffer,
531 basic_parser<isRequest>& parser,
532 ReadHandler&& handler)
533{
534 parser.eager(false);
535 return net::async_compose<
536 ReadHandler,
537 void(error_code, std::size_t)>(
538 detail::read_op<
539 AsyncReadStream,
540 DynamicBuffer,
541 isRequest,
542 detail::parser_is_header_done>(
543 stream, buffer, parser),
544 handler, stream);
545}
546
547//------------------------------------------------------------------------------
548
549template<
550 class SyncReadStream,
551 class DynamicBuffer,
552 bool isRequest>
553std::size_t
554read(
555 SyncReadStream& stream,
556 DynamicBuffer& buffer,
557 basic_parser<isRequest>& parser)
558{
559 static_assert(
560 is_sync_read_stream<SyncReadStream>::value,
561 "SyncReadStream type requirements not met");
562 static_assert(
563 net::is_dynamic_buffer<DynamicBuffer>::value,
564 "DynamicBuffer type requirements not met");
565 error_code ec;
566 auto const bytes_transferred =
567 http::read(stream, buffer, parser, ec);
568 if(ec)
569 BOOST_THROW_EXCEPTION(system_error{ec});
570 return bytes_transferred;
571}
572
573template<
574 class SyncReadStream,
575 class DynamicBuffer,
576 bool isRequest>
577std::size_t
578read(
579 SyncReadStream& stream,
580 DynamicBuffer& buffer,
581 basic_parser<isRequest>& parser,
582 error_code& ec)
583{
584 static_assert(
585 is_sync_read_stream<SyncReadStream>::value,
586 "SyncReadStream type requirements not met");
587 static_assert(
588 net::is_dynamic_buffer<DynamicBuffer>::value,
589 "DynamicBuffer type requirements not met");
590 parser.eager(true);
591 return detail::sync_read_op<
592 detail::parser_is_done>(
593 stream, buffer, parser, ec);
594}
595
596template<
597 class AsyncReadStream,
598 class DynamicBuffer,
599 bool isRequest,
600 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
601BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
602async_read(
603 AsyncReadStream& stream,
604 DynamicBuffer& buffer,
605 basic_parser<isRequest>& parser,
606 ReadHandler&& handler)
607{
608 static_assert(
609 is_async_read_stream<AsyncReadStream>::value,
610 "AsyncReadStream type requirements not met");
611 static_assert(
612 net::is_dynamic_buffer<DynamicBuffer>::value,
613 "DynamicBuffer type requirements not met");
614 parser.eager(true);
615 return net::async_compose<
616 ReadHandler,
617 void(error_code, std::size_t)>(
618 detail::read_op<
619 AsyncReadStream,
620 DynamicBuffer,
621 isRequest,
622 detail::parser_is_done>(
623 stream, buffer, parser),
624 handler, stream);
625}
626
627//------------------------------------------------------------------------------
628
629template<
630 class SyncReadStream,
631 class DynamicBuffer,
632 bool isRequest, class Body, class Allocator>
633std::size_t
634read(
635 SyncReadStream& stream,
636 DynamicBuffer& buffer,
637 message<isRequest, Body, basic_fields<Allocator>>& msg)
638{
639 static_assert(
640 is_sync_read_stream<SyncReadStream>::value,
641 "SyncReadStream type requirements not met");
642 static_assert(
643 net::is_dynamic_buffer<DynamicBuffer>::value,
644 "DynamicBuffer type requirements not met");
645 static_assert(is_body<Body>::value,
646 "Body type requirements not met");
647 static_assert(is_body_reader<Body>::value,
648 "BodyReader type requirements not met");
649 error_code ec;
650 auto const bytes_transferred =
651 http::read(stream, buffer, msg, ec);
652 if(ec)
653 BOOST_THROW_EXCEPTION(system_error{ec});
654 return bytes_transferred;
655}
656
657template<
658 class SyncReadStream,
659 class DynamicBuffer,
660 bool isRequest, class Body, class Allocator>
661std::size_t
662read(
663 SyncReadStream& stream,
664 DynamicBuffer& buffer,
665 message<isRequest, Body, basic_fields<Allocator>>& msg,
666 error_code& ec)
667{
668 static_assert(
669 is_sync_read_stream<SyncReadStream>::value,
670 "SyncReadStream type requirements not met");
671 static_assert(
672 net::is_dynamic_buffer<DynamicBuffer>::value,
673 "DynamicBuffer type requirements not met");
674 static_assert(is_body<Body>::value,
675 "Body type requirements not met");
676 static_assert(is_body_reader<Body>::value,
677 "BodyReader type requirements not met");
678 parser<isRequest, Body, Allocator> p(std::move(msg));
679 p.eager(true);
680 auto const bytes_transferred =
681 http::read(stream, buffer, p, ec);
682 if(ec)
683 return bytes_transferred;
684 msg = p.release();
685 return bytes_transferred;
686}
687
688template<
689 class AsyncReadStream,
690 class DynamicBuffer,
691 bool isRequest, class Body, class Allocator,
692 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
693BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
694async_read(
695 AsyncReadStream& stream,
696 DynamicBuffer& buffer,
697 message<isRequest, Body, basic_fields<Allocator>>& msg,
698 ReadHandler&& handler)
699{
700 static_assert(
701 is_async_read_stream<AsyncReadStream>::value,
702 "AsyncReadStream type requirements not met");
703 static_assert(
704 net::is_dynamic_buffer<DynamicBuffer>::value,
705 "DynamicBuffer type requirements not met");
706 static_assert(is_body<Body>::value,
707 "Body type requirements not met");
708 static_assert(is_body_reader<Body>::value,
709 "BodyReader type requirements not met");
710 return net::async_initiate<
711 ReadHandler,
712 void(error_code, std::size_t)>(
713 detail::run_read_msg_op{},
714 handler, &stream, &buffer, &msg);
715}
716
717} // http
718} // beast
719} // boost
720
721#endif
722

source code of boost/libs/beast/include/boost/beast/http/impl/read.hpp