Overview
This library is making http requests easy, yet still maintaining the full power of asio. As it’s basis, boost.beast, is very low-level, requests brings not only a high level interface but also an http library that makes creating your own high-level interfaces easy.
auto r = requests::get(urls::url_view("https://httpbin.org/basic-auth/user/pass"),
requests::http::headers({requests::basic_auth("user", "pass")}));
std::cout << r.result_code() << std::endl;
// 200
std::cout << r.headers["Content-Type"] << std::endl;
// 'application/json; charset=utf8'
std::cout << r.string_view() << std::endl;
// {"authenticated": true, ...
std::cout << requests::as_json(r) << std::endl;
// {'authenticated': True, ...}
High level Interface
Method functions
The high level interface consists of free functions to perform requests. These will follow redirects & return the body as raw memory.
requests::response res = requests::get(urls::url_view("https://boost.org/index.html"));
The get does the same as the following call to request:
requests::response res = requests::request(
requests::http::verb::get, // < method
urls::url_view("https://boost.org/index.html"),
requests::empty{}); // < request body
The request method requires users to specify the request body (which must empty for get), which can means the interface does allow ill-formed requests.
request always returns a [response] object. The response response to request may contain an empty body, while the named function may use [response_base] to indicate at compile time that the method never has a response with a body.
requests::response_base res = requests::head(urls::url_view("https://boost.org/index.html"));
Every method-function has multiple overloads, as exemplified by the following overloads of get:
// default-session requests
auto get(urls::url_view target, http::fields req = {}) -> response;
// non-throwing overload
auto get(urls::url_view target, http::fields req, system::error_code & ec) -> response;
// request on a connection, session or pool
template<typename Connection>
auto get(Connection & conn,
urls::url_view target,
typename Connection::request_type req = {}) -> response;
// non-throwing overload
template<typename Connection>
auto get(Connection & conn,
urls::url_view target,
typename Connection::request_type req,
system::error_code & ec) -> response
The overloads without a Connection parameter use the [default_session].
The req argument indicates how to perform the request.
On a session request and one on a [session] those are the request headers,
for connections & pools it’s a Request settings.
This is because the non-header attributes in request_settings are part of the session.
If the method has a body it’s argument is passed between the target & req arguments:
template<typename RequestBody>
auto post(
urls::url_view target,
RequestBody && request_body,
http::fields req = {}) -> response;
If the request-body is optional (as with delete), the function will provide overloads for either case, e.g.:
auto delete_(urls::url_view target, RequestBody && request_body, http::fields req = {}) -> response;
auto delete_(urls::url_view target, http::fields req = {}) -> response;
Additionally, every method has an asynchronous overload:
template< typename CompletionToken>
auto async_get(urls::url_view target, http::fields req, CompletionToken && completion_token);
template<typename Connection, typename CompletionToken>
auto async_get(Connection & conn,
urls::url_view target,
typename Connection::request_type req,
CompletionToken && completion_token);
Which will have a signature of void(system::error_code, response) or void(system::error_code, response_base), depending on the http method. The version that takes a Connection parameter supports default completion tokens.
Below are all the http methods:
| Http Method | Name | Async-Name | Response body [1] | Request Body | Remarks |
|---|---|---|---|---|---|
GET |
|
|
always |
never |
|
HEAD |
|
|
never |
never |
|
POST |
|
|
always |
always |
|
PUT |
|
|
optional |
always |
|
PATCH |
|
|
optional |
always |
|
DELETE |
|
|
optional |
optional |
|
OPTIONS |
|
|
optional |
never |
|
TRACE |
|
|
never |
never |
|
CONNECT |
|
|
never |
always |
Can only be used on a |
Request Body
The body used for the requests requires specializations of [body_traits], which is an adaptor for the beast-bodies and provides a default mime-type.
|
Note
|
The traits mime-type will only be used for Content-Type if not already set in the headers.
|
requests::post(
urls::url_view("https://httpbin.org/post")
R"({"message" : "hello-world"})");
The above will use a span<char> to represent the data and set the data to "text/plain; charset=utf-8".
You can override the Content-Type by just setting it manually:
requests::post(
urls::url_view("https://httpbin.org/post")
R"({"message" : "hello-world"})",
requests::headers({{"Content-Type", "application/json"}}));
Request settings
Request settings dictate how a request performs. It contains the headers, [request_options] and a pointer to the cookie_jar.
When performing the request through a [session] the options & jar pointer will be injected from the session itself.
Redirects
Redirects are automatically handled, and every redirect response is stored in the [response_base.history] field.
The [request_options.redirect] sets the mode of redirection, which can be adjusted based on security concerns.
The default mode is [redirect_mode.private_domain], which allows redirect within one subdomain, such as boost.org to api.boost.org.
The private domain patterns are available through the [default_public_suffix_list].
Json
Since json is ubiquitous in http requests due to it’s usage in REST APIs, requests has special treatment for it.
The Json namespace provides http method similar to the ones in the [requests] namespace; although it ignores the methods that never have a return body. The resulting type is an instantiation of [json::response] which will contain a parse json body. If the method’s return body is optional, it’ll be wrapped in boost::optional.
This means, by default a function like [json::get] will return json::response<json::value> and [json::delete_] json::response<optional<json::value>>.
json::response<json::value> res = json::get ("https://httpbin.org/get");
json::response<optional<json::value>> oes = json::delete_("https://httpbin.org/delete");
It is also possible to directly convert the json into a struct, if try_value_to is valid for the type.
struct httpbin_res
{
json::object args;
unordered_map<json::string, json::string> headers;
json::string origin;
json::string url;
};
// let describe generate the json conversion
BOOST_DESCRIBE_STRUCT(httpbin_res, (), (args, headers, origin, url));
json::response<httpbin_res> res = json::get <httpbin_res>("https://httpbin.org/get");
json::response<optional<httpbin_res>> oes = json::delete_<httpbin_res>("https://httpbin.org/delete");
Similarly, the request_body will be treated as if it is json, i.e. it will attempt to use boost::json::value_from
to send json data.
auto ptr = boost::json::make_shared_resource<boost::json::monotonic_resource>();
json::response<json::value> res = get(
urls::url_view("https://httpbin.org/headers"),
requests::headers({}, ptr.get()));
assert(ptr == res.value.storage());
Download
For big items, that should be directly transferred into files, requests provides the Download function.
It will perform a GET request and directly write it to disk. If the path points to a directory the path
will be deduced from the url-path.
requests::response_base res = requests::download(
urls::url_view("https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz"),
{}, filesystem::current_path());
Mid-level
Connections, Pools & Sessions
The basic building block is a [connection], which usually represents a single socket; this can be a tcp socket, a tcp socket or a domain socket. As such, a [connection] works on a single endpoint.
The pool is a dynamic collection of connections, working on a hostname & protocol pair, because a hostname can provide multiple endpoints. The pool will manage the amount of connections and distributing them over multiple endpoints.
A session represents a map of pools & hostname-protocol pairs, exclusively for http and https. It owns the cookie_jar & request settings, such as the [redirect_mode].
/---------\
| Session |
\---------/
:
: hostname /-------\ list /------------\
\------------>| pool |-------->| connection |
\-------/ \------------/
requests brings a [default_session], which will be inserted into an asio::execution_context through use_service.
By default that means the asio::system_executor is used. The async versions of the global function will however use the
associated_executor to install the default session in.
stream
The fundamental building block used by high level functions is the stream, which is a response read that implements the asio concepts of SyncReadStream and AsyncReadStream.
That means that any read algorithm that works on classes like asio::ip::tcp::socket will also work on the requests::stream.
std::size_t read_line(requests::stream &str,
DynamicBuffer_v2 && buf)
{
asio::read_until(str, buf, '\n');
}
Stream algorithms used by the high level functions are:
ropen
To obtain a stream session, connections & pools provide ropen and async_ropen functions.
These can either be used to construct a request on the fly, using the [body_traits],
or can pass in an http::request by reference.
auto s = request_stream(requests::default_session(),
requests::http::get,
urls::url_view("https://boost.org/index.html"),
requests::empty{});
compile time optimization
The library optimizes compile times as much as possible without too much overhead.
Because of that, everything uses a asio::generic::socket with an asio::any_io_executor,
to avoid templating everything.
# Reference
completion_handler_for and default_token are used instead of verbose asio macros.
connection.hpp
A connection pool represents a single http or domain socket connection to and endpoint.
namespace boost::requests
{
struct connection
{
/// The type of the next layer.
typedef asio::ssl::stream<asio::generic::stream_protocol::socket> next_layer_type;
/// The type of the executor associated with the object.
typedef typename next_layer_type::executor_type executor_type;
/// The type of the executor associated with the object.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// This helper type with a defaulted completion token.
template<typename Token>
struct defaulted;
/// Get the executor
executor_type get_executor() noexcept;
/// Get the underlying stream
const next_layer_type &next_layer() const noexcept;
/// Get the underlying stream
next_layer_type &next_layer() noexcept;
/// The protocol-type of the lowest layer.
using protocol_type = typename beast::lowest_layer_type<next_layer_type>::protocol_type;
/// The endpoint of the lowest lowest layer.
using endpoint_type = typename protocol_type::endpoint;
/// Construct a stream that uses ssl
template<typename ExecutorOrContext>
explicit connection(ExecutorOrContext && exec_or_ctx, asio::ssl::context & ctx);
/// Construct a stream that doesn't use ssl
template<typename ExecutorOrContext>
explicit connection(ExecutorOrContext && exec_or_ctx);
/// Move construct a connection
connection(connection && ) noexcept = default;
/// Rebinding constructor;
template<typename Other>
connection(connection<Other> && lhs);
/// Connect to an endpoint
void connect(endpoint_type ep);
void connect(endpoint_type ep, system::error_code & ec);
template<asio::token_for<void (boost::system::error_code)> CompletionToken
asio::default_token_t<executor_type>>
auto async_connect(endpoint_type ep,
CompletionToken && token = asio::default_token_t<executor_type>());
/// Close the socket.
void close();
void close(system::error_code & ec);
template<asio::token_for<void (boost::system::error_code)> CompletionToken =
asio::default_token_t<executor_type>>
auto async_close(CompletionToken && token = asio::default_token_t<executor_type>());
// Check if the connection is open.
bool is_open() const final;
// Get the Endpoint
endpoint_type endpoint() const {return endpoint_;}
// Timeout of the last connection-alive message
std::chrono::system_clock::time_point timeout() const;
// Amount of ongoing requests.
std::size_t working_requests() const;
// Reserve memory for the internal buffer.
void reserve(std::size_t size);
// Set the host of the endpoint
void set_host(core::string_view sv);
void set_host(core::string_view sv, system::error_code & ec);
// Get the host name
core::string_view host() const;
/// The stream type returned by ropen.
using stream = stream<executor_type>;
/// Send a preexisting request.
template<typename RequestBody>
auto ropen(beast::http::verb method,
urls::pct_string_view path,
http::fields & headers,
source & src,
cookie_jar * jar,
system::error_code & ec) -> stream;
template<typename RequestBody>
auto ropen(beast::http::verb method,
urls::pct_string_view path,
http::fields & headers,
source & src,
request_options opt,
cookie_jar * jar) -> stream;
template<typename RequestBody,
typename CompletionToken
= asio::default_token_t<executor_type>>
auto async_ropen(beast::http::verb method,
urls::pct_string_view path,
http::fields & headers,
source & src,
cookie_jar * jar = nullptr,
CompletionToken && token = asio::default_token_t<executor_type>());
};
}
connect
The connection function opens a connection to an endpoint. This will also perform the ssl handshake for ssl connections, which is why the host needs to be set previously with [connection::set_host] because the handshake will certify the hostname as well.
set_host
The set_host function sets the internal host-name and
does apply it to ssl verification if used.
|
Note
|
You will also need to set this field for domain socket connection, as it’ll also be sent in the http request. |
close
Closing a connection can involve an asynchronous operation if the socket is using ssl,
which is why async_close is provided.
connection_pool.hpp
A connection pool represents a collection [connection] objects pointing to the same host & port.
struct connection_pool
{
/// The type of the executor associated with the object.
typedef typename Stream::executor_type executor_type;
/// The type of the underlying connection.
typedef connection<Stream> connection_type;
/// Rebinds the socket type to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef connection_pool<typename Stream::template rebind_executor<Executor1>::other> other;
};
/// Get the executor
executor_type get_executor() noexcept;
/// The protocol-type of the lowest layer.
using protocol_type = typename connection_type::protocol_type;
/// The endpoint of the lowest lowest layer.
using endpoint_type = typename connection_type::endpoint_type;
/// The reolver_type of the lower layer.
using resolver_type = typename protocol_type::resolver::template rebind_executor<executor_type>::other;
/// Construct a pool from an executor.
template<typename Exec, typename = std::enable_if_t<!detail::has_ssl_v<Stream>, Exec>>
explicit connection_pool(Exec && exec,
std::size_t limit = BOOST_REQUESTS_DEFAULT_POOL_SIZE);
/// Construct a pool from an executor and sslctx
template<typename Exec>
explicit connection_pool(Exec && exec,
asio::ssl::context & ctx,
std::size_t limit = BOOST_REQUESTS_DEFAULT_POOL_SIZE);
/// Move constructor
connection_pool(connection_pool && ) = default;
/// rebind constructor.
template<typename Exec>
connection_pool(connection_pool<Exec> && lhs);
/// Lookup the endpoints for an authority and set the host.
void lookup(urls::authority_view av);
void lookup(urls::authority_view sv, system::error_code & ec);
template<completion_handler_for<void (boost::system::error_code)> CompletionToken
= asio::default_token_t<executor_type>>
auto async_lookup(urls::authority_view av, CompletionToken && token = asio::default_token_t<executor_type>());
/// Get the maximum amount of active connections.
std::size_t limit() const;
/// Get the amount of active connections.
std::size_t active() const;
/// Get the number of connected connections available
std::size_t free() const;
/// Get an open connection that shall be returned later
connection_type borrow_connection(error_code & ec);
/// Get an open connection that shall be returned later
connection_type borrow_connection();
/// Get an open connection asynchronously that shall be returned later
template<completion_handler_for<void (system::error_code, connection_type>>
CompletionToken = default_token_type<CompletionToken>>
auto async_borrow_connection(CompletionToken && completion_token = default_token<executor_type>);
/// Get an open connection that must not be returned later
connection_type steal_connection(error_code & ec);
/// Get an open connection that must not be returned later
connection_type steal_connection();
/// Get an open connection asynchronously that must not be returned later
template<completion_handler_for<void (system::error_code, connection_type>>
CompletionToken = default_token_type<CompletionToken>>
auto async_steal_connection(CompletionToken && completion_token = default_token<executor_type>);
// Check if it's using ssl
bool uses_ssl() cons;
// Return a previously borrowed connection
void return_connection(connection conn);
// Remove a previously borrowed connection
void remove_connection(const connection &conn);
// List all the endpoints used by the pool
const std::vector<endpoint_type> & endpoints() const;
};
async_lookup
Lookup uses a resolver for the given name and stores the endpoints associated with it. The pool will internally use all endpoints evenly when creating new connections. ## cookie.hpp
cookie_jar.hpp
download.hpp
// Write all the content of a stream to a file.
template<typename Stream>
std::size_t write_to_file(Stream && str, const filesystem::path & file);
template<typename Stream>
std::size_t write_to_file(Stream && str, const filesystem::path & file, system::error_code & ec);
template<typename Stream,
asio::completion_toke_for<void (boost::system::error_code, std::size_t)> CompletionToken
asio::default_token_t<executor_type>>
auto async_write_to_file(Stream & str, const filesystem::path & file,
CompletionToken && token = asio::default_token_t<executor_type>());
/// Perform a get request and write the response body to a file
template<typename Connection>
inline auto download(Connection & conn,
/* target type of Connection */ target,
/* request type of Connection */ req,
filesystem::path download_path,
system::error_code & ec) -> download_response;
template<typename Connection>
inline auto download(Connection & conn,
/* target type of Connection */ target,
/* request type of Connection */ req,
filesystem::path download_path) -> download_response;
template<typename Connection,
asio::completion_token_for<void (boost::system::error_code, download_response)> CompletionToken>
auto async_download(Connection & conn,
/* target type of Connection */ target,
/* request type of Connection */ req,
filesystem::path download_path,
CompletionToken && token = asio::default_token_t<executor_type>())
inline auto download(urls::url_view path,
http::fields req,
filesystem::path download_path,
system::error_code & ec) -> download_response;
inline auto download(urls::url_view path,
http::fields req,
filesystem::path download_path) -> download_response
template<asio::completion_token_for<void (boost::system::error_code, download_response)> CompletionToken>
auto async_download(urls::url_view path,
http::fields req,
filesystem::path download_path,
CompletionToken && completion_token);
The target type is urls::url_view for sessions, otherwise urls::pct_string_view.
The request type is requests::http::headers for sessions, otherwise request_parameters.
## error.hpp
namespace boost::requests {
/// The type of error code used by the library
using error_code = boost::system::error_code;
/// The type of system error thrown by the library
using system_error = boost::system::system_error;
/// The type of error category used by the library
using error_category = boost::system::error_category;
error_category & http_status_category();
error_code make_error(beast::http::status stat);
/// Error codes returned from library operations
enum class error
{
/// The redirect limit was exceeded
too_many_redirects = 1,
/// The redirect is disallowed by the settings
forbidden_redirect,
/// The redirect was invalid
invalid_redirect,
/// The request violates the tls requirement
insecure,
/// The target host is invalid
wrong_host
};
error_category & request_category();
error_code
make_error_code(error e);
} // boost::requests
form.hpp
struct form
{
form(std::initializer_list<urls::param_view> params);
form(form && ) = default;
form(const form & ) = default;
form(form & rhs) : storage(rhs.storage) {}
// construct the from any container
template<typename Container>
form(Container && ct);
};
The form class is a utility class to sent application/x-www-form-urlencoded data in a request.
requests::post("https://httpbin.org/post",
requests::form{{"foo", "42"}, {"bar", "21"}});
http.hpp
namespace boost::requests::http
{
using boost::beast::http::field;
using boost::beast::http::status;
using boost::beast::http::status_class;
using boost::beast::http::to_status_class;
using boost::beast::http::to_string;
using boost::beast::http::verb;
using boost::beast::http::fields;
struct header
{
http::field field = http::field::unknown;
core::string_view key;
core::string_view value;
std::string buffer;
header() = default;
header(http::field field, core::string_view value) : field(field), value(value) {}
header(core::string_view key, core::string_view value) : key(key), value(value) {}
};
// This class enables initializer_lists for requests.
struct headers : fields
{
headers(std::initializer_list<header> fields)
{
for (const auto & init : fields)
if (init.field != http::field::unknown)
set(init.field, init.value);
else
set(init.key, init.value);
}
headers(fields && fl) : fields(std::move(fl)) {}
using fields::fields;
using fields::operator=;
};
}
The http header contains aliases for beast::http members.
json.hpp
namespace boost::requests::json
{
// read an entire body as json and convert the json value into a `json::value`.
json::value read_json(stream & str, json::storage_ptr ptr = {});
json::value read_json(stream & str, json::storage_ptr ptr, system::error_code & ec);
template<asio::completion_token_for<void (boost::system::error_code, json::value)> CompletionToken
asio::default_token_t<typename Stream::executor_type>>
auto async_read_json(
stream & str,
json::storage_ptr ptr = {},
CompletionToken && token asio::default_token_t<typename Stream::executor_type>());
// read an entire body as json and convert the json value into a `json::value`
// if the response has a body. otherwise the result is empty.
optional<json::value> read_optional_json(stream & str, json::storage_ptr ptr = {});
optional<json::value> read_optional_json(stream & str, json::storage_ptr ptr, system::error_code & ec);
template<asio::completion_token_for<void (boost::system::error_code, optional<json::value>)> CompletionToken
asio::default_token_t<typename Stream::executor_type>>
auto async_read_optional_json(
stream & str,
json::storage_ptr ptr = {},
CompletionToken && token = asio::default_token_t<typename Stream::executor_type>());
/// the response of a json request
struct response : response_base
{
using allocator_type = std::allocator<char>;
using fields_type = http::fields;
response(allocator_type alloc, history_type history, json::value && value);
response(http::response_header header, history_type history, json::value && value);
response(allocator_type alloc , json::value && value = {});
response(http::response_header header, json::value && value = {});
using value_type = json::value;
value_type value;
};
// http-methods are , they follow the pattern below:
template<typename RequestBody, typename Connection>
auto ~method~(Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body, // omitted for some methods.
/* request type of Connection */ req = {},
json::storage_ptr ptr = {}) -> response;
template<typename RequestBody, typename Connection>
auto ~method~(Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body, // omitted for some methods.
/* request type of Connection */ req,
json::storage_ptr ptr,
system::error_code & ec) -> response;
template<typename Connection, typename RequestBody,
asio::completion_token_for<void (boost::system::error_code, response)> CompletionToken
= asio::default_token_t<typename Connection::executor_type>>
auto async_~method~(Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body,
/* request type of Connection */ req = {},
json::storage_ptr ptr = {},
CompletionToken && token = asio::default_token_t<typename Connection::executor_type>());
// requests on the default_session
template<typename RequestBody>
auto ~method~(urls::url_view target,
RequestBody && request_body, // omitted for some methods.
http::fields req,
json::storage_ptr ptr = {}) -> response;
template<typename RequestBody>
auto ~method~(urls::url_view target,
RequestBody && request_body, // omitted for some methods.
http::fields req,
json::storage_ptr ptr,
system::error_code & ec) -> response;
template<typename RequestBody,
asio::completion_token_for<void (boost::system::error_code, response)> CompletionToken>
auto async_~method~(
urls::url_view target,
RequestBody && request_body,
http::fields req,
json::storage_ptr ptr = {},
CompletionToken && token);
}
The json header contains methods to send and receive json messages.
Below is a table of all available methods.
Methods with an optional request body are overloaded.
| Http Method | Name | Async-Name | Response body | Request Body | Remarks |
|---|---|---|---|---|---|
GET |
|
|
always |
never |
|
POST |
|
|
always |
always |
|
PUT |
|
|
optional |
always |
|
PATCH |
|
|
optional |
always |
|
DELETE |
|
|
optional |
optional |
|
OPTIONS |
|
|
optional |
never |
|
Note
|
The above functions are function objects, not functions. |
The target type is urls::url_view for sessions, otherwise urls::pct_string_view.
The request type is requests::http::headers for sessions, otherwise request_parameters.
## method.hpp
namespace boost::requests
{
// methods - those with optional request bodies are overloaded
template<typename Connection, typename RequestBody>
auto ~method~(
Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body, // omitted if not required
/* request type of Connection */ req = {}) -> response;
template<typename Connection, typename RequestBody>
auto ~method~(
Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body, // omitted if not required
/* request type of Connection */ req,
system::error_code & ec) -> response;
template<typename Connection,
typename RequestBody,
asio::completion_token_for<void (boost::system::error_code, response)> CompletionToken
asio::default_token_t<executor_type>>
auto
async_~method~(
Connection & conn,
/* target type of Connection */ target,
RequestBody && request_body,
/* request type of Connection */ req = {},
CompletionToken && completion_token asio::default_token_t<executor_type>());
template<typename RequestBody>
auto ~method~(
urls::url_view target,
RequestBody && request_body,
http::fields req = {}) -> response;
template<typename RequestBody>
auto ~method~(
urls::url_view target,
RequestBody && request_body,
http::fields req,
system::error_code & ec) -> response;
template<typename RequestBody,
asio::completion_token_for<void (boost::system::error_code, response)> CompletionToken>
auto async_~method~(
urls::url_view target,
RequestBody && request_body,
http::fields req,
CompletionToken && completion_token)
}
The method header contains methods to send and receive method messages.
Below is a table of all available methods.
Methods with an optional request body are overloaded.
| Http Method | Name | Async-Name | Response body [1] | Request Body | Remarks |
|---|---|---|---|---|---|
GET |
|
|
always |
never |
|
HEAD |
|
|
never |
never |
|
POST |
|
|
always |
always |
|
PUT |
|
|
optional |
always |
|
PATCH |
|
|
optional |
always |
|
DELETE |
|
|
optional |
optional |
|
OPTIONS |
|
|
optional |
never |
|
TRACE |
|
|
never |
never |
|
CONNECT |
|
|
never |
always |
Can only be used on a |
|
Note
|
The above functions are function objects, not functions. |
The target type is urls::url_view for sessions, otherwise urls::pct_string_view.
The request type is requests::http::headers for sessions, otherwise request_parameters.
mime_types.hpp
using mime_type_map =
unordered_map<core::string_view,
core::string_view,
boost::urls::grammar::ci_hash,
boost::urls::grammar::ci_equal>;
const mime_type_map & default_mime_type_map();
The default mime types is a map of file suffixes to the most likely mime type as show below.
| file ending | Description | Mime type |
|---|---|---|
".3g2" |
3GPP2 audio/video container |
"video/3gpp2" |
".7z" |
7-zip archive |
"application/x-7z-compressed" |
".aac" |
AAC audio |
"audio/aac" |
".abw" |
AbiWord document |
"application-x-abiword" |
".arc" |
Archive document (multiple files embedded) |
"application-x-freearc" |
".avif" |
AVIF image |
"image/avif" |
".avi" |
AVI: Audio Video Interleave |
"videox-msvideo" |
".azw" |
Amazon Kindle eBook format |
"application/vnd.amazon.ebook" |
".bin" |
Any kind of binary data |
"application/octet-stream" |
".bmp" |
Windows OS/2 Bitmap Graphics |
"image/bmp" |
".bz" |
BZip archive |
"application/x-bzip" |
".bz2" |
BZip2 archive |
"application/x-bzip2" |
".cda" |
CD audio |
"application/x-cdf" |
".csh" |
C-Shell script |
"application/x-csh" |
".css" |
Cascading Style Sheets (CSS) |
"text/css" |
".csv" |
Comma-separated values (CSV) |
"text/csv" |
".doc" |
Microsoft Word |
"application/msword" |
".docx" |
Microsoft Word (OpenXML) |
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
".eot" |
MS Embedded OpenType fonts |
"application/vnd.ms-fontobject" |
".epub" |
Electronic publication (EPUB) |
"application/epub+zip" |
".gz" |
GZip Compressed Archive |
"application/gzip" |
".gif" |
Graphics Interchange Format (GIF) |
"image/gif" |
".htm" |
.html HyperText Markup Language (HTML) |
"text/html" |
".html" |
.html HyperText Markup Language (HTML) |
"text/html" |
".ico" |
Icon format |
"image/vnd" |
".ics" |
iCalendar format |
"text/calendar" |
".jar" |
Java Archive (JAR) |
"application/java-archive" |
".jpeg" |
.jpg JPEG images |
"image/jpeg" |
".js" |
JavaScript |
"text/javascript" |
".json" |
JSON format |
"application/json" |
".jsonld" |
JSON-LD format |
"application/ld+json" |
".mid" |
.midi Musical Instrument Digital Interface |
"audio/x-midi" |
".mjs" |
JavaScript module |
"text/javascript" |
".mp3" |
MP3 audio |
"audio/mpeg" |
".mp4" |
MP4 video |
"video/mp4" |
".mpeg" |
MPEG Video |
"video/mpeg" |
".mpkg" |
Apple Installer Package |
"application/vnd.apple.installer+xml" |
".odp" |
OpenDocument presentation document |
"application/vnd.oasis.opendocument.presentation" |
".ods" |
OpenDocument spreadsheet document |
"application/vnd.oasis.opendocument.spreadsheet" |
".odt" |
OpenDocument text document |
"application/vnd.oasis.opendocument.text" |
".oga" |
OGG audio |
"audio/ogg" |
".ogv" |
OGG video |
"video/ogg" |
".ogx" |
OGG |
"application/ogg" |
".opus" |
Opus audio |
"audio/opus" |
".otf" |
OpenType font |
"font/otf" |
".png" |
Portable Network Graphics |
"image/png" |
".pdf" |
Adobe Portable Document Format (PDF) |
"application/pdf" |
".php" |
Hypertext Preprocessor (Personal Home Page) |
"httpd-php" |
".ppt" |
Microsoft PowerPoint application/vnd |
"ms-powerpoint" |
".pptx" |
Microsoft PowerPoint (OpenXML) |
"application/vnd.openxmlformats-officedocument.presentationml.presentation" |
".rar" |
RAR archive |
"application/vnd.rar" |
".rtf" |
Rich Text Format (RTF) |
"application/rtf" |
".sh" |
Bourne shell script |
"application/x-sh" |
".svg" |
Scalable Vector Graphics (SVG) |
"image/svg+xml" |
".tar" |
Tape Archive (TAR) |
"application/x-tar" |
".tif" |
.tiff Tagged Image File Format (TIFF) |
"image/tiff" |
".tiff" |
.tiff Tagged Image File Format (TIFF) |
"image/tiff" |
".ts" |
MPEG transport stream |
"video/mp2t" |
".ttf" |
TrueType Font |
"font/ttf" |
".txt" |
Text, (generally ASCII or ISO 8859-n) |
"text/plain" |
".vsd" |
Microsoft Visio |
"application/vnd.visio" |
".wav" |
Waveform Audio Format |
"audio/wav" |
".weba" |
WEBM audio |
"audio/webm" |
".webm" |
WEBM video |
"video/webm" |
".webp" |
WEBP image |
"image/webp" |
".woff" |
Web Open Font Format (WOFF)" |
font/woff" |
".woff2" |
Web Open Font Format (WOFF)" |
font/woff2" |
".xhtml" |
XHTML |
"application/xhtml+xml" |
".xls" |
Microsoft Excel application/vnd |
"ms-excel" |
".xlsx" |
Microsoft Excel (OpenXML) |
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
".xml" |
"application/xml" |
public_suffix.hpp
namespace boost::request
{
// a public suffix list used for redirect restrictions.
struct public_suffix_list
{
unordered_set<core::string_view> full_matches;
unordered_set<core::string_view> whitelist;
unordered_set<core::string_view> wildcards;
};
// the public suffix list generated from https://publicsuffix.org/list/public_suffix_list.dat,
const public_suffix_list & default_public_suffix_list();
// lot a public suffix list
public_suffix_list load_public_suffix_list(core::string_view map);
/// check if the suffix is public according to the list passed in parameter 2
bool is_public_suffix(core::string_view value,
const public_suffix_list & pse = default_public_suffix_list());
}
redirect.hpp
namespace boost::request
{
enum redirect_mode
{
/// Follow no redirect at all.
none,
/// Follow redirect on the same endpoint, i.e. different target
endpoint,
/// Follow redirects on the same domain, e.g. http -> https
domain,
/// Follow redirects to subdomains, e.g. boost.org -> www.boost.org but not vice versa
subdomain,
/// Follow redirects withing a non-public suffix, e.g.
/// www.boost.org -> boost.org or api.boost.org, but not get-hacked.org.
private_domain,
/// Follow any redirect
any
};
bool should_redirect(
redirect_mode mode,
urls::url_view current,
urls::url_view target,
const public_suffix_list & pse = default_public_suffix_list());
/// Get the port from a url-view
std::uint16_t get_port(urls::url_view domain);
/// Check if the endpoint is the same as the endpoint
bool same_endpoint_on_host(const urls::url_view current, const asio::ip::tcp::endpoint);
/// Check if the endpoint is the same as the endpoint
bool same_endpoint_on_host(const urls::url_view current, const asio::local::stream_protocol::endpoint);
/// Check if a status is a redirect
bool is_redirect(http::status rc);
}
request_options.hpp
namespace boost::requests
{
/// The basic options attached to any request
struct request_options
{
/// Only allow SSL requests
bool enforce_tls{true};
/// The allowed redirect mode.
redirect_mode redirect{private_domain};
/// The maximum of allowed redirects.
std::size_t max_redirects{12};
};
/// The default options used by sessions.
request_options & default_options();
}
request_parameters.hpp
namespace boost::requests
{
/// A pair describing a header entry
struct field_entry
{
variant2::variant<http::field, core::string_view> key;
core::string_view value;
std::string buffer;
};
// helper to add basic authorization
field_entry basic_auth(core::string_view username,
core::string_view password);
// helper to add bearer authorization
field_entry bearer(core::string_view token);
// helper to create headers from an initializer list.
auto headers(std::initializer_list<field_entry> fields);
// The full request settings used in the connection.
struct request_parameters
{
using fields_type = beast::http::fields;
fields_type fields;
request_options opts{};
cookie_jar * jar = nullptr;
};
}
request.hpp
namespace boost::request
{
// Open a stream after following redirects
template<typename Connection, typename RequestBody>
auto request_stream(
Connection & conn,
http::verb method,
/* target type of Connection */ path, // pct_string_view when connection
RequestBody && body,
/* request type of Connection */ req, // headers for conn,
system::error_code & ec) -> std::pair<stream, history>;
template<typename Connection, typename RequestBody>
auto request_stream(
Connection & conn,
http::verb method,
/* target type of Connection */ path, // pct_string_view when connection
RequestBody && body,
/* request type of Connection */ req /* headers for conn*/ ) -> std::pair<stream, history>;
template<typename RequestBody,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, stream, history)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
void (boost::system::error_code, stream, history))
void (boost::system::error_code, stream, history))
async_request_stream(
http::verb method,
core::string_view path,
RequestBody && body,
http::fields req,
CompletionToken && completion_token);
template<typename Connection,
typename RequestBody,
BOOST_ASIO_COMPLETION_TOKEN_FOR( void (system::error_code, stream, history)) CompletionToken
= typename Connection::default_token>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void (system::error_code, stream, history))
async_request_stream(
Connection & conn,
http::verb method,
/* target type of Connection */ path,
RequestBody && body,
/* request type of Connection */ req,
CompletionToken && completion_token = typename Connection::default_token());
// Execute a request by using `request_stream` and read the body as raw memory.
template<typename Connection, typename RequestBody>
auto request(Connection & conn,
http::verb method,
urls::url_view path,
RequestBody && body,
/* request type of Connection */ req,
system::error_code & ec) -> response;
template<typename Connection, typename RequestBody>
auto request(Connection & conn,
http::verb method,
urls::url_view path,
RequestBody && body,
/* request type of Connection */ req) -> response;
template<typename RequestBody>
auto request(http::verb method,
urls::url_view path,
RequestBody && body,
http::fields req,
system::error_code & ec) -> response;
template<typename RequestBody>
auto request(http::verb method,
urls::url_view path,
RequestBody && body,
http::fields req) -> response;
template<typename Connection,
typename RequestBody,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (error_code, response)) CompletionToken
= typename Connection::default_token>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void (error_code, response))
async_request(Connection & conn,
http::verb method,
/* target type of Connection */ target,
RequestBody && body,
/* request type of Connection */ req,
CompletionToken && completion_token = typename Connection::default_token());
template<typename RequestBody,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (error_code, response)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void (error_code, response))
async_request(http::verb method,
urls::url_view target,
RequestBody && body,
http::headers req,
CompletionToken && completion_token);
}
The target type is urls::url_view for sessions, otherwise urls::pct_string_view.
The request type is requests::http::headers for sessions, otherwise request_parameters.
## response.hpp
namespace boost::requests
{
struct response_base
{
using allocator_type = std::allocator<char>;
using buffer_type = beast::basic_flat_buffer<allocator_type>;
using body_type = beast::http::basic_dynamic_body<buffer_type>;
http::response_header headers;
int result_code() const {return headers.result_int(); }
http::status result() const {return headers.result(); }
using string_body_type = typename beast::http::basic_string_body<char, std::char_traits<char>, allocator_type>;
using allocator_type = std::allocator<char>;
using history_type = std::vector<typename http::response<body_type>, vector_alloc>;
// The history contains all the redirect messages.
history_type history;
response_base(allocator_type alloc, history_type history);
response_base(http::response_header header, history_type history);
response_base(allocator_type alloc );
response_base(http::response_header header);
~response_base() = default;
response_base(const response_base & ) = default;
response_base(response_base && ) noexcept = default;
response_base& operator=(const response_base & ) = default;
response_base& operator=(response_base && ) noexcept = default;
// Return false if the status is not 2xx
bool ok () const;
// Return false if the status is not 2xx
explicit operator bool() const { return ok(); }
bool is_redirect() const;
bool is_permanent_redirect() const;
// Return an error if the status is not 2xx
system::error_code status_as_error() const;
// Throw if the status is not 2xx
void throw_status_if_error() const;
// Collect all the entires of the link header(s)
system::result<std::vector<struct link>> link() const;
};
// The response with the body as buffer.
struct response : response_base
{
// the full response content
buffer_type buffer;
response(allocator_type alloc = {});
response(http::response_header header, buffer_type buffer);
response(response_base header, buffer_type buffer);
response(http::response_header header, history_type history, buffer_type buffer);
response(const response & ) = default;
response(response && ) noexcept = default;
response& operator=(const response & ) = default;
response& operator=(response && ) noexcept = default;
template<typename Char = char,
typename CharTraits = std::char_traits<char>>
auto string_view() const -> basic_string_view<Char, CharTraits>;
template<typename Char = char,
typename CharTraits = std::char_traits<char>,
typename Allocator_>
auto string(Allocator_ && alloc) const -> std::basic_string<Char, CharTraits, std::decay_t<Allocator_>>;
template<typename Char = char,
typename CharTraits = std::char_traits<char>>
auto string() const -> std::basic_string<Char, CharTraits, allocator_type>;
template<typename Byte = unsigned char>
auto raw() const -> span<Byte>;
};
}
service.hpp
namespace boost::requests
{
struct session_service : asio::execution_context::service
{
using executor_type = asio::any_io_executor;
using session_type = session;
session_service(asio::execution_context & ctx);
~session_service();
void shutdown() override;
void destroy();
};
// get the session of the execution_context of the passed executor.
auto default_session(asio::any_io_executor exec = asio::system_executor()) -> session &;
}
session.hpp
namespace boost::requests
{
struct session
{
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef session<Executor1> other;
};
/// Constructor.
explicit session(const executor_type &ex);
/// Construct a session from a context.
template<typename ExecutionContext>
explicit session(ExecutionContext &context);
/// Rebinding construcotr.
template<typename Executor2>
explicit session(session<Executor2> && sess);
/// Get the executor associated with the object.
executor_type get_executor() BOOST_ASIO_NOEXCEPT;
struct request_options & options() {return options_;}
const struct request_options & options() const {return options_;}
// A variant of pools, depending on the url
using pool_ptr = variant2::variant<std::shared_ptr<http_connection_pool<Executor>>,
std::shared_ptr<https_connection_pool<Executor>>>;
// Get a pool for a given url.
pool_ptr get_pool(urls::url_view url, error_code & ec);
pool_ptr get_pool(urls::url_view url);
template<asio::token_for<void (boost::system::error_code, pool_ptr)> CompletionToken
= asio::default_token_t<executor_type>>
auto async_get_pool(urls::url_view path,
CompletionToken && token = asio::default_token_t<executor_type>());
void shutdown();
using stream = stream<Executor>;
};
}
source.hpp
struct source
{
virtual ~source() = default;
virtual optional<std::size_t> size() const = 0;
virtual void reset() = 0;
virtual std::pair<std::size_t, bool> read_some(void * data, std::size_t size, system::error_code & ) = 0;
virtual core::string_view default_content_type() {return "";}
};
The source class is used to write request bodies.
The source can be implemented to add more types by adding a tag_invoke function.
Below is an exemplary implementation.
template<>
struct meme_source
{
my_type data;
my_type::buffer buffer{data.make_buffer();}
meme_source(const my_type &data) : data(data) {}
core::string_view default_content_type()
{
return "text/my-meme-type";
}
// used to write again, useful for redirects
void reset() { buffer = data.make_buffer(); }
optional<std::size_t> size() const override {return buffer.size();};
std::pair<std::size_t, bool> read_some(void * data, std::size_t size, system::error_code & ec) override
{
if (buffer.done())
return {0u, false};
else
return {buffer.read_some(data, size, ec), true};
}
};
auto tag_invoke(const make_source_tag&, const my_type & data)
{
return meme_source(data);
}
The following tag_invoke`s are provided out of the box
(the `json ones requires you to include boost/requests/json.hpp and
form ones requires you to include boost/requests/form.hpp ).
|
Default Mime-Type |
|
|
"text/plain" |
|
|
"text/plain; charset=utf-8" |
|
|
"text/plain" |
|
|
"application/octet-stream" |
|
|
"application/octet-stream" |
|
|
"application/x-www-form-urlencoded" |
|
|
"application/x-www-form-urlencoded" |
|
|
Taken from [default_mime_type_map] or "text/plain" |
|
|
Taken from [default_mime_type_map] or "text/plain" |
|
|
"application/json" |
|
|
"application/json" |
|
|
"application/json" |
|
stream.hpp
namespace boost::requests
{
struct stream
{
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Get the executor
executor_type get_executor() noexcept;
/// Check if the underlying connection is open.
bool is_open() const;
/// Read some data from the request body.
template<typename MutableBuffer>
std::size_t read_some(const MutableBuffer & buffer);
/// Read some data from the request body.
template<typename MutableBuffer>
std::size_t read_some(const MutableBuffer & buffer, system::error_code & ec);
/// Read some data from the request body.
template<
typename MutableBufferSequence,
asio::completion_token_for<void (system::error_code, std::size_t)> CompletionToken
= asio::default_completion_token_t<executor_type>>
auto async_read_some(
const MutableBufferSequence & buffers,
CompletionToken && token = asio::default_completion_token_t<executor_type>());
/// Read all the data from the request body.
template<typename DynamicBuffer>
std::size_t read(DynamicBuffer & buffer);
template<typename DynamicBuffer>
std::size_t read(DynamicBuffer & buffer, system::error_code & ec);
template<
typename DynamicBuffer,
asio::completion_token_for<void (system::error_code, std::size_t)> CompletionToken
= asio::default_completion_token_t<executor_type>>
auto async_read(
DynamicBuffer & buffers,
CompletionToken && token asio::default_completion_token_t<executor_type>());
/// dump the rest of the data.
void dump();
void dump(system::error_code & ec);
template<asio::completion_token_for<void (boost::system::error_code)>
CompletionToken = asio::default_completion_token_t<executor_type>>
auto async_dump(CompletionToken && token asio::default_completion_token_t<executor_type>());
stream(stream && lhs) = default;
stream& operator=(stream && lhs) = default;
stream (const stream &) = delete;
stream& operator=(const stream &) = delete;
~stream();
using history_type = response_base::history_type;
bool done() const;
const http::response_header &headers() const &;
const history_type &history() const & { return history_; }
// get history & headers for a lvalue
http::response_header &&headers() &&;
history_type &&history() &&;
void prepend_history(history_type && pre_history);
};
using stream = stream<>;
}
The stream is used is to read the content of a response. On destruction the remaining data gets dumped.
Appendix A: Copyright, License, and Acknowledgments
This documentation is
-
Copyright 2023 Klemens Morgenstern
and is distributed under the Boost Software License, Version 1.0.