HTTP Server API — cpp-netlib v0.11.0

### Navigation

- next
- previous |
- cpp-netlib v0.11.0 »
- Reference Manual »

# HTTP Server API

## General

`cpp-netlib` includes and implements two distinct HTTP server implementations that you can use and embed in your own applications. Both HTTP Server implementations:

> - Cannot be copied. This means you may have to store instances of the HTTP Server in dynamic memory if you intend to use them as function parameters or pass them around in smart pointers of by reference.
> - Assume that requests made are independent of each other. None of the HTTP Server implementations support request pipelining (yet) so a single connection only deals with a single request.
> - Are header-only and are compiled-into your application. Future releases in case you want to upgrade the implementation you are using in your application will be distributed as header-only implementations, which means you have to re-compile your application to use a newer version of the implementations.

The HTTP Servers have different semantics, and in some cases require different APIs from the supplied template parameters.

## Implementations

There are two different user-facing template classes that differentiate the Synchronous Servers from the Asynchronous Servers. Both templates take a single template parameter named `Handler` which describes the type of the Handler function object.

There are two different Handler concepts, one concept for Synchronous Servers and another for Asynchronous Servers.

The SynchronousHandler concept for Synchronous Servers is described by the following table:

Legend:

H
  The Handler type.
h
  An instance of H.
Req
  A type that models the Request Concept.
Res
  A type that models the Response Concept.
req
  An instance of Req.
res
  An instance of Res.

Construct | Return Type | Description
--- | --- | ---
`h(req,res)` | `void` | Handle the request; res is passed in as a non-const lvalue, which represents the response to be returned to the client performing the request.

More information about the internals of the Synchronous Servers can be found in the following section.

The AsynchronousHandler concept for Asynchronous Servers is described by the following table:

Legend:

H
  The Handler type.
h
  An instance of H.
Req
  A type that models the Request Concept.
ConnectionPtr
  A type that models the Connection Pointer Concept.
req
  An instance of Req.
conn
  An instance of ConncetionPtr.

Construct | Return Type | Description
--- | --- | ---
`h(req, conn)` | `void` | Handle the request; conn is a shared pointer which exposes functions for writing to and reading from the connection.

More information about the internals of the Asynchronous Servers can be found in the following section.

## Synchronous Servers

The synchronous server implementation is represented by the template `server` in namespace `boost::network::http`. The `server` template takes in a single template parameter named `Handler` which models the SynchronousHandler concept (described above).

An instance of Handler is taken in by reference to the constructor of the HTTP server. This means the Handler is not copied around and only a single instance of the handler is used for all connections and requests performed against the HTTP server.

Warning

It is important to note that the HTTP server does not implement any locking upon invoking the Handler. In case you have any state in the Handler that will be associated with the synchronous server, you would have to implement your own synchronization internal to the Handler implementation. This matters especially if you run the synchronous server in multiple threads.

The general pattern of usage for the HTTP Server template is shown below:

    struct handler;
    typedef boost::network::http::server<handler> http_server;

    struct handler {
        void operator()(
            http_server::request const & req,
            http_server::response & res
        ) {
            // do something, and then edit the res object here.
        }
    };

More information about the actual HTTP Server API follows in the next section. It is important to understand that the HTTP Server is actually embedded in your application, which means you can expose almost all your application logic through the Handler type, which you can also initialize appropriately.

### API Documentation

The following sections assume that the following file has been included:

    #include <boost/network/include/http/server.hpp>

And that the following typedef’s have been put in place:

    struct handler_type;
    typedef boost::network::http::server<handler_type> http_server;

    struct handler_type {
        void operator()(
            http_server::request const & request,
            http_server::response & response
        ) {
            // do something here
        }
    };

#### Constructor

`explicit http_server(options)`
  Construct an HTTP Server instance, passing in a `server_options<Tag, Handler>` object. The following table shows the supported options in `server_options<Tag, Handler>`.

