2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
11 #define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
13 #include <boost/beast/websocket/impl/stream_impl.hpp>
14 #include <boost/beast/websocket/detail/type_traits.hpp>
15 #include <boost/beast/http/empty_body.hpp>
16 #include <boost/beast/http/parser.hpp>
17 #include <boost/beast/http/read.hpp>
18 #include <boost/beast/http/string_body.hpp>
19 #include <boost/beast/http/write.hpp>
20 #include <boost/beast/core/async_base.hpp>
21 #include <boost/beast/core/buffer_traits.hpp>
22 #include <boost/beast/core/stream_traits.hpp>
23 #include <boost/beast/core/detail/buffer.hpp>
24 #include <boost/beast/version.hpp>
25 #include <boost/asio/coroutine.hpp>
26 #include <boost/asio/post.hpp>
27 #include <boost/assert.hpp>
28 #include <boost/throw_exception.hpp>
30 #include <type_traits>
36 //------------------------------------------------------------------------------
40 template<class Body, class Allocator>
44 http::response<http::string_body>& res,
46 http::basic_fields<Allocator>> const& req)
51 pmd_negotiate(res, unused, offer, pmd_opts_);
54 template<class Body, class Allocator>
58 http::response<http::string_body>&,
60 http::basic_fields<Allocator>> const&)
66 template<class NextLayer, bool deflateSupported>
67 template<class Body, class Allocator, class Decorator>
69 stream<NextLayer, deflateSupported>::impl_type::
72 http::basic_fields<Allocator>> const& req,
73 Decorator const& decorator,
77 [this, &decorator](response_type& res)
81 if(! res.count(http::field::server))
82 res.set(http::field::server,
83 string_view(BOOST_BEAST_VERSION_STRING));
90 res.version(req.version());
91 res.result(http::status::bad_request);
92 res.body() = result.message();
93 res.prepare_payload();
97 if(req.version() != 11)
98 return err(error::bad_http_version);
99 if(req.method() != http::verb::get)
100 return err(error::bad_method);
101 if(! req.count(http::field::host))
102 return err(error::no_host);
104 auto const it = req.find(http::field::connection);
106 return err(error::no_connection);
107 if(! http::token_list{it->value()}.exists("upgrade"))
108 return err(error::no_connection_upgrade);
111 auto const it = req.find(http::field::upgrade);
113 return err(error::no_upgrade);
114 if(! http::token_list{it->value()}.exists("websocket"))
115 return err(error::no_upgrade_websocket);
119 auto const it = req.find(http::field::sec_websocket_key);
121 return err(error::no_sec_key);
123 if(key.size() > detail::sec_ws_key_type::max_size_n)
124 return err(error::bad_sec_key);
127 auto const it = req.find(http::field::sec_websocket_version);
129 return err(error::no_sec_version);
130 if(it->value() != "13")
133 res.result(http::status::upgrade_required);
134 res.version(req.version());
135 res.set(http::field::sec_websocket_version, "13");
136 result = error::bad_sec_version;
137 res.body() = result.message();
138 res.prepare_payload();
145 res.result(http::status::switching_protocols);
146 res.version(req.version());
147 res.set(http::field::upgrade, "websocket");
148 res.set(http::field::connection, "upgrade");
150 detail::sec_ws_accept_type acc;
151 detail::make_sec_ws_accept(acc, key);
152 res.set(http::field::sec_websocket_accept, acc);
154 this->build_response_pmd(res, req);
160 //------------------------------------------------------------------------------
162 /** Respond to an HTTP request
164 template<class NextLayer, bool deflateSupported>
165 template<class Handler>
166 class stream<NextLayer, deflateSupported>::response_op
167 : public beast::stable_async_base<
168 Handler, beast::executor_type<stream>>
169 , public asio::coroutine
171 boost::weak_ptr<impl_type> wp_;
172 error_code result_; // must come before res_
178 class Body, class Allocator,
182 boost::shared_ptr<impl_type> const& sp,
184 http::basic_fields<Allocator>> const& req,
185 Decorator const& decorator,
187 : stable_async_base<Handler,
188 beast::executor_type<stream>>(
189 std::forward<Handler_>(h),
190 sp->stream().get_executor())
192 , res_(beast::allocate_stable<response_type>(*this,
193 sp->build_response(req, decorator, result_)))
195 (*this)({}, 0, cont);
200 std::size_t bytes_transferred = 0,
203 boost::ignore_unused(bytes_transferred);
204 auto sp = wp_.lock();
207 ec = net::error::operation_aborted;
208 return this->complete(cont, ec);
211 BOOST_ASIO_CORO_REENTER(*this)
213 impl.change_status(status::handshake);
214 impl.update_timer(this->get_executor());
217 BOOST_ASIO_CORO_YIELD
219 impl.stream(), res_, std::move(*this));
220 if(impl.check_stop_now(ec))
226 impl.do_pmd_config(res_);
227 impl.open(role_type::server);
230 this->complete(cont, ec);
235 //------------------------------------------------------------------------------
237 // read and respond to an upgrade request
239 template<class NextLayer, bool deflateSupported>
240 template<class Handler, class Decorator>
241 class stream<NextLayer, deflateSupported>::accept_op
242 : public beast::stable_async_base<
243 Handler, beast::executor_type<stream>>
244 , public asio::coroutine
246 boost::weak_ptr<impl_type> wp_;
247 http::request_parser<http::empty_body>& p_;
251 template<class Handler_, class Buffers>
254 boost::shared_ptr<impl_type> const& sp,
255 Decorator const& decorator,
256 Buffers const& buffers)
257 : stable_async_base<Handler,
258 beast::executor_type<stream>>(
259 std::forward<Handler_>(h),
260 sp->stream().get_executor())
262 , p_(beast::allocate_stable<
263 http::request_parser<http::empty_body>>(*this))
269 beast::detail::dynamic_buffer_prepare(
270 impl.rd_buf, buffer_bytes(buffers),
271 ec, error::buffer_overflow);
274 net::buffer_copy(*mb, buffers));
280 std::size_t bytes_transferred = 0,
283 boost::ignore_unused(bytes_transferred);
284 auto sp = wp_.lock();
287 ec = net::error::operation_aborted;
288 return this->complete(cont, ec);
291 BOOST_ASIO_CORO_REENTER(*this)
293 impl.change_status(status::handshake);
294 impl.update_timer(this->get_executor());
296 // The constructor could have set ec
300 BOOST_ASIO_CORO_YIELD
301 http::async_read(impl.stream(),
302 impl.rd_buf, p_, std::move(*this));
303 if(ec == http::error::end_of_stream)
305 if(impl.check_stop_now(ec))
309 // Arguments from our state must be
310 // moved to the stack before releasing
312 auto const req = p_.release();
313 auto const decorator = d_;
314 response_op<Handler>(
315 this->release_handler(),
316 sp, req, decorator, true);
321 this->complete(cont, ec);
326 template<class NextLayer, bool deflateSupported>
327 struct stream<NextLayer, deflateSupported>::
332 class Body, class Allocator,
337 boost::shared_ptr<impl_type> const& sp,
339 http::basic_fields<Allocator>> const* m,
342 // If you get an error on the following line it means
343 // that your handler does not meet the documented type
344 // requirements for the handler.
347 beast::detail::is_invocable<AcceptHandler,
348 void(error_code)>::value,
349 "AcceptHandler type requirements not met");
352 typename std::decay<AcceptHandler>::type>(
353 std::forward<AcceptHandler>(h), sp, *m, d);
357 template<class NextLayer, bool deflateSupported>
358 struct stream<NextLayer, deflateSupported>::
368 boost::shared_ptr<impl_type> const& sp,
372 // If you get an error on the following line it means
373 // that your handler does not meet the documented type
374 // requirements for the handler.
377 beast::detail::is_invocable<AcceptHandler,
378 void(error_code)>::value,
379 "AcceptHandler type requirements not met");
382 typename std::decay<AcceptHandler>::type,
384 std::forward<AcceptHandler>(h),
391 //------------------------------------------------------------------------------
393 template<class NextLayer, bool deflateSupported>
394 template<class Body, class Allocator,
397 stream<NextLayer, deflateSupported>::
400 http::basic_fields<Allocator>> const& req,
401 Decorator const& decorator,
404 impl_->change_status(status::handshake);
407 auto const res = impl_->build_response(req, decorator, result);
408 http::write(impl_->stream(), res, ec);
414 // VFALCO TODO Respect keep alive setting, perform
415 // teardown if Connection: close.
418 impl_->do_pmd_config(res);
419 impl_->open(role_type::server);
422 template<class NextLayer, bool deflateSupported>
423 template<class Buffers, class Decorator>
425 stream<NextLayer, deflateSupported>::
427 Buffers const& buffers,
428 Decorator const& decorator,
433 beast::detail::dynamic_buffer_prepare(
434 impl_->rd_buf, buffer_bytes(buffers), ec,
435 error::buffer_overflow);
438 impl_->rd_buf.commit(net::buffer_copy(*mb, buffers));
440 http::request_parser<http::empty_body> p;
441 http::read(next_layer(), impl_->rd_buf, p, ec);
442 if(ec == http::error::end_of_stream)
446 do_accept(p.get(), decorator, ec);
449 //------------------------------------------------------------------------------
451 template<class NextLayer, bool deflateSupported>
453 stream<NextLayer, deflateSupported>::
456 static_assert(is_sync_stream<next_layer_type>::value,
457 "SyncStream type requirements not met");
461 BOOST_THROW_EXCEPTION(system_error{ec});
464 template<class NextLayer, bool deflateSupported>
466 stream<NextLayer, deflateSupported>::
467 accept(error_code& ec)
469 static_assert(is_sync_stream<next_layer_type>::value,
470 "SyncStream type requirements not met");
473 &default_decorate_res, ec);
476 template<class NextLayer, bool deflateSupported>
477 template<class ConstBufferSequence>
478 typename std::enable_if<! http::detail::is_header<
479 ConstBufferSequence>::value>::type
480 stream<NextLayer, deflateSupported>::
481 accept(ConstBufferSequence const& buffers)
483 static_assert(is_sync_stream<next_layer_type>::value,
484 "SyncStream type requirements not met");
485 static_assert(net::is_const_buffer_sequence<
486 ConstBufferSequence>::value,
487 "ConstBufferSequence type requirements not met");
491 BOOST_THROW_EXCEPTION(system_error{ec});
493 template<class NextLayer, bool deflateSupported>
494 template<class ConstBufferSequence>
495 typename std::enable_if<! http::detail::is_header<
496 ConstBufferSequence>::value>::type
497 stream<NextLayer, deflateSupported>::
499 ConstBufferSequence const& buffers, error_code& ec)
501 static_assert(is_sync_stream<next_layer_type>::value,
502 "SyncStream type requirements not met");
503 static_assert(net::is_const_buffer_sequence<
504 ConstBufferSequence>::value,
505 "ConstBufferSequence type requirements not met");
506 do_accept(buffers, &default_decorate_res, ec);
510 template<class NextLayer, bool deflateSupported>
511 template<class Body, class Allocator>
513 stream<NextLayer, deflateSupported>::
516 http::basic_fields<Allocator>> const& req)
518 static_assert(is_sync_stream<next_layer_type>::value,
519 "SyncStream type requirements not met");
523 BOOST_THROW_EXCEPTION(system_error{ec});
526 template<class NextLayer, bool deflateSupported>
527 template<class Body, class Allocator>
529 stream<NextLayer, deflateSupported>::
532 http::basic_fields<Allocator>> const& req,
535 static_assert(is_sync_stream<next_layer_type>::value,
536 "SyncStream type requirements not met");
538 do_accept(req, &default_decorate_res, ec);
541 //------------------------------------------------------------------------------
543 template<class NextLayer, bool deflateSupported>
546 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
547 stream<NextLayer, deflateSupported>::
549 AcceptHandler&& handler)
551 static_assert(is_async_stream<next_layer_type>::value,
552 "AsyncStream type requirements not met");
554 return net::async_initiate<
560 &default_decorate_res,
561 net::const_buffer{});
564 template<class NextLayer, bool deflateSupported>
566 class ResponseDecorator,
568 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
569 stream<NextLayer, deflateSupported>::
571 ResponseDecorator const& decorator,
572 AcceptHandler&& handler)
574 static_assert(is_async_stream<next_layer_type>::value,
575 "AsyncStream type requirements not met");
576 static_assert(detail::is_response_decorator<
577 ResponseDecorator>::value,
578 "ResponseDecorator requirements not met");
580 return net::async_initiate<
587 net::const_buffer{});
590 template<class NextLayer, bool deflateSupported>
592 class ConstBufferSequence,
594 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
595 stream<NextLayer, deflateSupported>::
597 ConstBufferSequence const& buffers,
598 AcceptHandler&& handler,
599 typename std::enable_if<
600 ! http::detail::is_header<
601 ConstBufferSequence>::value>::type*
604 static_assert(is_async_stream<next_layer_type>::value,
605 "AsyncStream type requirements not met");
606 static_assert(net::is_const_buffer_sequence<
607 ConstBufferSequence>::value,
608 "ConstBufferSequence type requirements not met");
610 return net::async_initiate<
616 &default_decorate_res,
620 template<class NextLayer, bool deflateSupported>
622 class ConstBufferSequence,
623 class ResponseDecorator,
625 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
626 stream<NextLayer, deflateSupported>::
628 ConstBufferSequence const& buffers,
629 ResponseDecorator const& decorator,
630 AcceptHandler&& handler,
631 typename std::enable_if<
632 ! http::detail::is_header<
633 ConstBufferSequence>::value>::type*)
635 static_assert(is_async_stream<next_layer_type>::value,
636 "AsyncStream type requirements not met");
637 static_assert(net::is_const_buffer_sequence<
638 ConstBufferSequence>::value,
639 "ConstBufferSequence type requirements not met");
640 static_assert(detail::is_response_decorator<
641 ResponseDecorator>::value,
642 "ResponseDecorator requirements not met");
644 return net::async_initiate<
654 template<class NextLayer, bool deflateSupported>
656 class Body, class Allocator,
658 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
659 stream<NextLayer, deflateSupported>::
661 http::request<Body, http::basic_fields<Allocator>> const& req,
662 AcceptHandler&& handler)
664 static_assert(is_async_stream<next_layer_type>::value,
665 "AsyncStream type requirements not met");
667 return net::async_initiate<
674 &default_decorate_res);
677 template<class NextLayer, bool deflateSupported>
679 class Body, class Allocator,
680 class ResponseDecorator,
682 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
683 stream<NextLayer, deflateSupported>::
685 http::request<Body, http::basic_fields<Allocator>> const& req,
686 ResponseDecorator const& decorator,
687 AcceptHandler&& handler)
689 static_assert(is_async_stream<next_layer_type>::value,
690 "AsyncStream type requirements not met");
691 static_assert(detail::is_response_decorator<
692 ResponseDecorator>::value,
693 "ResponseDecorator requirements not met");
695 return net::async_initiate<
705 //------------------------------------------------------------------------------
707 template<class NextLayer, bool deflateSupported>
708 template<class ResponseDecorator>
710 stream<NextLayer, deflateSupported>::
711 accept_ex(ResponseDecorator const& decorator)
713 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
714 static_assert(sizeof(ResponseDecorator) == 0,
715 BOOST_BEAST_DEPRECATION_STRING);
717 static_assert(is_sync_stream<next_layer_type>::value,
718 "SyncStream type requirements not met");
719 static_assert(detail::is_response_decorator<
720 ResponseDecorator>::value,
721 "ResponseDecorator requirements not met");
723 accept_ex(decorator, ec);
725 BOOST_THROW_EXCEPTION(system_error{ec});
728 template<class NextLayer, bool deflateSupported>
729 template<class ResponseDecorator>
731 stream<NextLayer, deflateSupported>::
732 accept_ex(ResponseDecorator const& decorator, error_code& ec)
734 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
735 static_assert(sizeof(ResponseDecorator) == 0,
736 BOOST_BEAST_DEPRECATION_STRING);
738 static_assert(is_sync_stream<next_layer_type>::value,
739 "SyncStream type requirements not met");
740 static_assert(detail::is_response_decorator<
741 ResponseDecorator>::value,
742 "ResponseDecorator requirements not met");
748 template<class NextLayer, bool deflateSupported>
750 class ConstBufferSequence,
751 class ResponseDecorator>
752 typename std::enable_if<! http::detail::is_header<
753 ConstBufferSequence>::value>::type
754 stream<NextLayer, deflateSupported>::
756 ConstBufferSequence const& buffers,
757 ResponseDecorator const &decorator)
759 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
760 static_assert(sizeof(ResponseDecorator) == 0,
761 BOOST_BEAST_DEPRECATION_STRING);
763 static_assert(is_sync_stream<next_layer_type>::value,
764 "SyncStream type requirements not met");
765 static_assert(net::is_const_buffer_sequence<
766 ConstBufferSequence>::value,
767 "ConstBufferSequence type requirements not met");
768 static_assert(detail::is_response_decorator<
769 ResponseDecorator>::value,
770 "ResponseDecorator requirements not met");
772 accept_ex(buffers, decorator, ec);
774 BOOST_THROW_EXCEPTION(system_error{ec});
777 template<class NextLayer, bool deflateSupported>
779 class ConstBufferSequence,
780 class ResponseDecorator>
781 typename std::enable_if<! http::detail::is_header<
782 ConstBufferSequence>::value>::type
783 stream<NextLayer, deflateSupported>::
785 ConstBufferSequence const& buffers,
786 ResponseDecorator const& decorator,
789 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
790 static_assert(sizeof(ResponseDecorator) == 0,
791 BOOST_BEAST_DEPRECATION_STRING);
793 static_assert(is_sync_stream<next_layer_type>::value,
794 "SyncStream type requirements not met");
795 static_assert(net::is_const_buffer_sequence<
796 ConstBufferSequence>::value,
797 "ConstBufferSequence type requirements not met");
798 static_assert(net::is_const_buffer_sequence<
799 ConstBufferSequence>::value,
800 "ConstBufferSequence type requirements not met");
801 do_accept(buffers, decorator, ec);
804 template<class NextLayer, bool deflateSupported>
806 class Body, class Allocator,
807 class ResponseDecorator>
809 stream<NextLayer, deflateSupported>::
812 http::basic_fields<Allocator>> const& req,
813 ResponseDecorator const& decorator)
815 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
816 static_assert(sizeof(ResponseDecorator) == 0,
817 BOOST_BEAST_DEPRECATION_STRING);
819 static_assert(is_sync_stream<next_layer_type>::value,
820 "SyncStream type requirements not met");
821 static_assert(detail::is_response_decorator<
822 ResponseDecorator>::value,
823 "ResponseDecorator requirements not met");
825 accept_ex(req, decorator, ec);
827 BOOST_THROW_EXCEPTION(system_error{ec});
830 template<class NextLayer, bool deflateSupported>
832 class Body, class Allocator,
833 class ResponseDecorator>
835 stream<NextLayer, deflateSupported>::
838 http::basic_fields<Allocator>> const& req,
839 ResponseDecorator const& decorator,
842 #ifndef BOOST_BEAST_ALLOW_DEPRECATED
843 static_assert(sizeof(ResponseDecorator) == 0,
844 BOOST_BEAST_DEPRECATION_STRING);
846 static_assert(is_sync_stream<next_layer_type>::value,
847 "SyncStream type requirements not met");
848 static_assert(detail::is_response_decorator<
849 ResponseDecorator>::value,
850 "ResponseDecorator requirements not met");
852 do_accept(req, decorator, ec);