Skip to content

Repository files navigation

bsrvcore

bsrvcore is a C++ HTTP server library built on Boost.Asio and Boost.Beast.

It focuses on a clean "learning-friendly" API:

  • Routing with path parameters
  • Aspects (before/after hooks, like middleware)
  • Sessions + request context
  • Optional TLS (HTTPS)
  • Optional client tasks (HTTP/HTTPS + SSE)

Tutorial-style manual (recommended):

Maintainer / internals notes:

API reference:

  • This project relies on Doxygen generated from public headers under include/.

Requirements

  • C++20 compiler
  • CMake 3.25+
  • Boost (components: headers, system, url, json, program_options)
  • OpenSSL

Toolchain Support

  • The project currently targets LLVM toolchains (Clang/LLVM) as the supported baseline.
  • Non-LLVM toolchains are not considered officially supported at this stage.
  • Support scope may expand in future releases when compatibility and CI coverage are ready.

Build and Install

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
sudo cmake --install build

Library type is controlled by BUILD_SHARED_LIBS:

  • Shared library (default):
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON
  • Static library:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF

As a subproject (add_subdirectory), set BUILD_SHARED_LIBS in the parent project before adding bsrvcore:

# Parent project's CMakeLists.txt
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libs across subprojects" FORCE)
add_subdirectory(external/bsrvcore)

add_executable(app main.cc)
target_link_libraries(app PRIVATE bsrvcore::bsrvcore)

Compile a standalone program against installed bsrvcore:

g++ a.cpp -std=c++20 $(pkg-config --cflags --libs bsrvcore)

For C applications, enable the C bindings and include the standalone header:

#include <bsrvcore-c/bsrvcore.h>

Recommended CMake consumption:

find_package(bsrvcore_c CONFIG REQUIRED)

add_executable(app main.c)
target_link_libraries(app PRIVATE bsrvcore::bsrvcore_c)

The C package links against the standalone wrapper library libbsrvcore-c.so.

Direct pkg-config use also works:

cc main.c $(pkg-config --cflags --libs bsrvcore-c)

See docs/manual/c-bindings.md for the full C API guide, package layout, stateful handlers, aspects, and request/response rules.

If you install shared libraries manually (without dnf/apt/rpm/dpkg), refresh the dynamic linker cache once:

sudo ldconfig

Quick Start

Source: examples/getting-started/quick_start.cc

The public API now exposes common Asio / Beast / JSON concepts through include/bsrvcore/core/types.h, and bsrvcore/bsrvcore.h re-exports those aliases. Prefer names such as bsrvcore::IoExecutor, bsrvcore::SslContext, bsrvcore::HttpField, and bsrvcore::HttpStatus in application code.

#include <bsrvcore/bsrvcore.h>

#include <boost/asio/ip/address.hpp>

#include <iostream>
#include <memory>

int main() {
  // Worker threads for Post/SetTimer callbacks.
  auto server = std::make_unique<bsrvcore::HttpServer>(4);
  server
      ->AddRouteEntry(
          bsrvcore::HttpRequestMethod::kGet, "/hello",
          [](const std::shared_ptr<bsrvcore::HttpServerTask>& task) {
            task->GetResponse().result(bsrvcore::HttpStatus::ok);
            task->SetField(bsrvcore::HttpField::content_type,
                           "text/plain; charset=utf-8");
            task->SetBody("Hello, bsrvcore.");
          })
      ->AddListen(
          bsrvcore::TcpEndpoint(boost::asio::ip::make_address("0.0.0.0"),
                                8080),
          2);

  if (!server->Start()) {
    std::cerr << "Failed to start server." << std::endl;
    return 1;
  }

  std::cout << "Listening on http://0.0.0.0:8080/hello" << std::endl;
  std::cout << "Press Enter to stop." << std::endl;
  std::cin.get();

  server->Stop();
  return 0;
}

C Binding Quick Start

Source: examples/c-binding/quick_start.c

#include <bsrvcore-c/bsrvcore.h>

#include <stdio.h>

static void hello_handler(bsrvcore_http_server_task_t* task) {
  bsrvcore_http_server_task_set_response(
      task, 200, "text/plain; charset=utf-8", "Hello, bsrvcore C binding.\n",
      sizeof("Hello, bsrvcore C binding.\n") - 1);
}