Parameter Name | Type | Description
--- | --- | ---
address | string_type | The hostname or IP address from which the server should be bound to. This parameter is required.
port | string_type | The port to which the server should bind and listen to. This parameter is required.
thread_pool | `shared_ptr<thread_pool>` | A shared pointer to an instance of `boost::network::utils::thread_pool` – this is the thread pool from where the handler is invoked. This parameter is only applicable and required for `async_server` instances.
io_service | `shared_ptr<io_service>` | An optional lvalue to an instance of `boost::asio::io_service` which allows the server to use an already-constructed `boost::asio::io_service` instance instead of instantiating one that it manages.
reuse_address | `bool` | A boolean that specifies whether to re-use the address and port on which the server will be bound to. This enables or disables the socket option for listener sockets. The default is `false`.
report_aborted | `bool` | A boolean that specifies whether the listening socket should report aborted connection attempts to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for future-proofing the code in case an optional error handler function is supported in later releases of cpp-netlib. The default is `false`.
receive_buffer_size | `int` | The size of the socket’s receive buffer. The default is defined by Boost.Asio and is platform-dependent.
send_buffer_size | `int` | The size of the socket’s send buffer. The default is defined by Boost.Asio and is platform-dependent.
receive_low_watermark | `int` | The size of the socket’s low watermark for its receive buffer. The default is defined by Boost.Asio and is platform-dependent.
send_buffer_size | `int` | The size of the socket’s send low watermark for its send buffer. The default is defined by Boost.Asio and is platform-dependent.
non_blocking_io | `bool` | An optional bool to define whether the socket should use non-blocking I/O in case the platform supports it. The default is `true`.
linger | `bool` | An optional bool to determine whether the socket should linger in case there’s still data to be sent out at the time of its closing. The default is `true`.
linger_timeout | `int` | An optional int to define the timeout to wait for socket closes before it is set to linger. The default is `0`.

To use the above supported named parameters, you’ll have code that looks like the following:

    using namespace boost::network::http; // parameters are in this namespace
    handler handler_instance;
    async_server<handler>::options options(handler_instance);
    options.address("0.0.0.0")
           .port("80")
           .io_service(boost::make_shared<boost::asio::io_service>())
           .thread_pool(boost::make_shared<boost::network::utils::thread_pool>(2))
           .reuse_address(true);
    async_server<handler> instance(options);
    instance.run();

#### Public Members

The following definitions assume that a properly constructed `http_server` instance has been constructed in the following manner:

    handler_type handler;
    http_server::options options(handler);
    http_server server(options.address("127.0.0.1").port("8000"));

`server.run()`
  Run the HTTP Server event loop. This function can be run on multiple threads following the example:

    boost::thread t1(boost::bind(&http_server::run, &server));
    boost::thread t2(boost::bind(&http_server::run, &server));
    server.run();
    t1.join();
    t2.join();

`server.stop()`
  Stop the HTTP Server acceptor and wait for all pending requests to finish.

#### Response Object

The response object has its own public member functions which can be very helpful in certain simple situations.

`response = http_server::response::stock_reply(status, body)`
  Code like the above should go inside the handler’s `operator()` overload. The body parameter is an `std::string`. The status parameter is any of the following values from the `http_server::response` enum `status_type`:

    enum status_type {
        ok = 200,
        created = 201,
        accepted = 202,
        no_content = 204,
        multiple_choices = 300,
        moved_permanently = 301,
        moved_temporarily = 302,
        not_modified = 304,
        bad_request = 400,
        unauthorized = 401,
        forbidden = 403,
        not_found = 404,
        not_supported = 405,
        not_acceptable = 406,
        internal_server_error = 500,
        not_implemented = 501,
        bad_gateway = 502,
        service_unavailable = 503
    };

The response object also has the following publicly accessible member values which can be directly manipulated by the handler.

Member Name | Type | Description
--- | --- | ---
status | `status_type` | The HTTP status of the response.
headers | `vector<header>` | Vector of headers. [1]
content | `string_type` [2] | The contents of the response.

[1] | A header is a struct of type `response_header<http::tags::http_server>`. An instance always has the members `name` and `value` both of which are of type `string_type`.

[2] | `string_type` is `boost::network::string<http::tags::http_server>::type`.

## Asynchronous Servers

The asynchronous server implementation is significantly different to the synchronous server implementation in three ways:

> 1. The Handler instance is invoked asynchronously. This means the I/O thread used to handle network-related events are free to handle only the I/O related events. This enables the server to scale better as to the number of concurrent connections it can handle.
> 2. The Handler is able to schedule asynchronous actions on the thread pool associated with the server. This allows handlers to perform multiple asynchronous computations that later on perform writes to the connection.
> 3. The Handler is able to control the (asynchronous) writes to and reads from the HTTP connection. Because the connection is available to the Handler, that means it can write out chunks of data at a time or stream data through the connection continuously.

The asynchronous server is meant to allow for better scalability in terms of the number of concurrent connections and for performing asynchronous actions within the handlers. If your application does not need to write out information asynchronously or perform potentially long computations, then the synchronous server gives a generally better performance profile than the asynchronous server.

The asynchronous server implementation is available from a single user-facing template named `async_server`. This template takes in a single template parameter which is the type of the Handler to be called once a request has been parsed from a connection.

An instance of Handler is taken as a reference to the constructor similar to the synchronous server implementation.

Warning

