mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
WebSocket Decorator is a socket option (API Change):
This changes the interface used to apply a decorator to the HTTP request or response messages used to perform the WebSocket handshake as follows: * Add the `stream_base::decorator` option object * Add `stream::set_option` overload to set the decorator from the option * The decorator applies to all client and server handshakes performed on the stream after the option is set. * Overloads of the following functions which accept a Decorator are deprecated: - accept, accept_ex - handshake, handshake_ex - async_accept, async_accept_ex - async_handshake, async_handshake_ex Actions Required: * Code which passes decorator to any `websocket::stream` member function should call `stream::set_option` instead with a newly constructed `stream_base::decorator` object containing the decorator. Alternatively, the macro `BOOST_BEAST_ALLOW_DEPRECATED` may be defined to 1.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
|
||||
[section Handshaking (Clients)]
|
||||
|
||||
A WebSocket session begins when a client sends the HTTP/1
|
||||
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],
|
||||
@ -19,69 +19,39 @@ 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. The stream member functions
|
||||
[link beast.ref.boost__beast__websocket__stream.handshake.overload1 `handshake`] and
|
||||
[link beast.ref.boost__beast__websocket__stream.async_handshake.overload1 `async_handshake`]
|
||||
are used to send the request with the required host and target strings.
|
||||
of the resource to request.
|
||||
A typical HTTP Upgrade request created and sent by the implementation
|
||||
will look like this:
|
||||
|
||||
[ws_snippet_8]
|
||||
|
||||
The implementation will create and send a request that typically
|
||||
looks like this:
|
||||
|
||||
[table WebSocket Upgrade HTTP Request
|
||||
[table WebSocket HTTP Upgrade Request
|
||||
[[Serialized Octets][Description]]
|
||||
[[
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
Host: localhost
|
||||
Host: www.example.com
|
||||
Upgrade: websocket
|
||||
Connection: upgrade
|
||||
Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
|
||||
Sec-WebSocket-Version: 13
|
||||
User-Agent: Beast
|
||||
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 may add fields or
|
||||
modify fields by providing a ['decorator], described below.
|
||||
modify fields by providing a ['decorator], described later.
|
||||
]]]
|
||||
|
||||
[heading Decorators]
|
||||
The
|
||||
[link beast.ref.boost__beast__websocket__stream `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. The
|
||||
code below sends the WebSocket HTTP Upgrade request, then reads and processes
|
||||
the response:
|
||||
|
||||
If the caller wishes to add or modify fields, the member functions
|
||||
[link beast.ref.boost__beast__websocket__stream.handshake_ex `handshake_ex`] and
|
||||
[link beast.ref.boost__beast__websocket__stream.async_handshake_ex `async_handshake_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 a subprotocol
|
||||
on the request:
|
||||
|
||||
[ws_snippet_9]
|
||||
|
||||
The HTTP Upgrade request produced by the previous call will look thusly:
|
||||
|
||||
[table Decorated WebSocket Upgrade HTTP Request
|
||||
[[Serialized Octets][Description]]
|
||||
[[
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
Host: localhost
|
||||
Upgrade: websocket
|
||||
Connection: upgrade
|
||||
Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
|
||||
Sec-WebSocket-Version: 13
|
||||
Sec-WebSocket-Protocol: xmpp;ws-chat
|
||||
User-Agent: Beast
|
||||
```
|
||||
][
|
||||
Undefined behavior results if the decorator modifies the fields
|
||||
specific to perform the WebSocket Upgrade , such as the Upgrade
|
||||
and Connection fields.
|
||||
]]]
|
||||
|
||||
[heading Filtering]
|
||||
[code_websocket_3_client_1]
|
||||
|
||||
When a client receives an HTTP Upgrade response from the server indicating
|
||||
a successful upgrade, the caller may wish to perform additional validation
|
||||
@ -92,6 +62,6 @@ received HTTP message in an output reference argument of type
|
||||
[link beast.ref.boost__beast__websocket__response_type `response_type`]
|
||||
as follows:
|
||||
|
||||
[ws_snippet_10]
|
||||
[code_websocket_3_client_2]
|
||||
|
||||
[endsect]
|
||||
|
@ -18,16 +18,10 @@ is received with the
|
||||
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.
|
||||
A typical HTTP Upgrade response created and sent by the implementation
|
||||
upon receiving an upgrade request handshake will look like this:
|
||||
|
||||
Performing a handshake for an incoming websocket upgrade request operates
|
||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||
|
||||
[ws_snippet_11]
|
||||
|
||||
Successful WebSocket Upgrade responses generated by the implementation will
|
||||
typically look like this:
|
||||
|
||||
[table Decorated WebSocket Upgrade HTTP Request
|
||||
[table WebSocket Upgrade HTTP Response
|
||||
[[Serialized Octets][Description]]
|
||||
[[
|
||||
```
|
||||
@ -35,7 +29,7 @@ typically look like this:
|
||||
Upgrade: websocket
|
||||
Connection: upgrade
|
||||
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
||||
Server: Beast/40
|
||||
Server: Boost.Beast/216
|
||||
```
|
||||
][
|
||||
The
|
||||
@ -44,39 +38,18 @@ typically look like this:
|
||||
the WebSocket protocol.
|
||||
]]]
|
||||
|
||||
[heading Decorators]
|
||||
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:
|
||||
|
||||
If the caller wishes to add or modify fields, the member functions
|
||||
[link beast.ref.boost__beast__websocket__stream.accept_ex `accept_ex`] and
|
||||
[link beast.ref.boost__beast__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:
|
||||
[code_websocket_3_server_1]
|
||||
|
||||
[ws_snippet_12]
|
||||
|
||||
The HTTP Upgrade response produced by the previous call looks 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: 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]
|
||||
|
||||
@ -87,16 +60,19 @@ the incoming HTTP request is a WebSocket Upgrade request, the function
|
||||
|
||||
Once the caller determines that the HTTP request is a WebSocket Upgrade,
|
||||
additional overloads of
|
||||
[link beast.ref.boost__beast__websocket__stream.accept `accept`],
|
||||
[link beast.ref.boost__beast__websocket__stream.accept_ex `accept_ex`],
|
||||
[link beast.ref.boost__beast__websocket__stream.async_accept `async_accept`], and
|
||||
[link beast.ref.boost__beast__websocket__stream.async_accept_ex `async_accept_ex`]
|
||||
[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. In this example, the request is first read
|
||||
in using the HTTP algorithms, and then passed to a newly constructed
|
||||
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:
|
||||
|
||||
[ws_snippet_13]
|
||||
[code_websocket_3_server_1b]
|
||||
|
||||
|
||||
|
||||
[heading Buffered Handshakes]
|
||||
|
||||
@ -106,10 +82,8 @@ 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.boost__beast__websocket__stream.accept `accept`],
|
||||
[link beast.ref.boost__beast__websocket__stream.accept_ex `accept_ex`],
|
||||
[link beast.ref.boost__beast__websocket__stream.async_accept `async_accept`], and
|
||||
[link beast.ref.boost__beast__websocket__stream.async_accept_ex `async_accept_ex`]
|
||||
[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 additional buffered octets and consume
|
||||
them as part of the handshake.
|
||||
|
||||
@ -117,7 +91,7 @@ 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:
|
||||
|
||||
[ws_snippet_14]
|
||||
[code_websocket_3_server_2]
|
||||
|
||||
The implementation uses a fixed-size storage area to hold buffers passed
|
||||
using these functions. If an application is reaching the limit of the
|
||||
@ -128,4 +102,6 @@ to wrap the underlying stream. The buffered handshake data may be first
|
||||
placed into the buffered read stream, which uses a dynamically sized
|
||||
buffer.
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
79
doc/qbk/06_websocket/05_decorator.qbk
Normal file
79
doc/qbk/06_websocket/05_decorator.qbk
Normal file
@ -0,0 +1,79 @@
|
||||
[/
|
||||
Copyright (c) 2016-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)
|
||||
|
||||
Official repository: https://github.com/boostorg/beast
|
||||
]
|
||||
|
||||
[section:decorator Custom HTTP Fields]
|
||||
|
||||
For programs which need to modify either the outgoing WebSocket HTTP Upgrade
|
||||
request, the outgoing WebSocket HTTP Upgrade response, or both, the stream
|
||||
supports an optional property called a ['decorator]. This is a function
|
||||
pointer or callable object which is invoked before the implementation
|
||||
sends an HTTP message. The decorator receives a modifiable reference to
|
||||
the message, allowing for modifications. The interface to this system
|
||||
uses:
|
||||
|
||||
[table WebSocket Decorator Interface
|
||||
[[Name][Description]]
|
||||
[[
|
||||
`request_type`
|
||||
][
|
||||
This is the type of the object passed to the decorator to
|
||||
represent HTTP Upgrade requests.
|
||||
]]
|
||||
[[
|
||||
`response_type`
|
||||
][
|
||||
This is the type of the object passed to the decorator to
|
||||
represent HTTP Upgrade response.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__websocket__stream_base__decorator `stream_base::decorator`]
|
||||
][
|
||||
Objects of this type are used to hold a decorator to be
|
||||
set on the stream using `set_option`.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__websocket__stream.set_option `stream::set_option`]
|
||||
][
|
||||
This function is used to set a `stream_base::decorator` on the stream.
|
||||
]]
|
||||
]
|
||||
|
||||
This declares a normal function which decorates outgoing HTTP requests:
|
||||
|
||||
[code_websocket_3_decorator_1b]
|
||||
|
||||
If a decorator is used, it must be set on the stream before any handshaking
|
||||
takes place. This sets the decorator on the stream, to be used for all
|
||||
subsequent calls to accept or handshake:
|
||||
|
||||
[code_websocket_3_decorator_1]
|
||||
|
||||
Alternatively, a function object may be used. Small function objects will
|
||||
not incur a memory allocation. The follow code declares and sets a function
|
||||
object as a decorator:
|
||||
|
||||
[code_websocket_3_decorator_2]
|
||||
|
||||
A lambda may be used in place of a named function object:
|
||||
|
||||
[code_websocket_3_decorator_3]
|
||||
|
||||
It also possible for a single decorator to handle both requests and
|
||||
responses, if it is overloaded for both types either as a generic
|
||||
lambda (C++14 and later) or as a class as shown here:
|
||||
|
||||
[code_websocket_3_decorator_4]
|
||||
|
||||
[important
|
||||
Undefined behavior results if the decorator modifies the fields
|
||||
specific to perform the WebSocket Upgrade, such as the Upgrade
|
||||
or Connection fields.
|
||||
]
|
||||
|
||||
[endsect]
|
@ -33,9 +33,10 @@ Boost.Asio with a consistent asynchronous model using a modern C++ approach.
|
||||
[include 02_connect.qbk]
|
||||
[include 03_client.qbk]
|
||||
[include 04_server.qbk]
|
||||
[include 05_messages.qbk]
|
||||
[include 06_control.qbk]
|
||||
[include 07_teardown.qbk]
|
||||
[include 08_notes.qbk]
|
||||
[include 05_decorator.qbk]
|
||||
[include 06_messages.qbk]
|
||||
[include 07_control.qbk]
|
||||
[include 08_teardown.qbk]
|
||||
[include 09_notes.qbk]
|
||||
|
||||
[endsect]
|
||||
|
@ -132,6 +132,7 @@
|
||||
|
||||
[import ../../test/doc/core_1_refresher.cpp]
|
||||
[import ../../test/doc/core_3_layers.cpp]
|
||||
[import ../../test/doc/websocket_3_handshake.cpp]
|
||||
|
||||
[section:quickref Reference]
|
||||
'''
|
||||
|
@ -251,6 +251,16 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
derived().ws().set_option(
|
||||
websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" advanced-server-flex");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
derived().ws().async_accept(
|
||||
req,
|
||||
|
@ -229,10 +229,6 @@ public:
|
||||
websocket_session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
}
|
||||
|
||||
// Start the asynchronous accept operation
|
||||
@ -240,6 +236,20 @@ public:
|
||||
void
|
||||
do_accept(http::request<Body, http::basic_fields<Allocator>> req)
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" advanced-server");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
req,
|
||||
|
@ -132,6 +132,15 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::client));
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-async-ssl");
|
||||
}));
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws_.async_handshake(host_, "/",
|
||||
beast::bind_front_handler(
|
||||
|
@ -110,6 +110,15 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::client));
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-async");
|
||||
}));
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws_.async_handshake(host_, "/",
|
||||
beast::bind_front_handler(
|
||||
|
@ -74,6 +74,15 @@ do_session(
|
||||
// Set a timeout on the operation
|
||||
beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-coro");
|
||||
}));
|
||||
|
||||
// Perform the SSL handshake
|
||||
ws.next_layer().async_handshake(ssl::stream_base::client, yield[ec]);
|
||||
if(ec)
|
||||
|
@ -74,6 +74,15 @@ do_session(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::client));
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-coro");
|
||||
}));
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws.async_handshake(host, "/", yield[ec]);
|
||||
if(ec)
|
||||
|
@ -73,6 +73,15 @@ int main(int argc, char** argv)
|
||||
// Perform the SSL handshake
|
||||
ws.next_layer().handshake(ssl::stream_base::client);
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-coro");
|
||||
}));
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws.handshake(host, "/");
|
||||
|
||||
|
@ -60,6 +60,15 @@ int main(int argc, char** argv)
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
net::connect(ws.next_layer(), results.begin(), results.end());
|
||||
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(http::field::user_agent,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-client-coro");
|
||||
}));
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws.handshake(host, "/");
|
||||
|
||||
|
@ -89,6 +89,15 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-async-ssl");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
beast::bind_front_handler(
|
||||
|
@ -52,16 +52,26 @@ public:
|
||||
session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
}
|
||||
|
||||
// Start the asynchronous operation
|
||||
void
|
||||
run()
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-async");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
beast::bind_front_handler(
|
||||
|
@ -17,10 +17,6 @@ websocket_session(
|
||||
: ws_(std::move(socket))
|
||||
, state_(state)
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
}
|
||||
|
||||
websocket_session::
|
||||
|
@ -57,6 +57,20 @@ void
|
||||
websocket_session::
|
||||
run(http::request<Body, http::basic_fields<Allocator>> req)
|
||||
{
|
||||
// Set suggested timeout settings for the websocket
|
||||
ws_.set_option(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-chat-multi");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
req,
|
||||
|
@ -75,6 +75,15 @@ do_session(
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-coro-ssl");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws.async_accept(yield[ec]);
|
||||
if(ec)
|
||||
|
@ -56,6 +56,15 @@ do_session(ws_type& ws, net::yield_context yield)
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-coro");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws.async_accept(yield[ec]);
|
||||
if(ec)
|
||||
|
@ -90,13 +90,15 @@ do_sync_session(ws_type& ws)
|
||||
|
||||
setup_stream(ws);
|
||||
|
||||
ws.accept_ex(
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
"Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION) + "-Sync");
|
||||
},
|
||||
ec);
|
||||
res.set(http::field::server, std::string(
|
||||
BOOST_BEAST_VERSION_STRING) + "-Sync");
|
||||
}));
|
||||
|
||||
ws.accept(ec);
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
@ -158,13 +160,16 @@ public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept_ex(
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
"Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION) + "-Async");
|
||||
},
|
||||
res.set(http::field::server, std::string(
|
||||
BOOST_BEAST_VERSION_STRING) + "-Async");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
beast::bind_front_handler(
|
||||
&async_session::on_accept,
|
||||
shared_from_this()));
|
||||
@ -324,13 +329,15 @@ do_coro_session(ws_type& ws, net::yield_context yield)
|
||||
|
||||
setup_stream(ws);
|
||||
|
||||
ws.async_accept_ex(
|
||||
[&](websocket::response_type& res)
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
"Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION) + "-Coro");
|
||||
},
|
||||
yield[ec]);
|
||||
res.set(http::field::server, std::string(
|
||||
BOOST_BEAST_VERSION_STRING) + "-Fiber");
|
||||
}));
|
||||
|
||||
ws.async_accept(yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
|
@ -102,6 +102,15 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-stackless-ssl");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
std::bind(
|
||||
|
@ -79,6 +79,15 @@ public:
|
||||
websocket::stream_base::suggested_settings(
|
||||
websocket::role_type::server));
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-stackless");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
std::bind(
|
||||
|
@ -48,6 +48,15 @@ do_session(tcp::socket& socket, ssl::context& ctx)
|
||||
// Perform the SSL handshake
|
||||
ws.next_layer().handshake(ssl::stream_base::server);
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-sync-ssl");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws.accept();
|
||||
|
||||
|
@ -39,6 +39,15 @@ do_session(tcp::socket& socket)
|
||||
// Construct the stream by moving in the socket
|
||||
websocket::stream<tcp::socket> ws{std::move(socket)};
|
||||
|
||||
// Set a decorator to change the Server of the handshake
|
||||
ws.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::response_type& res)
|
||||
{
|
||||
res.set(http::field::server,
|
||||
std::string(BOOST_BEAST_VERSION_STRING) +
|
||||
" websocket-server-sync");
|
||||
}));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws.accept();
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
void
|
||||
reset() noexcept
|
||||
{
|
||||
static_assert(sizeof(I) != 0,
|
||||
static_assert(I != 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
}
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
@ -37,14 +38,12 @@ class decorator
|
||||
void(*)(),
|
||||
void(incomplete::*)(),
|
||||
decltype(std::bind(
|
||||
std::declval<void(incomplete::*)()>(),
|
||||
std::declval<std::shared_ptr<incomplete>>()))
|
||||
std::declval<
|
||||
void(incomplete::*)(request_type&)>(),
|
||||
std::shared_ptr<incomplete>{},
|
||||
std::placeholders::_1))
|
||||
>();
|
||||
|
||||
struct none
|
||||
{
|
||||
};
|
||||
|
||||
struct base
|
||||
{
|
||||
virtual ~base() = default;
|
||||
@ -62,6 +61,16 @@ class decorator
|
||||
invoke(response_type&) = 0;
|
||||
};
|
||||
|
||||
using type = typename
|
||||
std::aligned_storage<Bytes>::type;
|
||||
|
||||
type buf_;
|
||||
base* base_;
|
||||
|
||||
struct none
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, class = void>
|
||||
struct is_req_op : std::false_type
|
||||
{
|
||||
@ -143,13 +152,42 @@ class decorator
|
||||
}
|
||||
};
|
||||
|
||||
using type = typename
|
||||
std::aligned_storage<Bytes>::type;
|
||||
void
|
||||
destroy()
|
||||
{
|
||||
if(is_inline())
|
||||
base_->~base();
|
||||
else if(base_)
|
||||
delete base_;
|
||||
}
|
||||
|
||||
type buf_;
|
||||
base* base_;
|
||||
template<class F>
|
||||
base*
|
||||
construct(F&& f, std::true_type)
|
||||
{
|
||||
return ::new(&buf_) impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<class F>
|
||||
base*
|
||||
construct(F&& f, std::false_type)
|
||||
{
|
||||
return new impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
public:
|
||||
decorator(decorator const&) = delete;
|
||||
decorator& operator=(decorator const&) = delete;
|
||||
|
||||
~decorator()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
decorator()
|
||||
: decorator(none{})
|
||||
{
|
||||
@ -171,25 +209,34 @@ public:
|
||||
impl<none>(none{});
|
||||
}
|
||||
|
||||
template<class F>
|
||||
template<class F,
|
||||
class = typename std::enable_if<
|
||||
! std::is_convertible<F, decorator>::value>::type>
|
||||
explicit
|
||||
decorator(F&& f)
|
||||
: base_(sizeof(F) <= sizeof(buf_) ?
|
||||
::new(&buf_) impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f)) :
|
||||
new impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f)))
|
||||
: base_(construct(std::forward<F>(f),
|
||||
std::integral_constant<bool,
|
||||
sizeof(F) <= sizeof(buf_)>{}))
|
||||
{
|
||||
}
|
||||
|
||||
~decorator()
|
||||
decorator&
|
||||
operator=(decorator&& other)
|
||||
{
|
||||
if(is_inline())
|
||||
base_->~base();
|
||||
this->destroy();
|
||||
base_ = nullptr;
|
||||
if(other.is_inline())
|
||||
{
|
||||
base_ = other.base_->move(&buf_);
|
||||
other.base_->~base();
|
||||
}
|
||||
else
|
||||
delete base_;
|
||||
{
|
||||
base_ = other.base_;
|
||||
}
|
||||
other.base_ = ::new(&other.buf_)
|
||||
impl<none>(none{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -75,12 +75,15 @@ build_response(
|
||||
error_code& result)
|
||||
{
|
||||
auto const decorate =
|
||||
[&decorator](response_type& res)
|
||||
[this, &decorator](response_type& res)
|
||||
{
|
||||
decorator_opt(res);
|
||||
decorator(res);
|
||||
if(! res.count(http::field::server))
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(BOOST_BEAST_VERSION_STRING) < 20);
|
||||
// VFALCO this is weird..
|
||||
BOOST_STATIC_ASSERT(sizeof(
|
||||
BOOST_BEAST_VERSION_STRING) < 20);
|
||||
static_string<20> s(BOOST_BEAST_VERSION_STRING);
|
||||
res.set(http::field::server, s);
|
||||
}
|
||||
@ -395,23 +398,6 @@ accept()
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
@ -424,22 +410,6 @@ accept(error_code& ec)
|
||||
&default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
do_accept(
|
||||
net::const_buffer{},
|
||||
decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
@ -457,32 +427,6 @@ accept(ConstBufferSequence const& buffers)
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const &decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(buffers, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ConstBufferSequence>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
@ -499,28 +443,6 @@ accept(
|
||||
do_accept(buffers, &default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
do_accept(buffers, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator>
|
||||
@ -538,28 +460,6 @@ accept(
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
ResponseDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(req, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Body, class Allocator>
|
||||
void
|
||||
@ -575,27 +475,6 @@ accept(
|
||||
do_accept(req, &default_decorate_res, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
impl_->reset();
|
||||
do_accept(req, decorator, ec);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
@ -769,6 +648,156 @@ async_accept_ex(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(ResponseDecorator const& decorator, error_code& ec)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
do_accept(
|
||||
net::const_buffer{},
|
||||
decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const &decorator)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(buffers, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(net::is_const_buffer_sequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
do_accept(buffers, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
ResponseDecorator const& decorator)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
error_code ec;
|
||||
accept_ex(req, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<
|
||||
class Body, class Allocator,
|
||||
class ResponseDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
accept_ex(
|
||||
http::request<Body,
|
||||
http::basic_fields<Allocator>> const& req,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(ResponseDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_response_decorator<
|
||||
ResponseDecorator>::value,
|
||||
"ResponseDecorator requirements not met");
|
||||
impl_->reset();
|
||||
do_accept(req, decorator, ec);
|
||||
}
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
||||
|
@ -195,57 +195,6 @@ async_handshake(response_type& res,
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
HandshakeHandler, void(error_code));
|
||||
handshake_op<BOOST_ASIO_HANDLER_TYPE(
|
||||
HandshakeHandler, void(error_code))>(
|
||||
std::move(init.completion_handler),
|
||||
impl_, nullptr, host, target,
|
||||
decorator)();
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
HandshakeHandler, void(error_code));
|
||||
handshake_op<BOOST_ASIO_HANDLER_TYPE(
|
||||
HandshakeHandler, void(error_code))>(
|
||||
std::move(init.completion_handler),
|
||||
impl_, &res, host, target,
|
||||
decorator)();
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
@ -276,45 +225,6 @@ handshake(response_type& res,
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(host, target, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(res, host, target, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
@ -341,6 +251,55 @@ handshake(response_type& res,
|
||||
host, target, &default_decorate_req, ec);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(host, target, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
error_code ec;
|
||||
handshake_ex(res, host, target, decorator, ec);
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator>
|
||||
void
|
||||
@ -350,6 +309,10 @@ handshake_ex(string_view host,
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
@ -369,6 +332,10 @@ handshake_ex(response_type& res,
|
||||
RequestDecorator const& decorator,
|
||||
error_code& ec)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_sync_stream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
@ -378,6 +345,68 @@ handshake_ex(response_type& res,
|
||||
host, target, decorator, ec);
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
HandshakeHandler, void(error_code));
|
||||
handshake_op<BOOST_ASIO_HANDLER_TYPE(
|
||||
HandshakeHandler, void(error_code))>(
|
||||
std::move(init.completion_handler),
|
||||
impl_, nullptr, host, target,
|
||||
decorator)();
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class RequestDecorator, class HandshakeHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
HandshakeHandler, void(error_code))
|
||||
stream<NextLayer, deflateSupported>::
|
||||
async_handshake_ex(response_type& res,
|
||||
string_view host,
|
||||
string_view target,
|
||||
RequestDecorator const& decorator,
|
||||
HandshakeHandler&& handler)
|
||||
{
|
||||
#if ! BOOST_BEAST_ALLOW_DEPRECATED
|
||||
static_assert(sizeof(RequestDecorator) == 0,
|
||||
BOOST_BEAST_DEPRECATION_STRING);
|
||||
#endif
|
||||
static_assert(is_async_stream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(detail::is_request_decorator<
|
||||
RequestDecorator>::value,
|
||||
"RequestDecorator requirements not met");
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
HandshakeHandler, void(error_code));
|
||||
handshake_op<BOOST_ASIO_HANDLER_TYPE(
|
||||
HandshakeHandler, void(error_code))>(
|
||||
std::move(init.completion_handler),
|
||||
impl_, &res, host, target,
|
||||
decorator)();
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
||||
|
@ -147,6 +147,16 @@ read_size_hint(DynamicBuffer& buffer) const
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// decorator
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
void
|
||||
stream<NextLayer, deflateSupported>::
|
||||
set_option(decorator opt)
|
||||
{
|
||||
impl_->decorator_opt = std::move(opt.d_);
|
||||
}
|
||||
|
||||
// timeout
|
||||
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
|
@ -96,7 +96,8 @@ struct stream<NextLayer, deflateSupported>::impl_type
|
||||
bool timed_out = false;
|
||||
int idle_counter = 0;
|
||||
|
||||
timeout timeout_opt;
|
||||
detail::decorator decorator_opt; // Decorator for HTTP messages
|
||||
timeout timeout_opt; // Timeout/idle settings
|
||||
|
||||
|
||||
template<class... Args>
|
||||
@ -532,6 +533,7 @@ build_request(
|
||||
req.set(http::field::sec_websocket_key, key);
|
||||
req.set(http::field::sec_websocket_version, "13");
|
||||
this->build_request_pmd(req);
|
||||
decorator_opt(req);
|
||||
decorator(req);
|
||||
if(! req.count(http::field::user_agent))
|
||||
req.set(http::field::user_agent,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/websocket/role.hpp>
|
||||
#include <boost/beast/websocket/detail/decorator.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace boost {
|
||||
@ -48,6 +49,25 @@ struct stream_base
|
||||
return (duration::max)();
|
||||
}
|
||||
|
||||
/** Stream option used to adjust HTTP fields of WebSocket upgrade request and responses.
|
||||
*/
|
||||
class decorator
|
||||
{
|
||||
detail::decorator d_;
|
||||
|
||||
template<class, bool>
|
||||
friend class stream;
|
||||
|
||||
public:
|
||||
decorator(decorator&&) = default;
|
||||
|
||||
template<class Decorator>
|
||||
decorator(Decorator&& f)
|
||||
: d_(f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Stream option to control the behavior of websocket timeouts.
|
||||
|
||||
Timeout features are available for asynchronous operations only.
|
||||
|
@ -70,10 +70,13 @@ public:
|
||||
|
||||
struct both_t : res_t , req_t
|
||||
{
|
||||
using req_t::operator();
|
||||
using res_t::operator();
|
||||
};
|
||||
|
||||
struct big_t : both_t
|
||||
{
|
||||
using both_t::operator();
|
||||
char buf[2048];
|
||||
};
|
||||
|
||||
@ -109,11 +112,15 @@ public:
|
||||
decorator d1{req_t{}};
|
||||
decorator d2{std::move(d1)};
|
||||
d2(req);
|
||||
decorator d3;
|
||||
d3 = std::move(d2);
|
||||
}
|
||||
|
||||
{
|
||||
// this would be leaner with bind_front
|
||||
decorator d(std::bind(
|
||||
&decorator_test::dec_req, this));
|
||||
&decorator_test::dec_req, this,
|
||||
std::placeholders::_1));
|
||||
BEAST_EXPECT(d.is_inline());
|
||||
}
|
||||
}
|
||||
@ -121,6 +128,7 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
log << "sizeof(decorator)==" << sizeof(decorator) << "\n";
|
||||
testDecorator();
|
||||
}
|
||||
};
|
||||
|
@ -28,6 +28,20 @@ public:
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws(ioc);
|
||||
|
||||
{
|
||||
ws.set_option(
|
||||
stream_base::decorator(
|
||||
[](request_type&)
|
||||
{
|
||||
}));
|
||||
|
||||
ws.set_option(
|
||||
stream_base::decorator(
|
||||
[](response_type&)
|
||||
{
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ws.set_option(
|
||||
stream_base::suggested_settings(
|
||||
|
@ -25,6 +25,7 @@ add_executable (tests-doc
|
||||
core_3_layers.cpp
|
||||
http_examples.cpp
|
||||
http_snippets.cpp
|
||||
websocket_3_handshake.cpp
|
||||
websocket_snippets.cpp
|
||||
exemplars.cpp
|
||||
)
|
||||
|
@ -23,6 +23,7 @@ alias run-tests :
|
||||
[ run core_1_refresher.cpp $(TEST_MAIN) ]
|
||||
[ run core_3_layers.cpp $(TEST_MAIN) ]
|
||||
[ run http_examples.cpp $(TEST_MAIN) ]
|
||||
[ run websocket_3_handshake.cpp $(TEST_MAIN) ]
|
||||
;
|
||||
|
||||
exe fat-tests :
|
||||
@ -31,6 +32,7 @@ exe fat-tests :
|
||||
core_1_refresher.cpp
|
||||
core_3_layers.cpp
|
||||
http_examples.cpp
|
||||
websocket_3_handshake.cpp
|
||||
;
|
||||
|
||||
explicit fat-tests ;
|
||||
|
236
test/doc/websocket_3_handshake.cpp
Normal file
236
test/doc/websocket_3_handshake.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
//
|
||||
// Copyright (c) 2016-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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#include "snippets.hpp"
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/beast/_experimental/test/stream.hpp>
|
||||
#include <boost/beast/core/async_op_base.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
websocket_3_handshake_snippets()
|
||||
{
|
||||
#include "snippets.ipp"
|
||||
stream<net::ip::tcp::socket> ws(ioc);
|
||||
{
|
||||
//[code_websocket_3_client_1
|
||||
|
||||
// Note that the stream must already be connected, this
|
||||
// function does not perform a DNS lookup on the host
|
||||
// name, nor does it establish an outgoing connection.
|
||||
|
||||
// Perform the websocket handshake in the client role.
|
||||
ws.handshake(
|
||||
"www.example.com", // The Host field
|
||||
"/", // The request-target
|
||||
ec // Set to the error
|
||||
);
|
||||
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[code_websocket_3_client_2
|
||||
|
||||
// Note that the stream must already be connected, this
|
||||
// function does not perform a DNS lookup on the host
|
||||
// name, nor does it establish an outgoing connection.
|
||||
|
||||
// This variable will receive the HTTP response from the server
|
||||
response_type res;
|
||||
|
||||
// Perform the websocket handshake in the client role.
|
||||
ws.handshake(
|
||||
res, // Receives the HTTP response
|
||||
"www.example.com", // The Host field
|
||||
"/" // The request-target
|
||||
,ec // Set to the error, if any
|
||||
);
|
||||
|
||||
// Upon success, `res` will be set to the complete
|
||||
// response received from the server.
|
||||
//]
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
{
|
||||
//[code_websocket_3_server_1
|
||||
|
||||
// Note that the stream must already be connected
|
||||
// to an incoming remote peer.
|
||||
|
||||
// Perform the websocket handshake in the server role.
|
||||
ws.accept(
|
||||
ec // Set to the error, if any
|
||||
);
|
||||
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[code_websocket_3_server_2
|
||||
// This buffer is required for reading HTTP messages
|
||||
flat_buffer buffer;
|
||||
|
||||
// Read into our buffer until we reach the end of the HTTP request.
|
||||
// No parsing takes place here, we are just accumulating data.
|
||||
// We use beast::dynamic_buffer_ref to pass a lightweight, movable
|
||||
// reference to our buffer, because Networking expects to take
|
||||
// ownership unlike Beast algorithms which use a reference.
|
||||
|
||||
net::read_until(sock, dynamic_buffer_ref(buffer), "\r\n\r\n");
|
||||
|
||||
// Now accept the connection, using the buffered data.
|
||||
ws.accept(buffer.data());
|
||||
//]
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
websocket_3_handshake_snippets_2()
|
||||
{
|
||||
using namespace boost::beast;
|
||||
namespace net = boost::asio;
|
||||
namespace ssl = boost::asio::ssl;
|
||||
using tcp = net::ip::tcp;
|
||||
error_code ec;
|
||||
net::io_context ioc;
|
||||
tcp::socket sock(ioc);
|
||||
|
||||
{
|
||||
//[code_websocket_3_server_1b
|
||||
// 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 its a WebSocket upgrade request
|
||||
if(websocket::is_upgrade(req))
|
||||
{
|
||||
// Construct the stream, transferring ownership of the socket
|
||||
stream<net::ip::tcp::socket> 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_3_decorator_1b
|
||||
void set_user_agent(request_type& req)
|
||||
{
|
||||
// Set the User-Agent on the request
|
||||
req.set(http::field::user_agent, "My User Agent");
|
||||
}
|
||||
//]
|
||||
|
||||
void
|
||||
websocket_3_handshake_snippets_3()
|
||||
{
|
||||
#include "snippets.ipp"
|
||||
stream<net::ip::tcp::socket> ws(ioc);
|
||||
{
|
||||
//[code_websocket_3_decorator_1
|
||||
|
||||
ws.set_option(stream_base::decorator(&set_user_agent));
|
||||
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[code_websocket_3_decorator_2
|
||||
|
||||
struct set_server
|
||||
{
|
||||
void operator()(response_type& res)
|
||||
{
|
||||
// Set the Server field on the response
|
||||
res.set(http::field::user_agent, "My Server");
|
||||
}
|
||||
};
|
||||
|
||||
ws.set_option(stream_base::decorator(set_server{}));
|
||||
|
||||
//]
|
||||
}
|
||||
{
|
||||
//[code_websocket_3_decorator_3
|
||||
|
||||
ws.set_option(stream_base::decorator(
|
||||
[](response_type& res)
|
||||
{
|
||||
// Set the Server field on the response
|
||||
res.set(http::field::user_agent, "My Server");
|
||||
}));
|
||||
|
||||
//]
|
||||
}
|
||||
//[code_websocket_3_decorator_4
|
||||
|
||||
struct multi_decorator
|
||||
{
|
||||
void operator()(request_type& req)
|
||||
{
|
||||
// Set the User-Agent on the request
|
||||
req.set(http::field::user_agent, "My User Agent");
|
||||
}
|
||||
|
||||
void operator()(response_type& res)
|
||||
{
|
||||
// Set the Server field on the response
|
||||
res.set(http::field::user_agent, "My Server");
|
||||
}
|
||||
};
|
||||
|
||||
ws.set_option(stream_base::decorator(multi_decorator{}));
|
||||
|
||||
//]
|
||||
}
|
||||
|
||||
} // (anon)
|
||||
|
||||
struct websocket_3_handshake_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
run() override
|
||||
{
|
||||
BEAST_EXPECT(&websocket_3_handshake_snippets);
|
||||
BEAST_EXPECT(&websocket_3_handshake_snippets_2);
|
||||
BEAST_EXPECT(&websocket_3_handshake_snippets_3);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,doc,websocket_3_handshake);
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
Reference in New Issue
Block a user