Building Scalable HTTP Applications with Cinatra

Overview

Cinatra is a modern C++ HTTP framework designed for high performance and ease of use. Built utilizing C++17 standards, it aims to streamline the development of robust web services. Key architectural features include:

  • Consistent and minimalistic API design
  • Header-only library structure
  • Cross-platform compatibility
  • High throughput efficiency
  • Aspect-Oriented Programming (AOP) support

The framework supports HTTP 1.0/1.1, SSL encryption, and WebSocket protocols. It is suitable for constructing various server types, such as database proxies, file transfer services, real-time messaging systems, or MQTT brokers.

Prerequisites

Cinatra leverages Boost.Asio for asynchronous operations. However, it also supports standalone Asio, meaning a full Boost installation is optional.

Dependencies

  • C++17 compliant compiler (e.g., GCC 7.2+, Clang 4.0+, MSSVC 2017 15.5+)
  • Boost.Asio or Standalone Asio
  • Boost.System

Since the library is header-only, integration requires only including the necessary header files.

Server Implementation Examples

Basic Hello World Service

The following example demonstrates initializing a server with a thread pool matching the hardware concurrency and setting up a basic route.

#include "cinatra.hpp"

int main() {
    constexpr auto thread_count = std::thread::hardware_concurrency();
    cinatra::http_server web_svc(thread_count);
    
    web_svc.listen("0.0.0.0", "9090");
    web_svc.set_http_handler<cinatra::GET, cinatra::POST>("/", 
        [](cinatra::request& req, cinatra::response& res) {
            res.set_status_and_content(cinatra::status_type::ok, "Service Online");
        });

    web_svc.run();
    return 0;
}

This configuration requires minimal boilerplate, allowing developers to focus primarily on business logic.

Handling Headers and Query Parameters

This example illustrates extracting data from request headers and query strings, including error handling for missing parameters.

#include "cinatra.hpp"

int main() {
    cinatra::http_server web_svc(std::thread::hardware_concurrency());
    web_svc.listen("0.0.0.0", "9090");
    
    web_svc.set_http_handler<cinatra::GET, cinatra::POST>("/validate", 
        [](cinatra::request& req, cinatra::response& res) {
            auto user_id = req.get_header_value("user-id");
            if (user_id.empty()) {
                res.set_status_and_content(cinatra::status_type::bad_request, "Missing User ID");
                return;
            }

            auto token = req.get_query_value("token");
            if (token.empty()) {
                res.set_status_and_content(cinatra::status_type::bad_request);
                return;
            }

            res.set_status_and_content(cinatra::status_type::ok, "Validation Passed");
        });

    web_svc.run();
    return 0;
}

Aspect-Oriented Programming (AOP)

Cinatra supports aspects for cross-cutting concerns like logging and security validation. Aspects are executed in order before and after the main handler.

#include "cinatra.hpp"

struct AccessLogger {
    bool before(cinatra::request& req, cinatra::response& res) {
        std::cout << "[Log] Request received" << std::endl;
        return true;
    }
    bool after(cinatra::request& req, cinatra::response& res) {
        std::cout << "[Log] Request completed" << std::endl;
        return true;
    }
};

struct IdentityVerifier {
    bool before(cinatra::request& req, cinatra::response& res) {
        std::cout << "[Security] Checking credentials" << std::endl;
        if (req.get_header_value("auth").empty()) {
            res.set_status_and_content(cinatra::status_type::unauthorized);
            return false;
        }
        return true;
    }
    bool after(cinatra::request& req, cinatra::response& res) {
        return true;
    }
};

int main() {
    cinatra::http_server web_svc(std::thread::hardware_concurrency());
    web_svc.listen("0.0.0.0", "9090");
    
    web_svc.set_http_handler<cinatra::GET, cinatra::POST>("/secure", 
        [](cinatra::request& req, cinatra::response& res) {
            res.set_status_and_content(cinatra::status_type::ok, "Secure Content");
        }, 
        IdentityVerifier{}, AccessLogger{});

    web_svc.run();
    return 0;
}

In this workflow, the verifier runs first. If authentication fails, the request halts. Otherwise, the logger records the entry, the business logic executes, and the logger records the exit.

File Upload Capabilities

The framework supports both multipart/form-data and application/octet-stream content types.

Multipart Upload

#include "cinatra.hpp"

int main() {
    cinatra::http_server web_svc(std::thread::hardware_concurrency());
    web_svc.listen("0.0.0.0", "9090");

    web_svc.set_http_handler<cinatra::POST>("/upload_form", 
        [](cinatra::request& req, cinatra::response& res) {
            assert(req.get_content_type() == cinatra::content_type::multipart);
            
            const auto& uploaded_files = req.get_upload_files();
            for (const auto& file : uploaded_files) {
                std::cout << "Path: " << file.get_file_path() 
                          << " Size: " << file.get_file_size() << std::endl;
            }
            res.set_status_and_content(cinatra::status_type::ok, "Upload Complete");
        });

    web_svc.run();
    return 0;
}

