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)

This library can be used to create applications that need to expose services through HTTP (e.g. embeddable ReST services).

Warning
This is not an official Boost C++ library. It wasn’t reviewed and can’t be downloaded from www.boost.org. This library will be reviewed eventually.

Conceptually Boost.Http is a Boost.Asio socket for HTTP, which means can leverage Boost.Asio features such as SSL and coroutines, and it integrates seemlessly with other Boost.Asio sockets.

Among its features:

  • Support for modern HTTP features.

    • Pipelining and persistent connection, where the same connection can be used to serve HTTP multiple requests.

    • Chunking, where the HTTP body can be split into smaller pieces that are sent one by one. This is useful for building event listeners.

    • Upgrading, where the HTTP protocol can be changed into another protocol such as WebSockets.

    • Security, where SSL is used to encrypt the traffic.

    • 100-continue status.

  • Lean API that unifies HTTP messages and HTTP chunking.

    • You can handle the request as soon as the metadata is available (request line plus header section).

    • There is only one API to acquire the request body. This API allows progressive downloading.

    • The response body can be be generated wholesale for normal HTTP responses, or be split into smaller pieces using HTTP chunking.

  • Extensible asynchronous design inherited from ASIO.

    • Interaction via futures, coroutines, or callbacks.

    • Various HTTP server architectures are possible, whether multi-threaded servers (one thread per request, either with or without a thread-pool), one coroutine per request, or completely single-threaded.

    • Seamless integration with other non-HTTP ASIO services.

Boost.Http also provides a couple of special-purpose server classes:

  • Lightweight standalone server.

    • The underlying socket type is customizable, so you can also use a queue_socket [1][2].

  • Flexible static file server with support for conditional requests, partial download and ETag recognition.

    • You can use the default file resolver or provide one yourself.

    • You can adapt the default resolver.

    • You can add a last hook to customize the response message before the file is served.

    • Stateless abstractions, relying on OS capabilities to provide cache.

Boost.Http has been designed for multiple backends, such HTTP/2, and FastGCI, which can be added in the future. You can choose between compile-time and runtime polymorphism. Adapters are provided.

1. Using

1.1. Requirements

This library is written in C++11 and requires a C++11 supporting compiler.

This library tries to reuse standard library components when possible, but this is not always the case. std::error_code, for instance, cannot be transparently replaced by boost::system::error_code within ASIO-using code.

The full list of dependencies is:

  • CMake 3.1.0 or more recent [3]. You can skip this requirement if you don’t intend to run the tests.

  • Boost 1.57 or more recent.

    • algorithm, container, string_ref, ASIO, date_time and system [4].

    • unit_test_framework [5].

    • context and coroutine [6].

    • filesystem [7].

  • asciidoctor [8]. You’ll also need pandoc if you want to generate the ePUB output.

2. Tutorial

In this tutorial, you’ll have a small and fast introduction to HTTP (if you’re already familiar with HTTP, you can skip the associated section and it’s more likely you’ll deeply understand Boost.Http faster). You’ll also learn incrementally how to build a proper handling of HTTP requests using Boost.Http.

A second step would be how to organize your application and make an useful application, but this second step is left for the user to tackle alone.

Warning
This tutorial assumes you’re already familiar with ASIO!
Note
This tutorial will make use of coroutines, to increase readability like nothing else could do. You might be interested in the use of alternative asynchronous models to achieve lower memory usage or something else. When C++ adds proper support for coroutines, this will not only be the most readable way, but also the most performant.

2.1. HTTP

HTTP is a protocol that shines in extensibility. Its 1.1 version has been used unchanged since 1997 and has been able to power very creative applications to this date. An HTTP/2.0 standard has been released, but most of the differencies are related to efficient connection management and the only feature that can affect higher-level layers of an application making use of HTTP is the HTTP push, which is used to speculatively send data to a client that the server anticipates the client will need.

HTTP also provides means to upgrade a protocol for a running connection and the WebSocket protocol is gaining importance where HTTP is used the most, in the web.

HTTP is a protocol that is oriented to exchange of request and reply messages. Each request is independent, hence the stateless nature of the protocol. Each request has an associated verb and path, used to tell what do to who. Every HTTP message has a body (a payload of binary data) and associated metadata (i.e. a multimap<string, string>). The HTTP response also has a status code associated which is used to indicate success of the requested action.

The metadata carried in every HTTP message is named as HTTP headers. The HTTP headers carry information on how to handle the data payload, with info such as the mime type, language and more. HTTP request messages can contain a token which is used to associate multiple different requests with the same client, so the user doesn’t need to type username and password for every page request.

GET is the most common HTTP verb and it has the simple semantic to retrieve the resource.

If you just want to expose a bunch of files from the local filesystem, you may be interested in async_response_transmit_dir, which will take several responsibilities from you (e.g. partial download and a few basic mechanisms to avoid corrupt files).

The usual setup for an HTTP application is to parse the request URL and choose an appropriate handler based on the path component. Optional middleware handlers can do some ACL based on authentication, resource usage and so on. An auxiliar database is almost always used.

2.2. Accepting new connections

Remember, the journey of a thousand miles begins with the first step.

First, we’re going to write the boilerplate code Asio require us to write if we want use stackful coroutines to handle a non predetermined number of concurrent connections.

#include <iostream>

#include <boost/asio/spawn.hpp>
#include <boost/http/buffered_socket.hpp>

using namespace std;
using namespace boost;

class connection: public std::enable_shared_from_this<connection>
{
public:
    void operator()(asio::yield_context yield)
    {
        auto self = shared_from_this();
        try {
            cout << "--\n[" << self->counter << "] Socket ready" << endl;
            // >>> OUR CODE GOES HERE <<<
        } catch (system::system_error &e) {
            if (e.code() != system::error_code{asio::error::eof}) {
                cerr << '[' << self->counter << "] Aborting on exception: "
                     << e.what() << endl;
                std::exit(1);
            }

            cout << '[' << self->counter << "] Error: "
                 << e.what() << endl;
        } catch (std::exception &e) {
            cerr << '[' << self->counter << "] Aborting on exception: "
                 << e.what() << endl;
            std::exit(1);
        }
    }

    asio::ip::tcp::socket &tcp_layer()
    {
        return socket.next_layer();
    }

    static std::shared_ptr<connection> make_connection(asio::io_service &ios,
                                                       int counter)
    {
        return std::shared_ptr<connection>{new connection{ios, counter}};
    }

private:
    connection(asio::io_service &ios, int counter)
        : socket(ios)
        , counter(counter)
    {}

    http::buffered_socket socket;
    int counter;
};

int main()
{
    asio::io_service ios;
    asio::ip::tcp::acceptor acceptor(ios,
                                     asio::ip::tcp
                                     ::endpoint(asio::ip::tcp::v6(), 8080));

    auto do_accept = [&acceptor](asio::yield_context yield) {
        int counter = 0;
        for ( ; true ; ++counter ) {
            try {
                auto connection
                    = connection::make_connection(acceptor.get_io_service(),
                                                  counter);
                cout << "About to accept a new connection" << endl;
                acceptor.async_accept(connection->tcp_layer(), yield);

                auto handle_connection
                    = [connection](asio::yield_context yield) mutable {
                    (*connection)(yield);
                };
                spawn(acceptor.get_io_service(), handle_connection);
            } catch (std::exception &e) {
                cerr << "Aborting on exception: " << e.what() << endl;
                std::exit(1);
            }
        }
    };

    cout << "About to schedule new connections acceptance" << endl;
    spawn(ios, do_accept);

    cout << "About to run the I/O scheduler/executor" << endl;
    ios.run();

    return 0;
}

Summarizing, we make use of shared_ptr to alloc object and ensure it’ll stay alive as long as there is some reference to it and we spawn an acceptor algorithm who will create a shared_ptr for every connection.

asio::ip::tcp::socket &connection::tcp_layer()
{
    return socket.next_layer();
}

The basic_buffered_socket<T>::next_layer() member-function will return the internal T object. The buffered_socket typedef uses asio::ip::tcp::socket as T.

spawn(acceptor.get_io_service(), handle_connection);

We spawn a new handler for every connection, so we’ll be able to handle them all concurrently.

auto self = shared_from_this();

We must create a reference to the shared_ptr before calling any asynchronous function to ensure the object will be live as long as the coroutine.

2.3. Receiving requests

