mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 14:24:31 +02:00
Document websocket sub-protocols
This commit is contained in:
@@ -150,6 +150,27 @@ stream:
|
|||||||
|
|
||||||
[code_websocket_2_5]
|
[code_websocket_2_5]
|
||||||
|
|
||||||
|
[heading Subprotocols]
|
||||||
|
|
||||||
|
The WebSocket protocol understands the concept of subprotocols. If the client
|
||||||
|
is requesting one of a set of subprotocols it will set the header
|
||||||
|
[@https://tools.ietf.org/html/rfc6455#section-11.3.4 Sec-WebSocket-Protocol]
|
||||||
|
in the initial WebSocket Upgrade HTTP request. It is up to the server to
|
||||||
|
parse the header and select one of the protocols to accept. The server
|
||||||
|
indicates the selected protocol by setting the
|
||||||
|
[@https://tools.ietf.org/html/rfc6455#section-11.3.4 Sec-WebSocket-Protocol]
|
||||||
|
header in the accept header.
|
||||||
|
|
||||||
|
This is accomplished with a
|
||||||
|
[link beast.ref.boost__beast__websocket__stream_base__decorator `decorator`].
|
||||||
|
|
||||||
|
The code that follows demonstrates how a server reads an HTTP request, identifies it
|
||||||
|
as a WebSocket Upgrade, and then checks for a preferred matching subprotocol before
|
||||||
|
performing the WebSocket handshake:
|
||||||
|
|
||||||
|
[code_websocket_2_6]
|
||||||
|
|
||||||
|
|
||||||
[/-----------------------------------------------------------------------------]
|
[/-----------------------------------------------------------------------------]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -132,6 +132,96 @@ snippets()
|
|||||||
|
|
||||||
//]
|
//]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[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<string_view, 3>
|
||||||
|
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<http::string_body> 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<http::string_body> 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<tcp_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
|
struct websocket_2_test
|
||||||
|
Reference in New Issue
Block a user