Skip to the content.

< Previous: Getting Started | 🏠 Home | Next: Advanced Usage >


Basic Usage

The HttpServer class allows you to create a high-performance, asynchronous HTTP/1.1 server. It handles incoming connections, parses HTTP packets, and routes them to user-defined route handlers.

Starting the Server

Here is a minimal example demonstrating how to construct a server, register simple GET and POST routes, and start listening for HTTP requests:

#include "cpphttp.hpp"
#include <iostream>

int main() {
    // Construct HttpServer listening on port 8080
    cpphttp::HttpServer server(8080);

    // Register a basic GET route
    server.Get("/", [](const cpphttp::HttpRequest& request) {
        cpphttp::HttpResponse response;
        response.status_code = 200;
        response.status_message = "OK";
        response.headers["Content-Type"] = "text/html";
        response.body = "<h1>Welcome to cpp-http!</h1>";
        return response;
    });

    // Register a POST route to accept client data
    server.Post("/submit", [](const cpphttp::HttpRequest& request) {
        std::cout << "POST content: " << request.body << "\n";

        cpphttp::HttpResponse response;
        response.status_code = 201;
        response.status_message = "Created";
        response.headers["Content-Type"] = "text/plain";
        response.body = "Submission successful!";
        return response;
    });

    // Start the server background loop
    try {
        server.Start();
        std::cout << "HTTP Server running on port 8080. Press Enter to stop.\n";
        std::cin.get();
        server.Stop();
    } catch (const std::exception& e) {
        std::cerr << "Failed to start HTTP server: " << e.what() << "\n";
    }

    return 0;
}

Custom Bind Address

By default, the server binds to all available network interfaces (0.0.0.0). You can restrict the server to a specific interface by providing an optional second parameter to the constructor:

// Bind only to localhost / loopback interface (local development)
cpphttp::HttpServer server(8080, "127.0.0.1");

The HttpRequest Structure

The server maps incoming requests to a structured HttpRequest object:

// Case-insensitive maps used for headers
using HeaderMap = std::unordered_map<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>;
using MultiHeaderMap = std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>;

struct HttpRequest
{
    std::string method;                                        // e.g., "GET", "POST"
    std::string path;                                          // stripped of query variables, e.g., "/profile"
    std::string version;                                       // e.g., "HTTP/1.1"
    HeaderMap headers;                                         // Case-insensitive HTTP Header Map
    MultiHeaderMap multi_headers;                              // Multi-headers map (allows duplicate keys like Set-Cookie)
    std::string body;                                          // Request payload
    std::string client_ip;                                     // Client IP address (from X-Forwarded-For or Peer Address)
    std::unordered_map<std::string, std::string> query_params; // Query params (e.g. ?name=val)
    std::unordered_map<std::string, std::string> path_params;  // Dynamically matched segments (e.g. :id)

    // Lookup headers case-insensitively
    std::string GetHeader(const std::string &key) const;
};

When a request is received, headers are automatically parsed, query parameters are separated and decoded, and path parameters are matched. Headers in HttpRequest::headers are case-insensitive, meaning request.headers["Content-Type"] and request.headers["content-type"] refer to the same value.

The HttpResponse Structure

Route handlers return a HttpResponse structure:

struct HttpResponse
{
    int status_code = 200;
    std::string status_message = "OK";
    HeaderMap headers;            // Case-insensitive HTTP Header Map
    MultiHeaderMap multi_headers; // Multi-headers map (allows duplicate keys like Set-Cookie)
    std::string body;

    // Lookup headers case-insensitively
    std::string GetHeader(const std::string &key) const;

    // Static Response Builders
    static HttpResponse Json(const std::string &json_body, int status_code = 200);
    static HttpResponse Html(const std::string &html_body, int status_code = 200);
    static HttpResponse Plain(const std::string &text_body, int status_code = 200);
    static HttpResponse Redirect(const std::string &location, int status_code = 302);

    // Serializes the response object into a valid HTTP/1.1 raw string.
    std::string Serialize() const;
};

Static Response Builders

To simplify returning responses, you can use the static helpers inside route callbacks:

server.Get("/api/data", [](const cpphttp::HttpRequest& req) {
    return cpphttp::HttpResponse::Json("{\"status\":\"ok\"}");
});

Performing Client Requests

cpp-http includes a client HttpClient supporting both synchronous (blocking) and asynchronous (non-blocking) request execution.

Synchronous Requests

#include "cpphttp.hpp"
#include <iostream>

int main() {
    // Construct client
    cpphttp::HttpClient client("127.0.0.1", 8080);
    client.SetMaxBodySize(10 * 1024 * 1024); // Protect against large response bodies (10MB)

    try {
        // Send a GET request
        cpphttp::HttpResponse response = client.Get("/api/data");
        std::cout << "Status: " << response.status_code << "\n";
        std::cout << "Body: " << response.body << "\n";
    } catch (const std::exception &e) {
        std::cerr << "Request failed: " << e.what() << "\n";
    }

    return 0;
}

Connection Persistence & Keep-Alive

HttpClient automatically manages the lifetime of its underlying TCP connection. By default, it uses Connection: keep-alive to keep the connection open for subsequent requests, reducing connection handshake overhead.

Automatic Redirect Following

When the server replies with redirection codes (301, 302, etc.), the client automatically parses the Location header and follows the redirect (up to a depth of 5).

Asynchronous Requests (Using cpp-asyncworker)

The client also provides asynchronous counterparts (e.g. GetAsync, PostAsync, PutAsync, DeleteAsync) which return a std::future<HttpResponse> executing concurrently in a background thread pool:

#include "cpphttp.hpp"
#include <iostream>
#include <future>

int main() {
    cpphttp::HttpClient client("127.0.0.1", 8080);

    try {
        // Send a GET request asynchronously
        std::future<cpphttp::HttpResponse> future = client.GetAsync("/api/data");

        // ... do other work while the network request runs in the background ...

        cpphttp::HttpResponse response = future.get(); // Blocks until response is received
        std::cout << "Status: " << response.status_code << "\n";
        std::cout << "Body: " << response.body << "\n";
    } catch (const std::exception &e) {
        std::cerr << "Request failed: " << e.what() << "\n";
    }

    return 0;
}

🏠 Home | Next: Advanced Usage >