forked from boostorg/beast
145 lines
5.1 KiB
Plaintext
145 lines
5.1 KiB
Plaintext
|
|
[/
|
||
|
|
Copyright (c) 2013-2017 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)
|
||
|
|
]
|
||
|
|
|
||
|
|
[section:server Handshaking (Servers)]
|
||
|
|
|
||
|
|
A
|
||
|
|
[link beast.ref.websocket__stream `stream`]
|
||
|
|
automatically handles receiving and processing the HTTP response to the
|
||
|
|
handshake request. The call to handshake is successful if a HTTP response
|
||
|
|
is received with the 101 "Switching Protocols" status code. On failure,
|
||
|
|
an error is returned or an exception is thrown. Depending on the keep alive
|
||
|
|
setting, the connection may remain open for a subsequent handshake attempt.
|
||
|
|
|
||
|
|
Performing a handshake for an incoming websocket upgrade request operates
|
||
|
|
similarly. If the handshake fails, an error is returned or exception thrown:
|
||
|
|
```
|
||
|
|
...
|
||
|
|
ws.accept();
|
||
|
|
```
|
||
|
|
|
||
|
|
Successful WebSocket Upgrade responses generated by the implementation will
|
||
|
|
typically look like this:
|
||
|
|
|
||
|
|
[table Decorated WebSocket Upgrade HTTP Request
|
||
|
|
[[Serialized Octets][Description]]
|
||
|
|
[[
|
||
|
|
```
|
||
|
|
HTTP/1.1 101 Switching Protocols
|
||
|
|
Upgrade: websocket
|
||
|
|
Connection: upgrade
|
||
|
|
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
||
|
|
Server: Beast/40
|
||
|
|
```
|
||
|
|
][
|
||
|
|
The Sec-WebSocket-Accept field value is generated from the
|
||
|
|
request in a fashion specified by the WebSocket protocol.
|
||
|
|
]]]
|
||
|
|
|
||
|
|
[heading Decorators]
|
||
|
|
|
||
|
|
If the caller wishes to add or modify fields, the member functions
|
||
|
|
[link beast.ref.websocket__stream.accept_ex `accept_ex`] and
|
||
|
|
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
|
||
|
|
are provided which allow an additional function object, called a
|
||
|
|
['decorator], to be passed. The decorator is invoked to modify
|
||
|
|
the HTTP Upgrade request as needed. This example sets the Server
|
||
|
|
field on the response:
|
||
|
|
```
|
||
|
|
ws.accept_ex(
|
||
|
|
[](websocket::response_type& res)
|
||
|
|
{
|
||
|
|
res.fields.insert("Server", "AcmeServer");
|
||
|
|
});
|
||
|
|
|
||
|
|
```
|
||
|
|
|
||
|
|
The HTTP Upgrade response produced by the previous call will look thusly:
|
||
|
|
|
||
|
|
[table Decorated WebSocket Upgrade HTTP Request
|
||
|
|
[[Serialized Octets][Description]]
|
||
|
|
[[
|
||
|
|
```
|
||
|
|
HTTP/1.1 101 Switching Protocols
|
||
|
|
Upgrade: websocket
|
||
|
|
Connection: upgrade
|
||
|
|
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
||
|
|
Server: AcmeServer
|
||
|
|
```
|
||
|
|
][
|
||
|
|
When the Upgrade request fails, the implementation will still invoke
|
||
|
|
the decorator to modify the response. In this case, the response
|
||
|
|
object will have a status code other than 101.
|
||
|
|
|
||
|
|
Undefined behavior results when the upgrade request is successful
|
||
|
|
and the decorator modifies the fields specific to perform the
|
||
|
|
WebSocket Upgrade , such as the Upgrade and Connection fields.
|
||
|
|
]]]
|
||
|
|
|
||
|
|
[heading Passing HTTP Requests]
|
||
|
|
|
||
|
|
When implementing an HTTP server that also supports WebSocket, the
|
||
|
|
server usually reads the HTTP request from the client. To detect when
|
||
|
|
the incoming HTTP request is a WebSocket Upgrade request, the function
|
||
|
|
[link beast.ref.websocket__is_upgrade `is_upgrade`] may be used.
|
||
|
|
|
||
|
|
Once the caller determines that the HTTP request is a WebSocket Upgrade,
|
||
|
|
additional overloads of
|
||
|
|
[link beast.ref.websocket__stream.accept `accept`],
|
||
|
|
[link beast.ref.websocket__stream.accept_ex `accept_ex`],
|
||
|
|
[link beast.ref.websocket__stream.async_accept `async_accept`], and
|
||
|
|
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
|
||
|
|
are provided which receive the entire HTTP request header as an object
|
||
|
|
to perform the handshake. In this example, the request is first read
|
||
|
|
in using the HTTP algorithms, and then passed to a newly constructed
|
||
|
|
stream:
|
||
|
|
```
|
||
|
|
void handle_connection(boost::asio::ip::tcp::socket& sock)
|
||
|
|
{
|
||
|
|
flat_buffer buffer;
|
||
|
|
http::request<http::string_body> req;
|
||
|
|
http::read(sock, buffer, req);
|
||
|
|
if(websocket::is_upgrade(req))
|
||
|
|
{
|
||
|
|
websocket::stream<decltype(sock)> ws{std::move(sock)};
|
||
|
|
ws.accept(req);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
[heading Buffered Handshakes]
|
||
|
|
|
||
|
|
Sometimes a server implementation wishes to read octets on the stream
|
||
|
|
in order to route the incoming request. For example, a server may read
|
||
|
|
the first 6 octets after accepting an incoming connection to determine
|
||
|
|
if a TLS protocol is being negotiated, and choose a suitable implementation
|
||
|
|
at run-time. In the case where the server wishes to accept the incoming
|
||
|
|
request as an HTTP WebSocket Upgrade request, additional overloads of
|
||
|
|
[link beast.ref.websocket__stream.accept `accept`],
|
||
|
|
[link beast.ref.websocket__stream.accept_ex `accept_ex`],
|
||
|
|
[link beast.ref.websocket__stream.async_accept `async_accept`], and
|
||
|
|
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
|
||
|
|
are provided which receive the additional buffered octects and consume
|
||
|
|
them as part of the handshake.
|
||
|
|
|
||
|
|
In this example, the server reads the initial HTTP message into the
|
||
|
|
specified dynamic buffer as an octet sequence in the buffer's output
|
||
|
|
area, and later uses those octets to attempt an HTTP WebSocket Upgrade:
|
||
|
|
```
|
||
|
|
void do_accept(boost::asio::ip::tcp::socket& sock)
|
||
|
|
{
|
||
|
|
boost::asio::streambuf sb;
|
||
|
|
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||
|
|
...
|
||
|
|
websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||
|
|
ws.accept(sb.data());
|
||
|
|
...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
[endsect]
|