BeastHttp

by 0xdead4ead

0xdead4ead / BeastHttp

Provides helper tools for creating RESTful services using Boost.Beast

217 Stars 26 Forks Last release: about 2 years ago (1.0.4) BSD 2-Clause "Simplified" License 380 Commits 4 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

SYNOPSIS license build badge.cpp

Easy HTTP (Header-only) library implemented using minimum C++11 and Boost.Beast. Allows you to get or provide REST resources available from an application in C ++. Use all the features of the Boost.Beast when constructing queries and answers.

FEATURES

  • HTTP 1.0 / 1.1
  • TLS/SSL
  • Pipeline request
  • Used I/O multiplexing model (Asio library implementation)
  • Timer manage (default action: Closing connection)
  • Server-Sent Events
  • Simple way to dynamic add REST resources using regex for path, and anonymous functions
  • Support accepted plain and SSL session on the same port

DEPENDENCIES

USAGE

More examples is

here...
The following notes show the standard syntax for setting up routes and starting a server!

Alias's represent instances of default classes for reactive (select/epool) design.

    using namespace _0xdead4ead;
    namespace beast = boost::beast;

using http_session = http::reactor::_default::session_type;
using http_listener = http::reactor::_default::listener_type;

Creating a new callback functions storage and route path for GET request with "/" resource:

    static const std::regex::flag_type regex_flags = std::regex::ECMAScript;

http::basic_router<http_session> router{regex_flags};

router.get("^/$", [](auto beast_http_request, auto context) {
    context.send(make_200<:http::string_body>(beast_http_request, "Main page\n", "text/html"));
});

router.all("^.*$", [](auto beast_http_request, auto context) {
    context.send(make_404<:http::string_body>(beast_http_request, "Resource is not found\n", "text/html"));
});

// or so ...

using http::literals::operator""_get;

"^/$"_get.advance(router, [](auto beast_http_request, auto context) {
    // as above...
});

"^.*$"_all.advance(router, [](auto beast_http_request, auto context) {
    // as above...
});

</:http::string_body></:http::string_body>

It is possible to add multiple handlers for one route. For movement on them

std::next
or
std::advance
is used:
    router.get("^/a/b$",
       [](auto /*beast_http_request*/, auto /*context*/, auto iterator){
        // process /a
        std::next(iterator)();
    }, [](auto /*beast_http_request*/, auto /*context*/){
        // process /b
    });

Getting a parameter from a URI. Request send example

curl localhost --request 'GET' --request-target '/user/param?y=1992'
:
    using pack = http::param::pack;

router.param<pack>().get("^/user/param[?]y=(\\d+)$",
   [](auto /*beast_http_request*/, auto /*context*/, auto args){
    assert(std::get&lt;0&gt;(args) == 1992);
});

// or

router.param<pack>().get("^/user/param[?]y=(\\d+)$",
   [](auto /*beast_http_request*/, auto /*context*/, auto iterator, auto /*args*/){
    // process /user
    std::next(iterator)();
}, [](auto /*beast_http_request*/, auto /*context*/, auto args){
    // process /param
    assert(std::get&lt;0&gt;(args) == 1992);
});

Getting a parameter using a string literal (as above) :

    // For value f'n is required c++14
    using http::literals::value;
    using http::literals::operator""_c;

auto param = router.param<pack>();

"^/user/param[?]y=(\\d+)$"_get.advance(std::move(param),
   [](auto /*beast_http_request*/, auto /*context*/, auto args){
    assert(value(args, 0_c) == 1992);
});

Create modular, mounted route handlers:

    http::basic_router animals{regex_flags};

animals.get("^/cat$", [](auto beast_http_request, auto context){ // '/animals/cat'
    context.send(make_200<:http::string_body>(beast_http_request, "me-ow\n", "text/html"));
});

animals.get("^/dog$", [](auto beast_http_request, auto context){ // '/animals/dog'
    context.send(make_200<:http::string_body>(beast_http_request, "aw! aw! Rrrrr\n", "text/html"));
});

animals.get("^/mouse$", [](auto beast_http_request, auto context){ // '/animals/mouse'
    context.send(make_200<:http::string_body>(beast_http_request, "...\n", "text/html"));
});

animals.get("^[/]??$", [](auto beast_http_request, auto context){ // '/animals' or '/animals/'
    context.send(make_200<:http::string_body>(beast_http_request, "animals home page\n", "text/html"));
});

router.use("^/animals$", animals);

</:http::string_body></:http::string_body></:http::string_body></:http::string_body>

Create handlers routes, forming a chain, for the route path:

    http::chain_router books{regex_flags};

books.route("^/book$")
        .get([](auto beast_http_request, auto context) {
    context.send(make_200<:http::string_body>(beast_http_request, "get a random book\n", "text/html"));
})
        .post([](auto beast_http_request, auto context) {
    context.send(make_200<:http::string_body>(beast_http_request, "add a book\n", "text/html"));
})
        .put([](auto beast_http_request, auto context) {
    context.send(make_200<:http::string_body>(beast_http_request, "update the book\n", "text/html"));
});

router.use("^/books$", books);

</:http::string_body></:http::string_body></:http::string_body>

Start listening on 0.0.0.0:8080

    // global namespace
    static boost::asio::io_context ioc;
    static boost::asio::posix::stream_descriptor out{ioc, ::dup(STDERR_FILENO)};
    //

const auto&amp; onError = [](auto system_error_code, auto from){
    http::out::pushn<:ostream>(
                out, "From:", from, "Info:", system_error_code.message());
};

const auto&amp; onAccept = [&amp;](auto asio_socket){
    auto endpoint = asio_socket.remote_endpoint();

    http::out::prefix::version::time::pushn<:ostream>(
                out, endpoint.address().to_string() + ':' + std::to_string(endpoint.port()), "connected!");

    http_session::recv(std::move(asio_socket), router, onError);
};

auto const address = boost::asio::ip::address_v4::any();
auto const port = static_cast<unsigned short>(8080);

http_listener::launch(ioc, {address, port}, onAccept, onError);

</:ostream></:ostream>

Run the I/O service on the requested number of threads:

    std::thread t{[](){
        ioc.run();
    }};

// do other work...

t.join();

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.