Octet-Stream Upload

#include "cinatra.hpp"

int main() {
    cinatra::http_server web_svc(std::thread::hardware_concurrency());
    web_svc.listen("0.0.0.0", "9090");

    web_svc.set_http_handler<cinatra::POST>("/upload_raw", 
        [](cinatra::request& req, cinatra::response& res) {
            assert(req.get_content_type() == cinatra::content_type::octet_stream);
            const auto& uploaded_files = req.get_upload_files();
            for (const auto& file : uploaded_files) {
                std::cout << "Binary Size: " << file.get_file_size() << std::endl;
            }
            res.set_status_and_content(cinatra::status_type::ok, "Binary Received");
        });

    web_svc.run();
    return 0;
}

File Download

Large files (typically exceeding 5MB) are automatically served using chunked trensfer encoding, supporting resume capabilities.

WebSocket Support

WebSocket connections are handled via event callbacks for opening, messaging, and errors.

#include "cinatra.hpp"

int main() {
    cinatra::http_server web_svc(std::thread::hardware_concurrency());
    web_svc.listen("0.0.0.0", "9090");

    web_svc.set_http_handler<cinatra::GET>("/ws", 
        [](cinatra::request& req, cinatra::response& res) {
            assert(req.get_content_type() == cinatra::content_type::websocket);

            req.on(cinatra::ws_open, [](cinatra::request& req){
                std::cout << "Connection Established" << std::endl;
            });

            req.on(cinatra::ws_message, [](cinatra::request& req) {
                auto data = req.get_part_data();
                std::string msg = std::string(data.data(), data.length());
                // Transform message before echoing
                std::transform(msg.begin(), msg.end(), msg.begin(), ::toupper);
                req.get_conn()->send_ws_string(std::move(msg));
            });

            req.on(cinatra::ws_error, [](cinatra::request& req) {
                std::cout << "Connection Error" << std::endl;
            });
        });

    web_svc.run();
    return 0;
}

Manual Event Loop Control

For scenarios requiring custom thread management, io_service_inplace allows manual control over the server loop.

#include "cinatra.hpp"

int main() {
    bool service_active = true;
    cinatra::http_server_<cinatra::io_service_inplace> web_svc;
    web_svc.listen("9090");

    web_svc.set_http_handler<cinatra::GET>("/", 
        [](cinatra::request& req, cinatra::response& res) {
            res.set_status_and_content(cinatra::status_type::ok, "Active");
        });

    web_svc.set_http_handler<cinatra::GET>("/shutdown", 
        [&](cinatra::request& req, cinatra::response& res) {
            res.set_status_and_content(cinatra::status_type::ok, "Shutting Down");
            service_active = false;
            web_svc.stop();
        });

    while(service_active) {
        web_svc.poll_one();
    }
    return 0;
}

Client Implementation

Cinatra includes a HTTP client supporting both synchronous and asynchronous operations. Response data includes error codes, status, body, and headers.

Synchronous Requests

void inspect_response(const cinatra::response_data& result) {
    // Process ec, status, body, headers
}

void execute_sync_calls() {
    auto client = cinatra::client_factory::instance().new_client();
    std::string endpoint = "http://example.com";
    
    auto result = client->get(endpoint);
    inspect_response(result);

    auto post_result = client->post(endpoint, "payload");
    inspect_response(post_result);
}

Asynchronous Requests

void execute_async_calls() {
    std::string endpoint = "http://example.com";
    auto client = cinatra::client_factory::instance().new_client();
    
    client->async_get(endpoint, [](cinatra::response_data data) {
        inspect_response(data);
    });
}

Client File Operations

Asynchronous uploads and chunked downloads are suported. Downloads can be saved directly to disk or processed via callbacks.

void transfer_files() {
    std::string url = "http://example.com/upload";
    auto client = cinatra::client_factory::instance().new_client();
    
    // Upload
    client->upload(url, "data.zip", [](cinatra::response_data data) {
        if (!data.ec) {
            std::cout << "Upload Success" << std::endl;
        }
    });

    // Download
    client->download(url, "local_copy.zip", [](cinatra::response_data data) {
        if (!data.ec) {
            std::cout << "Download Success" << std::endl;
        }
    });
}

Technical Considerations

When implementing WebSocket handlers, be aware that callback functions may be invoked multiple times during the connection lifecycle. Business logic should be designed to handle stateless invocations appropriately. While the framework is optimized for performance, it is recommended to validate stability within a staging environment before deploying to critical production systems.

Tags: cinatra C++17 asio http-server WebSocket

Posted on Mon, 14 Sep 2026 16:43:17 +0000 by UTAlan