mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
Document websocket sub-protocols
This commit is contained in:
@@ -150,6 +150,27 @@ stream:
|
||||
|
||||
[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]
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user