Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for a snapshot of the develop branch, built from commit 31c6e1f53a.
PrevUpHomeNext

Decorator

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 1.32. 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.

stream_base::decorator

Objects of this type are used to hold a decorator to be set on the stream using 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:

void set_user_agent(request_type& req)
{
    // Set the User-Agent on the request
    req.set(http::field::user_agent, "My User Agent");
}

When using a decorator, 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:

stream<tcp_stream> ws(ioc);

// The function `set_user_agent` will be invoked with
// every upgrade request before it is sent by the stream.

ws.set_option(stream_base::decorator(&set_user_agent));

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:

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{}));

A lambda may be used in place of a named function object:

ws.set_option(stream_base::decorator(
    [](response_type& res)
    {
        // Set the Server field on the response
        res.set(http::field::user_agent, "My Server");
    }));

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:

struct set_message_fields
{
    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(set_message_fields{}));

The implementation takes ownership by decay-copy of the invocable object used as the decorator. Move-only types are possible:

struct set_auth
{
    std::unique_ptr<std::string> key;

    void operator()(request_type& req)
    {
        // Set the authorization field
        req.set(http::field::authorization, *key);
    }
};

// The stream takes ownership of the decorator object
ws.set_option(stream_base::decorator(
    set_auth{boost::make_unique<std::string>("Basic QWxhZGRpbjpPcGVuU2VzYW1l")}));
[Important] Important

Undefined behavior results if the decorator modifies the fields specific to perform the WebSocket Upgrade, such as the Upgrade or Connection fields.


PrevUpHomeNext