You can find the whole code at the end of the secion. For now, we build upon the code from the previous code (just replace the “our code goes” here comment with the code we’ll build in this section.

while (self->socket.is_open()) {

So, the first thing you should do is loop while the socket is open, so the whole pipelining of requests will be handled. If the connection closes ungracefully, an error code will be generated (converted to exceptions by the coroutine completion token) during one of the operations. If the connection closes gracefully, the loop will eventually stop by is_open() returning false.

self->socket.async_read_request(self->request, yield);

So, the first part to actually handle is to ask for the request message. You’ll get the full method and path by the time the completion handler is called (in the case of coroutines, this means the next line of code). You must not touch any of these variables while the operation is in progress (hard to get it wrong if you’re using coroutines). self→request→headers() will also be filled and whatever part of the body that has already been received.

while (self->socket.read_state() != http::read_state::empty) {
    // ...
    switch (self->socket.read_state()) {
    case http::read_state::message_ready:
        // ...
        self->socket.async_read_some(self->request, yield);
        break;
    case http::read_state::body_ready:
        // ...
        self->socket.async_read_trailers(self->request, yield);
        break;

You can use self→socket.read_state() to know which part of the request is still missing and ask for the rest.

But there is a little gotcha. You should send a 100-continue to ask for the rest of the body if required. This feature appeared first in HTTP/1.1 as a mean to better use network traffic, by allowing you to reject requests sooner.

if (http::request_continue_required(self->request)) {
    // ...
    self->socket.async_write_response_continue(yield);
}

This is how we check if we should send 100-continue. It must be done after async_read_request and before async_read_some.

By this time, we have already fully received the request and we can do something with it. Pretty easy, see?

http::response reply;

The response message we’re about to send.

std::string body{"Hello World from \""};
body += self->request.target();
body += "\"\n";
std::copy(body.begin(), body.end(),
          std::back_inserter(reply.body()));

We feed some bytes to the body.

reply.status_code() = 200;
reply.reason_phrase() = "OK";
self->socket.async_write_response(reply, yield);

And then we send the response. Our application is complete.

There is a gotcha here. If you use pure asio::ip::tcp::socket, you’re subject to Asio composed operations restrictions and you should not schedule any operation while the previous one is in progress. You can wrap asio::ip::tcp::socket into some queuing socket [9] to work around this bug and Boost.Http will give you the required customization points to allow you to use it. We don’t worry about this problem here, because with coroutines we’re done.

if (we_are_halting())
    reply.headers().emplace("connection", "close");

If we’re going to halt the server and want to gracefully close current connections, this code can be used to close the HTTP pipeline after the current response end. You should pay attention to safe and idempotent methods if you want to learn more about HTTP pipelining and HTTP in general.

self->request.body().clear(); // free unused resources

Given we’re consuming the body, it’s a good idea to free unused resources. We don’t use C++11’s shrink_to_fit because it could trigger another reallocation in the next piece of body received. The idea is to reuse a small allocated buffer instead. You could also create your own message type to discard feeded bytes.

acceptor.async_accept(connection->tcp_layer(), yield);

HTTP doesn’t require you to handle protocol negotiation separately from the remaining protocol or any super special handshaking flow. Therefore, we use a “naked” acceptor to fuel an usable HTTP socket. Other HTTP backends may have different usage.

And, like I promised, here is the complete code (with a lot of print statements and a few lines to demonstrate more usage):

#include <iostream>

#include <boost/asio/spawn.hpp>
#include <boost/http/buffered_socket.hpp>
#include <boost/http/algorithm/query.hpp>
#include <boost/http/request.hpp>
#include <boost/http/response.hpp>

using namespace std;
using namespace boost;

bool we_are_halting()
{
    return false;
}

class connection: public std::enable_shared_from_this<connection>
{
public:
    void operator()(asio::yield_context yield)
    {
        auto self = shared_from_this();
        try {
            cout << "[" << self->counter << "] Socket ready" << endl;
            while (self->socket.is_open()) {
                cout << "--\n[" << self->counter
                     << "] About to receive a new message" << endl;
                self->socket.async_read_request(self->request, yield);
                self->request.body().clear(); // free unused resources

                if (http::request_continue_required(self->request)) {
                    cout << '[' << self->counter
                         << "] Continue required. About to send"
                        " \"100-continue\""
                         << std::endl;
                    self->socket.async_write_response_continue(yield);
                }

                while (self->socket.read_state() != http::read_state::empty) {
                    cout << '[' << self->counter
                         << "] Message not fully received" << endl;
                    switch (self->socket.read_state()) {
                    case http::read_state::message_ready:
                        cout << '[' << self->counter
                             << "] About to receive some body" << endl;
                        self->socket.async_read_some(self->request, yield);
                        self->request.body().clear(); // free unused resources
                        break;
                    case http::read_state::body_ready:
                        cout << '[' << self->counter
                             << "] About to receive trailers" << endl;
                        self->socket.async_read_trailers(self->request, yield);
                        self->request.body().clear(); // free unused resources
                        break;
                    default:;
                    }
                }

                cout << '[' << self->counter << "] Message received. State = "
                     << int(self->socket.read_state()) << endl;
                cout << '[' << self->counter << "] Method: "
                     << self->request.method() << endl;
                cout << '[' << self->counter << "] Path: "
                     << self->request.target() << endl;
                {
                    auto host = self->request.headers().find("host");
                    if (host != self->request.headers().end())
                        cout << '[' << self->counter << "] Host header: "
                             << host->second << endl;
                }

                std::cout << '[' << self->counter << "] Write state = "
                          << int(self->socket.write_state()) << std::endl;

                cout << '[' << self->counter << "] About to send a reply"
                     << endl;

                http::response reply;

                if (we_are_halting())
                    reply.headers().emplace("connection", "close");

                std::string body{"Hello World from \""};
                body += self->request.target();
                body += "\"\n";
                std::copy(body.begin(), body.end(),
                          std::back_inserter(reply.body()));

                reply.status_code() = 200;
                reply.reason_phrase() = "OK";
                self->socket.async_write_response(reply, yield);
            }
        } catch (system::system_error &e) {
            if (e.code() != system::error_code{asio::error::eof}) {
                cerr << '[' << self->counter << "] Aborting on exception: "
                     << e.what() << endl;
                std::exit(1);
            }

            cout << '[' << self->counter << "] Error: "
                 << e.what() << endl;
        } catch (std::exception &e) {
            cerr << '[' << self->counter << "] Aborting on exception: "
                 << e.what() << endl;
            std::exit(1);
        }
    }

    asio::ip::tcp::socket &tcp_layer()
    {
        return socket.next_layer();
    }

    static std::shared_ptr<connection> make_connection(asio::io_service &ios,
                                                       int counter)
    {
        return std::shared_ptr<connection>{new connection{ios, counter}};
    }

private:
    connection(asio::io_service &ios, int counter)
        : socket(ios)
        , counter(counter)
    {}

    http::buffered_socket socket;
    int counter;

    http::request request;
};

int main()
{
    asio::io_service ios;
    asio::ip::tcp::acceptor acceptor(ios,
                                     asio::ip::tcp
                                     ::endpoint(asio::ip::tcp::v6(), 8080));

    auto do_accept = [&acceptor](asio::yield_context yield) {
        int counter = 0;
        for ( ; true ; ++counter ) {
            try {
                auto connection
                    = connection::make_connection(acceptor.get_io_service(),
                                                  counter);
                cout << "About to accept a new connection" << endl;
                acceptor.async_accept(connection->tcp_layer(), yield);

                auto handle_connection
                    = [connection](asio::yield_context yield) mutable {
                    (*connection)(yield);
                };
                spawn(acceptor.get_io_service(), handle_connection);
            } catch (std::exception &e) {
                cerr << "Aborting on exception: " << e.what() << endl;
                std::exit(1);
            }
        }
    };

    cout << "About to schedule new connections acceptance" << endl;
    spawn(ios, do_accept);

    cout << "About to run the I/O scheduler/executor" << endl;
    ios.run();

    return 0;
}

2.4. Using chunked messages

In the previous example, we used atomic messages to respond the request. But this is limiting when we’re trying to achieve certain kind of tasks, like serving a live video stream. A second option for us is to use chunked messages to respond the request.

Warning
Chunked messages are not always available and you must check if you can use chunked messages for every request with the write_response_native_stream() socket member-function.

If chunked messages are available, you can use the following sequence of actions to respond the request:

  1. async_write_response_metadata once.

  2. async_write zero or more times.

  3. async_write_trailers or async_write_end_of_message, once.

2.5. Runtime-based polymorphic abstractions

If you want to create a function that will handle requests originated from different HTTP backends, you have three choices:

  • Rewrite the handler for every HTTP backend.

  • Write generic handlers.

  • Type-erase the HTTP backends.

Boost.Http provide some abstractions to type erase the HTTP backends (playing a similar role to std::function). The starting point to learn about it is the server_socket_adaptor page.

void handler(http::polymorphic_server_socket &socket)
{
    // ...
}

http::server_socket_adaptor<http::buffered_socket>
    socket(acceptor.get_io_service());
handler(socket);

2.6. Next steps

Jump into design choices.

3. Design choices

3.1. FAQ

  1. Why build on top of Boost.Asio?

    One of the requirements of Boost.Http is scalable performance. Scalable performance requires an asynchronous design. Asio is expected to become the future C++ standard for sockets. So, Asio it is.

    Also, reuse existing std or Boost components is nice and Asio is the Boost solution for asynchronous socket I/O.

  2. Why C++11?

    Asynchronous code can be largely simplified with language support for lambdas. To speed up the development (and decrease bugs), C++11 was chosen, but interface-wise, the only real C++11 feature is enum classes, which can be emulated in C++98 easily.

    C++98 support might be added later. The priority is to prove the core set of abstractions is correct. Then I can move on the task to fatten the library. The proof comes in the act of passing the Boost review process.

    To be fair, I also depend on the C++11 definition of multimap, but Boost containers can do the job easily.

  3. Have you considered contribute to project X/Y?

    Yes, I have.

    But current Boost.Http is not like what I was expecting when I started to writing it. Boost.Http is better. The gap between Boost.Http and other projects became even larger. My previous research won’t mention every difference.

    Boost.Http supports pipelining. Pion has separate functions for chunking. Boost.Http is designed for multiple backends. POCO, QtHttp and Casablanca aren’t build on top of Asio. Pion and cpp-netlib will use their own thread-pool, instead adhering to Asio threading model.

  4. Why is it only server-side?

    Server-side and client-side are of interest to different applications. Initially, the focus was to provide a library just to server-side, but with the time spent on research and development, it became apparent that many of the proposed abstractions are also useful for client-side.

    After this fact, a lot of caution was devoted to design the interface to retain the usefulness in client-side, where it makes sense. But this is not enough. A lot of time was spent on research just to get the server-side right and I expect that much time (or more) to also get the client-side right.

    Before any serious effort is spent on client-side, I want to focus on server-side, where the application load may be way higher and C++ may be way more desired. And just as the server-side interface development was driven by a strict set of guidelines (multiple backends, modularity with specific use cases…​), we need to define what we want to achieve with the client-side abstraction. What kind of usage will be appropriate with such design.

  5. Why isn’t a router available?

    Advocates of tree-based routers tend to ignore the middleware-based approach and the other way around is also true. It happens that some even only know one way and don’t even stop to consider that their approach isn’t appropriate for every project. This subject will affect the life of the users a lot and can be rather polemic.

    I just provide the building blocks and you can create the router any way you want. Actually, I intend to implement them later, because implementing them now will just distract the attention of the reviewers and it’d be a waste of time if the review proves the core set of abstractions is wrong.

    Most of the designs I see propose dynamic routers, where you can change the routing rules at runtime, but this feature is rarely needed. Wouldn’t be wonderful if you could use great syntax sugars to declare routers that receive as much optimization as possible at compile-time? Wouldn’t be wonderful to use nested routers? Wouldn’t be wonderful if you could collaborate the tree-based and middleware-based approach very easily? Maybe even some kind of collaboration between the statically declared routers and dynamic routers? I hope this will be rather polemic and will require a lot of iterations to get it right, maybe with a mini-review for acceptance.

3.2. Design choices

To convince you about the solution, I’ll start the text highlighting some problems and requirements. If you understand the problem, you’ll understand why the solution was proposed like that.

One of the wanted features for this library since the very beginning was to make it possible to make a small change in code to expose the HTTP service through a different communication mechanism. Like, change from embedded HTTP server to FastCGI-exposed server.

There are several libraries who will provide some object you can use to consume HTTP traffic from the world and will act as a request-reply door to create web applications. Libraries who will expose a request object you can use to consume TCP traffic and will export url and headers properties. The problem with this approach is the coupling between HTTP messages and HTTP communication channels.

In Boost.Http, HTTP messages and HTTP communication channels are decoupled, so it is easier to replace the communication channel later. You could easily use an unprotected embedded HTTP server on development environment to tests and replace it in favor of a full-blow solution during production.

Boost.Http defines some type requirements to abstract communication channels and provide some polymorphic adapters who will type erase them. The abstraction was specified carefully to allow robust applications. Your application will not hang trying to live stream a video because the request was done from an HTTP/1.0 client. Also, your handler won’t know what HTTP version (if any) the HTTP request was made with.

Also among the wanted features was to retain the usefulness of the library whether you’re using it to power an application intended to run from an low-end embedded device or an application intended to run on a cluster with plenty of resources to be made use of. An embdeded device may not have the luxury to host a pool or a cache layer, but a cluster may even demand these layers to properly handle thousands of requests every second. With this use case in mind, modularity was achieved.

The plan to finish such ambitious project was “to expose an HTTP abstraction able to make use of the HTTP power (chunking/streaming, pipelining, upgrade for supporting channels and multiplexing for supporting channels), at the same time that a complete separation of communication channels and HTTP messages is achieved”.

With the separation of HTTP messages and HTTP communication channels, alongside the use of an active model (you ask by the next request instead providing a handler and waiting for them), several of the requirements became very easy to fulfill, such as HTTP pipelining, custom memory allocation, buffers, cache layers and pools of objects.

With such very generalized abstractions, you may be worried about the need to type too much to get something done. This is being solved by providing higher level flexible abstractions, such as the file server you can already find.

3.2.1. The what

request handling

The above image shows an overview of how to build HTTP servers using Boost.Http.

Let’s assume you’re going to use the provided http::socket, suitable for embedding HTTP servers in your application.

You must instantiate a TCP socket acceptor and accept new connections. You should handle all connections concurrently.

Each connection you handle is a pipeline of request-reply pair. To receive the full request, your action may be required at several points. First, you should receive the request metadata, then it may be necessary to issue a 100-continue response. Then you need to issue reads for the body and the trailers until the whole request has been received.

You’re finally able to send the reply. You have two options, atomic messages or chunked messages. Chunked messages are not always available and must check if they can be used for each request you receive, using write_response_native_stream().

If you spread the handling logic among several functions, a good approach would be to always share the triplet <communication channel, request message, response message> around.

Still missing is URL parsing and request routing, so you must do this yourself, possibly managing pools of message and socket objects.

This system allows you to implement powerful schedulers doing fair share of resources over different IPs, whether the requests originate from HTTP or HTTPS, using all cores of your CPU and deferring new work when the work load is too high. You should be able to do all fine-grained tuning you need and also easily create higher level that are suitable for your application. Not only that, this library could become an interoperability layer for all higher-level that web application developers create.

request

Also, if you pay attention, you’ll realize that this proposal just expose HTTP with a message oriented abstraction. All procedures in the diagram are related to HTTP events and actions. And this is a modern API and you can use pretty much every modern HTTP feature (persistent streams & HTTP pipelining, chunked entities, 100-continue status, …​). And you won’t handle any parsing or low-level detail at all. It’s abstracted enough to allow alternative backends.

However, this can easily become a callback hell, and futures wouldn’t help much, given the need to use while-constructs. If you use coroutines, there is hope your code will be readable. Boost.Http follows Asio extensible asynchronous model and you’re free to use callbacks, futures, coroutines or others.

3.2.2. ASIO familiarity

This library may be very pleasant to use for any ASIO-centered mind.

  • Completion tokens received as the last argument for aync functions.

  • Async operations have the async_ prefix.

  • User control the bufferring mechanism, passing the opaque asio::buffer type.

  • User provides output arguments as references and they’ll be “filled” by the time the operation completes.

  • Memory management is left for the user.

  • An active model is presented.

  • Similar nomenclature.

The ASIO way saved us from many problems that otherwise would force us to propose solutions to already know problems such as:

  • Object pools.

  • Deferring acceptance to later on high load scenarios.

  • HTTP pipelining problems.

  • Partially filling response objects from different layers of abstractions.

  • A wrapping/wrapped socket can take care of tasks such as synchronization/queueing and timeout.

3.2.3. The mysterious/weird/news API

One of the maybe surprising things to start with is the use of highly structured objects as opposed to things like opaque buffers. You pass a message object to the initiating function and you’ll have a fully decomposed object with an URL, a method and even an associative container for the headers!!!

If you do have special memory requirements for the messages, you’re free to implementing an alternative container, as long as it fulfills the documented Message concept. Connections channels and HTTP messages are not coupled together. You can reuse these pieces in many many different contexts.

The uncoupled architecture is more general and it is the default mode, but let’s say you work at a more constrained environment where memory copying is banned, for instance. You could provide your HTTP backend (e.g. a non-copying embedded server) tied to your specific HTTP message type implementing our ideas and you still may benefit from this libray. This library provides some HTTP algorithms and some HTTP handlers (e.g. file server) and these abstractions will save some time from you.

Another difference in this library is the presence of an associated state for reading and writing messages. I believe this abstraction can be extended to also support very simple HTTP clients. To avoid confusion, if some member-function cannot be used for both modes (clients and servers), it’ll have one of the following prefixes:

  • async_read_request

  • async_read_response

  • async_write_request

  • async_write_response

We gave special attention to read_state and write_state to make sure it’ll also be usable for simple and asynchronous HTTP clients.

3.2.4. The why

Boost.Http provides an HTTP socket, which can be used to manage a pipeline of HTTP messages (i.e. an HTTP request or an HTTP reply). HTTP is stateless and each message coming from the same socket is independent. The HTTP socket from Boost.Http is a concept and specific implementations from this concept may provide more guarantees about the communication properties. The reasons to provide few guarantees are (#1) because we want a common denominator from which we can provide implementation for multiple communication channels and (#2) because implementation details are usually not required for the application, which is only interested in a high-level abstraction. The provided boost::http::basic_socket implementation will handle actual HTTP traffic from TCP sockets and you can use it to handle HTTP/1.0 and HTTP/1.1 traffic from TCP and SSL sockets.

read_state() and write_state() are used to inspect the current state of interaction and react appropriately. There are rules regarding when the socket can mutate and change its states. Once you request the socket to read a new HTTP request, you’ll be notified as soon as the request metadata (request line and HTTP headers) are ready, then you can progressively download the body and react appropriately. This idea is very useful to improve communication between the library authors and application authors and also helps to create some tests.

You’ll have to inspect the socket to know whether the current message-exchange requires 100-continue, allows chunked entities (streaming response) and alike. There is like two kind of replies. With atomic replies, you write the whole message at once. With chunked message, you compose a message spreading its construction among several API calls. You may want to use chunked messages when you don’t know the whole body in advance (e.g. reading a file, video live stream…​), but chunked messages can only be used in certain message exchanges. The reason behind providing two kind of replies is to properly support a wider range of HTTP communication channels.

You create one HTTP socket for each HTTP client and should handle them all concurrently. In case you’re using the embeddable HTTP server backend, you must use an acceptor to initialize the basic_sockets' next_layer() and then consume them. basic_socket templatize the underlying internal socket, so you can use SSL, queue wrapping socket (to work around Asio’s composed operations) and so on. The intention of Boost.Http is not only to generalize over data structures and HTTP backends, but about any place where it may be helpful.

The choice to represent the HTTP messages in separate objects and the whole combination of this design ease supports for HTTP pipelining a lot. In passive styles, a request is generated and generated and you must act on them. In this active style, you explicitly request the next message, handle it and then request another one. In this scenario, two unrelated messages won’t be mixed up, because you won’t see the next message while you don’t handle the current one. The read and write states gives a mean to communicate how to use the API and how to detect some logical errors in the application.

The choice to hide details from the HTTP connection (HTTP version, socket object…​) was done to properly support multiple backends. The ability to query certain properties from the underlying communication channel is necessary to achieve reliability under this model. A lot of responsibilies and expected behaviour is documented on the type requirements for ServerSocket objects.

A C++11 multimap is used to represent HTTP headers because that’s what HTTP headers conceptually are. HTTP spec specifies you must handle HTTP header elements with equivalent keys as if there was a single header where the values are joined with commas. Some old headers don’t work with this approach and their values, when multiple elements with equivalent keys are present, must be stored separately. The order matters, just as the C++11 definition of multimap.

Runtime-based polymorphic behaviour isn’t used by default, because not all projects are willing to pay for this price. Well defined type requirements are provided and some polymorphic adaptors will convert models of these type requirements to classes inheriting a single specific abstract base class.

Member-functions as opposed to member-variables are used in HTTP messages, because some setup (e.g. a proxy who doesn’t want to reformat the messages) may want to move the HTTP parser to the HTTP message object. I want to allow a library who will beat C servers in every aspect.

As per RFC 7230, “a server MUST NOT apply a request to the target resource until the entire request header section is received, since later header fields might include conditionals, authentication credentials, or deliberately misleading duplicate header fields that would impact request processing”, so we define an interface who will only expose a message once the complete header section is ready. The message body can be progressively received later. The API also unifies HTTP messages and HTTP chunking.

URL-decomposed objects aren’t used because all an HTTP backend needs is some string-like container to push bytes. This container can implement an in-place URL parsing algorithm and it is all solved. The generic HTTP backends you find in Boost.Http won’t care about the url concrete type and you don’t need to expect any barrier from this side.

We do not use the message itself as a buffer object while we’re parsing the connection stream. We require a separate buffer to be able to properly handle HTTP pipelining (and futurely multiplexing in HTTP/2.0).

3.2.5. The when

I couldn’t resist the temptation of adding a “when” named section after I already had written a “what” and a “why” section.

Just too much research time went into this proposal. Really, a lot of time. I developed some broken HTTP projects some years ago, learned a lot of design with really different approaches (PHP, Django, Node.js) trying to solve this problem, developed my own serious project (Tufão) and continued to study and research a lot (the HTTP spec resurrection project, or RFC 7230, helped a lot). I’ve gathered info around where interoperability may be a problem if API doesn’t help and what features will be desired, sooner or later, by users, among other data. I’ve done real effort to gather feedback from C++ programmers for quite a while already.

A special thanks to Bjørn Reese for mentoring me on Asio quirks and API general design, the feedback which changed the proposal the most. Also a special thanks to any friend who helped to maintain my mind at a happy state.

3.3. Roadmap

  • C++98.

  • Client-side HTTP.

  • HTTP/2.0.

  • Request-router.

  • Forms and file uploads.

  • Cookies and sessions (RFC 6265).

  • WebSocket.

  • Alternative backends.

  • Increase test coverage a lot.

  • Benchmarks.

  • Compress replies.

  • WebDAV (it will depend on Boost.XML, which doesn’t exist yet).

  • World domination.

4. Reference

All declarations from this library resides within the boost::http namespace. For brevity, this prefix is not repeated on the documentation.

4.1. Summary

4.1.4. Enumerations

4.1.5. Error Codes

4.1.6. Type Requirements

4.1.8. Macros

BOOST_HTTP_SOCKET_DEFAULT_BUFFER_SIZE

This macro defines the default buffer size for basic_buffered_socket. It’s safe to override this value (per using class or globally) and should be done before including the file <boost/http/buffered_socket.hpp>. The default provided value (i.e. the non-overriden version) is unspecified (e.g. can change among versions and platforms).

4.2. Detailed

4.2.1. headers

#include <boost/http/headers.hpp>

headers is a simple typedef for some unspecified multimap container.

The user can safely assume that headers::key_type will be std::string and headers::mapped_type will be std::string. std::string is used because fulfills the requirements perfectly and is very unlikely it will ever cause any controversy.

The user can also assume that this type fulfills the Headers definition of message.

Note
Previously, headers was guaranteed to be a typedef for boost::container::flat_multimap.

4.2.2. request

#include <boost/http/request.hpp>

request is a simple typedef for basic_request. It’s defined as follows:

typedef basic_request<std::string, headers, std::vector<std::uint8_t>> request;

std::vector<std::uint8_t> is used over std::string, because fits the purpose of the body (binary data payload container) better (no '\0' character terminator, well-defined behaviours of capacity, size and iterator invalidation, …​).

4.2.2.1. See also

4.2.3. response

#include <boost/http/response.hpp>

response is a simple typedef for basic_response. It’s defined as follows:

typedef basic_response<std::string, headers, std::vector<std::uint8_t>> response;

std::vector<std::uint8_t> is used over std::string, because fits the purpose of the body (binary data payload container) better (no '\0' character terminator, well-defined behaviours of capacity, size and iterator invalidation, …​).

4.2.3.1. See also

4.2.4. socket

#include <boost/http/socket.hpp>

socket is a simple typedef for basic_socket. It’s defined as follows:

typedef basic_socket<boost::asio::ip::tcp::socket> socket;

4.2.5. buffered_socket

#include <boost/http/buffered_socket.hpp>

buffered_socket is a simple typedef for basic_buffered_socket. It’s defined as follows:

typedef basic_buffered_socket<boost::asio::ip::tcp::socket> buffered_socket;

4.2.6. request_response_wrapper

#include <boost/http/request_response_wrapper.hpp>

request_response_wrapper is an adapter which acts like a common type (akin to std::common_type) for different Request and Response types. There is no type erasure and only Message interface will be available.

The purpose of this class is not to be a polymorphic wrapper. Therefore, it’s not our concern to make sure compatible objects (i.e. objects with the same header_type and so on) are of the same request_response_wrapper type. In other words, request_response_wrapper will not free you from the template work if you want to support different Request/Response types. This is not a design issue. However, there is a templated constructor which can accept some different types.

4.2.6.1. Template parameters
Request

A model of the Message concept.

Response

A model of the Message concept.

Note
Response::headers_type must be the same as Request::headers_type. And the same applies to Response::body_type. Also, if const is applied to Request or Response, it must be applied to both.
4.2.6.2. Member types
headers_type

If Request is const, then it is defined as const typename Request::headers_type. Otherwise, it’s defined as typename Request::headers_type.

body_type

If Request is const, then it is defined as const typename Request::body_type. Otherwise, it’s defined as typename Request::body_type.

4.2.6.3. Member functions
request_response_wrapper(Request &request)

Constructs a request_response_wrapper from a Request.

request_response_wrapper(Response &response)

Constructs a request_response_wrapper from a Response.

template<class Request2, class Response2> request_response_wrapper(request_response_wrapper<Request2, Response2> &other)

Constructs a request_response_wrapper from another request_response_wrapper with compatible headers_type and body_type.

Message concept
headers_type &headers()

Returns the wrapped headers object.

const headers_type &headers() const

Returns the wrapped headers object.

body_type &body()

Returns the wrapped body object.

const body_type &body() const

Returns the wrapped body object.

headers_type &trailers()

Returns the wrapped trailers object.

const headers_type &trailers() const

Returns the wrapped trailers object.

4.2.6.4. See also

4.2.7. basic_polymorphic_socket_base

#include <boost/http/polymorphic_socket_base.hpp>

basic_polymorphic_socket_base is the base class for all classes in the hierarchy defined for runtime-based polymorphic HTTP producers. It is an abstract class that only contains functionality useful for simultaneously both channel ends (client and server).

References for objects of this class are expected to fulfill the Socket concept.

This class has no state to ease multiple inheritance and it is inherited by basic_polymorphic_server_socket.

The design for the hierarchy started with this class was a little inspired by C++'s iostream and N3525: Polymorphic Allocators.

4.2.7.1. Template parameters
Message

The message type.

4.2.7.2. Member types

These are the types chosen set in stone to guarantee ABI stability across binaries (including possible plugins).

typedef Message message_type

The message type usable within this class’s operations.

typedef std::function<void(boost::system::error_code)> callback_type

It is so standard that is the only of its kind living in the standard library. It’s flexible enough to type erase any other handler. Needless to say more.

4.2.7.3. Member functions
Overwritable functions

These are the functions that subclasses need to implement in order to lose the abstract class property.

virtual asio::io_service& get_io_service() = 0

This function presents no differences (besides mandatory virtual) from the one with the same name found on the Socket concept.

virtual bool is_open() const = 0

This function presents no differences (besides mandatory virtual) from the one with the same name found on the Socket concept.

virtual read_state read_state() const = 0

This function presents no differences (besides mandatory virtual) from the one with the same name found on the Socket concept.

virtual write_state write_state() const = 0

This function presents no differences (besides mandatory virtual) from the one with the same name found on the Socket concept.

virtual void async_read_some(message_type &message, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the Socket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_read_trailers(message_type &message, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the Socket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write(const message_type &message, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the Socket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write_trailers(const message_type &message, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the Socket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write_end_of_message(callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the Socket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual ~basic_polymorphic_socket_base() = 0

Destructor. Inline definition done with = default.

Wrappers to fulfill the ASIO extensible model

These functions rewrite usual function calls in terms of the ABI stable interface. They also enable the ASIO extensible model within this hierarchy.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_some(message_type &message, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_read_some.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_trailers(message_type &message, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_read_trailers.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write(const message_type &message, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_trailers(const message_type &message, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write_trailers.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_end_of_message(CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write_end_of_message.

4.2.7.4. See also

4.2.8. basic_polymorphic_server_socket

#include <boost/http/polymorphic_server_socket.hpp>

This class inherits basic_polymorphic_socket_base<Message> and extends its interface with virtual functions useful for server sockets. This class itself is also an abstract class with no state (i.e. an interface).

References for objects of this class are expected to fulfill the ServerSocket concept.

This class is inherited by server_socket_adaptor.

4.2.8.1. Template parameters
Request

The request type.

Response

The response type.

Message = request_response_wrapper<Request, Response>

The message type.

4.2.8.2. Member types

These are the types chosen set in stone to guarantee ABI stability across binaries (including possible plugins).

typedef Request request_server_type

The server_type suffix is used to avoid name clashing with a possible HTTP client abstraction.

typedef Response response_server_type

The server_type suffix is used to avoid name clashing with a possible HTTP client abstraction.

4.2.8.3. Member functions
Overwritable functions

These are the functions that subclasses need to implement in order to lose the abstract class property.

virtual bool write_response_native_stream() const = 0

This function presents no differences (besides mandatory virtual) from the one with the same name found on the ServerSocket concept.

virtual void async_read_request(request_server_type &request, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the ServerSocket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write_response(const response_server_type &response, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the ServerSocket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write_response_continue(callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the ServerSocket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual void async_write_response_metadata(const response_server_type &response, callback_type handler) = 0

The only difference between this function (besides mandatory virtual) and the one with the same name found on the ServerSocket concept is the lack of support for completion tokens and the use of a type erased handler instead.

virtual ~basic_polymorphic_server_socket()

Destructor.

Wrappers to fulfill the ASIO extensible model

These functions rewrite usual function calls in terms of the ABI stable interface. They also enable the ASIO extensible model within this hierarchy.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_request(request_server_type &request, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_read_request.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response(const response_server_type &response, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write_response.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_continue(CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write_response_continue.

template<class CompletionToken> typename boost::asio::async_result<typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_metadata(const response_server_type &response, CompletionToken &&token)

Handle the token and dispatch the operation to the ABI stable async_write_response_metadata.

4.2.8.4. See also

4.2.9. polymorphic_socket_base

#include <boost/http/polymorphic_socket_base.hpp>

polymorphic_socket_base is a simple typedef for basic_polymorphic_socket_base. It’s defined as follows:

typedef basic_polymorphic_socket_base<request_response_wrapper<request, response>>
  polymorphic_socket_base;

4.2.10. polymorphic_server_socket

#include <boost/http/polymorphic_server_socket.hpp>

polymorphic_server_socket is a simple typedef for basic_polymorphic_server_socket. It’s defined as follows:

typedef basic_polymorphic_server_socket<request, response>
  polymorphic_server_socket;

4.2.11. basic_request

#include <boost/http/request.hpp>

This template can be used to easily define classes fulfilling the Request concept and specializing the is_request_message trait.

4.2.11.1. Template parameters
String

The type to fulfill the X::string_type from the Request concept.

Headers

The type to fulfill the X::headers_type from the Request concept.

Body

The type to fulfill the X::body_type from the Request concept.

4.2.11.2. Member types
typedef String string_type

The type to fulfill the X::string_type from the Request concept.

typedef Headers headers_type

The type to fulfill the X::headers_type from the Request concept.

typedef Body body_type

The type to fulfill the X::body_type from the Request concept.

4.2.11.3. Member functions
string_type &method()

Returns the internal method object.

const string_type &method() const

Returns the internal method object.

string_type &target()

Returns the internal request target object.

const string_type &target() const

Returns the internal request target object.

headers_type &headers()

Returns the internal headers object.

const headers_type &headers() const

Returns the internal headers object.

body_type &body()

Returns the internal body object.

const body_type &body() const

Returns the internal body object.

headers_type &trailers()

Returns the internal trailers object.

const headers_type &trailers() const

Returns the internal trailers object.

4.2.11.4. See also

4.2.12. basic_response

#include <boost/http/response.hpp>

This template can be used to easily define classes fulfilling the Response concept and specializing the is_response_message trait.

4.2.12.1. Template parameters
String

The type to fulfill the X::string_type from the Response concept.

Headers

The type to fulfill the X::headers_type from the Response concept.

Body

The type to fulfill the X::body_type from the Response concept.

4.2.12.2. Member types
typedef String string_type

The type to fulfill the X::string_type from the Response concept.

typedef Headers headers_type

The type to fulfill the X::headers_type from the Response concept.

typedef Body body_type

The type to fulfill the X::body_type from the Response concept.

4.2.12.3. Member functions
std::uint_least16_t &status_code()

Returns the internal status code object.

const std::uint_least16_t &status_code() const

Returns the internal status code object.

string_type &reason_phrase()

Returns the internal reason phrase object.

const string_type &reason_phrase() const

Returns the internal reason phrase object.

headers_type &headers()

Returns the internal headers object.

const headers_type &headers() const

Returns the internal headers object.

body_type &body()

Returns the internal body object.

const body_type &body() const

Returns the internal body object.

headers_type &trailers()

Returns the internal trailers object.

const headers_type &trailers() const

Returns the internal trailers object.

4.2.12.4. See also

4.2.13. basic_socket

#include <boost/http/socket.hpp>

This template can be used to easily define classes fulfilling the strict ServerSocket concept and specializing the is_server_socket trait. These classes exposes the HTTP/1.1 wire format (i.e. a builtin/standalone HTTP server) into an easy-to-use API.

The underlying I/O object is expected to have the following properties:

  • It is stream-oriented (i.e. no message boundaries; read or write operations may transfer fewer bytes than requested…​).

  • It fulfills the ASIO’s AsyncReadStream requirement.

  • It fulfills the ASIO’s AsyncWriteStream requirement.

  • It is backed by a reliable transport or session-layer “connection” with in-order delivery of octets (i.e. any 8-bit sequence of data).

Note

This class doesn’t restrict the message, method, path and reason phrase types. Therefore, the following members are not defined:

  • message_type

  • request_server_type

  • response_server_type

Warning
The API from this class is implemented in terms of composed operations. As such, you MUST NOT initiate any async read operation while there is another read operation in progress and you MUST NOT initiate any async write operation while there is another write operation in progress. If you cannot guarantee the ordering of the operations, you should use some queueing socket (e.g. AxioMQ’s basic_queue_socket).
Tip
You cannot detect the lack of network inactivity properly under this layer. If you need to implement timeouts, you should do so under the lower layer.
4.2.13.1. Template parameters
Socket

The underlying communication channel type. It MUST fulfill the requirements for ASIO’s AsyncReadStream and ASIO’s AsyncWriteStream.

4.2.13.2. Member types
typedef Socket next_layer_type

The type of the underlying communication channel.

4.2.13.3. Member functions
basic_socket(boost::asio::io_service &io_service, boost::asio::mutable_buffer inbuffer)

Constructor. io_service is passed to the constructor from the underlying stream.

Exceptions:
  • std::invalid_argument: If buffer size is zero.

template<class…​ Args> basic_socket(boost::asio::mutable_buffer inbuffer, Args&&…​ args)

Constructor. args are forwarded to the constructor from the underlying stream.

Exceptions:
  • std::invalid_argument: If buffer size is zero.

next_layer_type &next_layer()

Returns a reference to the underlying stream.

const next_layer_type &next_layer() const

Returns a reference to the underlying stream.

void open()

Change socket state to open.

Note
See is_open()
Warning
You MUST cancel current ongoing operations and wait for their completion handlers to be called before call this function. Otherwise, undefined behaviour is invoked.
Socket concept

See the Socket concept.

  • asio::io_service& get_io_service()

  • bool is_open() const

  • read_state read_state() const

  • write_state write_state() const

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_some(Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_trailers(Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write(const Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_trailers(const Message &message, CompletionToken &&token)

  • template<class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_end_of_message(CompletionToken &&token)

ServerSocket concept
  • bool write_response_native_stream() const

  • template<class Request, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_request(Request &request, CompletionToken &&token)

  • template<class Response, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response(const Response &response, CompletionToken &&token)

  • template<class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_continue(CompletionToken &&token)

  • template<class Response, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_metadata(const Response &response, CompletionToken &&token)

4.2.14. basic_buffered_socket

#include <boost/http/buffered_socket.hpp>

This template can be used to easily define classes fulfilling the strict ServerSocket concept. These classes exposes the HTTP/1.1 wire format (i.e. a builtin/standalone HTTP server) into an easy-to-use API.

The underlying I/O object is expected to have the following properties:

  • It is stream-oriented (i.e. no message boundaries; read or write operations may transfer fewer bytes than requested…​).

  • It fulfills the ASIO’s AsyncReadStream requirement.

  • It fulfills the ASIO’s AsyncWriteStream requirement.

  • It is backed by a reliable transport or session-layer “connection” with in-order delivery of octets (i.e. any 8-bit sequence of data).

Note

This class doesn’t restrict the message, method, path and reason phrase types. Therefore, the following members are not defined:

  • message_type

  • request_server_type

  • response_server_type

Warning
The API from this class is implemented in terms of composed operations. As such, you MUST NOT initiate any async read operation while there is another read operation in progress and you MUST NOT initiate any async write operation while there is another write operation in progress. If you cannot guarantee the ordering of the operations, you should use some queueing socket (e.g. AxioMQ’s basic_queue_socket).
Tip
You cannot detect the lack of network inactivity properly under this layer. If you need to implement timeouts, you should do so under the lower layer.
4.2.14.1. Template parameters
Socket

The underlying communication channel type. It MUST fulfill the requirements for ASIO’s AsyncReadStream and ASIO’s AsyncWriteStream.

N

The internal buffer size. It defaults to BOOST_HTTP_SOCKET_DEFAULT_BUFFER_SIZE

4.2.14.2. Member types
typedef Socket next_layer_type

The type of the underlying communication channel.

4.2.14.3. Member functions
basic_buffered_socket(boost::asio::io_service &io_service)

Constructor. io_service is passed to the constructor from the underlying stream.

template<class…​ Args> basic_buffered_socket(Args&&…​ args)

Constructor. args are forwarded to the constructor from the underlying stream.

next_layer_type &next_layer()

Returns a reference to the underlying stream.

const next_layer_type &next_layer() const

Returns a reference to the underlying stream.

Socket concept

See the Socket concept.

  • asio::io_service& get_io_service()

  • bool is_open() const

  • read_state read_state() const

  • write_state write_state() const

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_some(Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_trailers(Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write(const Message &message, CompletionToken &&token)

  • template<class Message, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_trailers(const Message &message, CompletionToken &&token)

  • template<class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_end_of_message(CompletionToken &&token)

ServerSocket concept
  • bool write_response_native_stream() const

  • template<class Request, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_read_request(Request &request, CompletionToken &&token)

  • template<class Response, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response(const Response &response, CompletionToken &&token)

  • template<class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_continue(CompletionToken &&token)

  • template<class Response, class CompletionToken> typename boost::asio::async_result< typename boost::asio::handler_type<CompletionToken, void(boost::system::error_code)>::type>::type async_write_response_metadata(const Response &response, CompletionToken &&token)

4.2.15. server_socket_adaptor

#include <boost/http/server_socket_adaptor.hpp>

This class adapts a class fulfilling the ServerSocket concept to implement the basic_polymorphic_server_socket<Request, Response, Message> interface.

This design was chosen taking a number of shortcomings in consideration.

If the user can control object construction, he might benefit by less levels of indirection by constructing both (the HTTP socket and its runtime-based polymorphic adaptor) at once and at a single memory space.

The scenario where the user don’t control the object construction was also taken in consideration. In these cases, it’s possible to use the std::reference_wrapper type found in the <functional> header. There is a server_socket_adaptor specialization that will do the job for std::reference_wrapper.

Also, if the user needs to query for the specific type at runtime, the user can do so with a single call to dynamic_cast to the specific polymorphic wrapper (rather than calling a second function to query for the wrapped object).

The design is simple to use, to learn and to read. These values were chasen to avoid misuse by the user’s part.

Although very different, the name and inspiration were borrowed from N3525: Polymorphic Allocators.

4.2.15.1. Template parameters
Socket

The type to be wrapped.

Request = request

The request message type. Default argument is request.

Response = response

The response message type. Default argument is response.

Message = request_response_wrapper<Request, Response>

The message type. Default argument is request_response_wrapper<Request, Response>.

4.2.15.2. Specializations
  • server_socket_adaptor<std::reference_wrapper<Socket>>

4.2.15.3. Member types
typedef Socket next_layer_type

The type of the wrapped socket.

4.2.15.4. Member functions
template<class…​ Args> server_socket_adaptor(Args&&…​ args)

Constructor. args are forwarded to the underlying socket constructor.

Note
Not available under the server_socket_adaptor<std::reference_wrapper<Socket>> specialization.
server_socket_adaptor(Socket &socket)

Constructor. socket is passed to the std::reference_wrapper constructor.

Note
Only available under the server_socket_adaptor<std::reference_wrapper<Socket>> specialization.
next_layer_type &next_layer()

Socket isn’t exposed directly to avoid confusion over the duplication of interfaces.

The name socket is not used because both (the wrapped object and this object itself) are sockets and it would be confusing.

const next_layer_type &next_layer() const

Socket isn’t exposed directly to avoid confusion over the duplication of interfaces.

The name socket is not used because both (the wrapped object and this object itself) are sockets and it would be confusing.

4.2.16. header_to_ptime

#include <boost/http/algorithm/header.hpp>
template<class StringRef>
boost::posix_time::ptime header_to_ptime(const StringRef &value)

Converts an HTTP-date [10] field value into boost::posix_time::ptime.

Note
Values containing extra whitespace at the beginning or at the end of value will be rejected and no conversion will be done. This behaviour is intentional.
4.2.16.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

4.2.16.2. Paremeters
const StringRef &value

An HTTP-date.

4.2.16.3. Return value

The converted value if value is a valid HTTP-date or boost::posix_time::ptime(date_time::not_a_date_time) otherwise.

Tip
You can use ptime’s `is_not_a_date_time() member-function to check if the conversion failed.
4.2.16.4. See also

4.2.17. to_http_date

#include <boost/http/algorithm/header.hpp>
template<class String>
String to_http_date(const boost::posix_time::ptime &datetime)

Converts a boost::posix_time::ptime into the preferred string representation according to section 7.1.1.1 of RFC 7231 (i.e. fixed length/zone/capitalization subset of the format defined in section 3.3 of RFC 5322).

4.2.17.1. Template parameters
String

It MUST fulfill the requirements of the String concept (i.e. std::basic_string).

4.2.17.2. Parameters
const boost::posix_time::ptime &datetime

The timepoint to be converted. It MUST be in UTC timezone.

4.2.17.3. Return value

The string representation in the preferred format (a.k.a. IMF-fixdate).

4.2.17.4. Exceptions
  • std::out_of_range: If invalid datetime is given.

4.2.17.5. See also

4.2.18. header_value_all_of

#include <boost/http/algorithm/header.hpp>
template<class StringRef, class Predicate>
bool header_value_all_of(const StringRef &header_value, const Predicate &p)

Checks if unary predicate p returns true for all elements from the comma-separated list defined by the header_value HTTP field value.

Note
This algorithm is liberal in what it accepts and it will skip invalid elements. An invalid element is a sequence, possibly empty, containing no other character than optional white space (i.e. '\x20' or '\t').
4.2.18.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

Predicate

A type whose instances are callable and have the following signature:

bool(StringRef)
4.2.18.2. Parameters
const StringRef &header_value

The HTTP field value.

const Predicate &p

The functor predicate that will be called for the elements found on the comma-separated list.

Optional white space (only at the beginning and at the end) is trimmed before applying the element to p.

4.2.18.3. Return value

true if p doesn’t returns false for any element from the list and false otherwise. This also means that you’ll get the return value true for empty lists.

4.2.19. header_value_any_of

#include <boost/http/algorithm/header.hpp>
template<class StringRef, class Predicate>
bool header_value_any_of(const StringRef &header_value, const Predicate &p)

Checks if unary predicate p returns true for at least one element from the comma-separated list defined by the header_value HTTP field value.

Note
This algorithm is liberal in what it accepts and it will skip invalid elements. An invalid element is a sequence, possibly empty, containing no other character than optional white space (i.e. '\x20' or '\t').
4.2.19.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

Predicate

A type whose instances are callable and have the following signature:

bool(StringRef)
4.2.19.2. Parameters
const StringRef &header_value

The HTTP field value.

const Predicate &p

The functor predicate that will be called for the elements found on the comma-separated list.

Optional white space (only at the beginning and at the end) is trimmed before applying the element to p.

4.2.19.3. Return value

true if the p returns true for at least one element from the list and false otherwise. This also means that you’ll get the return value false for empty lists.

4.2.20. header_value_none_of

#include <boost/http/algorithm/header.hpp>
template<class StringRef, class Predicate>
bool header_value_none_of(const StringRef &header_value, const Predicate &p)

Checks if unary predicate p returns true for no elements from the comma-separated list defined by the header_value HTTP field value.

Note
This algorithm is liberal in what it accepts and it will skip invalid elements. An invalid element is a sequence, possibly empty, containing no other character than optional white space (i.e. '\x20' or '\t').
4.2.20.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

Predicate

A type whose instances are callable and have the following signature:

bool(StringRef)
4.2.20.2. Parameters
const StringRef &header_value

The HTTP field value.

const Predicate &p

The functor predicate that will be called for the elements found on the comma-separated list.

Optional white space (only at the beginning and at the end) is trimmed before applying the element to p.

4.2.20.3. Return value

true if p doesn’t returns true for any element from the list and false otherwise. This also means that you’ll get the return value true for empty lists.

4.2.21. header_value_for_each

#include <boost/http/algorithm/header.hpp>
template<class StringRef, class F>
F header_value_for_each(const StringRef &header_value, F f)

Apply f for each element from the comma-separated list defined by the header_value HTTP field value.

Note
This algorithm is liberal in what it accepts and it will skip invalid elements. An invalid element is a sequence, possibly empty, containing no other character than optional white space (i.e. '\x20' or '\t').
4.2.21.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

F

A type whose instances are callable and have the following signature:

void(StringRef)
4.2.21.2. Parameters
const StringRef &header_value

The HTTP field value.

F f

The functor that will be called for the elements found on the comma-separated list.

Optional white space (only at the beginning and at the end) is trimmed before applying the element to f.

4.2.21.3. Return value
std::move(f)

4.2.22. etag_match_strong

#include <boost/http/algorithm/header.hpp>
template<class StringRef>
bool etag_match_strong(const StringRef &a, const StringRef &b)

Check if a and b match.

Note

This function doesn’t pedantically check if both arguments are actual entity tags and you should validate at least one of the arguments yourself.

Builtin validation is only done enough to protect against attacks.

4.2.22.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

4.2.22.2. Parameters
const StringRef &a

The entity tag to compare against b.

const StringRef &b

The entity tag to compare against a.

4.2.22.3. Return value

true if the entity tags match, using the strong comparison [11] or false otherwise.

4.2.23. etag_match_weak

#include <boost/http/algorithm/header.hpp>
template<class StringRef>
bool etag_match_weak(const StringRef &a, const StringRef &b)

Check if a and b match.

Note

This function doesn’t pedantically check if both arguments are actual entity tags and you should validate at least one of the arguments yourself.

Builtin validation is only done enough to protect against attacks.

4.2.23.1. Template parameters
StringRef

It MUST fulfill the requirements of the StringRef concept (i.e. boost::basic_string_ref).

4.2.23.2. Parameters
const StringRef &a

The entity tag to compare against b.

const StringRef &b

The entity tag to compare against a.

4.2.23.3. Return value

true if the entity tags match, using the weak comparison [12] or false otherwise.

4.2.24. request_continue_required

#include <boost/http/algorithm/query.hpp>
template<class Request>
bool request_continue_required(const Request &request)

Check if the request represented by request requires a “100 (Continue) response” [13].

If you can properly process and reply the message without its body, you’re free to go. Otherwise, you should send a “100 (Continue) response” to ask for the message body from the HTTP client.

This feature was designed to decrease network traffic, by allowing servers to sooner reject messages that would be discarded anyway.

The name required is used instead supported, because an action from the server is required.

4.2.24.1. Template parameters
Request

A type fulfilling the requirements for the Request concept.

4.2.24.2. Parameters
const Request &request

The read message.

4.2.24.3. Return value

Whether the request represented by request requires a “100 (Continue) response”.

4.2.25. request_upgrade_desired

#include <boost/http/algorithm/query.hpp>
template<class Request,
         class StringRef = boost::basic_string_ref<
             typename Request::headers_type::mapped_type::value_type>>
bool request_upgrade_desired(const Request &request)

Check if the client desires to initiate a protocol upgrade.

The desired protocols are present in the "upgrade" header as a comma-separated list.

Warning
You MUST NOT upgrade to a protocol listed in the "upgrade" header if this function returns false.

The upgrade desire can always be safely ignored.

The user MUST wait till the whole request is received before proceeding to the protocol upgrade.

4.2.25.1. Template parameters
Request

A type fulfilling the requirements for the Request concept.

StringRef

A type fulfilling the requirements for the StringRef concept (i.e. boost::basic_string_ref).

4.2.25.2. Parameters
const Request &request

The read message.

4.2.25.3. Return value

Whether the client desires to initiate a protocol upgrade.

4.2.26. async_response_transmit_file

#include <boost/http/file_server.hpp>

This function has two overloads.

template<class ServerSocket, class Request, class Response,
         class CompletionToken>
typename boost::asio::async_result<
    typename boost::asio::handler_type<CompletionToken,
                                void(boost::system::error_code)>::type>::type
async_response_transmit_file(ServerSocket &socket, const Request &imessage,
                             Response &omessage,
                             const boost::filesystem::path &file,
                             CompletionToken &&token); // (1)
template<class ServerSocket, class Request, class Response,
         class CompletionToken>
typename boost::asio::async_result<
    typename boost::asio::handler_type<CompletionToken,
                                void(boost::system::error_code)>::type>::type
async_response_transmit_file(ServerSocket &socket, const Request &imessage,
                             Response &omessage,
                             const boost::filesystem::path &file,
                             bool is_head_request,
                             CompletionToken &&token); // (2)

This function will handle a big part of the file serving job for you, such as:

  • It’ll interpret and process the request headers. However, it doesn’t process the request method nor the the input path. This means you still have to guarantee the method is applicable and you’re also expected to resolve the input path to a valid local file path.

  • It’ll fill all the applicable response headers appropriate to the request.

  • It’ll interpret the file attributes to process conditional requests and partial download. However, MIME detection (the "content-type" optional header) is still left for the user to handle.

Summarizing your responsibilities:

  • Ensure it is a "GET" method or a method with similar semantics before calling this function. Overload 2 also accepts the "HEAD" method.

  • Resolve the input URL to the appropriate file.

  • Optional: MIME detection (the "content-type" header).

  • Optional: ETag detection (see below).

A method with semantics similar to the "GET" method is any method fulfilling the following conditions:

  • The body data payload for the response message is compatible.

  • The following headers for the request message have the same meaning:

    • "if-modified-since"

    • "if-range"

    • "if-unmodified-since"

    • "range"

  • The following headers for the response message have the same meaning or don’t affect the message processing:

    • "accept-ranges"

    • "content-range"

    • "content-type"

    • "date"

    • "last-modified"

  • The same set of status code for the response are applicable.

    • "200 OK"

    • "206 Partial Content"

    • "304 Not Modified"

    • "412 Precondition Failed"

    • "416 Range Not Satisfiable"

Note
This function will call the handler with file_server_errc::io_error if any operation on the file stream fails or throws an exception.
Note
The response headers filled by this function MUST NOT be sent through trailers. Therefore, this function will not do any operation and it will call the handler with an error_code (file_server_errc::write_state_not_supported) set if you pass a socket for which the headers were already sent.
Caution

async_response_transmit_file will make use of the streaming interface only if available.

If you want to avoid wasting memory under HTTP/1.0 and other non-streaming capable channels, starting points for two solutions are:

  • Reject channels without a streaming interface (e.g. HTTP/1.0). RFC 2068 (a.k.a. HTTP/1.1) has been available since January 1997.

  • Write a custom message type that adapts the filestream to the message concept and specialize the algorithm for such message.

Note
omessage.body() will be used as output buffer. If omessage.body().capacity() == 0, an unspecified buffer size will be used and it is very likely it’ll be highly inefficient.
4.2.26.1. ETags

An ETag is a string that identify a representation of a resource. The ETag can be used to perform conditional requests more robust than the ones done with dates (limited by HTTP to seconds-based precision). In the conditional request context, an etag is a validator.

If you want to make use of the ETag implementation, just set the "etag" header in the omessage object to the appropriate value, as described below (also described in more details in RFC7232).

The first decision you must do if you decide to provide an etag is if you’re going to provide a strong validator or a weak validator.

Strong validators

A strong validator changes whenever a change occurs to the representation data that would be observable in the payload body. A strong validator is unique across all versions of all representations associated with a particular resource over time.

A strong etag has the form (specified in Augmented Backus-Naur Form (ABNF) notation of [RFC5234]):

strong-etag = DQUOTE *etagc DQUOTE
etagc       = %x21 / %x23-7E / obs-text
            ; VCHAR except double quotes, plus obs-text
obs-text    = %x80-FF
Caution
Some recipients might perform backslash unescaping. Therefore, it is a good practice to avoid backslash characters.

Some examples:

  • "xyasdzzy"

  • "xyz9czy"

  • ""

Note
A strong validator might change for reasons other than a change to the representation data.
Note
There is no implication of uniqueness across representations of different resources.
Weak validators

A weak validator might not change for every change to the representation data.

A weak etag has the form (specified in Augmented Backus-Naur Form (ABNF) notation of [RFC5234]):

weak-etag  = weak opaque-tag
weak       = %x57.2F ; "W/", case-sensitive
opaque-tag = DQUOTE *etagc DQUOTE
etagc      = %x21 / %x23-7E / obs-text
           ; VCHAR except double quotes, plus obs-text
obs-text   = %x80-FF
Caution
Some recipients might perform backslash unescaping. Therefore, it is a good practice to avoid backslash characters.

Some examples:

  • W/"xyasdzzy"

  • W/"xyz9czy"

  • W/""

4.2.26.2. Template parameters
ServerSocket

Must fulfill the requirements for the ServerSocket concept.

Request

Must fulfill the requirements for the Request concept.

Response

Must fulfill the requirements for the Response concept.

Caution

Response::body_type MUST fulfill the following extra requirements:

  • Its elements MUST be stored contiguously (e.g. std::vector).

  • It MUST support C++11 std::vector capicity and data semantics (vector.capacity and vector.data, respectively).

These extra requirements are posed because file APIs are defined in terms of buffer [14] operations.

CompletionToken

Must fulfill the ASIO requirements for a completion token.

The used handler signature is void(boost::system::error_code).

4.2.26.3. Parameters
ServerSocket &socket

The socket associated with the imessage and omessage that will be used for the response.

const Request &imessage

The request message received.

Response &omessage

The message object that should be used to reply the message.

The user might be interested in filling some extra headers here like "content-type" or cache policies.

const filesystem::path &file

The requested file that should be transmitted.

Caution
If you cannot guarantee the file did not change twice during the second covered by the last write time, you should remove all "range" and "if-range" headers from imessage before calling this function. It’s possible to construct a more robust file server by making use of system-level APIs that can provide unique identifiers for file revisions.
bool is_head_request

Whether the request was made with a "HEAD" method.

If the received request isn’t "GET" nor "HEAD", you MAY remove all "range" and "if-range" headers and pass the value false to this argument.

Note
Available only for overload 2.
CompletionToken &&token

The token from which the handler and the return value are extracted.

The extracted handler is called when the operation completes.

4.2.26.4. Return value

Extracted using token.

4.2.27. async_response_transmit_dir

#include <boost/http/file_server.hpp>

This function has two overloads.

template<class ServerSocket, class ConvertibleToPath, class Request,
         class Response, class CompletionToken>
typename boost::asio::async_result<
    typename boost::asio::handler_type<CompletionToken,
                                void(boost::system::error_code)>::type>::type
async_response_transmit_dir(ServerSocket &socket,
                            const ConvertibleToPath &ipath,
                            const Request &imessage, Response &omessage,
                            const boost::filesystem::path &root_dir,
                            CompletionToken &&token); // (1)
template<class ServerSocket, class ConvertibleToPath, class Request,
         class Response, class Predicate, class CompletionToken>
typename asio::async_result<
    typename boost::asio::handler_type<CompletionToken,
                                void(boost::system::error_code)>::type>::type
async_response_transmit_dir(ServerSocket &socket,
                            const ConvertibleToPath &ipath,
                            const Request &imessage, Response &omessage,
                            const boost::filesystem::path &root_dir,
                            Predicate filter, CompletionToken &&token); // (2)

This function does a lot more than just sending bytes. It carries the responsibilities from async_response_transmit_file, but add a few more of its own:

  • It’ll also handle the HTTP method.

  • It’ll also handle the file resolution. It does so with respect to the given root_dir argument.

The only feature missing is mime support ("content-type" header). It cannot be done reliably within this abstraction.

This function will handle even the start line and the only acceptable write_state is empty. It’ll fail on any other write_state.

All urls are absolute, but are absolute with respect to the given root_dir. This interface provides no means to disable this security check. If the user needs that much complex logic, then it should write its own path resolving solution and use async_response_transmit_file.

Caution
This function will call the handler with file_server_category::file_not_found if the requested file, with respect to the given root_dir, cannot be found. The channel remains untouched in this case, giving the user the opportunity to send custom 404 messages.
Caution
This function will call the handler with file_server_category::file_type_not_supported if resolution finishes but this function cannot process the result because the file is not regular (directories, block devices…​). The channel is also left untouched, giving the user the opportunity to use another HTTP consumer.
4.2.27.1. Template parameters
ServerSocket

Must fulfill the requirements for the ServerSocket concept.

ConvertibleToPath

A type whose instances can be used to construct a boost::filesystem::path object.

Request

Must fulfill the requirements for the Request concept.

Response

Must fulfill the requirements for the Response concept.

Predicate

A type whose instances are callable and have the following signature:

bool(boost::filesystem::path &resolved_path)
CompletionToken

Must fulfill the ASIO requirements for a completion token.

The used handler signature is void(boost::system::error_code).

4.2.27.2. Parameters
ServerSocket &socket

The socket associated with the imessage and omessage that will be used for the response.

const ConvertibleToPath &ipath

ipath (standing for input path) is the parsed path from the requested url.

It’s guaranteed that it’ll only be used to construct a boost::filesystem::path object. Thus, the user can fake the requested path to force an internal redirect.

Warning
This is the input path component, not the input URL. Therefore, you MUST parse the input url before dispatching it to this function and only the path component must be forwarded. Extracting the path is an extra responsibility for the user, but it is an useful abstraction for scenarios where the user doesn’t control the served root dir. Thanks to the security check, this internal redirect trick doesn’t work for files outside the root_dir.
const Request &imessage

The request message received.

Note
Any request method is acceptable, but any method other than "GET" and "HEAD" will be responded with "405 Method Not Allowed".
Response &omessage

The message object that should be used to reply the message.

The user might be interested in filling some extra headers here like "content-type" or cache policies.

const boost::filesystem::path &root_dir

The dir to be interpreted as the root dir of requested files.

Predicate filter

It is applied to the resolved path as the last step before proceeding to file and network operations.

If filter returns false, the functions finishes before touching the channel, with the error_code file_server_category::filter_set.

Tip
It’s possible to use a stateful non-pure filter to add response headers and properly process mime types (content-type header).
Tip
filter can also be used to redirect files by modifying the input arg.
Note
This function might throw if filter throws. In this case, we provide the basic exception guarantee.
Note
Available only for overload 2.
CompletionToken &&token

The token from which the handler and the return value are extracted.

The extracted handler is called when the operation completes.

4.2.27.3. Return value

Extracted using token.

4.2.28. read_state

#include <boost/http/read_state.hpp>
enum class read_state
read state

Represents the current state in the HTTP incoming request or HTTP incoming response.

Be prepared to face multiple state changes after a single action is scheduled (e.g. you issue receive_message action and the state already changed to empty when the handler is invoked). However, the message producer (e.g. the embedded server) is not allowed to change the state from empty to request_ready without another iteraction from the library user.

4.2.28.1. Member constants
empty

This is the initial state.

There are two ways to interpret this state. It might mean that the request object wasn’t used/read yet.

Another interpretation is that it was reached from the body_ready state, after all trailers have been received. It’s safe to assume that all message data is available if this is the case.

An easy to interpret this state is that it is complete for the previous message and empty for the next one.

At this state, you can only issue a receive_message action.

message_ready

This state is reached from the empty state, once you ask for a new request.

No more receive_message actions can be issued from this state.

From this state, you can issue the receive_some_body action. The state will change to body_ready once all body was read. In streaming connections (e.g. HTTP/1.1 chunked entities), this condition (body fully received) might never happen.

Once this state is reached, you can safely read the first line and the headers.

body_ready

This state is reached from the request_ready, once the http producer (e.g. embedded server) fully received the message body.

From this state, you can only issue the receive_trailers action.

Once this state is reached, you can safely assume that no more body parts will be received.

finished

Only possible in incoming response mode. It means the message is complete and you can no longer issue another receive_message until something else is done (e.g. send another http request). This is a different/special value, because the “something else to do” might not be related to read actions.

It can be reached from body_ready state, after all trailers have been received. It’s safe to assume that all message data is available at the time this state is reached.

4.2.28.2. See also

4.2.29. write_state

#include <boost/http/write_state.hpp>
enum class write_state
write state

Represents the current state in the HTTP outgoing response or HTTP outgoing request.

It has extra values that won’t be used in “outgoing-request” mode. Explanation focuses in “outgoing-response” mode.

4.2.29.1. Member constants
empty

This is the initial state.

It means that the response object wasn’t used yet.

At this state, you can only issue the metadata or issue a continue action, if continue is supported/used in this HTTP session. Even if continue was requested, issue a continue action is optional and only required if you need the request’s body.

continue_issued

This state is reached from the empty state, once you issue a continue action.

No more continue actions can be issued from this state.

Only makes sense in server mode, when issuing an outgoing response.

metadata_issued

This state can be reached either from empty or continue_issued.

It happens when the metadata (start line + header section) is reached (through write_metadata).

From this state, you can only issue the body, the trailers or the end of the message.

finished

The message is considered complete once this state is reached.

You can no longer issue anything once this state is reached. The underlying channel will change the outgoing_state once some unspecified event occurs. This event is usually a new request in server mode or the response fully received in client mode.

4.2.29.2. See also

4.2.30. status_code

#include <boost/http/status_code.hpp>
enum class status_code: std::uint_fast16_t

This scoped enumeration defines the values for the “Hypertext Transfer Protocol (HTTP) Status Code Registry”.

4.2.30.1. Member constants
continue_request

100

switching_protocols

101

processing

102

ok

200

created

201

accepted

202

non_authoritative_information

203

no_content

204

reset_content

205

partial_content

206

multi_status

207

already_reported

208

im_used

226

multiple_choices

300

moved_permanently

301

found

302

see_other

303

not_modified

304

use_proxy

305

switch_proxy

306

Note
No longer used.
temporary_redirect

307

permanent_redirect

308

bad_request

400

unauthorized

401

payment_required

402

forbidden

403

not_found

404

method_not_allowed

405

not_acceptable

406

proxy_authentication_required

407

request_timeout

408

conflict

409

gone

410

length_required

411

precondition_failed

412

payload_too_large

413

uri_too_long

414

unsupported_media_type

415

requested_range_not_satisfiable

416

expectation_failed

417

unprocessable_entity

422

locked

423

failed_dependency

424

upgrade_required

426

precondition_required

428

too_many_requests

429

request_header_fields_too_large

431

internal_server_error

500

not_implemented

501

bad_gateway

502

service_unavailable

503

gateway_timeout

504

http_version_not_supported

505

variant_also_negotiates

506

insufficient_storage

507

loop_detected

508

not_extended

510

network_authentication_required

511

4.2.30.2. Non-member functions
bool operator==(status_code lhs, std::uint_fast16_t rhs)

Tests if lhs and rhs are equal.

bool operator==(std::uint_fast16_t lhs, status_code rhs)

Tests if lhs and rhs are equal.

template<class String> String to_string(status_code sc)

Returns the textual representation (i.e. the reason phrase) of sc.

4.2.31. http_errc

#include <boost/http/http_errc.hpp>
enum class http_errc

This scoped enumeration defines the values for the standard error codes reported by HTTP message producers and consumers. They are intended to be generic and usable by a variety of HTTP producers.

They are designed to work together http_category.

The traits boost::system::is_error_code_enum and boost::system::is_error_condition_enum are specialized to recognize http_errc.

4.2.31.1. Member constants
out_of_order

Actions issued on the wrong order by the library user.

Make sure to check the examples and the return value from socket.read_state() and socket.write_state().

native_stream_unsupported

The issued action can only be used when the underlying channel supports native stream, as defined in the Socket concept page.

Tip
If you’re using a type fulfilling the ServerSocket concept, you may be interested in the write_response_native_stream() member function.
parsing_error

The underlying communication channel sent an invalid message.

buffer_exhausted

This error should only happen if a poor parser is used.

wrong_direction

For flexible sockets that select the channel type upon the first use. It happens if you started the socket operations behaving like an HTTP client and later started to behave as an HTTP server, or vice versa, on the same channel.

4.2.31.2. Non-member functions
boost::system::error_code make_error_code(http_errc e)

Creates an error code using e and http_category.

boost::system::error_condition make_error_condition(http_errc e)

Creates an error codition using e and http_category.

4.2.31.3. http_category
const boost::system::error_category& http_category()

Obtains a reference to the static error category object for HTTP errors. The object overrides the member function name to return "http" and overrides message to support all values from http_errc.

4.2.32. file_server_errc

#include <boost/http/file_server.hpp>
enum class file_server_errc

This scoped enumeration defines the values for the error codes reported by HTTP file server abstraction shipped with this library.

They’re designed to work with file_server_category.

The traits boost::system::is_error_code_enum and boost::system::is_error_condition_enum are specialized to recognize file_server_errc.

4.2.32.1. Member constants
io_error

When any operation on the file stream fails or throws an exception.

Note
It’s guaranteed that no operations on the underlying socket were done when this error happens.
irrecoverable_io_error

When any operation on the file stream fails or throws an exception AFTER some operation on the underlying socket already was issued.

write_state_not_supported

If some write operation already was issued before the call to the function that raised this error code.

file_not_found

The requested file wasn’t found. The channel is left untouched to give the user the opportunity to send a custom “404 response” or to further forward the request.

file_type_not_supported

The requested file was found but it is not regular (e.g. directories, block devices, links…​). Channel remains untouched.

filter_set

The user provided filter predicate returned false to cancel the operation. Channel remains untouched.

4.2.32.2. Non-member functions
boost::system::error_code make_error_code(file_server_errc e)

Creates an error code using e and file_server_category

boost::system::error_condition make_error_condition(file_server_errc e)

Creates an error code using e and file_server_category

4.2.32.3. file_server_category
const boost::system::error_category& file_server_category();

Obtains a reference to the static error category object for the file server errors. The object overrides the member function name to return "file_server" and overrides message to support all values from file_server_errc.

4.2.33. Message

A container able to hold generic HTTP messages.

4.2.33.1. Definitions
HTTP field name

A string encoded with the ISO-8859-1 charset whose contents are limited to the chars listed below (case-sensitive):

  • A digit (i.e. '0', '1', '2', '3', '4', '5', '6', '7', '8' or '9').

  • A lowercase alphabetic (i.e. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y' or 'z').

  • A few special characters: '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', backtick (i.e. '\x60'), '|' or '~'.

    Note
    Any uppercase character received through the wire MUST be normalized (i.e. converted to lowercase).
HTTP field value

A string encoded with the ISO-8859-1 charset whose contents are limited to the chars listed below (whether they’re case-sensitive or not is defined on a header-by-header basis and, as such, they all are considered case-sensitive in this layer of abstraction):

  • Any visible USASCII character.

  • Any character in the closed interval (i.e. both ends are inclusive) between '\x80' and '\xFF'. The use of these characters within the HTTP field value is obsolete and should be avoided.

  • Space (i.e. '\x20') and horizontal tab (i.e. '\t'). These characters are not allowed in the beginning or in the end of the HTTP field value.

HTTP field

A pair whose first element is an HTTP field name and second element is an HTTP field value.

HTTP header section

A set of HTTP fields received in the same chunk (e.g. the HTTP header section defined in the RFC 7230).

Note
For fields with equivalent field names, the relative order is preserved.
4.2.33.2. Notation
X

A type that is a model of Message.

Headers

A type fulfilling the following requirements:

  • The C++11 concept of associative containers (associative.reqmts) [15].

  • It supports equivalent keys.

  • Value type is equal to pair<const Key, T>.

  • mapped_type is available with the same semantics for multimap.

  • Headers::key_type MUST fulfill the requirements for the String concept (i.e. std::basic_string).

    Headers::key_type::value_type MUST be able to represent all values in the ISO-8859-1 charset except for the upper case versions of the alphabetic characters.

    Warning
    Inserting elements in Headers instances whose keys contains uppercase char(s) invoke undefined behaviour.
  • Headers::mapped_type MUST fulfill the requirements for the String concept (i.e. std::basic_string).

    Headers::mapped_type::value_type MUST be able to represent all values in the ISO-8859-1 charset.

Body

A type fulfilling the C++ concept of sequence containers (sequence.reqmts) whose value_type can represent byte octets.

a

Object of type X.

ca

Object of type const X.

4.2.33.3. Requirements
Expression Return type Precondition Semantics Postcondition

std::is_base_of<std::true_type, http::is_message<X>>

std::true_type

X::headers_type

Headers

X::body_type

Body

a.headers()

X::headers_type&

  • It should be used to represent the HTTP header section received/to-be-sent before the HTTP body data payload.

  • Always returns a reference to the same object.

  • The returned object MUST NOT be shared with the one returned by a.trailers().

ca.headers()

const X::headers_type&

  • It should be used to represent the HTTP header section received/to-be-sent before the HTTP body data payload.

  • Always returns a reference to the same object.

  • The returned object MUST NOT be shared with the one returned by a.trailers().

a.body()

X::body_type&

  • It should be used to represent chunks of the HTTP body data payload.

  • Always returns a reference to the same object.

ca.body()

const X::body_type&

  • It should be used to represent chunks of the HTTP body data payload.

  • Always returns a reference to the same object.

a.trailers()

X::headers_type&

  • It should be used to represent the HTTP header section received/to-be-sent after the HTTP body data payload.

  • Always returns a reference to the same object.

  • The returned object MUST NOT be shared with the one returned by a.headers().

ca.trailers()

const X::headers_type&

  • It should be used to represent the HTTP header section received/to-be-sent after the HTTP body data payload.

  • Always returns a reference to the same object.

  • The returned object MUST NOT be shared with the one returned by a.headers().

  1. Failing to comply with the “MUST” and “MUST NOT” conditions described previously invokes undefined behaviour.

4.2.33.4. See also

4.2.34. Request

A container able to hold HTTP request messages.

4.2.34.1. Refinement of
4.2.34.2. Notation
X

A type that is a model of Request.

String

A type that is a model of C++'s String.

a

Object of type X.

ca

Object of type const X.

4.2.34.3. Requirements
Expression Return type Precondition Semantics Postcondition

std::is_base_of<std::true_type, http::is_request_message<X>>

std::true_type

X::string_type

String

a.method()

X::string_type&

  • It should be used to represent the HTTP request method.

  • Always returns a reference to the same object.

ca.method()

const X::string_type&

  • It should be used to represent the HTTP request method.

  • Always returns a reference to the same object.

a.target()

X::string_type&

  • It should be used to represent the HTTP request target.

  • Always returns a reference to the same object.

ca.target()

const X::string_type&

  • It should be used to represent the HTTP request target.

  • Always returns a reference to the same object.

4.2.34.4. Models

4.2.35. Response

A container able to hold HTTP response messages.

4.2.35.1. Refinement of
4.2.35.2. Notation
X

A type that is a model of Response.

String

A type that is a model of C++'s String.

a

Object of type X.

ca

Object of type const X.

4.2.35.3. Requirements
Expression Return type Precondition Semantics Postcondition

std::is_base_of<std::true_type, http::is_response_message<X>>

std::true_type

X::string_type

String

a.status_code()

std::uint_least16_t&

  • It should be used to represent the HTTP response status code.

  • Always returns a reference to the same object.

ca.status_code()

const std::uint_least16_t&

  • It should be used to represent the HTTP response status code.

  • Always returns a reference to the same object.

a.reason_phrase()

X::string_type&

  • It should be used to represent the HTTP response reason phrase.

  • Always returns a reference to the same object.

ca.reason_phrase()

const X::string_type&

  • It should be used to represent the HTTP response reason phrase.

  • Always returns a reference to the same object.

4.2.35.4. Models

4.2.36. Socket

Common operations between request and response that the underlying channel should provide.

4.2.36.1. Definitions
Types fulfilling the Socket concept and also possessing the strict property

Instances from this type will not insert illegal characters [16] in the HTTP fields.

Native stream

The message size doesn’t need to be know prior to writing the response message. The use of the streaming API can only be used when this property holds. Buffering the body MUST NOT be done and the message parts MUST be written as soon as convenient. If this property holds, the user MAY safely use the socket to transmit a live video stream, for instance.

Message metadata

The HTTP status line plus the header section.

Atomic message

A message which is issued and fully know with a single API call.

Every message is either atomic or chunked.

Chunked message

A message which is issued among several API calls.

Every message is either atomic or chunked.

Chunked messages are useful if you don’t know the message in advance (e.g. video streaming). These messages can only be used if native stream is supported.

You always need to be prepared to receive chunked messages and it’s only useful to differ operations which only apply to atomic messages or chunked messages when you’re about to send a message.

4.2.36.2. Notation
Message

A type fulfilling the requirements for the Message concept.

m

Object of type Message.

cm

Object of type const Message.

CompletionToken

A type fulfilling the concept of a completion token, as defined in N4045: Library Foundations for Asynchronous Operations, Revision 2.

AsyncResultType
boost::asio::async_result<
    boost::asio::handler_type<
        CompletionToken, void(boost::system::error_code)>::type>::type
token

An object of the type CompletionToken.

X

A type that is a model of Socket.

a

Object of type X.

ca

Object of type const X.

4.2.36.3. Requirements
Expression Return type Precondition Semantics Postcondition

std::is_base_of<std::true_type, http::is_socket<X>>

std::true_type

a.get_io_service()

asio::io_service&

Returns the io_service object through which the handlers of asynchronous operations will be invoked.

X::message_type

Socket only supports operations involving a single type of message.

Must be a type fulfilling the Message concept.

ca.is_open()

bool

Determine whether the socket is open.

ca.read_state()

read_state

Returns the state associated with the Socket meaningful for reading operations.

ca.write_state()

write_state

Returns the state associated with the Socket meaningful for writing operations.

a.async_read_some(m, token)

AsyncResultType

a.read_state() == read_state::message_ready

Initiate an asynchronous operation to read a part of the message body. Handler is called when at least one byte is read (called with no error set), when the end of message is reached (called with no error set) or when some error occurs.

m.body() and m.trailers() are left in an unspecified state while the operation is in progress.

By the time the handler is called, the part of the message read (if any) is appended to m.body(), if no error happened.

a.async_read_some(m, token)

AsyncResultType

a.read_state() != read_state::message_ready

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_read_trailers(m, token)

AsyncResultType

a.read_state() == read_state::body_ready

Initiate an asynchronous operation to read the trailers. Handler is called when the rest of the message is fully received (called with no error set) or when some error occurs.

m.trailers() is left in an unspecified state while the operation is in progress.

By the time the handler is called, if no error happened:

  • a.read_state() == http::read_state::empty

  • The read trailers (if any) are inserted into m.trailers().

a.async_read_trailers(m, token)

AsyncResultType

a.read_state() != read_state::body_ready

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_write(cm, token)

AsyncResultType

a.write_state() == write_state ::metadata_issued

Initiate an asynchronous operation to write a chunk of the HTTP body data payload (chunked message). Handler is called when the operation completes with an appropriate parameter.

cm.body() MUST NOT be modified while the operation is in progress.

By the time the handler is called, the cm.body() data is considered delivered, if no error happened.

a.async_write(cm, token)

AsyncResultType

a.write_state() != write_state ::metadata_issued

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_write_trailers(cm, token)

AsyncResultType

a.write_state() == write_state ::metadata_issued

Initiate an asynchronous operation to write the trailer part of the message (chunked message). Handler is called when the operation completes with an appropriate parameter.

cm.trailers() MUST NOT be modified while the operation is in progress.

  • a.write_state() == write_state::finished

  • By the time the operation completes, the cm.trailers() data is considered delivered, if no error happened.

a.async_write_trailers(cm, token)

AsyncResultType

a.write_state() != write_state ::metadata_issued

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_write_end_of_message (token)

AsyncResultType

a.write_state() == write_state ::metadata_issued

Initiate an asynchronous operation to signalize the sent message is complete (chunked message). Handler is called when the operation completes with an appropriate parameter.

  • a.write_state() == write_state::finished

  • By the time the operation completes, the message is considered complete, if no error happened.

a.async_write_end_of_message (token)

AsyncResultType

a.write_state() != write_state ::metadata_issued

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

  1. Failing to comply with the “MUST” and “MUST NOT” conditions described previously invokes undefined behaviour.

  2. Any HTTP field name received through the wire is normalized (i.e. uppercase characters are converted to lowercase) before they’re inserted into objects of type Message::headers_type.

  3. The Socket object has the freedom to store information required to further process the incoming message in the user-provided message object. Thus, the library user MUST NOT use different message objects in the functions that initiate read operations, in the context of the same message exchange (i.e. the user can use a different message object to receive a different message). This requirement is extended to refinements of this concept.

  4. The Socket object MUST NOT insert HTTP headers with empty keys (i.e. "") in message, request or response objects provided by the user.

  5. You MUST NOT write messages with the "transfer-encoding: chunked" header.

  6. You MUST NOT write atomic messages with the "transfer-encoding" header.

4.2.36.5. See also

4.2.37. ServerSocket

Provides operations for HTTP servers.

4.2.37.1. Refinement of
4.2.37.2. Definitions
Types fulfilling the ServerSocket concept and also possessing the strict property

Instances from this type will not insert illegal characters [17] in the HTTP fields.

4.2.37.3. Notation
Request

A type fulfilling the requirements for the Request concept.

Response

A type fulfilling the requirements for the Response concept.

im

Object of type Request.

om

Object of type const Response.

CompletionToken

A type fulfilling the concept of a completion token, as defined in N4045: Library Foundations for Asynchronous Operations, Revision 2.

AsyncResultType
boost::asio::async_result<
     boost::asio::handler_type<
         CompletionToken, void(boost::system::error_code)>::type>::type
token

An object of the type CompletionToken.

X

A type that is a model of ServerSocket.

a

Object of type X.

ca

Object of type const X.

4.2.37.4. Requirements
Expression Return type Precondition Semantics Postcondition

std::is_base_of<std::true_type, http::is_server_socket<X>>

std::true_type

X::request_type

ServerSocket only supports operations involving a single type of request message.

Must be a type fulfilling the requirements for the Request concept.

X::response_type

ServerSocket only supports operations involving a single type of response message.

Must be a type fulfilling the requirements for the Response concept.

ca.write_response_native_stream()

bool

a.read_state() != read_state::empty

Returns whether the current message exchange supports native stream.

The same value and property is maintained until the end of the current message exchange.

a.async_read_request(im, token)

AsyncResultType

a.read_state() == read_state::empty

Initiate an asynchronous operation to read enough of the message to apply the request to a target resource (i.e. request line plus the header section). Handler is called when the operation completes with an appropriate parameter.

im is left in a unspecified state while the operation is in progress.

The ServerSocket object MUST prevent the user from issuing new replies while the request isn’t ready. The prevention MUST be done by changing the write state to write_state::finished while the read_request operation is in progress.

By the time the handler is called, im.method() value represents the read method, im.target() represents the read url and all headers for the current request are inserted into m.headers(), if no error happened.

a.async_read_request(im, token)

AsyncResultType

a.read_state() != read_state::empty

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_write_response(om, token)

AsyncResultType

a.write_state() == write_state::empty || a.write_state() == write_state::continue_issued

Initiate an asynchronous operation to write the response message (atomic message). Handler is called with an appropriate argument when the operation completes.

om MUST NOT be modified while the operation is in progress.

  • a.write_state() == write_state ::finished

  • By the time the handler is called, the om message is considered delivered, if no error happened.

a.async_write_response(om, token)

AsyncResultType

a.write_state() != write_state::empty && a.write_state() != write_state::continue_issued

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a.async_write_response_continue (token)

AsyncResultType

a.write_state() == write_state::empty

Initiate an asynchronous operation to write a response with the semantics from a “100 (Continue) response” [18]. Handler is called when the operation completes with an appropriate parameter.

  • a.write_state() == write_state ::continue_issued

  • By the time the handler is called, the “100 (Continue) response” is considered delivered.

a.async_write_response_continue (token)

AsyncResultType

a.write_state() != write_state::empty

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order}.

a .async_write_response_metadata(om, token)

AsyncResultType

(a.write_state() == write_state::empty || a.write_state() == write_state::continue_issued) && a.write_response_native_stream() == true

Initiate an asynchronous operation to write the response metadata (chunked message). Handler is called with an appropriate argument when the operation completes.

om MUST NOT be modified while the operation is in progress.

  • a.write_state() == write_state ::metadata_issued

  • By the time the handler is called, the response metadata (i.e. om.status_code(), om.reason_phrase() and cm.headers()) is considered delivered, if no error happened.

a .async_write_response_metadata(om, token)

AsyncResultType

a.write_state() != write_state::empty && a.write_state() != write_state::continue_issued

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc::out_of_order} [19].

a .async_write_response_metadata(om, token)

AsyncResultType

(a.write_state() == write_state::empty || a.write_state() == write_state::continue_issued) && a.write_response_native_stream() == false

No actions are done and the handler from the completion token is called with boost::system::error_code {http_errc ::native_stream_unsupported}.

  1. Failing to comply with the “MUST” and “MUST NOT” conditions described previously invokes undefined behaviour.

  2. Any HTTP field name received through the wire is normalized (i.e. uppercase characters are converted to lowercase) before they’re inserted into objects of type Request::headers_type.

  3. If the user pass a "connection: close" header on the message object passed as argument to the async_write_response or async_write_response_metadata member-functions and no errors arose during the delivery of the message, the ServerSocket MUST call the handler with http_errc::stream_finished.

    This behaviour is intended for the communication between the user of this library and the ServerSocket and can differ from the communication between the ServerSocket and the underlying channel.

  4. If the ServerSocket reads a message that expects a “100 (Continue) response”, it MUST insert the "expect: 100-continue" header and only one element with the HTTP field name "expect" MUST be present.

    This behaviour is intended for the communication between the user of this library and the ServerSocket and can differ from the communication between the ServerSocket and the underlying channel.

  5. If the ServerSocket reads a message that does NOT expect a “100 (Continue) response”, it MUST erase all the "expect: 100-continue" headers.

    This behaviour is intended for the communication between the user of this library and the ServerSocket and can differ from the communication between the ServerSocket and the underlying channel.

  6. If the ServerSocket reads a message that represent a desire from the HTTP client to initiate a protocol upgrade, the ServerSocket supports a protocol upgrade and it’ll communicate the client desire to the user of this library, it MUST communicate the desire ensuring all of the following conditions:

    • Ensuring that the "upgrade" (case-insensitive) string is present in the comma-separated list of values from some "connection" header. This rule implictly requires the presence of at least one "connection" header.

    • There is at least one "upgrade" header and all of the "upgrade" headers respect the conditions established in the section 6.7 of the RFC7230.

    This behaviour is intended for the communication between the user of this library and the ServerSocket and can differ from the communication between the ServerSocket and the underlying channel.

  7. If the ServerSocket isn’t willing to provide a protocol upgrade, then no "upgrade" headers can be present (in other words, all "upgrade" headers MUST be erased before delivering the message to the user of this library).

    This behaviour is intended for the communication between the user of this library and the ServerSocket and can differ from the communication between the ServerSocket and the underlying channel.

  8. If the "content-length" header is provided to async_write_response, then the ServerSocket MUST ignore the message body (i.e. there is no data payload in the reply message) and SHOULD use the user-provided header.

    The ServerSocket MUST adopt a behaviour that is compatible with the behaviour defined in the section 3.3.2 of the RFC 7230.

  9. The ServerSocket object MUST NOT insert HTTP headers with empty keys (i.e. "") in message, request or response objects provided by the user.

4.2.38. <boost/http/algorithm.hpp>

A shorthand to write:

#include <boost/http/algorithm/header.hpp>
#include <boost/http/algorithm/query.hpp>

4.2.40. <boost/http/algorithm/query.hpp>

Import the following symbols:

4.2.41. <boost/http/file_server.hpp>

Import the following symbols:

4.2.42. <boost/http/headers.hpp>

Import the following symbol:

4.2.43. <boost/http/http_category.hpp>

Import the http_category symbol documented at http_errc page.

4.2.44. <boost/http/http_errc.hpp>

Import all the symbols documented at the http_errc page.

4.2.45. <boost/http/request.hpp>

Import the following symbols:

4.2.46. <boost/http/response.hpp>

Import the following symbols:

4.2.47. <boost/http/request_response_wrapper.hpp>

Import the following symbols:

4.2.48. <boost/http/polymorphic_server_socket.hpp>

Import the following symbols:

4.2.49. <boost/http/polymorphic_socket_base.hpp>

Import the following symbols:

4.2.50. <boost/http/read_state.hpp>

Import the following symbol:

4.2.51. <boost/http/server_socket_adaptor.hpp>

Import the following symbols:

4.2.52. <boost/http/socket.hpp>

Import the following symbols:

4.2.53. <boost/http/buffered_socket.hpp>

Import the following symbols:

4.2.54. <boost/http/status_code.hpp>

Import the following symbol:

4.2.55. <boost/http/write_state.hpp>

Import the following symbol:

4.2.56. <boost/http/traits.hpp>

Import the following symbols:

4.2.57. <boost/http/basic_router.hpp>

Import the following symbols:

4.2.58. <boost/http/regex_router.hpp>

Import the following symbols:

4.2.59. is_message

#include <boost/http/traits.hpp>

If T is an object fulfilling the Message concept, this template inherits std::true_type. For any other type, this template inherits std::false_type.

This template may be specialized for a user-defined type to indicate that the type is eligible for operations involving Message objects.

Initially, it was considered to create a trait that would automatically detect if T is fullfilling the Message concept, but the idea was abandoned, because the Message concept includes behaviour that can only be detected at runtime.

The default definition follows:

template<class T>
struct is_message
    : public std::integral_constant<bool,
                                    is_request_message<T>::value
                                    || is_response_message<T>::value>
{};
4.2.59.1. Template parameters
T

The type to query.

4.2.60. is_request_message

#include <boost/http/traits.hpp>

If T is an object fulfilling the Request concept, this template inherits std::true_type. For any other type, this template inherits std::false_type.

This template may be specialized for a user-defined type to indicate that the type is eligible for operations involving Request objects.

4.2.60.1. Template parameters
T

The type to query.

4.2.61. is_response_message

#include <boost/http/traits.hpp>

If T is an object fulfilling the Response concept, this template inherits std::true_type. For any other type, this template inherits std::false_type.

This template may be specialized for a user-defined type to indicate that the type is eligible for operations involving Response objects.

4.2.61.1. Template parameters
T

The type to query.

4.2.62. is_socket

#include <boost/http/traits.hpp>

If T is an object fulfilling the Socket concept, this template inherits std::true_type. For any other type, this template inherits std::false_type.

This template may be specialized for a user-defined type to indicate that the type is eligible for operations involving Socket objects. If your user-defined type already specializes is_server_socket, there is no need to also specialize this template, because this template will, by default, inherit std::true_type if is_server_socket<T>::value evaluates to true.

Note
In the future, when the client code is added, this trait will also detect if T is a client socket.

Initially, it was considered to create a trait that would automatically detect if T is fullfilling the Socket concept, but the idea was abandoned, because the Socket concept includes behaviour that can only be detected at runtime.

4.2.62.1. Template parameters
T

The type to query.

4.2.62.2. See also

4.2.63. is_server_socket

#include <boost/http/traits.hpp>

If T is an object fulfilling the ServerSocket concept, this template inherits std::true_type. For any other type, this template inherits std::false_type.

This template may be specialized for a user-defined type to indicate that the type is eligible for operations involving ServerSocket objects.

Initially, it was considered to create a trait that would automatically detect if T is fullfilling the ServerSocket concept, but the idea was abandoned, because the ServerSocket concept includes behaviour that can only be detected at runtime.

4.2.63.1. Template parameters
T

The type to query.

4.2.63.2. See also

4.2.64. basic_router

#include <boost/http/basic_router.hpp>

Router based on simple test functions. It is implemented as a vector of pairs<test,router>. Where test is a functor that tests a specific path received by a connection, and if returns ture, calls the router function with an arbitary number of arguments.

A test functor could be as simple as bool test_path(string path) { return path.empty(); }.

The router is an arbitary function, that must match the call to the router itself. So if we call the route as basic_router(path, arg1, arg2) the router function will be called with router(arg1, arg2).

4.2.64.1. Template parameters
unary_predicate

Functor that recieves std::string path as an argument and returns true if this route should be selected.

route_function_type

Functor of the route destination function.

typename…​ arguments

List of argument type to be passed onto the route destination function.

4.2.64.2. See also

4.2.65. regex_router

#include <boost/http/regex_router.hpp>

Router based on regular expressions. It is implemented as a vector of pairs<regex,router>. Where regex is a std::regex that tests a specific path received by a connection, and if matches, calls the router function with an arbitary number of arguments.

The router is an arbitary function, that must match the call to the router itself. So if we call the route as basic_router(path, arg1, arg2) the router function will be called with router(arg1, arg2).

4.2.65.1. Template parameters
route_function_type

Functor of the route destination function.

typename…​ arguments

List of argument type to be passed onto the route destination function.

4.2.65.2. See also

1. Useful to avoid the gotchas of ASIO composed operations. See http://sourceforge.net/p/asio/mailman/message/32259256/ for more information.
2. See an example at http://sourceforge.net/p/axiomq/code/ci/master/tree/include/axiomq/basic_queue_socket.hpp.
3. for tests
4. Used in the core library.
5. For tests.
6. For the examples and tests.
7. For the file_server.
8. For the documentation.
9. Like axiomq’s basic_queue_socket
10. Defined in RFC 7231, section 7.1.1.1.
11. Defined in RFC 7232.
12. Defined in RFC 7232.
13. Defined in RFC 7231, section 5.1.1.
14. objects with contiguous storage of bytes.
15. The C++11 update gives extra guarantees about preserving the insertion ordering for elements with equivalent keys.
16. Defined in the Message concept’s “definitions” section.
17. Defined in the Message concept’s “definitions” section.
18. Defined in RFC 7231, section 5.1.1.
19. The notification of the error http_errc::out_of_order has priority over http_errc::native_stream_unsupported because these errors present a programming logic error that always will happen (i.e. they aren’t tied to specific runtime behaviour). If they aren’t fixed, the program won’t work either way.