Skip to content

Router: 1. Router Setup Procedure

Ilia Munaev edited this page Sep 21, 2025 · 7 revisions

1. Router Setup

Cluster object using config() method and configuration file as argument setups Router

// main.cpp
Cluster cluster;
	try {
		cluster.config(av[1]); // setup Router
		cluster.create();
		cluster.run();

	} catch (std::exception& e) {
		std::cout << e.what() << std::endl;
	}

The same function in action

// av[1] => _configs
_router.setupRouter(_configs);

2. Cofigs Structure

_configs is a list of Server structures

std::vector<Server> _configs;

3. Server class

The Server class represents a web server instance, which listens for incoming HTTP requests and handles them based on its configuration and associated Location blocks.

class Server {
private:
    uint32_t _address;                        // IP address to bind (e.g., 127.0.0.1)
    int _port;                                // Port to listen on (e.g., 80, 443)
    std::string _name;                        // Server name (e.g., "example.com")
    std::string _root;                        // Root directory for serving files
    std::string _index;                       // Default index file for the server
    std::map<int, std::string> _error_pages;  // Error code to error page mapping
    size_t _client_max_body_size = MAX_BODY_SIZE; // Max size for client request body
    std::vector<Location> _locations;         // List of location blocks

public:
...
};

4. Location structure

The Location struct represents a specific location (or route) on the server, such as a URL path (e.g., /, /api, or /images). It defines how the server handles requests to that path.

struct Location
{
    std::string location;                     // The URL path (e.g., "/", "/api")
    std::vector<std::string> allowed_methods; // HTTP methods allowed (e.g., "GET", "POST")
    std::string index;                       // Default file to serve (e.g., "index.html")
    bool autoindex;                          // Enable/disable directory listing
    std::string cgi_path;                    // Path to CGI executable for dynamic content
    std::vector<std::string> cgi_ext;        // File extensions for CGI scripts (e.g., ".php", ".py")
    std::string upload_path;                 // Directory for file uploads
    std::string return_url;                  // URL for redirection
};

5. Routes variable

This declares a nested std::map data structure with three levels of key-value mappings, where the innermost value is of type Handler.

std::map<std::string, std::map<std::string, std::map<std::string, Handler>>> _routes;

The _routes variable can be visualized as:

_routes
├── "example.com" (server name)
│   ├── "/users" (path)
│   │   ├── "GET" → Handler (function/class to handle GET /users)
│   │   ├── "POST" → Handler (function/class to handle POST /users)
│   ├── "/login" (path)
│   │   ├── "POST" → Handler (function/class to handle POST /login)
├── "api.example.com" (server name)
│   ├── "/data" (path)
│   │   ├── "GET" → Handler (function/class to handle GET /data)

std::map is a sorted associative container that stores key-value pairs.

Keys are unique and sorted (in this case, std::string keys are sorted lexicographically).

Lookup time is logarithmic (O(log n)).

6. setupRouter() method

void Router::setupRouter(const std::vector<Server>& configs);

The loop iterates through each Server object in the configs vector to process its configuration and set up routing rules for the web server using addRoute() method.

void Router::setupRouter(const std::vector<Server>& configs) {
    // ...
    for (const auto& server : configs) {
        // Process each server configuration
        // ...
        // Register the route in the routing table
        addRoute(server.getName(), method, location_path, handler);
    }
}

Process each location block in the server configuration.

void Router::setupRouter(const std::vector<Server>& configs) {
    _routes.clear();
    for (const auto& server : configs) {
        for (const auto& location : server.getLocations()) {
            std::string location_path = location.location;
            for (const auto& method : location.allowed_methods) { // <--- Process a location block
                // Process HTTP methods and assign handlers
                Handler handler;
                // ...
                addRoute(server.getName(), method, location_path, handler);
                // ...
            }
        }
    }
    // ...
}

The core of the routing logic, determining how HTTP requests to a specific server and URL path are handled based on the HTTP method and Location configuration.

// Register routes for each allowed HTTP method in this location
for (const auto& method : location.allowed_methods) {
    // Choose the appropriate handler based on location configuration and method
    Handler handler;

    // Handler selection logic based on location properties:

    if (!location.return_url.empty()) {
        // Redirect location: return_url is configured
        // Use redirect handler for all HTTP methods
        handler = redirect;
        } else if (!location.cgi_path.empty() && !location.cgi_ext.empty()) {
            // CGI location: Both CGI path and extension are configured
            // Use CGI handler for script execution (supports any HTTP method)
            handler = cgi;
        } else if (method == "POST" && !location.upload_path.empty()) {
            // POST request to upload location: Handle file uploads
            handler = post;
        } else if (method == "DELETE" && !location.upload_path.empty()) {
            // DELETE request from upload location: Handle file deletions
            handler = del;
        } else {
            // Default handler for other methods or configurations
            handler = get;
        }
        // Register the route in the routing table
            addRoute(server.getName(), method, location_path, handler);
            }
        }
    }
    // ...
}

Clone this wiki locally