Usage Guide¶
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().
#include <httpserver>
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:
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.
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.
// 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:
Exact Matches: Static routes take the highest priority.
Dynamic Routes: If no exact match is found, the server looks for dynamic routes with placeholders.
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.
// 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-Typebased 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.
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:
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.
#include <httpserver_impl/monitoring/log_event.h>
LOG_EVENT(LogLevel::INFO,
LogEvent("request_processed")
.add("method", req.method)
.add("path", req.path)
.add("status", 200)
.add("duration_ms", 5)
);