The asynchronous server implementation, like the synchronous server implementation, does not perform any synchronization on the calls to the Handler invocation. This means if your handler contains or maintains internal state, you are responsible for implementing your own synchronization on accesses to the internal state of the Handler.

The general pattern for using the `async_server` template is shown below:

    struct handler;
    typedef boost::network::http::async_server<handler> http_server;

    struct handler {
        void operator()(
            http_server::request const & req,
            http_server::connection_ptr connection
        ) {
            // handle the request here, and use the connection to
            // either read more data or write data out to the client
        }
    };

### API Documentation

The following sections assume that the following file has been included:

    #include <boost/network/include/http/server.hpp>
    #include <boost/network/utils/thread_pool.hpp>

And that the following typedef’s have been put in place:

    struct handler_type;
    typedef boost::network::http::server<handler_type> http_server;

    struct handler_type {
        void operator()(
            http_server::request const & request,
            http_server::connection_ptr connection
        ) {
            // do something here
        }
    };

#### Constructor

`explicit http_server(options)`
  Construct an HTTP server instance passing in a `server_options<Tag, Handler>` instance.

#### Public Members

The following definitions assume that a properly constructed `http_server` instance has been constructed in the following manner:

    handler_type handler;
    http_server::options options(handler);
    options.thread_pool(boost::make_shared<boost::network::utils::thread_pool>(2));
    http_server server(options.address("127.0.0.1").port("8000"));

`server.run()`
  Run the HTTP Server event loop. This function can be run on multiple threads following the example:

    boost::thread t1(boost::bind(&http_server::run, &server));
    boost::thread t2(boost::bind(&http_server::run, &server));
    server.run();
    t1.join();
    t2.join();

`server.stop()`
  Stop the HTTP Server acceptor and wait for all pending requests to finish.

#### Connection Object

The connection object has its own public member functions which will be the primary means for reading from and writing to the connection.

`template <class Range> write(Range range)`

  The connection object exposes a function `write` that can be given a parameter that adheres to the Boost.Range `Single Pass Range` Concept. The write function, although it looks synchronous, starts of a series of asynchronous writes to the connection as soon as the range is serialized to appropriately sized buffers.

  To use this in your handler, it would look something like this:

    connection->write("Hello, world!");
    std::string sample = "I have a string!";
    connection->write(sample);

`template <class Range, class Callback> void write(Range range, Callback callback)`
  The connection object also exposes a function `write` that can be given a parameter that adheres to the Boost.Range `Single Pass Range` Concept, as well as a Callback function that returns `void` and takes a `boost::system::error_code` as a parameter. This overload of `write` is useful for writing streaming applications that send out chunks of data at a time, or for writing data that may not all fit in memory right away.
`template <class ReadCallback> void read(ReadCallback callback)`

  The connection object has a function `read` which can be used to read more information from the connection. This `read` function takes in a callback that can be assigned to a Boost.Function with the signature `void(input_range,error_code,size_t,connection_ptr)`. The following list shows what the types actually mean:

  > - input_range – `boost::iterator_range<char const *>` : The range that denotes the data read from the connection.
  > - error_code – `boost::system::error_code` : The error code if there were any errors encountered from the read.
  > - size_t – `std::size_t` : The number of bytes transferred.
  > - connection_ptr – `http_server::connection_ptr` : A handle to the current connection, so that it is kept alive at the time of the read callback invocation.

  This interface is useful when doing reads of uploaded data that can be potentially large and may not fit in memory. The read handler is then responsible for dealing with the chunks of data available from the connection.

`void set_status(status_t new_status)`
  The `set_status` function takes a parameter of type `status_t` which is an enum type nested in `http_status::connection` which is given in the following code listing.

    enum status_t {
        ok = 200
        , created = 201
        , accepted = 202
        , no_content = 204
        , multiple_choices = 300
        , moved_permanently = 301
        , moved_temporarily = 302
        , not_modified = 304
        , bad_request = 400
        , unauthorized = 401
        , forbidden = 403
        , not_found = 404
        , not_supported = 405
        , not_acceptable = 406
        , internal_server_error = 500
        , not_implemented = 501
        , bad_gateway = 502
        , service_unavailable = 503
    };

Note

You may set and re-set the status several times as long as you have not set the headers or sent data through the connection. If you do this after data has already been set, the function will throw an instance of `std::logic_error`.

`template <class Range> void set_headers(Range range)`

  The `set_headers` function takes a Single Pass Range of `boost::network::http::response_header<http::tags::http_async_server>` instances and linearizes them to a buffer with at most `BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE` and immediately schedules an asynchronous write once that is done.

  The function throws an instance of `std::logic_error` if you try to set the headers for a connection more than once.

### Navigation

- next
- previous |
- cpp-netlib v0.11.0 »
- Reference Manual »