summaryrefslogtreecommitdiff
path: root/boost/beast/websocket/impl/handshake.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/websocket/impl/handshake.hpp')
-rw-r--r--boost/beast/websocket/impl/handshake.hpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/boost/beast/websocket/impl/handshake.hpp b/boost/beast/websocket/impl/handshake.hpp
new file mode 100644
index 0000000000..21fba99738
--- /dev/null
+++ b/boost/beast/websocket/impl/handshake.hpp
@@ -0,0 +1,540 @@
+//
+// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_HPP
+#define BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_HPP
+
+#include <boost/beast/websocket/impl/stream_impl.hpp>
+#include <boost/beast/websocket/detail/type_traits.hpp>
+#include <boost/beast/http/empty_body.hpp>
+#include <boost/beast/http/message.hpp>
+#include <boost/beast/http/read.hpp>
+#include <boost/beast/http/write.hpp>
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/flat_buffer.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <memory>
+
+namespace boost {
+namespace beast {
+namespace websocket {
+
+//------------------------------------------------------------------------------
+
+// send the upgrade request and process the response
+//
+template<class NextLayer, bool deflateSupported>
+template<class Handler>
+class stream<NextLayer, deflateSupported>::handshake_op
+ : public beast::stable_async_base<Handler,
+ beast::executor_type<stream>>
+ , public net::coroutine
+{
+ struct data
+ {
+ // VFALCO This really should be two separate
+ // composed operations, to save on memory
+ request_type req;
+ http::response_parser<
+ typename response_type::body_type> p;
+ flat_buffer fb;
+ bool overflow = false; // could be a member of the op
+
+ explicit
+ data(request_type&& req_)
+ : req(std::move(req_))
+ {
+ }
+ };
+
+ boost::weak_ptr<impl_type> wp_;
+ detail::sec_ws_key_type key_;
+ response_type* res_p_;
+ data& d_;
+
+public:
+ template<class Handler_>
+ handshake_op(
+ Handler_&& h,
+ boost::shared_ptr<impl_type> const& sp,
+ request_type&& req,
+ detail::sec_ws_key_type key,
+ response_type* res_p)
+ : stable_async_base<Handler,
+ beast::executor_type<stream>>(
+ std::forward<Handler_>(h),
+ sp->stream().get_executor())
+ , wp_(sp)
+ , key_(key)
+ , res_p_(res_p)
+ , d_(beast::allocate_stable<data>(
+ *this, std::move(req)))
+ {
+ sp->reset(); // VFALCO I don't like this
+ (*this)({}, 0, false);
+ }
+
+ void
+ operator()(
+ error_code ec = {},
+ std::size_t bytes_used = 0,
+ bool cont = true)
+ {
+ boost::ignore_unused(bytes_used);
+ auto sp = wp_.lock();
+ if(! sp)
+ {
+ ec = net::error::operation_aborted;
+ return this->complete(cont, ec);
+ }
+ auto& impl = *sp;
+ BOOST_ASIO_CORO_REENTER(*this)
+ {
+ impl.change_status(status::handshake);
+ impl.update_timer(this->get_executor());
+
+ // write HTTP request
+ impl.do_pmd_config(d_.req);
+ BOOST_ASIO_CORO_YIELD
+ http::async_write(impl.stream(),
+ d_.req, std::move(*this));
+ if(impl.check_stop_now(ec))
+ goto upcall;
+
+ // read HTTP response
+ BOOST_ASIO_CORO_YIELD
+ http::async_read(impl.stream(),
+ impl.rd_buf, d_.p,
+ std::move(*this));
+ if(ec == http::error::buffer_overflow)
+ {
+ // If the response overflows the internal
+ // read buffer, switch to a dynamically
+ // allocated flat buffer.
+
+ d_.fb.commit(net::buffer_copy(
+ d_.fb.prepare(impl.rd_buf.size()),
+ impl.rd_buf.data()));
+ impl.rd_buf.clear();
+
+ BOOST_ASIO_CORO_YIELD
+ http::async_read(impl.stream(),
+ d_.fb, d_.p, std::move(*this));
+
+ if(! ec)
+ {
+ // Copy any leftovers back into the read
+ // buffer, since this represents websocket
+ // frame data.
+
+ if(d_.fb.size() <= impl.rd_buf.capacity())
+ {
+ impl.rd_buf.commit(net::buffer_copy(
+ impl.rd_buf.prepare(d_.fb.size()),
+ d_.fb.data()));
+ }
+ else
+ {
+ ec = http::error::buffer_overflow;
+ }
+ }
+
+ // Do this before the upcall
+ d_.fb.clear();
+ }
+ if(impl.check_stop_now(ec))
+ goto upcall;
+
+ // success
+ impl.reset_idle();
+ impl.on_response(d_.p.get(), key_, ec);
+ if(res_p_)
+ swap(d_.p.get(), *res_p_);
+
+ upcall:
+ this->complete(cont ,ec);
+ }
+ }
+};
+
+template<class NextLayer, bool deflateSupported>
+struct stream<NextLayer, deflateSupported>::
+ run_handshake_op
+{
+ template<class HandshakeHandler>
+ void operator()(
+ HandshakeHandler&& h,
+ boost::shared_ptr<impl_type> const& sp,
+ request_type&& req,
+ detail::sec_ws_key_type key,
+ response_type* res_p)
+ {
+ // If you get an error on the following line it means
+ // that your handler does not meet the documented type
+ // requirements for the handler.
+
+ static_assert(
+ beast::detail::is_invocable<HandshakeHandler,
+ void(error_code)>::value,
+ "HandshakeHandler type requirements not met");
+
+ handshake_op<
+ typename std::decay<HandshakeHandler>::type>(
+ std::forward<HandshakeHandler>(h),
+ sp, std::move(req), key, res_p);
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator>
+void
+stream<NextLayer, deflateSupported>::
+do_handshake(
+ response_type* res_p,
+ string_view host,
+ string_view target,
+ RequestDecorator const& decorator,
+ error_code& ec)
+{
+ auto& impl = *impl_;
+ impl.change_status(status::handshake);
+ impl.reset();
+ detail::sec_ws_key_type key;
+ {
+ auto const req = impl.build_request(
+ key, host, target, decorator);
+ impl.do_pmd_config(req);
+ http::write(impl.stream(), req, ec);
+ }
+ if(impl.check_stop_now(ec))
+ return;
+ http::response_parser<
+ typename response_type::body_type> p;
+ http::read(next_layer(), impl.rd_buf, p, ec);
+ if(ec == http::error::buffer_overflow)
+ {
+ // If the response overflows the internal
+ // read buffer, switch to a dynamically
+ // allocated flat buffer.
+
+ flat_buffer fb;
+ fb.commit(net::buffer_copy(
+ fb.prepare(impl.rd_buf.size()),
+ impl.rd_buf.data()));
+ impl.rd_buf.clear();
+
+ http::read(next_layer(), fb, p, ec);;
+
+ if(! ec)
+ {
+ // Copy any leftovers back into the read
+ // buffer, since this represents websocket
+ // frame data.
+
+ if(fb.size() <= impl.rd_buf.capacity())
+ {
+ impl.rd_buf.commit(net::buffer_copy(
+ impl.rd_buf.prepare(fb.size()),
+ fb.data()));
+ }
+ else
+ {
+ ec = http::error::buffer_overflow;
+ }
+ }
+ }
+ if(impl.check_stop_now(ec))
+ return;
+
+ impl.on_response(p.get(), key, ec);
+ if(impl.check_stop_now(ec))
+ return;
+
+ if(res_p)
+ *res_p = p.release();
+}
+
+//------------------------------------------------------------------------------
+
+template<class NextLayer, bool deflateSupported>
+template<class HandshakeHandler>
+BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
+stream<NextLayer, deflateSupported>::
+async_handshake(
+ string_view host,
+ string_view target,
+ HandshakeHandler&& handler)
+{
+ static_assert(is_async_stream<next_layer_type>::value,
+ "AsyncStream type requirements not met");
+ detail::sec_ws_key_type key;
+ auto req = impl_->build_request(
+ key, host, target, &default_decorate_req);
+ return net::async_initiate<
+ HandshakeHandler,
+ void(error_code)>(
+ run_handshake_op{},
+ handler,
+ impl_,
+ std::move(req),
+ key,
+ nullptr);
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class HandshakeHandler>
+BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
+stream<NextLayer, deflateSupported>::
+async_handshake(
+ response_type& res,
+ string_view host,
+ string_view target,
+ HandshakeHandler&& handler)
+{
+ static_assert(is_async_stream<next_layer_type>::value,
+ "AsyncStream type requirements not met");
+ detail::sec_ws_key_type key;
+ auto req = impl_->build_request(
+ key, host, target, &default_decorate_req);
+ return net::async_initiate<
+ HandshakeHandler,
+ void(error_code)>(
+ run_handshake_op{},
+ handler,
+ impl_,
+ std::move(req),
+ key,
+ &res);
+}
+
+template<class NextLayer, bool deflateSupported>
+void
+stream<NextLayer, deflateSupported>::
+handshake(string_view host,
+ string_view target)
+{
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ error_code ec;
+ handshake(
+ host, target, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+}
+
+template<class NextLayer, bool deflateSupported>
+void
+stream<NextLayer, deflateSupported>::
+handshake(response_type& res,
+ string_view host,
+ string_view target)
+{
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ error_code ec;
+ handshake(res, host, target, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+}
+
+template<class NextLayer, bool deflateSupported>
+void
+stream<NextLayer, deflateSupported>::
+handshake(string_view host,
+ string_view target, error_code& ec)
+{
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ do_handshake(nullptr,
+ host, target, &default_decorate_req, ec);
+}
+
+template<class NextLayer, bool deflateSupported>
+void
+stream<NextLayer, deflateSupported>::
+handshake(response_type& res,
+ string_view host,
+ string_view target,
+ error_code& ec)
+{
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ do_handshake(&res,
+ host, target, &default_decorate_req, ec);
+}
+
+//------------------------------------------------------------------------------
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator>
+void
+stream<NextLayer, deflateSupported>::
+handshake_ex(string_view host,
+ string_view target,
+ RequestDecorator const& decorator)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ error_code ec;
+ handshake_ex(host, target, decorator, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator>
+void
+stream<NextLayer, deflateSupported>::
+handshake_ex(response_type& res,
+ string_view host,
+ string_view target,
+ RequestDecorator const& decorator)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ error_code ec;
+ handshake_ex(res, host, target, decorator, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator>
+void
+stream<NextLayer, deflateSupported>::
+handshake_ex(string_view host,
+ string_view target,
+ RequestDecorator const& decorator,
+ error_code& ec)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ do_handshake(nullptr,
+ host, target, decorator, ec);
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator>
+void
+stream<NextLayer, deflateSupported>::
+handshake_ex(response_type& res,
+ string_view host,
+ string_view target,
+ RequestDecorator const& decorator,
+ error_code& ec)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_sync_stream<next_layer_type>::value,
+ "SyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ do_handshake(&res,
+ host, target, decorator, ec);
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator, class HandshakeHandler>
+BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
+stream<NextLayer, deflateSupported>::
+async_handshake_ex(string_view host,
+ string_view target,
+ RequestDecorator const& decorator,
+ HandshakeHandler&& handler)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_async_stream<next_layer_type>::value,
+ "AsyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ detail::sec_ws_key_type key;
+ auto req = impl_->build_request(
+ key, host, target, decorator);
+ return net::async_initiate<
+ HandshakeHandler,
+ void(error_code)>(
+ run_handshake_op{},
+ handler,
+ impl_,
+ std::move(req),
+ key,
+ nullptr);
+}
+
+template<class NextLayer, bool deflateSupported>
+template<class RequestDecorator, class HandshakeHandler>
+BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
+stream<NextLayer, deflateSupported>::
+async_handshake_ex(response_type& res,
+ string_view host,
+ string_view target,
+ RequestDecorator const& decorator,
+ HandshakeHandler&& handler)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(RequestDecorator) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+ static_assert(is_async_stream<next_layer_type>::value,
+ "AsyncStream type requirements not met");
+ static_assert(detail::is_request_decorator<
+ RequestDecorator>::value,
+ "RequestDecorator requirements not met");
+ detail::sec_ws_key_type key;
+ auto req = impl_->build_request(
+ key, host, target, decorator);
+ return net::async_initiate<
+ HandshakeHandler,
+ void(error_code)>(
+ run_handshake_op{},
+ handler,
+ impl_,
+ std::move(req),
+ key,
+ &res);
+}
+
+} // websocket
+} // beast
+} // boost
+
+#endif