restinio

Cross-platform, efficient, customizable, and robust asynchronous HTTP(S)/WebSocket server C++ library with the right balance between performance and ease of use

OTHER License

Stars
1.2K

Bot releases are hidden (Show)

restinio - Latest Release

Published by eao197 9 months ago

It's a maintenance release. If fixes several issues related to RESTinio's dependencies:

  • #207,
  • #208,
  • and #209 (thanks to @yurkoy).

NOTE! If you have no problem with RESTinio-0.7.1 there is no need to update to v.0.7.2. An update may be necessary if you manage RESTinio's dependencies by yorself.

restinio -

Published by eao197 10 months ago

It's a maintenance release.

It fixes #198, #199, #200, #201, #203, #204.

restinio -

Published by eao197 11 months ago

This is the first significant release since v.0.6.13 and there are several breaking changes.

  • Switch to C++17. Since v.0.7.0 RESTinio requires C++17 as the minimal C++ standard.
  • Switch to nodejs/llhttp library for parsing HTTP requests. Previous versions of RESTinio used nodejs/http-parser, but it is now deprecated and no longer maintained. Since v.0.7.0 RESTinio uses nodejs/llhttp.
  • No more external projects for optional, variant and string_view. After switching to C++17 RESTinio uses std::optional, std::variant and std::string_view. Note that for the expected class RESTinio still needs the expected-lite project as a dependency.
  • Switch to Catch2 v3. The Catch2 library is used in RESTinio for testing. The first versions of Catch2 were header-only, but since v3 the Catch2 needs to be compiled as a library. Since v.0.7.0 RESTinio uses Catch2 v3 and can’t be used with previous versions of Catch2 library.
  • The Clara library is no longer used in RESTinio samples/tests/benchmarks. Parsing of command line arguments in some samples/tests/benchmarks becomes more simple and arguments with long names can’t be shortened now. It means that if --address is required then it can’t be specified as --addr.
  • The RapidJSON/json_dto libraries are no longer used in RESTinio samples/tests/benchmarks.
  • CMake is now the only build system supported. The previous versions of RESTinio used CMake and our own Mxx_ru build systems. Since v.0.7.0 only CMake is used. But Mxx_ru is still in use for managing dependencies.
  • RESTinio's CMake scripts have been refactored significantly. Most of the old CMake variables/options used for the configuration (like RESTINIO_FIND_DEPS) have been removed. There are several new variables/options that have to be used since v0.7.0: RESTINIO_ASIO_SOURCE, RESTINIO_DEP_STANDALONE_ASIO, RESTINIO_DEP_BOOST_ASIO, RESTINIO_DEP_LLHTTP, RESTINIO_DEP_FMT, RESTINIO_DEP_EXPECTED_LITE and so on. Please see the corresponding section in the documentation for more details.
  • Several classes/methods/functions marked as deprecated in previous versions are now removed.
  • The core restinio/all.hpp header file has been deprecated. It will be removed in v.0.8.0. The new core restinio/core.hpp header file must be used instead.
  • The format and behavior of restinio::on_pool_runner_t::stop changed. Now it may accept on_error-callback. The default on_error-callback calls std::abort if an exception is thrown in http_server_t::close_async.
  • Added support of chains of asynchronous handlers. Please see the corresponding section in the documentation for more details.
  • Added a basic support for chunk extensions in incoming requests.
restinio -

Published by eao197 about 1 year ago

This is a maintenance release.

Asio updated to 1-28-1.
fmtlib updated to 10.1.0.

Adaptation for SObjectizer-5.8.0.

Fix for compilation error with GCC-13. Thanks to @bandali0 for PR #183

Fix for #184

restinio -

Published by eao197 over 1 year ago

This is a bug-fix release.

