// // 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 // #include #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable: 4459) // declaration hides global declaration #endif #include #include #include #include #include namespace { #include "websocket_common.ipp" void snippets() { { //[code_websocket_2_1 stream ws(ioc); net::ip::tcp::resolver resolver(ioc); get_lowest_layer(ws).connect(resolver.resolve("www.example.com", "ws")); // Do the websocket handshake in the client role, on the connected stream. // The implementation only uses the Host parameter to set the HTTP "Host" field, // it does not perform any DNS lookup. That must be done first, as shown above. ws.handshake( "www.example.com", // The Host field "/" // The request-target ); //] } { stream ws(ioc); { //[code_websocket_2_2 // This variable will receive the HTTP response from the server response_type res; // Perform the websocket handshake in the client role. // On success, `res` will hold the complete HTTP response received. ws.handshake( res, // Receives the HTTP response "www.example.com", // The Host field "/" // The request-target ); //] } //-------------------------------------------------------------------------- { //[code_websocket_2_3 // Perform the websocket handshake in the server role. // The stream must already be connected to the peer. ws.accept(); //] } { //[code_websocket_2_4 // This buffer will hold the HTTP request as raw characters std::string s; // Read into our buffer until we reach the end of the HTTP request. // No parsing takes place here, we are just accumulating data. net::read_until(sock, net::dynamic_buffer(s), "\r\n\r\n"); // Now accept the connection, using the buffered data. ws.accept(net::buffer(s)); //] } } { //[code_websocket_2_5 // This buffer is required for reading HTTP messages flat_buffer buffer; // Read the HTTP request ourselves http::request req; http::read(sock, buffer, req); // See if its a WebSocket upgrade request if(websocket::is_upgrade(req)) { // Construct the stream, transferring ownership of the socket stream ws(std::move(sock)); // Clients SHOULD NOT begin sending WebSocket // frames until the server has provided a response. BOOST_ASSERT(buffer.size() == 0); // Accept the upgrade request ws.accept(req); } else { // Its not a WebSocket upgrade, so // handle it like a normal HTTP request. } //] } { //[code_websocket_2_6 // a function to select the most preferred protocol from a comma-separated list auto select_protocol = [](string_view offered_tokens) -> std::string { // tokenize the Sec-Websocket-Protocol header offered by the client http::token_list offered( offered_tokens ); // an array of protocols supported by this server // in descending order of preference static const std::array supported = { "v3.my.chat", "v2.my.chat", "v1.my.chat" }; std::string result; for (auto proto : supported) { auto iter = std::find(offered.begin(), offered.end(), proto); if (iter != offered.end()) { // we found a supported protocol in the list offered by the client result.assign(proto.begin(), proto.end()); break; } } return result; }; // This buffer is required for reading HTTP messages flat_buffer buffer; // Read the HTTP request ourselves http::request req; http::read(sock, buffer, req); // See if it's a WebSocket upgrade request if(websocket::is_upgrade(req)) { // we store the selected protocol in a std::string here because // we intend to capture it in the decorator's lambda below std::string protocol = select_protocol( req[http::field::sec_websocket_protocol]); if (protocol.empty()) { // none of our supported protocols were offered http::response res; res.result(http::status::bad_request); res.body() = "No valid sub-protocol was offered." " This server implements" " v3.my.chat," " v2.my.chat" " and v1.my.chat"; http::write(sock, res); } else { // Construct the stream, transferring ownership of the socket stream ws(std::move(sock)); ws.set_option( stream_base::decorator( [protocol](http::response_header<> &hdr) { hdr.set( http::field::sec_websocket_protocol, protocol); })); // Accept the upgrade request ws.accept(req); } } else { // Its not a WebSocket upgrade, so // handle it like a normal HTTP request. } //] } } struct websocket_2_test : public boost::beast::unit_test::suite { void run() override { BEAST_EXPECT(&snippets); } }; BEAST_DEFINE_TESTSUITE(beast,doc,websocket_2); } // (anon) #ifdef BOOST_MSVC #pragma warning(pop) #endif