// // Copyright (c) 2013-2016 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) // #ifndef BEAST_WEBSOCKET_IMPL_HANDSHAKE_OP_HPP #define BEAST_WEBSOCKET_IMPL_HANDSHAKE_OP_HPP #include #include #include #include #include #include #include namespace beast { namespace websocket { // send the upgrade request and process the response // template template class stream::handshake_op { using alloc_type = handler_alloc; struct data { stream& ws; Handler h; std::string key; http::request_v1 req; http::response_v1 resp; bool cont; int state = 0; template data(DeducedHandler&& h_, stream& ws_, boost::string_ref const& host, boost::string_ref const& resource) : ws(ws_) , h(std::forward(h_)) , req(ws.build_request(host, resource, key)) , cont(boost_asio_handler_cont_helpers:: is_continuation(h)) { } }; std::shared_ptr d_; public: handshake_op(handshake_op&&) = default; handshake_op(handshake_op const&) = default; template handshake_op(DeducedHandler&& h, stream& ws, Args&&... args) : d_(std::allocate_shared(alloc_type{h}, std::forward(h), ws, std::forward(args)...)) { (*this)(error_code{}, 0, false); } void operator()(error_code const& ec) { (*this)(ec, 0); } void operator()(error_code ec, std::size_t bytes_transferred, bool again = true); friend void* asio_handler_allocate( std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: allocate(size, op->d_->h); } friend void asio_handler_deallocate( void* p, std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: deallocate(p, size, op->d_->h); } friend bool asio_handler_is_continuation(handshake_op* op) { return op->d_->cont; } template friend void asio_handler_invoke(Function&& f, handshake_op* op) { return boost_asio_handler_invoke_helpers:: invoke(f, op->d_->h); } }; template template void stream::handshake_op< Handler>::operator()(error_code ec, std::size_t bytes_transferred, bool again) { auto& d = *d_; d.cont = d.cont || again; while(! ec && d.state != 99) { switch(d.state) { case 0: { // send http upgrade d.state = 1; // VFALCO Do we need the ability to move // a message on the async_write? http::async_write(d.ws.stream_, d.req, std::move(*this)); return; } // sent upgrade case 1: // read http response d.state = 2; http::async_read(d.ws.next_layer(), d.ws.stream_.buffer(), d.resp, std::move(*this)); return; // got response case 2: { d.ws.do_response(d.resp, d.key, ec); // call handler d.state = 99; break; } } } d.h(ec); } } // websocket } // beast #endif