Thanks to @horu for PR (#179) with the fix.

restinio -

Published by eao197 about 2 years ago

Since v.0.6.17 RESTinio can be used with fmtlib in FMT_ENFORCE_COMPILE_STRING mode. In this mode FMT_STRING macro has to be used for format string in C++11/14/17 for compile-time checking of format string validity.

Now RESTinio checks the presence of FMT_ENFORCE_COMPILE_STRING and uses FMT_STRING when it's required.

NOTE. FMT_ENFORCE_COMPILE_STRING has to be defined before inclusion of any of RESTinio's headers.

fmtlib-9.1.0 in now used inside RESTinio (and included in restinio-0.6.17-full.* archives).

restinio -

Published by eao197 over 2 years ago

This release adapts RESTinio to fmtlib-9.0.0.

Since v.0.6.16 RESTinio can be used with fmtlib-8 or fmtlib-9, but fmtlib-8 is still used in RESTinio development.

NOTE: restinio-0.6.14-full.* archives contain asio-1-21-1, fmt-8.1.1 and catch-2.13.9. Versions of 3rd party libraries in restinio/third_party updated to the latest versions:

expected-lite at commit 34524d46e538f1e6ed114d8f8409f7cd173d96e6.
optional-lite at commit ea502a6472c85dbc0174764df218a0c3443c6772.
string-view-lite at commit f7aca36f5caa05e451f6887aa707df89197e6de6.
variant-lite at commit f1af3518e4c28f12b09839b9d2ee37984cbf137a.

restinio -

Published by eao197 over 2 years ago

This is a maintenance release.

A fix for CMake script for case when RESTINIO_FIND_DEPS=ON and RESTINIO_FMT_HEADER_ONLY=OFF (#159).

Usage of std::aligned_storage_t in implementation of writable_item_t has been removed (it's deprecated in C++23).

In some places std::launder is used (if available) to avoid UB accessing a pointer after placement new.

NOTE: restinio-0.6.14-full.* archives contain asio-1-21-1, fmt-8.1.1 and catch-2.13.9. Versions of 3rd party libraries in restinio/third_party weren't upgraded.

restinio -

Published by eao197 almost 3 years ago

This is just a maintenance release.

NOTE: restinio-0.6.14-full.* archives contain asio-1-21-1 and fmt-8.0.1. Versions of other dependencies are not changed.

restinio -

Published by eao197 almost 4 years ago

This version introduces a couple of new big features and contains several changes some of that can affect existing code.


A new value not_handled added to request_handling_status_t enumeration (+ new helper function request_not_handled()). This value should be returned if a request-handler doesn't accept nor reject the current request and some other request-handler should be tried (if such a handler exists). If all request-handlers called for request processing return not_handled then RESTinio treats that value as rejected.


It's possible now to incorporate some additional (extra) data into a request-object. To do so a user has to perform the following steps:

Define a type for holding such an extra data:

struct per_request_data {
  user_indentity user_info_;
  ...
};

Define a extra-data-factory that should look like:

struct my_extra_data_factory {
  using data_t = per_request_data;
  void make_within(restinio::extra_data_buffer_t<data_t> buf) {
    new(buf.get()) data_t{};
  }
};

Or, if extra-data-factory is a simple and stateless object as shown above:

using my_extra_data_factory = restinio::simple_extra_data_factory_t<per_request_data>;

Specify my_extra_data_factory in server's traits:

struct my_traits : public restinio::default_traits_t {
  using extra_data_factory_t = my_extra_data_factory;
};

Change the format of request-handlers this way:

restinio::request_handling_status_t request_handler(
  const restinio::generic_request_handle_t<per_request_data> & req);

// or

restinio::request_handling_status_t request_handler(
  const restinio::generic_request_handle_t<my_extra_data_factory::data_t> & req);

Extra-data is available inside a request-handler via new method request_t::extra_data:

restinio::request_handling_status_t request_handler(
  const restinio::generic_request_handle_t<per_request_data> & req)
{
  auto & ed = req->extra_data();
  ...
}

See the documentation for more details.


It's possible now to bind several synchronous request-handlers into a chain (somewhat similar to ExpressJS's middleware):

#include <restinio/all.hpp>
#include <restinio/sync_chain/fixed_size.hpp>

auto incoming_req_logger(const restinio::request_handle_t & req)
{
  ... // Perform logging.
  // Allow the passing of the request to the next handler.
  return restinio::request_not_handled();  
}

auto mandatory_fields_checker(const restinio::request_handle_t & req)
{
  ... // Perform all necessary checks.
  if(!ok) {
    // Negative response has to be sent.
    return req->create_response(restinio::status_bad_request())
      ...
      .done();
  }
  // Allow the passing of the request to the next handler.
  return restinio::request_not_handled();  
}

auto permissions_checker(const restinio::request_handle_t & req)
{
  ... // Check user credentials and permissions.
  if(!ok) {
    // Negative response has to be sent.
    return req->create_response(restinio::status_unauthorized())
      ...
      .done();
  }
  // Allow the passing of the request to the next handler.
  return restinio::request_not_handled();
}

auto actual_processor(const restinio::request_handle_t & req)
{
  ... // Do actual request processing.
  return restinio::request_accepted();
}

struct my_traits : public restinio::default_traits_t {
  // Change the type of request handler.
  using request_handler_t = restinio::sync_chain::fixed_size_chain_t<4>;
};

restinio::run(restinio::on_this_thread<my_traits>()
  .port(...)
  .address(...)
  .request_handler(
    // Enumerate all handlers in the chain in the order of invocation.
    incoming_req_logger,
    mandatory_fields_checker,
    permissions_checker,
    actual_processor)
  ...
);

When a new incoming request will be parsed the RESTinio will call incoming_req_logger, then mandatory_req_logger, then (if necessary) permissions_checker, and only then (if necessary) actual_processor.

See the documentation for more details.

restinio -

Published by eao197 almost 4 years ago

A new method incoming_http_msg_limits added to restinio::server_settings_t. This method allows to set up limits for the maximum length of various parts of an incoming HTTP message (like URL, HTTP-field’s name and value):

struct my_traits : public restinio::default_traits_t { ... };

restinio::server_settings_t<my_traits> settings;
settings.incoming_http_msg_limits(
   restinio::incoming_http_msg_limits_t{}
      .max_url_size(8000u)
      .max_field_name_size(2048u)
      .max_field_value_size(4096u)
);
...
auto server = restinio::run_async(
   restinio::own_io_context(),
   std::move(settings),
   std::thread::hardware_concurrency());

A possibility to limit the number of parallel connection has been added:

struct my_traits : public restinio::default_traits_t {
   // Force the usage of connection count limiter.
   static constexpr bool use_connection_count_limiter = true;
};

restinio::server_settings_t<my_traits> settings;
settings.max_parallel_connections(1000u);
...
auto server = restinio::run_async(
   restinio::own_io_context(),
   std::move(settings),
   std::thread::hardware_concurrency());

A support for SObjectizer 5.6/5.7 has been added. Now RESTinio can be user either with SObjectizer 5.5 and SObjectizer 5.6/5.7. The version of SObjectizer is detected automatically. But if a user wants to use SObjectizer 5.6/5.7 he/she should set C++ standard to C++17 manually.

restinio -

Published by eao197 almost 4 years ago

Conversion functions passed to restinio::easy_parser::convert can now return expected_t<T, error_reason_t> as well as just T. Returning expected_t<T, error_reason_t> allows to report conversion errors without throwing an exception. This is a fix for #99.

A new overload for restinio::server_settings_t::address() method. The new overload accepts an instance of asio::ip::address (or boost::asio::ip::address). This is a fix for #100.

A new optional post-bind hook added. This hook is called just after a succesful return from bind() for server’s acceptor. A reference to asio::ip::tcp::acceptor is passed to that hook. This new hook can be used for application-specific tuning of bound acceptor or to gathering some information about the acceptor. This is a fix for #126. For example, this code snippet shows how RESTinio server can be started on a random port assigned by the Operating System:

std::promise<unsigned short> port_promise; // For getting the port.
auto server = restinio::run_async(
      restinio::use_own_context(),
      restinio::server_settings_t{}
         .address("localhost")
         .port(0u) // Zero means that port will be assigned by the OS.
         .acceptor_post_bind_hook(
            [&port_promise](asio::ip::tcp::acceptor & acceptor) {
               // Gathering the actual port number.
               port_promise.set_value(acceptor.local_endpoint().port());
            })
         .request_handler(...),
      4u);
// Now we can safely get the actual port number from the promise.
const auto actual_port = port_promise.get_future().get();
restinio -

Published by eao197 about 4 years ago

A TLS-context object can be passed to server_settings_t as a shared pointer. This makes it possible to use one TLS-context by several instances of RESTinio server, or TLS-context can be shared between a RESTinio server and other parts of an application.

New example shared_tls_context added.

restinio -

Published by eao197 about 4 years ago

Now RESTinio works with Asio 1.17. Version 0.6.9 can be used with Asio 1.12, 1.14, 1.16, and 1.17.

Support for incoming requests with chunked encoding has been added. Previous versions of RESTinio didn’t support such requests, HTTP 501 error was returned. Since v.0.6.9 RESTinio accepts such requests and glues all chunks together into the one body. Information about an individual chunk is preserved and is available via request_t::chunked_input_info.

Since v.0.6.9 the value OFF for CMake-option RESTINIO_ALLOW_SOBJECTIZER is handled differently: all tests/examples/benchmarks those require SObjectizer as a dependency won't be compiled. All other tests/examples will be compiled as usual. There is also a new CMake-option RESTINIO_USE_EXTERNAL_SOBJECTIZER.

New methods for http_header_fields_t class: remove_all_of and add_field.

New helpers for parsing the following HTTP-fields: Connection, Host, Transfer-Encoding.

New tools for easy_parser and HTTP-field parsers: expected_token_p, expected_caseless_token_p, symbol_from_range_p, caseless_exact, caseless_exact_p.

There are also some thoughts about the future development of RESTinio.

restinio -

Published by eao197 over 4 years ago

This is a bug-fix release.

Issue #105 fixed.

Several warnings detected by GCC compilers are fixed.

restinio -

Published by eao197 over 4 years ago

Implementation of extraction of Bearer authentification parameters fixed. Now it looks like:

#include <restinio/all.hpp>
#include <restinio/http_field_parser/bearer_auth.hpp>
...
auto on_request(const restinio::request_handle_t & req) {
   using namespace restinio::http_field_parsers::bearer_auth;
   const auto auth_params = try_extract_params(*req,
         restinio::http_field::authorization);
   if(auth_params) { // Parameters successfully extracted.
      if(is_valid_user(auth_params->token)) {
         ...
      }
   }
   ...
}

New helper function try_parse_field for simplification of HTTP-fields parsing added:

#include <restinio/all.hpp>
#include <restinio/helpers/http_fields_parsers/try_parse_field.hpp>
#include <restinio/helpers/http_fields_parsers/accept.hpp>
...
auto on_request(const restinio::request_handle_t & req) {
   using namespace restinio::http_field_parsers;
   // Try to get and parse the value of `Accept` header.
   const auto parse_result = try_parse_field<accept_value_t>(
         req, restinio::http_field::accept);
   if(const auto * value =
         restinio::get_if<accept_value_t>(&parse_result)) {
      // Value of the field is successfully parsed.
      ... // Some usage of parsed value.
   }
}

Several new overloads for try_extract_params functions from restinio::http_field_parsers::basic_auth and restinio::http_field_parsers::bearer_auth namespaces. They allow to work with several authentication schemes after the parsing of Authorization (Proxy-Authorization) field:

auto on_request(const restinio::request_handle_t & req) {
   using namespace restinio::http_field_parsers;

   const auto field = try_parse_field<authorization_value_t>(
         req, restinio::http_field::authorization);
   if(const auto * auth = restinio::get_if<authorization_value_t>(field)) {
      // We have valid Authorization field value.
      if("basic" == auth->auth_scheme) {
         // Basic authentification scheme should be used.
         using namespace restinio::http_field_parsers::basic_auth;
         const auto params = try_extract_params(auth->auth_params);
         if(params) { // Parameters successfully extracted.
            if(is_valid_user(params->username, params->password)) {
               ...
            }
         }
         ...
      }
      else if("bearer" == auth->auth_scheme) {
         // Bearer authentification scheme should be used.
         using namespace restinio::http_field_parsers::bearer_auth;
         const auto params = try_extract_params(auth->auth_params);
         if(auth_params) { // Parameters successfully extracted.
            if(is_valid_user(auth_params->token)) {
               ...
            }
         }
         ...
      }
      else {
         ... // Handling of different schemes.
      }
   }
}
restinio -

Published by eao197 over 4 years ago

New helpers for extraction of parameters for Bearer authentication (thanks to @prince-chrismc):

#include <restinio/all.hpp>
#include <restinio/http_field_parser/bearer_auth.hpp>
...
auto on_request(const restinio::request_handle_t & req) {
   using namespace restinio::http_field_parsers::bearer_auth;
   const auto auth_params = try_extract_params(*req,
         restinio::http_field::authorization);
   if(auth_params) { // Parameters successfully extracted.
      if(is_valid_user(auth_params->client_id, auth_params->client_secret)) {
         ...
      }
   }
   ...
}
restinio -

Published by eao197 over 4 years ago

New configuration options for CMake-based builds: RESTINIO_USE_EXTERNAL_EXPECTED_LITE, RESTINIO_USE_EXTERNAL_OPTIONAL_LITE, RESTINIO_USE_EXTERNAL_STRING_VIEW_LITE, RESTINIO_USE_EXTERNAL_VARIANT_LITE.

New helper function run_async that allows to run an instance of RESTinio's server on a separate thread-pool or thread:

int main() {
   auto server = restinio::run_async(
      // Asio's io_context to be used.
      // HTTP-server will use own Asio's io_context object.
      restinio::own_io_context(),
      // The settings for the HTTP-server.
      restinio::server_settings_t{}
         .address("127.0.0.1")
         .port(8080)
         .request_handler(...),
      // The size of thread-pool for the HTTP-server.
      16);
   // If we are here and run_async doesn't throw then HTTP-server
   // is started.

   ... // Some other actions.

   // No need to stop HTTP-server manually. It will be automatically
   // stopped in the destructor of `server` object.
}

New helpers for working with HTTP-fields like Authorization and Proxy-Authorization, and helpers for the extraction of parameters for Basic authentication:

#include <restinio/all.hpp>
#include <restinio/http_field_parser/basic_auth.hpp>
...
auto on_request(const restinio::request_handle_t & req) {
   using namespace restinio::http_field_parsers::basic_auth;
   const auto auth_params = try_extract_params(*req,
         restinio::http_field::authorization);
   if(auth_params) { // Parameters successfully extracted.
      if(is_valid_user(auth_params->username, auth_params->password)) {
         ...
      }
   }
   ...
}

Some bug fixes.

restinio -

Published by eao197 over 4 years ago

An experimental type-safe request-router that can be used as a type-safe alternative of express-like router with additional compile-time checking. That new easy_parser_router allows to write:

namespace epr = restinio::router::easy_parser_router;
router->http_get(
   epr::path_to_params("/api/v1/posts/",
      epr::non_negative_decimal_number_p<std::uint64_t>(),
      "/revisions/",
      epr::non_negative_decimal_number_p<std::int16_t>()),
   [](const auto & req, std::uint64_t post_id, std::int16_t rev_id) {...});

instead of:

router->http_get("/api/v1/posts/:post_id(\d{1,10})/revisions/:rev_id(\d{1,5})",
   [](const auto & req, const auto & params) {
      const auto post_id = restinio::cast_to<std::uint64_t>(params["post_id"]);
      const auto rev_id = restinio::cast_to<std::int16_t>(params["rev_id"]);
   });

More information about the new router can be found here.


An ability to specify a request handler for several HTTP-methods (see #82 for a motivation). It's possible now to write routes like:

router->add_handler(
   restinio::router::any_of_methods(
      restinio::http_method_lock(), restinio::http_method_unlock()),
   "/api/v1/resources/:rid",
   [](const auto & req, const auto & params) {...});

router->add_handler(
   restinio::router::none_of_methods(
      restinio::http_method_get(), restinio::http_method_post(), restinio::http_method_delete()),
   "/api/v1/users/:user",
   [](const auto & req, const auto & params) {...});

Those new method matchers can be used for express-like or easy_parser-based routers.

More information about method matchers is here.


New RESTINIO_FMT_HEADER_ONLY CMake option added. It allows to use the compiled version of fmtlib with RESTinio. Thanks for @prince-chrismc for a patch.

restinio -

Published by eao197 over 4 years ago

Set of symbols supported by restinio::parse_query_traits::javascript_compatible is extended (#76).

Addition of restinio::parse_query_traits::x_www_form_urlencoded, restinio::parse_query_traits::relaxed trais.

Introduction of try_parse_query function.

Some functions that work with query-string and URI (like parse_query, try_parse_query) now do basic control of the validity of UTF-8 sequences represented as percent-encoded characters.

New RESTINIO_USE_EXTERNAL_HTTP_PARSER option for CMake-based builds.