]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/_experimental/http/impl/icy_stream.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / beast / _experimental / http / impl / icy_stream.hpp
1 //
2 // Copyright (c) 2016-2019 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_CORE_IMPL_ICY_STREAM_HPP
11 #define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
12
13 #include <boost/beast/core/async_base.hpp>
14 #include <boost/beast/core/buffer_traits.hpp>
15 #include <boost/beast/core/error.hpp>
16 #include <boost/beast/core/stream_traits.hpp>
17 #include <boost/beast/core/detail/is_invocable.hpp>
18 #include <boost/asio/coroutine.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/throw_exception.hpp>
21 #include <cstring>
22 #include <memory>
23 #include <utility>
24
25 namespace boost {
26 namespace beast {
27 namespace http {
28
29 namespace detail {
30
31 template<class ConstBufferSequence>
32 boost::tribool
33 is_icy(ConstBufferSequence const& buffers)
34 {
35 char buf[3];
36 auto const n = net::buffer_copy(
37 net::mutable_buffer(buf, 3),
38 buffers);
39 if(n >= 1 && buf[0] != 'I')
40 return false;
41 if(n >= 2 && buf[1] != 'C')
42 return false;
43 if(n >= 3 && buf[2] != 'Y')
44 return false;
45 if(n < 3)
46 return boost::indeterminate;
47 return true;
48 }
49
50 } // detail
51
52 template<class NextLayer>
53 struct icy_stream<NextLayer>::ops
54 {
55
56 template<class Buffers, class Handler>
57 class read_op
58 : public beast::async_base<Handler,
59 beast::executor_type<icy_stream>>
60 , public asio::coroutine
61 {
62 icy_stream& s_;
63 Buffers b_;
64 std::size_t n_ = 0;
65 error_code ec_;
66 bool match_ = false;
67
68 public:
69 template<class Handler_>
70 read_op(
71 Handler_&& h,
72 icy_stream& s,
73 Buffers const& b)
74 : async_base<Handler,
75 beast::executor_type<icy_stream>>(
76 std::forward<Handler_>(h), s.get_executor())
77 , s_(s)
78 , b_(b)
79 {
80 (*this)({}, 0, false);
81 }
82
83 void
84 operator()(
85 error_code ec,
86 std::size_t bytes_transferred,
87 bool cont = true)
88 {
89 BOOST_ASIO_CORO_REENTER(*this)
90 {
91 if(s_.detect_)
92 {
93 BOOST_ASSERT(s_.n_ == 0);
94 for(;;)
95 {
96 // Try to read the first three characters
97 BOOST_ASIO_CORO_YIELD
98 {
99 BOOST_ASIO_HANDLER_LOCATION((
100 __FILE__, __LINE__,
101 "http::icy_stream::async_read_some"));
102
103 s_.next_layer().async_read_some(
104 net::mutable_buffer(
105 s_.buf_ + s_.n_, 3 - s_.n_),
106 std::move(*this));
107 }
108 s_.n_ += static_cast<char>(bytes_transferred);
109 if(ec)
110 goto upcall;
111 auto result = detail::is_icy(
112 net::const_buffer(s_.buf_, s_.n_));
113 if(boost::indeterminate(result))
114 continue;
115 if(result)
116 s_.n_ = static_cast<char>(net::buffer_copy(
117 net::buffer(s_.buf_, sizeof(s_.buf_)),
118 icy_stream::version()));
119 break;
120 }
121 s_.detect_ = false;
122 }
123 if(s_.n_ > 0)
124 {
125 bytes_transferred = net::buffer_copy(
126 b_, net::const_buffer(s_.buf_, s_.n_));
127 s_.n_ -= static_cast<char>(bytes_transferred);
128 std::memmove(
129 s_.buf_,
130 s_.buf_ + bytes_transferred,
131 sizeof(s_.buf_) - bytes_transferred);
132 }
133 else
134 {
135 BOOST_ASIO_CORO_YIELD
136 {
137 BOOST_ASIO_HANDLER_LOCATION((
138 __FILE__, __LINE__,
139 "http::icy_stream::async_read_some"));
140
141 s_.next_layer().async_read_some(
142 b_, std::move(*this));
143 }
144 }
145 upcall:
146 if(! cont)
147 {
148 ec_ = ec;
149 n_ = bytes_transferred;
150 BOOST_ASIO_CORO_YIELD
151 {
152 BOOST_ASIO_HANDLER_LOCATION((
153 __FILE__, __LINE__,
154 "http::icy_stream::async_read_some"));
155
156 s_.next_layer().async_read_some(
157 net::mutable_buffer{},
158 std::move(*this));
159 }
160 ec = ec_;
161 bytes_transferred = n_;
162 }
163 this->complete_now(ec, bytes_transferred);
164 }
165 }
166 };
167
168 struct run_read_op
169 {
170 template<class ReadHandler, class Buffers>
171 void
172 operator()(
173 ReadHandler&& h,
174 icy_stream* s,
175 Buffers const& b)
176 {
177 // If you get an error on the following line it means
178 // that your handler does not meet the documented type
179 // requirements for the handler.
180
181 static_assert(
182 beast::detail::is_invocable<ReadHandler,
183 void(error_code, std::size_t)>::value,
184 "ReadHandler type requirements not met");
185
186 read_op<
187 Buffers,
188 typename std::decay<ReadHandler>::type>(
189 std::forward<ReadHandler>(h), *s, b);
190 }
191 };
192
193 };
194
195 //------------------------------------------------------------------------------
196
197 template<class NextLayer>
198 template<class... Args>
199 icy_stream<NextLayer>::
200 icy_stream(Args&&... args)
201 : stream_(std::forward<Args>(args)...)
202 {
203 std::memset(buf_, 0, sizeof(buf_));
204 }
205
206 template<class NextLayer>
207 template<class MutableBufferSequence>
208 std::size_t
209 icy_stream<NextLayer>::
210 read_some(MutableBufferSequence const& buffers)
211 {
212 static_assert(is_sync_read_stream<next_layer_type>::value,
213 "SyncReadStream type requirements not met");
214 static_assert(net::is_mutable_buffer_sequence<
215 MutableBufferSequence>::value,
216 "MutableBufferSequence type requirements not met");
217 error_code ec;
218 auto n = read_some(buffers, ec);
219 if(ec)
220 BOOST_THROW_EXCEPTION(system_error{ec});
221 return n;
222 }
223
224 template<class NextLayer>
225 template<class MutableBufferSequence>
226 std::size_t
227 icy_stream<NextLayer>::
228 read_some(MutableBufferSequence const& buffers, error_code& ec)
229 {
230 static_assert(is_sync_read_stream<next_layer_type>::value,
231 "SyncReadStream type requirements not met");
232 static_assert(net::is_mutable_buffer_sequence<
233 MutableBufferSequence>::value,
234 "MutableBufferSequence type requirements not met");
235 std::size_t bytes_transferred;
236 if(detect_)
237 {
238 BOOST_ASSERT(n_ == 0);
239 for(;;)
240 {
241 // Try to read the first three characters
242 bytes_transferred = next_layer().read_some(
243 net::mutable_buffer(buf_ + n_, 3 - n_), ec);
244 n_ += static_cast<char>(bytes_transferred);
245 if(ec)
246 return 0;
247 auto result = detail::is_icy(
248 net::const_buffer(buf_, n_));
249 if(boost::indeterminate(result))
250 continue;
251 if(result)
252 n_ = static_cast<char>(net::buffer_copy(
253 net::buffer(buf_, sizeof(buf_)),
254 icy_stream::version()));
255 break;
256 }
257 detect_ = false;
258 }
259 if(n_ > 0)
260 {
261 bytes_transferred = net::buffer_copy(
262 buffers, net::const_buffer(buf_, n_));
263 n_ -= static_cast<char>(bytes_transferred);
264 std::memmove(
265 buf_,
266 buf_ + bytes_transferred,
267 sizeof(buf_) - bytes_transferred);
268 }
269 else
270 {
271 bytes_transferred =
272 next_layer().read_some(buffers, ec);
273 }
274 return bytes_transferred;
275 }
276
277 template<class NextLayer>
278 template<
279 class MutableBufferSequence,
280 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
281 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
282 icy_stream<NextLayer>::
283 async_read_some(
284 MutableBufferSequence const& buffers,
285 ReadHandler&& handler)
286 {
287 static_assert(is_async_read_stream<next_layer_type>::value,
288 "AsyncReadStream type requirements not met");
289 static_assert(net::is_mutable_buffer_sequence<
290 MutableBufferSequence >::value,
291 "MutableBufferSequence type requirements not met");
292 return net::async_initiate<
293 ReadHandler,
294 void(error_code, std::size_t)>(
295 typename ops::run_read_op{},
296 handler,
297 this,
298 buffers);
299 }
300
301 template<class NextLayer>
302 template<class MutableBufferSequence>
303 std::size_t
304 icy_stream<NextLayer>::
305 write_some(MutableBufferSequence const& buffers)
306 {
307 static_assert(is_sync_write_stream<next_layer_type>::value,
308 "SyncWriteStream type requirements not met");
309 static_assert(net::is_const_buffer_sequence<
310 MutableBufferSequence>::value,
311 "MutableBufferSequence type requirements not met");
312 return stream_.write_some(buffers);
313 }
314
315 template<class NextLayer>
316 template<class MutableBufferSequence>
317 std::size_t
318 icy_stream<NextLayer>::
319 write_some(MutableBufferSequence const& buffers, error_code& ec)
320 {
321 static_assert(is_sync_write_stream<next_layer_type>::value,
322 "SyncWriteStream type requirements not met");
323 static_assert(net::is_const_buffer_sequence<
324 MutableBufferSequence>::value,
325 "MutableBufferSequence type requirements not met");
326 return stream_.write_some(buffers, ec);
327 }
328
329 template<class NextLayer>
330 template<
331 class MutableBufferSequence,
332 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
333 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
334 icy_stream<NextLayer>::
335 async_write_some(
336 MutableBufferSequence const& buffers,
337 WriteHandler&& handler)
338 {
339 static_assert(is_async_write_stream<next_layer_type>::value,
340 "AsyncWriteStream type requirements not met");
341 static_assert(net::is_const_buffer_sequence<
342 MutableBufferSequence>::value,
343 "MutableBufferSequence type requirements not met");
344 return stream_.async_write_some(
345 buffers, std::forward<WriteHandler>(handler));
346 }
347
348 } // http
349 } // beast
350 } // boost
351
352 #endif