Working with http headers
When using RESTinio one should work with two types of headers:
request headers presented by restinio::http_request_header_t
class
and response header presented by restinio::http_response_header_t
class.
The first one is used in read-only mode, while the second is mostly used in write-only mode, however, it also can be used for getting already specified values.
Both header classes mimic the structure of HTTP request/response header.
They are derived from http_header_common_t
which in turn is derived
from http_header_fields_t
. These classes expose the interface for
working with common data in headers.
The most important part is setters/getters for http header fields.
HTTP header fields
Working with most of the fields is done with http_header_fields_t
class.
Its brief interface is the following:
struct http_header_fields_t
{
// ...
using const_iterator = ...; // Some implementation-defined type.
bool has_field( string_view_t field_name ) const noexcept;
bool has_field( http_field_t field_id ) const noexcept;
void set_field( http_header_field_t field );
void set_field( std::string field_name, std::string field_value );
void set_field( http_field_t field_id, std::string field_value );
void append_field( string_view_t field_name, string_view_t field_value );
void append_field( http_field_t field_id, string_view_t field_value );
// Throws if the field is not found.
const std::string & get_field( string_view_t field_name ) const;
const std::string & get_field( http_field_t field_id ) const;
// Throws if the field is not found.
string_view_t value_of( string_view_t field_name ) const;
string_view_t value_of( http_field_t field_id ) const;
// Returns nullptr if the field is not found.
nullable_pointer_t<const std::string> // It's just const std::string*
try_get_field( string_view_t field_name ) const noexcept
nullable_pointer_t<const std::string> // It's just const std::string*
try_get_field( http_field_t field_name ) const noexcept
// Returns empty optional if the field is not found.
optional_t<string_view_t> opt_value_of( string_view_t field_name ) const noexcept;
optional_t<string_view_t> opt_value_of( http_field_t field_id ) const noexcept;
// Returns the default_value converted to std::string if the field is not found.
std::string get_field_or(
const std::string & field_name,
/*some type*/ default_value ) const; // Some type can be const char*,
// std::string, string_view.
std::string get_field_or(
http_field_t field_id,
/*some type*/ default_value ) const; // Some type can be const char*,
// std::string, string_view.
void remove_field( const std::string & field_name );
void remove_field( http_field_t field_id );
const_iterator begin() const;
const_iterator end() const;
auto fields_count() const
// ...
};
Each operation with a field has two versions of a function performing it:
the one with referring field by its string name and another on referring
a field by its enum element restinio::http_field_t
that lists all that can be found here
except Connection
and Content-Length
fields, because these fields have very special meaning and
are handled explicitly with separate functions of http_header_common_t
class.
It is recommended to use restinio::http_field_t
for manipulating
with standard fields, while string referencing can be used for working
with custom fields.
Usually, response header is used implicitly through one of response builder
classes (Response builder) which has append_header()
functions,
and for most of the cases,
it is enough to set all necessary header fields for a response.
Here is a sample example for using header fields:
restinio::request_handling_status_t handler( request_handle_t req )
{
auto do_compression = [&]{
if( 0< settings().compression_level() )
{
// Conmpression can be used, so check if it can be handled by client.
const auto accept_encoding = req->header().get_field_of(
restinio::http_field::accept_encoding,
"gzip" );
return settings().compression_is_possible( accept_encoding );
}
return false;
};
auto response_body = handling_logic( *req );
auto resp = req->create_response();
// Add 'Server' header field.
resp.append_header( restinio::http_field::server, "RESTinio deleyed response server" );
// Add 'Date' header field with current timestamp.
resp.append_header_date_field();
// Add custom fields.
for( const auto & hf: settings().extra_headers() )
resp.append_header( hf.first, hf.second );
if( do_compression() )
{
// Add 'Content-Encoding' for compressed response body.
resp.append_header( restinio::http_field::content_encoding, "gzip" );
// Set compressed output here:
resp.set_body( compress( response_body, settings().compression_level() ) );
}
else
{
resp.set_body( std::move( response_body ) );
}
return resp.done();
}
There are two special cases: Connection
and Content-Length
fields.
http_header_common_t
gives the following interface for them:
enum class http_connection_header_t : std::uint8_t
{
keep_alive,
close,
upgrade
};
strut http_header_common_t
{
// ...
std::uint64_t content_length() const;
void content_length( std::uint64_t l );
bool should_keep_alive() const
void should_keep_alive( bool keep_alive )
//! Get the value of 'connection' header field.
http_connection_header_t connection() const;
//! Set the value of 'connection' header field.
void connection( http_connection_header_t ch );
// ...
};
As mentioned above normally one would use response builder for setting response header.
So Connection
and Content-Length
are also manipulated through response builder.
To close connection use resp_builder.connection_close()
for
keeping connection use resp_builder.connection_keep_alive()
.
Note: by default, value for connection field is set from the corresponding value
of the original request.
Content length is handled by response builders automaticaly, except for response_builder_t<user_controlled_output_t>
(see User controlled output response builder).
Request header
Request header exposes the following extra interface:
struct http_request_header_t
{
// ...
http_method_t method() const;
const std::string & request_target() const;
string_view_t path() const;
string_view_t query() const;
string_view_t fragment() const;
};
http_request_header_t::method()
returns http method of the request:http_method_t::http_get
,http_method_t::http_post
…http_request_header_t::request_target()
returns request target (e.g. ‘/path’ from request to ‘http://mysever:8090/path’) .- functions
path()
,query()
,fragment()
return a string view object within request target representing the path, query and fragment part of the URL, e.g. for request target/weather/temperature?from=2012-01-01&to=2012-01-10#fahrenheit
it will be/weather/temperature
,from=2012-01-01&to=2012-01-10
andfahrenheit
.
For handing query string parameter refer to Query string parameters section
Response header
The only important thing to mention is how status code and reason phrase are set. The standard way is to set them when creating response builder:
if( restinio::http_method_get() == req->header().method() &&
req->header().request_target() == "/" )
{
return req->create_response() // Default status_code=200; reason_phrase="OK"
.append_header( restinio::http_field::server, "RESTinio" )
.append_header_date_field()
.append_header( restinio::http_field::content_type, "text/plain; charset=utf-8" )
.set_body( "Hello world!")
.done();
}
return req->create_response( 404, "Not found") // Set the status_code and reason_phrase.
.append_header_date_field()
.connection_close()
.done();
More details
For more details see restinio/http_headers.hpp file.