Request handler

Request handler

Simplified view

In general request handler is a function-object receiving exactly one parameter: request handle. The function signature of the handler must be:

restinio::request_handling_status_t
handler( restinio::request_handle_t req );

Each request handler receives a handle on a conrete request. restinio::request_handle_t is a alias for std::shared_ptr<restinio::request_t>. req parameters is passed by value and thus can be passed to another processing flow (that is where an async handling becomes possible).

Handler must return handling status via request_handling_status_t enum. If the handler does handle request it must return accepted value. If handler refuses to handle request it must return rejected. There are two helper functions: restinio::request_accepted() and restinio::request_rejected() for refering an itemes of the enum.

Default request handler used in traits is the following.

using default_request_handler_t =
    std::function<request_handling_status_t (request_handle_t)>;

The actual picture

Since v.0.6.13 there is the support for extra-data incorporated into a request object. Because of that since v.0.6.13 request object is represented as a class template:

template<typename User_Data>
class generic_request_t;

There is also a template generic_request_handle_t:

template<typename User_Data>
using generic_request_handle_t = std::shared_ptr<
      generic_request_t<User_Data>>;

The old names request_t and request_handle_t are just aliases now:

using request_t = generic_request_t< no_extra_data_factory_t::data_t >;

using request_handle_t = generic_request_handle_t<
      no_extra_data_factory_t::data_t>;

It means that if you do not need to work with additional extra-data incorporated into a request object, then you can just use names restinio::request_t and restinio::request_handle_t. But if you have to incorporate some extra-data into a request object or have to write a generic request-handler, you should use generic_request_t and generic_request_handle_t. For example:

// The definition of extra-data-factory.
struct my_extra_data_factory {
   // The type to be incorporated into a request.
   struct data_t {...};
   ...
};

// User's extra-data-factory have to be specified in traits.
struct my_traits {
   using extra_data_factory_t = my_user_data_factory;
};

// A request-handler for incoming request that knows what data is
// incorporated into a request.
restinio::request_handling_status_t handler(
   // Note the usage of generic_request_handle_t.
   restinio::generic_request_handle_t<my_extra_data_factory::data_t> req)
{
   ...
}

// A generic request-handler.
template<typename User_Data>
restinio::request_handling_status_t handling(
   restinio::generic_request_handle_t<User_Data> req)
{
   ...
}

Request structure

Note. For simplicity, we’ll speak using just ``request_t`` and ``request_handle_t`` names. But note, that those types are just aliases for templates ``generic_request_t`` and ``generic_request_handle_t``.

Let’s have a look at a very important object – restinio::request_t. It brings all the data of a given HTTP request and some internal stuff to make response mechanism work.

There are two major data pieces of request: request header and request body.

Request header can be accesed by request_t::header() function which returns a reference to restinio::http_request_header_t object. Refer to Working with http headers section for more detail on a header.

Body can be accesed by request_t::body() function which returns a reference to std::string.

Support for incoming requests with chunked encoding

Since v.0.6.9 RESTinio accepts incoming requests with chunked encoding (previous versions of RESTinio returned HTTP 501 error in such cases). RESTino v.0.6.9 glues all chunks together and holds them in a single concatenated body (that is accessible via request_t::body() method).

Information about individual chunks is preserved and can be accessed via request_t::chunked_input_info() method. But note that this method returns nullptr if the request uses different Transfer-Encoding scheme. It means that the result of request_t::chunked_input_info() should be checked before the use:

auto my_handler(restinio::request_handle_t req)
{
   const auto chunked_info = req->chunked_input_info();
   if(chunked_info)
   {
      for(const auto chunk : chunked_info->chunks())
         ... // Do something with chunk.
   }
}

If an incoming request with chunked encoding has trailing HTTP fields those fields can be accessed via chunked_input_info_t object too:

auto my_handler(restinio::request_handle_t req)
{
   const auto chunked_info = req->chunked_input_info();
   if(chunked_info)
   {
      const restinio::http_header_fields_t & trailing_fields =
         chunked_info->trailing_fields();
      trailing_fields.for_each_value_of("My-Trailing-Field",
         [](auto value) {
            ... // Handling of field value.
         });
   }
}