]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/websocket/impl/accept.ipp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / beast / websocket / impl / accept.ipp
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_WEBSOCKET_IMPL_ACCEPT_IPP
11 #define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
12
13 #include <boost/beast/websocket/detail/type_traits.hpp>
14 #include <boost/beast/http/empty_body.hpp>
15 #include <boost/beast/http/parser.hpp>
16 #include <boost/beast/http/read.hpp>
17 #include <boost/beast/http/string_body.hpp>
18 #include <boost/beast/http/write.hpp>
19 #include <boost/beast/core/buffers_prefix.hpp>
20 #include <boost/beast/core/handler_ptr.hpp>
21 #include <boost/beast/core/detail/type_traits.hpp>
22 #include <boost/asio/coroutine.hpp>
23 #include <boost/asio/associated_allocator.hpp>
24 #include <boost/asio/associated_executor.hpp>
25 #include <boost/asio/handler_continuation_hook.hpp>
26 #include <boost/asio/post.hpp>
27 #include <boost/assert.hpp>
28 #include <boost/throw_exception.hpp>
29 #include <memory>
30 #include <type_traits>
31
32 namespace boost {
33 namespace beast {
34 namespace websocket {
35
36 // Respond to an upgrade HTTP request
37 template<class NextLayer>
38 template<class Handler>
39 class stream<NextLayer>::response_op
40 : public boost::asio::coroutine
41 {
42 struct data
43 {
44 stream<NextLayer>& ws;
45 response_type res;
46
47 template<class Body, class Allocator, class Decorator>
48 data(Handler&, stream<NextLayer>& ws_, http::request<
49 Body, http::basic_fields<Allocator>> const& req,
50 Decorator const& decorator)
51 : ws(ws_)
52 , res(ws_.build_response(req, decorator))
53 {
54 }
55 };
56
57 handler_ptr<data, Handler> d_;
58
59 public:
60 response_op(response_op&&) = default;
61 response_op(response_op const&) = default;
62
63 template<class DeducedHandler, class... Args>
64 response_op(DeducedHandler&& h,
65 stream<NextLayer>& ws, Args&&... args)
66 : d_(std::forward<DeducedHandler>(h),
67 ws, std::forward<Args>(args)...)
68 {
69 }
70
71 using allocator_type =
72 boost::asio::associated_allocator_t<Handler>;
73
74 allocator_type
75 get_allocator() const noexcept
76 {
77 return boost::asio::get_associated_allocator(d_.handler());
78 }
79
80 using executor_type = boost::asio::associated_executor_t<
81 Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
82
83 executor_type
84 get_executor() const noexcept
85 {
86 return boost::asio::get_associated_executor(
87 d_.handler(), d_->ws.get_executor());
88 }
89
90 void operator()(
91 error_code ec = {},
92 std::size_t bytes_transferred = 0);
93
94 friend
95 bool asio_handler_is_continuation(response_op* op)
96 {
97 using boost::asio::asio_handler_is_continuation;
98 return asio_handler_is_continuation(
99 std::addressof(op->d_.handler()));
100 }
101 };
102
103 template<class NextLayer>
104 template<class Handler>
105 void
106 stream<NextLayer>::
107 response_op<Handler>::
108 operator()(
109 error_code ec,
110 std::size_t)
111 {
112 auto& d = *d_;
113 BOOST_ASIO_CORO_REENTER(*this)
114 {
115 // Send response
116 BOOST_ASIO_CORO_YIELD
117 http::async_write(d.ws.next_layer(),
118 d.res, std::move(*this));
119 if(! ec && d.res.result() !=
120 http::status::switching_protocols)
121 ec = error::handshake_failed;
122 if(! ec)
123 {
124 pmd_read(d.ws.pmd_config_, d.res);
125 d.ws.open(role_type::server);
126 }
127 d_.invoke(ec);
128 }
129 }
130
131 //------------------------------------------------------------------------------
132
133 // read and respond to an upgrade request
134 //
135 template<class NextLayer>
136 template<class Decorator, class Handler>
137 class stream<NextLayer>::accept_op
138 : public boost::asio::coroutine
139 {
140 struct data
141 {
142 stream<NextLayer>& ws;
143 Decorator decorator;
144 http::request_parser<http::empty_body> p;
145 data(Handler&, stream<NextLayer>& ws_,
146 Decorator const& decorator_)
147 : ws(ws_)
148 , decorator(decorator_)
149 {
150 }
151 };
152
153 handler_ptr<data, Handler> d_;
154
155 public:
156 accept_op(accept_op&&) = default;
157 accept_op(accept_op const&) = default;
158
159 template<class DeducedHandler, class... Args>
160 accept_op(DeducedHandler&& h,
161 stream<NextLayer>& ws, Args&&... args)
162 : d_(std::forward<DeducedHandler>(h),
163 ws, std::forward<Args>(args)...)
164 {
165 }
166
167 using allocator_type =
168 boost::asio::associated_allocator_t<Handler>;
169
170 allocator_type
171 get_allocator() const noexcept
172 {
173 return boost::asio::get_associated_allocator(d_.handler());
174 }
175
176 using executor_type = boost::asio::associated_executor_t<
177 Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
178
179 executor_type
180 get_executor() const noexcept
181 {
182 return boost::asio::get_associated_executor(
183 d_.handler(), d_->ws.get_executor());
184 }
185
186 template<class Buffers>
187 void run(Buffers const& buffers);
188
189 void operator()(
190 error_code ec = {},
191 std::size_t bytes_used = 0);
192
193 friend
194 bool asio_handler_is_continuation(accept_op* op)
195 {
196 using boost::asio::asio_handler_is_continuation;
197 return asio_handler_is_continuation(
198 std::addressof(op->d_.handler()));
199 }
200 };
201
202 template<class NextLayer>
203 template<class Decorator, class Handler>
204 template<class Buffers>
205 void
206 stream<NextLayer>::
207 accept_op<Decorator, Handler>::
208 run(Buffers const& buffers)
209 {
210 using boost::asio::buffer_copy;
211 using boost::asio::buffer_size;
212 auto& d = *d_;
213 error_code ec;
214 boost::optional<typename
215 static_buffer_base::mutable_buffers_type> mb;
216 auto const len = buffer_size(buffers);
217 try
218 {
219 mb.emplace(d.ws.rd_buf_.prepare(len));
220 }
221 catch(std::length_error const&)
222 {
223 ec = error::buffer_overflow;
224 return (*this)(ec);
225 }
226 d.ws.rd_buf_.commit(
227 buffer_copy(*mb, buffers));
228 (*this)(ec);
229 }
230
231 template<class NextLayer>
232 template<class Decorator, class Handler>
233 void
234 stream<NextLayer>::
235 accept_op<Decorator, Handler>::
236 operator()(error_code ec, std::size_t)
237 {
238 auto& d = *d_;
239 BOOST_ASIO_CORO_REENTER(*this)
240 {
241 if(ec)
242 {
243 BOOST_ASIO_CORO_YIELD
244 boost::asio::post(
245 d.ws.get_executor(),
246 bind_handler(std::move(*this), ec));
247 }
248 else
249 {
250 BOOST_ASIO_CORO_YIELD
251 http::async_read(
252 d.ws.next_layer(), d.ws.rd_buf_,
253 d.p, std::move(*this));
254 if(ec == http::error::end_of_stream)
255 ec = error::closed;
256 if(! ec)
257 {
258 // Arguments from our state must be
259 // moved to the stack before releasing
260 // the handler.
261 auto& ws = d.ws;
262 auto const req = d.p.release();
263 auto const decorator = d.decorator;
264 #if 1
265 return response_op<Handler>{
266 d_.release_handler(),
267 ws, req, decorator}(ec);
268 #else
269 // VFALCO This *should* work but breaks
270 // coroutine invariants in the unit test.
271 // Also it calls reset() when it shouldn't.
272 return ws.async_accept_ex(
273 req, decorator, d_.release_handler());
274 #endif
275 }
276 }
277 d_.invoke(ec);
278 }
279 }
280
281 //------------------------------------------------------------------------------
282
283 template<class NextLayer>
284 void
285 stream<NextLayer>::
286 accept()
287 {
288 static_assert(is_sync_stream<next_layer_type>::value,
289 "SyncStream requirements not met");
290 error_code ec;
291 accept(ec);
292 if(ec)
293 BOOST_THROW_EXCEPTION(system_error{ec});
294 }
295
296 template<class NextLayer>
297 template<class ResponseDecorator>
298 void
299 stream<NextLayer>::
300 accept_ex(ResponseDecorator const& decorator)
301 {
302 static_assert(is_sync_stream<next_layer_type>::value,
303 "SyncStream requirements not met");
304 static_assert(detail::is_ResponseDecorator<
305 ResponseDecorator>::value,
306 "ResponseDecorator requirements not met");
307 error_code ec;
308 accept_ex(decorator, ec);
309 if(ec)
310 BOOST_THROW_EXCEPTION(system_error{ec});
311 }
312
313 template<class NextLayer>
314 void
315 stream<NextLayer>::
316 accept(error_code& ec)
317 {
318 static_assert(is_sync_stream<next_layer_type>::value,
319 "SyncStream requirements not met");
320 reset();
321 do_accept(&default_decorate_res, ec);
322 }
323
324 template<class NextLayer>
325 template<class ResponseDecorator>
326 void
327 stream<NextLayer>::
328 accept_ex(ResponseDecorator const& decorator, error_code& ec)
329 {
330 static_assert(is_sync_stream<next_layer_type>::value,
331 "SyncStream requirements not met");
332 static_assert(detail::is_ResponseDecorator<
333 ResponseDecorator>::value,
334 "ResponseDecorator requirements not met");
335 reset();
336 do_accept(decorator, ec);
337 }
338
339 template<class NextLayer>
340 template<class ConstBufferSequence>
341 typename std::enable_if<! http::detail::is_header<
342 ConstBufferSequence>::value>::type
343 stream<NextLayer>::
344 accept(ConstBufferSequence const& buffers)
345 {
346 static_assert(is_sync_stream<next_layer_type>::value,
347 "SyncStream requirements not met");
348 static_assert(boost::asio::is_const_buffer_sequence<
349 ConstBufferSequence>::value,
350 "ConstBufferSequence requirements not met");
351 error_code ec;
352 accept(buffers, ec);
353 if(ec)
354 BOOST_THROW_EXCEPTION(system_error{ec});
355 }
356
357 template<class NextLayer>
358 template<
359 class ConstBufferSequence,
360 class ResponseDecorator>
361 typename std::enable_if<! http::detail::is_header<
362 ConstBufferSequence>::value>::type
363 stream<NextLayer>::
364 accept_ex(
365 ConstBufferSequence const& buffers,
366 ResponseDecorator const &decorator)
367 {
368 static_assert(is_sync_stream<next_layer_type>::value,
369 "SyncStream requirements not met");
370 static_assert(boost::asio::is_const_buffer_sequence<
371 ConstBufferSequence>::value,
372 "ConstBufferSequence requirements not met");
373 static_assert(detail::is_ResponseDecorator<
374 ResponseDecorator>::value,
375 "ResponseDecorator requirements not met");
376 error_code ec;
377 accept_ex(buffers, decorator, ec);
378 if(ec)
379 BOOST_THROW_EXCEPTION(system_error{ec});
380 }
381
382 template<class NextLayer>
383 template<class ConstBufferSequence>
384 typename std::enable_if<! http::detail::is_header<
385 ConstBufferSequence>::value>::type
386 stream<NextLayer>::
387 accept(
388 ConstBufferSequence const& buffers, error_code& ec)
389 {
390 static_assert(is_sync_stream<next_layer_type>::value,
391 "SyncStream requirements not met");
392 static_assert(boost::asio::is_const_buffer_sequence<
393 ConstBufferSequence>::value,
394 "ConstBufferSequence requirements not met");
395 using boost::asio::buffer_copy;
396 using boost::asio::buffer_size;
397 reset();
398 boost::optional<typename
399 static_buffer_base::mutable_buffers_type> mb;
400 try
401 {
402 mb.emplace(rd_buf_.prepare(
403 buffer_size(buffers)));
404 }
405 catch(std::length_error const&)
406 {
407 ec = error::buffer_overflow;
408 return;
409 }
410 rd_buf_.commit(
411 buffer_copy(*mb, buffers));
412 do_accept(&default_decorate_res, ec);
413 }
414
415 template<class NextLayer>
416 template<
417 class ConstBufferSequence,
418 class ResponseDecorator>
419 typename std::enable_if<! http::detail::is_header<
420 ConstBufferSequence>::value>::type
421 stream<NextLayer>::
422 accept_ex(
423 ConstBufferSequence const& buffers,
424 ResponseDecorator const& decorator,
425 error_code& ec)
426 {
427 static_assert(is_sync_stream<next_layer_type>::value,
428 "SyncStream requirements not met");
429 static_assert(boost::asio::is_const_buffer_sequence<
430 ConstBufferSequence>::value,
431 "ConstBufferSequence requirements not met");
432 static_assert(boost::asio::is_const_buffer_sequence<
433 ConstBufferSequence>::value,
434 "ConstBufferSequence requirements not met");
435 using boost::asio::buffer_copy;
436 using boost::asio::buffer_size;
437 reset();
438 boost::optional<typename
439 static_buffer_base::mutable_buffers_type> mb;
440 try
441 {
442 mb.emplace(rd_buf_.prepare(
443 buffer_size(buffers)));
444 }
445 catch(std::length_error const&)
446 {
447 ec = error::buffer_overflow;
448 return;
449 }
450 rd_buf_.commit(buffer_copy(*mb, buffers));
451 do_accept(decorator, ec);
452 }
453
454 template<class NextLayer>
455 template<class Body, class Allocator>
456 void
457 stream<NextLayer>::
458 accept(
459 http::request<Body,
460 http::basic_fields<Allocator>> const& req)
461 {
462 static_assert(is_sync_stream<next_layer_type>::value,
463 "SyncStream requirements not met");
464 error_code ec;
465 accept(req, ec);
466 if(ec)
467 BOOST_THROW_EXCEPTION(system_error{ec});
468 }
469
470 template<class NextLayer>
471 template<
472 class Body, class Allocator,
473 class ResponseDecorator>
474 void
475 stream<NextLayer>::
476 accept_ex(
477 http::request<Body,
478 http::basic_fields<Allocator>> const& req,
479 ResponseDecorator const& decorator)
480 {
481 static_assert(is_sync_stream<next_layer_type>::value,
482 "SyncStream requirements not met");
483 static_assert(detail::is_ResponseDecorator<
484 ResponseDecorator>::value,
485 "ResponseDecorator requirements not met");
486 error_code ec;
487 accept_ex(req, decorator, ec);
488 if(ec)
489 BOOST_THROW_EXCEPTION(system_error{ec});
490 }
491
492 template<class NextLayer>
493 template<class Body, class Allocator>
494 void
495 stream<NextLayer>::
496 accept(
497 http::request<Body,
498 http::basic_fields<Allocator>> const& req,
499 error_code& ec)
500 {
501 static_assert(is_sync_stream<next_layer_type>::value,
502 "SyncStream requirements not met");
503 reset();
504 do_accept(req, &default_decorate_res, ec);
505 }
506
507 template<class NextLayer>
508 template<
509 class Body, class Allocator,
510 class ResponseDecorator>
511 void
512 stream<NextLayer>::
513 accept_ex(
514 http::request<Body,
515 http::basic_fields<Allocator>> const& req,
516 ResponseDecorator const& decorator,
517 error_code& ec)
518 {
519 static_assert(is_sync_stream<next_layer_type>::value,
520 "SyncStream requirements not met");
521 static_assert(detail::is_ResponseDecorator<
522 ResponseDecorator>::value,
523 "ResponseDecorator requirements not met");
524 reset();
525 do_accept(req, decorator, ec);
526 }
527
528 //------------------------------------------------------------------------------
529
530 template<class NextLayer>
531 template<
532 class AcceptHandler>
533 BOOST_ASIO_INITFN_RESULT_TYPE(
534 AcceptHandler, void(error_code))
535 stream<NextLayer>::
536 async_accept(
537 AcceptHandler&& handler)
538 {
539 static_assert(is_async_stream<next_layer_type>::value,
540 "AsyncStream requirements requirements not met");
541 boost::asio::async_completion<AcceptHandler,
542 void(error_code)> init{handler};
543 reset();
544 accept_op<
545 decltype(&default_decorate_res),
546 BOOST_ASIO_HANDLER_TYPE(
547 AcceptHandler, void(error_code))>{
548 init.completion_handler,
549 *this,
550 &default_decorate_res}({});
551 return init.result.get();
552 }
553
554 template<class NextLayer>
555 template<
556 class ResponseDecorator,
557 class AcceptHandler>
558 BOOST_ASIO_INITFN_RESULT_TYPE(
559 AcceptHandler, void(error_code))
560 stream<NextLayer>::
561 async_accept_ex(
562 ResponseDecorator const& decorator,
563 AcceptHandler&& handler)
564 {
565 static_assert(is_async_stream<next_layer_type>::value,
566 "AsyncStream requirements requirements not met");
567 static_assert(detail::is_ResponseDecorator<
568 ResponseDecorator>::value,
569 "ResponseDecorator requirements not met");
570 boost::asio::async_completion<AcceptHandler,
571 void(error_code)> init{handler};
572 reset();
573 accept_op<
574 ResponseDecorator,
575 BOOST_ASIO_HANDLER_TYPE(
576 AcceptHandler, void(error_code))>{
577 init.completion_handler,
578 *this,
579 decorator}({});
580 return init.result.get();
581 }
582
583 template<class NextLayer>
584 template<
585 class ConstBufferSequence,
586 class AcceptHandler>
587 typename std::enable_if<
588 ! http::detail::is_header<ConstBufferSequence>::value,
589 BOOST_ASIO_INITFN_RESULT_TYPE(
590 AcceptHandler, void(error_code))>::type
591 stream<NextLayer>::
592 async_accept(
593 ConstBufferSequence const& buffers,
594 AcceptHandler&& handler)
595 {
596 static_assert(is_async_stream<next_layer_type>::value,
597 "AsyncStream requirements requirements not met");
598 static_assert(boost::asio::is_const_buffer_sequence<
599 ConstBufferSequence>::value,
600 "ConstBufferSequence requirements not met");
601 boost::asio::async_completion<AcceptHandler,
602 void(error_code)> init{handler};
603 reset();
604 accept_op<
605 decltype(&default_decorate_res),
606 BOOST_ASIO_HANDLER_TYPE(
607 AcceptHandler, void(error_code))>{
608 init.completion_handler,
609 *this,
610 &default_decorate_res}.run(buffers);
611 return init.result.get();
612 }
613
614 template<class NextLayer>
615 template<
616 class ConstBufferSequence,
617 class ResponseDecorator,
618 class AcceptHandler>
619 typename std::enable_if<
620 ! http::detail::is_header<ConstBufferSequence>::value,
621 BOOST_ASIO_INITFN_RESULT_TYPE(
622 AcceptHandler, void(error_code))>::type
623 stream<NextLayer>::
624 async_accept_ex(
625 ConstBufferSequence const& buffers,
626 ResponseDecorator const& decorator,
627 AcceptHandler&& handler)
628 {
629 static_assert(is_async_stream<next_layer_type>::value,
630 "AsyncStream requirements requirements not met");
631 static_assert(boost::asio::is_const_buffer_sequence<
632 ConstBufferSequence>::value,
633 "ConstBufferSequence requirements not met");
634 static_assert(detail::is_ResponseDecorator<
635 ResponseDecorator>::value,
636 "ResponseDecorator requirements not met");
637 boost::asio::async_completion<AcceptHandler,
638 void(error_code)> init{handler};
639 reset();
640 accept_op<
641 ResponseDecorator,
642 BOOST_ASIO_HANDLER_TYPE(
643 AcceptHandler, void(error_code))>{
644 init.completion_handler,
645 *this,
646 decorator}.run(buffers);
647 return init.result.get();
648 }
649
650 template<class NextLayer>
651 template<
652 class Body, class Allocator,
653 class AcceptHandler>
654 BOOST_ASIO_INITFN_RESULT_TYPE(
655 AcceptHandler, void(error_code))
656 stream<NextLayer>::
657 async_accept(
658 http::request<Body, http::basic_fields<Allocator>> const& req,
659 AcceptHandler&& handler)
660 {
661 static_assert(is_async_stream<next_layer_type>::value,
662 "AsyncStream requirements requirements not met");
663 boost::asio::async_completion<AcceptHandler,
664 void(error_code)> init{handler};
665 reset();
666 using boost::asio::asio_handler_is_continuation;
667 response_op<
668 BOOST_ASIO_HANDLER_TYPE(
669 AcceptHandler, void(error_code))>{
670 init.completion_handler,
671 *this,
672 req,
673 &default_decorate_res}();
674 return init.result.get();
675 }
676
677 template<class NextLayer>
678 template<
679 class Body, class Allocator,
680 class ResponseDecorator,
681 class AcceptHandler>
682 BOOST_ASIO_INITFN_RESULT_TYPE(
683 AcceptHandler, void(error_code))
684 stream<NextLayer>::
685 async_accept_ex(
686 http::request<Body, http::basic_fields<Allocator>> const& req,
687 ResponseDecorator const& decorator,
688 AcceptHandler&& handler)
689 {
690 static_assert(is_async_stream<next_layer_type>::value,
691 "AsyncStream requirements requirements not met");
692 static_assert(detail::is_ResponseDecorator<
693 ResponseDecorator>::value,
694 "ResponseDecorator requirements not met");
695 boost::asio::async_completion<AcceptHandler,
696 void(error_code)> init{handler};
697 reset();
698 using boost::asio::asio_handler_is_continuation;
699 response_op<
700 BOOST_ASIO_HANDLER_TYPE(
701 AcceptHandler, void(error_code))>{
702 init.completion_handler,
703 *this,
704 req,
705 decorator}();
706 return init.result.get();
707 }
708
709 //------------------------------------------------------------------------------
710
711 template<class NextLayer>
712 template<class Decorator>
713 void
714 stream<NextLayer>::
715 do_accept(
716 Decorator const& decorator,
717 error_code& ec)
718 {
719 http::request_parser<http::empty_body> p;
720 http::read(next_layer(), rd_buf_, p, ec);
721 if(ec == http::error::end_of_stream)
722 ec = error::closed;
723 if(ec)
724 return;
725 do_accept(p.get(), decorator, ec);
726 }
727
728 template<class NextLayer>
729 template<class Body, class Allocator,
730 class Decorator>
731 void
732 stream<NextLayer>::
733 do_accept(
734 http::request<Body,http::basic_fields<Allocator>> const& req,
735 Decorator const& decorator,
736 error_code& ec)
737 {
738 auto const res = build_response(req, decorator);
739 http::write(stream_, res, ec);
740 if(ec)
741 return;
742 if(res.result() != http::status::switching_protocols)
743 {
744 ec = error::handshake_failed;
745 // VFALCO TODO Respect keep alive setting, perform
746 // teardown if Connection: close.
747 return;
748 }
749 pmd_read(pmd_config_, res);
750 open(role_type::server);
751 }
752
753 } // websocket
754 } // beast
755 } // boost
756
757 #endif