177 lines
6.9 KiB
Plaintext
177 lines
6.9 KiB
Plaintext
[/
|
|
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
|
|
]
|
|
|
|
[section Handshaking]
|
|
|
|
[/-----------------------------------------------------------------------------]
|
|
|
|
[heading Client Role]
|
|
|
|
A WebSocket session begins when a client sends the HTTP/1.1
|
|
[@https://tools.ietf.org/html/rfc7230#section-6.7 Upgrade]
|
|
request for
|
|
[@https://tools.ietf.org/html/rfc6455#section-1.3 WebSocket]
|
|
on an established connection, and the server sends an appropriate response
|
|
indicating that the request was accepted and that the connection has been
|
|
upgraded. The Upgrade request must include the
|
|
[@https://tools.ietf.org/html/rfc7230#section-5.4 Host]
|
|
field, and the
|
|
[@https://tools.ietf.org/html/rfc7230#section-5.3 target]
|
|
of the resource to request.
|
|
A typical HTTP Upgrade request created and sent by the implementation
|
|
will look like this:
|
|
|
|
[table WebSocket HTTP Upgrade Request
|
|
[[Wire Format][Description]]
|
|
[[
|
|
```
|
|
GET / HTTP/1.1
|
|
Host: www.example.com
|
|
Upgrade: websocket
|
|
Connection: upgrade
|
|
Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
|
|
Sec-WebSocket-Version: 13
|
|
User-Agent: Boost.Beast/216
|
|
```
|
|
][
|
|
The host and target parameters become part of the Host field
|
|
and request-target in the resulting HTTP request. The key is
|
|
generated by the implementation. Callers who wish to add,
|
|
modify, or inspect fields may set the ['decorator] option
|
|
on the stream (described later).
|
|
]]]
|
|
|
|
The
|
|
[link beast.ref.boost__beast__websocket__stream `websocket::stream`]
|
|
member functions
|
|
[link beast.ref.boost__beast__websocket__stream.handshake `handshake`] and
|
|
[link beast.ref.boost__beast__websocket__stream.async_handshake `async_handshake`]
|
|
are used to send the request with the required host and target strings. This
|
|
code connects to the IP address returned from a hostname lookup, then performs
|
|
the WebSocket handshake in the client role.
|
|
|
|
[code_websocket_2_1]
|
|
|
|
When a client receives an HTTP Upgrade response from the server indicating
|
|
a successful upgrade, the caller may wish to perform additional validation
|
|
on the received HTTP response message. For example, to check that the
|
|
response to a basic authentication challenge is valid. To achieve this,
|
|
overloads of the handshake member function allow the caller to store the
|
|
received HTTP message in an output reference argument of type
|
|
[link beast.ref.boost__beast__websocket__response_type `response_type`]
|
|
as follows:
|
|
|
|
[code_websocket_2_2]
|
|
|
|
[/-----------------------------------------------------------------------------]
|
|
|
|
[heading Server Role]
|
|
|
|
For servers accepting incoming connections, the
|
|
[link beast.ref.boost__beast__websocket__stream `websocket::stream`]
|
|
can read the incoming upgrade request and automatically reply. If the handshake
|
|
meets the requirements, the stream sends back the upgrade response with a
|
|
[@https://tools.ietf.org/html/rfc6455#section-4.2.2 ['101 Switching Protocols]]
|
|
status code. If the handshake does not meet the requirements, or falls outside
|
|
the range of allowed parameters specified by stream options set previously by
|
|
the caller, the stream sends back an HTTP response with a status code indicating
|
|
an error. Depending on the keep alive setting, the connection may remain open
|
|
for a subsequent handshake attempt. A typical HTTP Upgrade response created and
|
|
sent by the implementation upon receiving an upgrade request handshake will
|
|
look like this:
|
|
|
|
[table WebSocket Upgrade HTTP Response
|
|
[[Wire Format][Description]]
|
|
[[
|
|
```
|
|
HTTP/1.1 101 Switching Protocols
|
|
Upgrade: websocket
|
|
Connection: upgrade
|
|
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
|
Server: Boost.Beast
|
|
```
|
|
][
|
|
The
|
|
[@https://tools.ietf.org/html/rfc6455#section-11.3.3 ['Sec-WebSocket-Accept]]
|
|
field value is generated from the request in a fashion specified by
|
|
the WebSocket protocol.
|
|
]]]
|
|
|
|
The
|
|
[link beast.ref.boost__beast__websocket__stream `stream`]
|
|
member functions
|
|
[link beast.ref.boost__beast__websocket__stream.accept `accept`] and
|
|
[link beast.ref.boost__beast__websocket__stream.async_accept `async_accept`]
|
|
are used to read the WebSocket HTTP Upgrade request handshake from a stream
|
|
already connected to an incoming peer, and then send the WebSocket HTTP
|
|
Upgrade response, as shown:
|
|
|
|
[code_websocket_2_3]
|
|
|
|
[heading Handshake Buffering]
|
|
|
|
It is possible for servers to read data from the stream and decide later
|
|
that the buffered bytes should be interpreted as a WebSocket upgrade
|
|
request. To address this usage, overloads of
|
|
[link beast.ref.boost__beast__websocket__stream.accept `accept`] and
|
|
[link beast.ref.boost__beast__websocket__stream.async_accept `async_accept`]
|
|
which accept an additional buffer sequence parameter are provided.
|
|
|
|
In this example, the server reads the initial HTTP request header into a
|
|
dynamic buffer, then later uses the buffered data to attempt a websocket
|
|
upgrade.
|
|
|
|
[code_websocket_2_4]
|
|
|
|
[heading Inspecting 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.boost__beast__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.boost__beast__websocket__stream.accept `accept`] and
|
|
[link beast.ref.boost__beast__websocket__stream.async_accept `async_accept`]
|
|
are provided which receive the entire HTTP request header as an object
|
|
to perform the handshake. By reading the request manually, the program
|
|
can handle normal HTTP requests as well as upgrades. The program may
|
|
also enforce policies based on the HTTP fields, such as Basic
|
|
Authentication. In this example, the request is first read in
|
|
using the HTTP algorithms, and then passed to a newly constructed
|
|
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]
|