Line data Source code
1 : //
2 : // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : // Copyright (c) 2025 Mohammad Nejati
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/cppalliance/beast2
9 : //
10 :
11 : #ifndef BOOST_BEAST2_IMPL_READ_HPP
12 : #define BOOST_BEAST2_IMPL_READ_HPP
13 :
14 : #include <boost/beast2/detail/except.hpp>
15 : #include <boost/http_proto/error.hpp>
16 : #include <boost/http_proto/parser.hpp>
17 : #include <boost/asio/append.hpp>
18 : #include <boost/asio/compose.hpp>
19 : #include <boost/asio/coroutine.hpp>
20 : #include <boost/asio/immediate.hpp>
21 : #include <boost/assert.hpp>
22 :
23 : namespace boost {
24 : namespace beast2 {
25 :
26 : namespace detail {
27 :
28 : template<class AsyncStream>
29 : class read_until_op
30 : : public asio::coroutine
31 : {
32 : AsyncStream& stream_;
33 : http_proto::parser& pr_;
34 : std::size_t total_bytes_ = 0;
35 : bool (&condition_)(http_proto::parser&);
36 :
37 : public:
38 834 : read_until_op(
39 : AsyncStream& s,
40 : http_proto::parser& pr,
41 : bool (&condition)(http_proto::parser&)) noexcept
42 834 : : stream_(s)
43 834 : , pr_(pr)
44 834 : , condition_(condition)
45 : {
46 834 : }
47 :
48 : template<class Self>
49 : void
50 1918 : operator()(
51 : Self& self,
52 : system::error_code ec = {},
53 : std::size_t bytes_transferred = 0)
54 : {
55 3836 : BOOST_ASIO_CORO_REENTER(*this)
56 : {
57 834 : self.reset_cancellation_state(
58 834 : asio::enable_total_cancellation());
59 :
60 476 : for(;;)
61 : {
62 2 : for(;;)
63 : {
64 1312 : pr_.parse(ec);
65 1312 : if(ec == http_proto::condition::need_more_input)
66 : {
67 549 : if(!!self.cancelled())
68 : {
69 39 : ec = asio::error::operation_aborted;
70 39 : goto upcall;
71 : }
72 : // specific to http_io::async_read_some
73 510 : if(total_bytes_ != 0 && condition_(pr_))
74 : {
75 31 : ec = {};
76 31 : goto upcall;
77 : }
78 479 : break;
79 : }
80 763 : if(ec.failed() || condition_(pr_))
81 : {
82 761 : if(total_bytes_ == 0)
83 : {
84 1815 : BOOST_ASIO_CORO_YIELD
85 : {
86 : BOOST_ASIO_HANDLER_LOCATION((
87 : __FILE__, __LINE__,
88 : "immediate"));
89 605 : auto io_ex = self.get_io_executor();
90 605 : asio::async_immediate(
91 : io_ex,
92 605 : asio::append(std::move(self), ec));
93 605 : }
94 : }
95 761 : goto upcall;
96 : }
97 : }
98 1437 : BOOST_ASIO_CORO_YIELD
99 : {
100 : BOOST_ASIO_HANDLER_LOCATION((
101 : __FILE__, __LINE__,
102 : "async_read_some"));
103 479 : stream_.async_read_some(
104 958 : pr_.prepare(),
105 479 : std::move(self));
106 : }
107 479 : pr_.commit(bytes_transferred);
108 479 : total_bytes_ += bytes_transferred;
109 479 : if(ec == asio::error::eof)
110 : {
111 0 : BOOST_ASSERT(
112 : bytes_transferred == 0);
113 0 : pr_.commit_eof();
114 0 : ec = {};
115 : }
116 479 : else if(ec.failed())
117 : {
118 3 : goto upcall;
119 : }
120 : }
121 :
122 834 : upcall:
123 834 : self.complete(ec, total_bytes_);
124 : }
125 1918 : }
126 : };
127 :
128 : inline
129 : bool
130 998 : got_header_condition(http_proto::parser& pr)
131 : {
132 998 : return pr.got_header();
133 : }
134 :
135 : inline
136 : bool
137 44 : is_complete_condition(http_proto::parser& pr)
138 : {
139 44 : return pr.is_complete();
140 : }
141 :
142 : } // detail
143 :
144 : //------------------------------------------------
145 :
146 : template<
147 : class AsyncReadStream,
148 : BOOST_ASIO_COMPLETION_TOKEN_FOR(
149 : void(system::error_code, std::size_t)) CompletionToken>
150 : BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
151 : void (system::error_code, std::size_t))
152 832 : async_read_some(
153 : AsyncReadStream& s,
154 : http_proto::parser& pr,
155 : CompletionToken&& token)
156 : {
157 : return asio::async_compose<
158 : CompletionToken,
159 832 : void(system::error_code, std::size_t)>(
160 : detail::read_until_op<AsyncReadStream>
161 : {s, pr, detail::got_header_condition},
162 : token,
163 832 : s);
164 : }
165 :
166 : template<
167 : class AsyncReadStream,
168 : BOOST_ASIO_COMPLETION_TOKEN_FOR(
169 : void(system::error_code, std::size_t)) CompletionToken>
170 : BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
171 : void (system::error_code, std::size_t))
172 143 : async_read_header(
173 : AsyncReadStream& s,
174 : http_proto::parser& pr,
175 : CompletionToken&& token)
176 : {
177 : // TODO: async_read_header should not perform a read
178 : // operation if `parser::got_header() == true`.
179 143 : return async_read_some(s, pr, std::move(token));
180 : }
181 :
182 : template<
183 : class AsyncReadStream,
184 : BOOST_ASIO_COMPLETION_TOKEN_FOR(
185 : void(system::error_code, std::size_t)) CompletionToken>
186 : BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
187 : void (system::error_code, std::size_t))
188 2 : async_read(
189 : AsyncReadStream& s,
190 : http_proto::parser& pr,
191 : CompletionToken&& token)
192 : {
193 : return asio::async_compose<
194 : CompletionToken,
195 2 : void(system::error_code, std::size_t)>(
196 : detail::read_until_op<AsyncReadStream>
197 : {s, pr, detail::is_complete_condition},
198 : token,
199 2 : s);
200 : }
201 :
202 : } // beast2
203 : } // boost
204 :
205 : #endif
|