Usage Guide =========== .. This file is auto-generated by scripts/generate_api_rst.py. This guide provides examples of how to use the ``HTTPServer`` library to build a web server. Basic Server Setup ------------------ To start a server, you need to initialize the ``Server`` object (optionally with a configuration file), register your routes, and call ``start()``. .. code-block:: cpp #include int main() { using namespace HTTPServer; // Initialize server with a config file Server server("config.toml"); // Safe shutdown on SIGINT/SIGTERM server.installSignalHandlers(); // Define routes... // Start the blocking event loop server.start(); } Routing ------- The ``Router`` is a singleton used to map HTTP methods and paths to callback functions. Static Routes ~~~~~~~~~~~~~ Simple path matching for specific methods: .. code-block:: cpp Router::instance().addRoute("GET", "/hello", [](const HttpRequest& req) { return Responses::ok(req, "Hello, World!"); }); Dynamic Routes ~~~~~~~~~~~~~~ Paths can contain placeholders in the format ``{name}``. These are extracted and passed in the ``req.params`` map. You can use multiple placeholders in a single path. .. code-block:: cpp Router::instance().addRoute("GET", "/post/{year}/{slug}", [](const HttpRequest& req) { auto year = req.params.at("year"); auto slug = req.params.at("slug"); return Responses::ok(req, "Viewing post from " + year + ": " + slug); }); Query Parameters ~~~~~~~~~~~~~~~~ The server also parses query parameters from the URL (e.g., ``?key=value``) and merges them into the same ``req.params`` map used for dynamic path variables. .. code-block:: cpp // Handling a request like GET /search?q=cpp Router::instance().addRoute("GET", "/search", [](const HttpRequest& req) { auto it = req.params.find("q"); if (it != req.params.end()) { return Responses::ok(req, "Search results for: " + it->second); } return Responses::badRequest(StatusCode::BadRequest); }); Route Precedence ~~~~~~~~~~~~~~~~ When multiple routes could potentially match a single request, the ``Router`` follows these precedence rules: 1. **Exact Matches**: Static routes take the highest priority. 2. **Dynamic Routes**: If no exact match is found, the server looks for dynamic routes with placeholders. 3. **Wildcard/Directory Routes**: If neither of the above match, the server attempts to match static directory routes. For directory routes, the **longest prefix match** always wins. If you have both ``/static/`` and ``/static/images/`` registered, a request to ``/static/images/logo.png`` will be served from the more specific ``/static/images/`` handler. Security & Sanitization ----------------------- The router includes built-in protection against **Directory Traversal** attacks. Any attempt to use ``..`` in a URI to access files outside of a registered static directory (e.g., ``/static/../../etc/passwd``) will be blocked and return a ``401 Unauthorized`` response. Serving Static Files -------------------- You can serve an entire directory of static assets (HTML, CSS, JS) using a single route. .. code-block:: cpp // Map /static/* to the local public/ directory Router::instance().addStaticDirectoryRoute("/static", "public/"); // Or serve a specific file for a route Router::instance().addRoute("GET", "/", [](const HttpRequest& req) { return Responses::file(req, "public/index.html"); }); Pre-made Responses ------------------ The ``Responses`` namespace provides high-level helpers for common response types. * **Responses::ok(req, body, [mime_type])**: Returns a 200 OK response with the given body. Defaults to ``text/plain``. * **Responses::file(req, path)**: Reads a file from disk and serves it with the correct ``Content-Type`` based on its extension. * **Responses::notFound(req)**: Returns a 404 response with a standard HTML error page. * **Responses::badRequest(status_code)**: Returns a response with the specified error code (e.g., 400, 403) and a standard HTML error page. * **Responses::redirection(req, port)**: Returns a 301 Moved Permanently response redirecting to the HTTPS version of the current path. Response Building ----------------- For more control, use the ``HttpResponseBuilder`` fluent API. .. code-block:: cpp Router::instance().addRoute("POST", "/data", [](const HttpRequest& req) { return HttpResponseBuilder() .setStatus(StatusCode::CREATED) .setBody("{\"status\":\"success\"}") .addHeader("Content-Type", "application/json") .build(req); }); Logging ------- The library includes a thread-safe singleton ``Logger`` and a ``LogEvent`` helper for structured logging. Simple Logging ~~~~~~~~~~~~~~ Use the convenience macros for basic messages: .. code-block:: cpp LOG_INFO << "Server starting..."; LOG_WARN << "Rate limit exceeded for IP: " << ip; LOG_ERROR << "Failed to open configuration file"; Structured Logging ~~~~~~~~~~~~~~~~~~ The ``LogEvent`` class allows you to build structured log lines with key-value pairs, which are easier to parse with log aggregators. .. code-block:: cpp #include LOG_EVENT(LogLevel::INFO, LogEvent("request_processed") .add("method", req.method) .add("path", req.path) .add("status", 200) .add("duration_ms", 5) );