// // 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_STREAM_IPP #define BEAST_WEBSOCKET_IMPL_STREAM_IPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace beast { namespace websocket { template template stream:: stream(Args&&... args) : stream_(std::forward(args)...) { } //------------------------------------------------------------------------------ template void stream:: reset() { failed_ = false; rd_need_ = 0; rd_cont_ = false; wr_close_ = false; wr_.cont = false; wr_block_ = nullptr; // should be nullptr on close anyway pong_data_ = nullptr; // should be nullptr on close anyway stream_.buffer().consume( stream_.buffer().size()); } template http::request stream:: build_request(boost::string_ref const& host, boost::string_ref const& resource, std::string& key) { http::request req; req.url = { resource.data(), resource.size() }; req.version = 11; req.method = "GET"; req.fields.insert("Host", host); req.fields.insert("Upgrade", "websocket"); key = detail::make_sec_ws_key(maskgen_); req.fields.insert("Sec-WebSocket-Key", key); req.fields.insert("Sec-WebSocket-Version", "13"); (*d_)(req); http::prepare(req, http::connection::upgrade); return req; } template template http::response stream:: build_response(http::request const& req) { auto err = [&](std::string const& text) { http::response res; res.status = 400; res.reason = http::reason_string(res.status); res.version = req.version; res.body = text; (*d_)(res); prepare(res, (is_keep_alive(req) && keep_alive_) ? http::connection::keep_alive : http::connection::close); return res; }; if(req.version < 11) return err("HTTP version 1.1 required"); if(req.method != "GET") return err("Wrong method"); if(! is_upgrade(req)) return err("Expected Upgrade request"); if(! req.fields.exists("Host")) return err("Missing Host"); if(! req.fields.exists("Sec-WebSocket-Key")) return err("Missing Sec-WebSocket-Key"); if(! http::token_list{req.fields["Upgrade"]}.exists("websocket")) return err("Missing websocket Upgrade token"); { auto const version = req.fields["Sec-WebSocket-Version"]; if(version.empty()) return err("Missing Sec-WebSocket-Version"); if(version != "13") { http::response res; res.status = 426; res.reason = http::reason_string(res.status); res.version = req.version; res.fields.insert("Sec-WebSocket-Version", "13"); prepare(res, (is_keep_alive(req) && keep_alive_) ? http::connection::keep_alive : http::connection::close); return res; } } http::response res; res.status = 101; res.reason = http::reason_string(res.status); res.version = req.version; res.fields.insert("Upgrade", "websocket"); { auto const key = req.fields["Sec-WebSocket-Key"]; res.fields.insert("Sec-WebSocket-Accept", detail::make_sec_ws_accept(key)); } res.fields.replace("Server", "Beast.WSProto"); (*d_)(res); http::prepare(res, http::connection::upgrade); return res; } template template void stream:: do_response(http::response const& res, boost::string_ref const& key, error_code& ec) { // VFALCO Review these error codes auto fail = [&]{ ec = error::response_failed; }; if(res.version < 11) return fail(); if(res.status != 101) return fail(); if(! is_upgrade(res)) return fail(); if(! http::token_list{res.fields["Upgrade"]}.exists("websocket")) return fail(); if(! res.fields.exists("Sec-WebSocket-Accept")) return fail(); if(res.fields["Sec-WebSocket-Accept"] != detail::make_sec_ws_accept(key)) return fail(); open(detail::role_type::client); } template void stream:: do_read_fh(detail::frame_streambuf& fb, close_code::value& code, error_code& ec) { fb.commit(boost::asio::read( stream_, fb.prepare(2), ec)); if(ec) return; auto const n = read_fh1(fb, code); if(code != close_code::none) return; if(n > 0) { fb.commit(boost::asio::read( stream_, fb.prepare(n), ec)); if(ec) return; } read_fh2(fb, code); } } // websocket } // beast #endif