int main(void) {
  bsrvcore_server_t* server = NULL;

  if (bsrvcore_server_create(4, &server) != BSRVCORE_RESULT_OK) {
    return 1;
  }

  if (bsrvcore_server_add_route(server, BSRVCORE_HTTP_METHOD_GET, "/hello",
                                hello_handler) != BSRVCORE_RESULT_OK ||
      bsrvcore_server_add_listen(server, "0.0.0.0", 8080, 2) !=
          BSRVCORE_RESULT_OK ||
      bsrvcore_server_start(server) != BSRVCORE_RESULT_OK) {
    bsrvcore_server_destroy(server);
    return 1;
  }

  puts("Listening on http://0.0.0.0:8080/hello");
  (void)getchar();

  (void)bsrvcore_server_stop(server);
  bsrvcore_server_destroy(server);
  return 0;
}

Upgrade Information

API Change (v0.16.0+)

Handler and aspect virtual functions now accept const std::shared_ptr<T>& instead of std::shared_ptr<T> by value. This is a breaking change that requires:

  1. Recompilation required for all code using custom handler/aspect classes.

  2. Code updates only if you define custom handlers or aspects:

    // OLD (v0.14.x)
    class MyHandler : public HttpRequestHandler {
      void Service(std::shared_ptr<HttpServerTask> task) override { ... }
    };
    
    // NEW (v0.16.0+)
    class MyHandler : public HttpRequestHandler {
      void Service(const std::shared_ptr<HttpServerTask>& task) override { ... }
    };
  3. Aspect scope update: route aspect registration now distinguishes between subtree and exact-route behavior:

    • AddAspect(...) now registers a subtree aspect that affects the matched route and its descendants.
    • AddTerminalAspect(...) replaces the old exact-route behavior.
    • The same split applies to BluePrint, ReuseableBluePrint, the C binding, and bsrvrun route config (aspects vs terminal_aspects).
  4. Lambda handlers (in examples and application code) auto-adapt—no changes needed.

  5. Object handler/aspect ownership choices:

    • Application code and examples should normally use std::make_unique<T>().
    • bsrvcore runtime internals use allocator-backed ownership on hot paths.

Benefit: ~5-15% throughput improvement in typical request paths through reduced atomic reference-count operations. See IO Thread Optimizations in the design docs.

Next steps (tutorial)

Optional Extensions

  • OAI chat completion has moved to the standalone boai library.
  • bsrvcore now stays focused on the reusable server/client foundation that other libraries can depend on.
  • For the same ecosystem, bcas, boai, and bozo are also recommended companion components depending on your use case.

bsrvrun (runtime executable)

bsrvrun is installed in the runtime package and starts a server from YAML. It can load logger, service, handler, and aspect factories from shared libraries. These plugins use the C++ bsrvcore public API and should be built as part of the same release/deployment as the matching bsrvrun and libbsrvcore. They are not a long-term stable C++ ABI boundary.

Config path resolution order:

  1. -c/--config <path>
  2. ./bsrvrun.yaml
  3. /etc/bsrvrun/bsrvrun.yaml

Run:

bsrvrun -c ./bsrvrun.yaml

For full schema and plugin compatibility notes, see:

Examples

The examples/ folder contains runnable programs:

  • examples/getting-started/

  • examples/c-binding/

  • examples/http-server/

  • examples/sse/

  • examples/routing/

  • examples/aspects/

  • examples/sessions-context/

  • examples/logging/

  • examples/client-tasks/

  • examples/websocket-tasks/

  • examples/bsrvrun/

  • See docs/manual/examples.md

Testing

Formatting

Format the repository with clang-format:

./scripts/format.sh

Use IWYU to remove unused includes and normalize include blocks:

./scripts/iwyu.sh --dry-run
./scripts/iwyu.sh

The IWYU script reuses an existing compile_commands.json when available and otherwise configures a build directory automatically. If IWYU is not installed, it prints a message and exits without changing files.

Benchmarking

Build the standalone benchmark suite:

cmake -S . -B build-bench \
  -DCMAKE_BUILD_TYPE=Release \
  -DBSRVCORE_BUILD_EXAMPLES=OFF \
  -DBSRVCORE_BUILD_TESTS=OFF \
  -DBSRVCORE_BUILD_BENCHMARKS=ON
cmake --build build-bench --target bsrvcore_http_benchmark --parallel

Run a short sweep:

./build-bench/benchmarks/bsrvcore_http_benchmark --profile quick --wrk-bin /usr/bin/wrk

Notes:

  • The repository does not ship wrk binaries by default.
  • The benchmark probes /bin/wrk, /usr/bin/wrk, /usr/local/bin/wrk, then PATH.
  • You can enable bundled build explicitly with -DBSRVCORE_BENCHMARK_BUILD_BUNDLED_WRK=ON.

For benchmark methodology and shipped snapshots, see:

About

A simple asynchorized server framework based on Boost.Asio and Boost.Beast which is easy for developers to build an http server with traditional session support.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages