Ejemplos de Funciones Web C++ Windows

Ejemplos de desarrollo de servidor web C++ Windows incluyendo enrutamiento URL, middleware y servicio de archivos estáticos

💻 Enrutamiento URL cpp

🟡 intermediate ⭐⭐⭐⭐

Implementar análisis y coincidencia de rutas URL con parámetros de ruta y cadenas de consulta

⏱️ 35 min 🏷️ cpp, web, routing, http, windows
Prerequisites: Intermediate C++, HTTP protocol basics
// Windows C++ URL Routing Examples
// Using Windows HTTP Server API

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <regex>
#include <windows.h>
#include <http.h>

#pragma comment(lib, "httpapi.lib")

// 1. Basic Route Structure
struct Route {
    std::string method;
    std::string path;
    std::function<void(const std::map<std::string, std::string>&)> handler;

    Route(const std::string& m, const std::string& p,
          std::function<void(const std::map<std::string, std::string>&)> h)
        : method(m), path(p), handler(h) {}
};

// 2. URL Parser
class URLParser {
public:
    static std::string getPath(const std::string& url) {
        size_t queryPos = url.find('?');
        if (queryPos == std::string::npos) {
            return url;
        }
        return url.substr(0, queryPos);
    }

    static std::map<std::string, std::string> getQueryParams(const std::string& url) {
        std::map<std::string, std::string> params;
        size_t queryPos = url.find('?');

        if (queryPos == std::string::npos) {
            return params;
        }

        std::string queryString = url.substr(queryPos + 1);
        size_t start = 0;

        while (start < queryString.length()) {
            size_t ampPos = queryString.find('&', start);
            std::string pair;

            if (ampPos == std::string::npos) {
                pair = queryString.substr(start);
                break;
            } else {
                pair = queryString.substr(start, ampPos - start);
                start = ampPos + 1;
            }

            size_t eqPos = pair.find('=');
            if (eqPos != std::string::npos) {
                std::string key = pair.substr(0, eqPos);
                std::string value = pair.substr(eqPos + 1);
                params[key] = value;
            }
        }

        return params;
    }

    static std::string decodeURL(const std::string& encoded) {
        std::string decoded;
        size_t i = 0;

        while (i < encoded.length()) {
            if (encoded[i] == '%' && i + 2 < encoded.length()) {
                std::string hexStr = encoded.substr(i + 1, 2);
                int charCode = std::stoi(hexStr, nullptr, 16);
                decoded += static_cast<char>(charCode);
                i += 3;
            } else if (encoded[i] == '+') {
                decoded += ' ';
                i++;
            } else {
                decoded += encoded[i];
                i++;
            }
        }

        return decoded;
    }
};

// 3. Simple Router
class Router {
private:
    std::vector<Route> routes;

public:
    void addRoute(const std::string& method, const std::string& path,
                  std::function<void(const std::map<std::string, std::string>&)> handler) {
        routes.emplace_back(method, path, handler);
    }

    void get(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        addRoute("GET", path, handler);
    }

    void post(const std::string& path,
              std::function<void(const std::map<std::string, std::string>&)> handler) {
        addRoute("POST", path, handler);
    }

    void put(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        addRoute("PUT", path, handler);
    }

    void del(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        addRoute("DELETE", path, handler);
    }

    bool handleRequest(const std::string& method, const std::string& url) {
        std::string path = URLParser::getPath(url);
        std::map<std::string, std::string> queryParams = URLParser::getQueryParams(url);

        for (const auto& route : routes) {
            if (route.method == method && route.path == path) {
                route.handler(queryParams);
                return true;
            }
        }

        return false;
    }
};

// 4. Parameterized Route Matcher
class ParameterizedRouter {
private:
    struct RoutePattern {
        std::regex pattern;
        std::vector<std::string> paramNames;
        std::function<void(const std::map<std::string, std::string>&)> handler;
    };

    std::vector<RoutePattern> routes;

public:
    void addRoute(const std::string& method, const std::string& pathPattern,
                  std::function<void(const std::map<std::string, std::string>&)> handler) {
        std::regex paramRegex(R"({(w+)})");
        std::string regexPattern = pathPattern;
        std::vector<std::string> paramNames;

        // Replace {param} with regex groups
        std::sregex_iterator it(pathPattern.begin(), pathPattern.end(), paramRegex);
        std::sregex_iterator end;

        for (; it != end; ++it) {
            paramNames.push_back((*it)[1].str());
        }

        regexPattern = std::regex_replace(regexPattern, paramRegex, R"(([^/]+))");
        regexPattern = "^" + regexPattern + "$";

        RoutePattern route;
        route.pattern = std::regex(regexPattern);
        route.paramNames = paramNames;
        route.handler = handler;

        routes.push_back(route);
    }

    bool handleRequest(const std::string& method, const std::string& url,
                      std::map<std::string, std::string>& pathParams) {
        std::string path = URLParser::getPath(url);

        for (const auto& route : routes) {
            std::smatch matches;
            if (std::regex_match(path, matches, route.pattern)) {
                for (size_t i = 0; i < route.paramNames.size() && i + 1 < matches.size(); ++i) {
                    pathParams[route.paramNames[i]] = matches[i + 1].str();
                }
                route.handler(pathParams);
                return true;
            }
        }

        return false;
    }
};

// 5. RESTful Router
class RESTfulRouter {
private:
    struct ResourceHandler {
        std::function<void()> getList;
        std::function<void(const std::string&)> getOne;
        std::function<void()> create;
        std::function<void(const std::string&)> update;
        std::function<void(const std::string&)> remove;
    };

    std::map<std::string, ResourceHandler> resources;

public:
    void resource(const std::string& path, const ResourceHandler& handler) {
        resources[path] = handler;
    }

    bool handleRequest(const std::string& method, const std::string& url) {
        for (const auto& entry : resources) {
            const std::string& basePath = entry.first;
            const ResourceHandler& handler = entry.second;

            // List and Create
            if (url == basePath || url == basePath + "/") {
                if (method == "GET" && handler.getList) {
                    handler.getList();
                    return true;
                } else if (method == "POST" && handler.create) {
                    handler.create();
                    return true;
                }
            }

            // Get, Update, Delete by ID
            std::string withId = basePath + "/([^/]+)";
            std::regex idRegex("^" + withId + "$");
            std::smatch matches;

            if (std::regex_match(url, matches, idRegex) && matches.size() > 1) {
                std::string id = matches[1].str();

                if (method == "GET" && handler.getOne) {
                    handler.getOne(id);
                    return true;
                } else if (method == "PUT" && handler.update) {
                    handler.update(id);
                    return true;
                } else if (method == "DELETE" && handler.remove) {
                    handler.remove(id);
                    return true;
                }
            }
        }

        return false;
    }
};

// 6. Route Group with Prefix
class RouteGroup {
private:
    std::string prefix;
    Router& router;

public:
    RouteGroup(const std::string& p, Router& r) : prefix(p), router(r) {}

    void get(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        router.get(prefix + path, handler);
    }

    void post(const std::string& path,
              std::function<void(const std::map<std::string, std::string>&)> handler) {
        router.post(prefix + path, handler);
    }

    void put(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        router.put(prefix + path, handler);
    }

    void del(const std::string& path,
             std::function<void(const std::map<std::string, std::string>&)> handler) {
        router.del(prefix + path, handler);
    }
};

// 7. Middleware Support
class MiddlewareRouter {
private:
    struct RouteWithMiddleware {
        std::string method;
        std::string path;
        std::vector<std::function<void()>> middlewares;
        std::function<void()> handler;
    };

    std::vector<RouteWithMiddleware> routes;

public:
    void addRoute(const std::string& method, const std::string& path,
                  std::vector<std::function<void()>> middlewares,
                  std::function<void()> handler) {
        RouteWithMiddleware route;
        route.method = method;
        route.path = path;
        route.middlewares = middlewares;
        route.handler = handler;
        routes.push_back(route);
    }

    bool handleRequest(const std::string& method, const std::string& path) {
        for (const auto& route : routes) {
            if (route.method == method && route.path == path) {
                // Execute middlewares
                for (const auto& middleware : route.middlewares) {
                    middleware();
                }
                // Execute handler
                route.handler();
                return true;
            }
        }
        return false;
    }
};

// 8. HTTP Method Router
class HTTPMethodRouter {
private:
    std::map<std::string, std::map<std::string, std::function<void()>>> routes;
    std::function<void()> notFoundHandler;

public:
    void setNotFoundHandler(std::function<void()> handler) {
        notFoundHandler = handler;
    }

    void addRoute(const std::string& method, const std::string& path,
                  std::function<void()> handler) {
        routes[method][path] = handler;
    }

    bool handleRequest(const std::string& method, const std::string& path) {
        auto methodIt = routes.find(method);
        if (methodIt != routes.end()) {
            auto pathIt = methodIt->second.find(path);
            if (pathIt != methodIt->second.end()) {
                pathIt->second();
                return true;
            }
        }

        if (notFoundHandler) {
            notFoundHandler();
        }
        return false;
    }

    // Support for HEAD requests (auto-generated from GET)
    bool supportsHEAD(const std::string& path) {
        auto getIt = routes.find("GET");
        if (getIt != routes.end()) {
            return getIt->second.find(path) != getIt->second.end();
        }
        return false;
    }

    // Support for OPTIONS requests
    std::vector<std::string> allowedMethods(const std::string& path) {
        std::vector<std::string> methods;
        for (const auto& entry : routes) {
            if (entry.second.find(path) != entry.second.end()) {
                methods.push_back(entry.first);
            }
        }
        return methods;
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ URL Routing Examples ===" << std::endl;

    // 1. Basic Router
    std::cout << "\n--- 1. Basic Router ---" << std::endl;
    Router router;

    router.get("/", [](const std::map<std::string, std::string>& params) {
        std::cout << "GET / - Home Page" << std::endl;
    });

    router.get("/about", [](const std::map<std::string, std::string>& params) {
        std::cout << "GET /about - About Page" << std::endl;
    });

    router.post("/submit", [](const std::map<std::string, std::string>& params) {
        std::cout << "POST /submit - Form Submission" << std::endl;
    });

    router.handleRequest("GET", "/");
    router.handleRequest("GET", "/about");
    router.handleRequest("POST", "/submit");

    // 2. Query Parameters
    std::cout << "\n--- 2. Query Parameters ---" << std::endl;
    std::string testUrl = "/search?q=routing&page=2&limit=10";
    auto queryParams = URLParser::getQueryParams(testUrl);
    std::cout << "Query params for: " << testUrl << std::endl;
    for (const auto& param : queryParams) {
        std::cout << "  " << param.first << " = " << param.second << std::endl;
    }

    // 3. Parameterized Routes
    std::cout << "\n--- 3. Parameterized Routes ---" << std::endl;
    ParameterizedRouter paramRouter;

    paramRouter.addRoute("GET", "/users/{id}",
        [](const std::map<std::string, std::string>& params) {
            auto it = params.find("id");
            if (it != params.end()) {
                std::cout << "GET /users/{id} - User ID: " << it->second << std::endl;
            }
        });

    paramRouter.addRoute("GET", "/posts/{postId}/comments/{commentId}",
        [](const std::map<std::string, std::string>& params) {
            std::cout << "GET /posts/{postId}/comments/{commentId}" << std::endl;
            for (const auto& p : params) {
                std::cout << "  " << p.first << " = " << p.second << std::endl;
            }
        });

    std::map<std::string, std::string> pathParams;
    paramRouter.handleRequest("GET", "/users/123", pathParams);
    paramRouter.handleRequest("GET", "/posts/45/comments/789", pathParams);

    // 4. RESTful Router
    std::cout << "\n--- 4. RESTful Router ---" << std::endl;
    RESTfulRouter restRouter;

    RESTfulRouter::ResourceHandler userHandler;
    userHandler.getList = []() { std::cout << "GET /users - List all users" << std::endl; };
    userHandler.getOne = [](const std::string& id) { std::cout << "GET /users/" << id << " - Get user" << std::endl; };
    userHandler.create = []() { std::cout << "POST /users - Create user" << std::endl; };
    userHandler.update = [](const std::string& id) { std::cout << "PUT /users/" << id << " - Update user" << std::endl; };
    userHandler.remove = [](const std::string& id) { std::cout << "DELETE /users/" << id << " - Delete user" << std::endl; };

    restRouter.resource("/users", userHandler);

    restRouter.handleRequest("GET", "/users");
    restRouter.handleRequest("GET", "/users/42");
    restRouter.handleRequest("POST", "/users");
    restRouter.handleRequest("PUT", "/users/42");
    restRouter.handleRequest("DELETE", "/users/42");

    // 5. Route Groups
    std::cout << "\n--- 5. Route Groups ---" << std::endl;
    Router apiRouter;

    RouteGroup apiGroup("/api/v1", apiRouter);
    apiGroup.get("/users", [](const auto& p) { std::cout << "GET /api/v1/users" << std::endl; });
    apiGroup.get("/products", [](const auto& p) { std::cout << "GET /api/v1/products" << std::endl; });
    apiGroup.post("/orders", [](const auto& p) { std::cout << "POST /api/v1/orders" << std::endl; });

    apiRouter.handleRequest("GET", "/api/v1/users");
    apiRouter.handleRequest("GET", "/api/v1/products");
    apiRouter.handleRequest("POST", "/api/v1/orders");

    // 6. HTTP Method Router
    std::cout << "\n--- 6. HTTP Method Router ---" << std::endl;
    HTTPMethodRouter methodRouter;

    methodRouter.addRoute("GET", "/resource", []() {
        std::cout << "GET /resource" << std::endl;
    });
    methodRouter.addRoute("POST", "/resource", []() {
        std::cout << "POST /resource" << std::endl;
    });

    methodRouter.setNotFoundHandler([]() {
        std::cout << "404 - Not Found" << std::endl;
    });

    methodRouter.handleRequest("GET", "/resource");
    methodRouter.handleRequest("POST", "/resource");
    methodRouter.handleRequest("DELETE", "/resource");

    // Check allowed methods
    auto methods = methodRouter.allowedMethods("/resource");
    std::cout << "Allowed methods for /resource: ";
    for (const auto& m : methods) {
        std::cout << m << " ";
    }
    std::cout << std::endl;

    std::cout << "\n=== All URL Routing Examples Completed ===" << std::endl;
    return 0;
}

💻 Middleware HTTP cpp

🟡 intermediate ⭐⭐⭐⭐

Implementar pipeline de middleware de procesamiento de solicitudes para registro, autenticación y manejo de CORS

⏱️ 40 min 🏷️ cpp, web, middleware, http, windows
Prerequisites: Intermediate C++, HTTP protocol, Functional programming
// Windows C++ HTTP Middleware Examples
// Implementing middleware pipeline for web server

#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <map>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>

// 1. HTTP Request/Response Structures
struct HttpRequest {
    std::string method;
    std::string path;
    std::map<std::string, std::string> headers;
    std::string body;
};

struct HttpResponse {
    int statusCode;
    std::map<std::string, std::string> headers;
    std::string body;

    HttpResponse() : statusCode(200) {}
};

// 2. Middleware Function Type
using MiddlewareFunc = std::function<bool(HttpRequest&, HttpResponse&)>;
using HandlerFunc = std::function<void(HttpRequest&, HttpResponse&)>;

// 3. Logging Middleware
class LoggingMiddleware {
private:
    std::vector<std::string> logs;

public:
    bool operator()(HttpRequest& req, HttpResponse& res) {
        auto now = std::chrono::system_clock::now();
        auto time = std::chrono::system_clock::to_time_t(now);

        std::stringstream ss;
        ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");

        std::string logEntry = "[" + ss.str() + "] " + req.method + " " + req.path;
        logs.push_back(logEntry);
        std::cout << "[LOG] " << logEntry << std::endl;

        return true; // Continue to next middleware
    }

    void displayLogs() const {
        std::cout << "\n--- Request Logs ---" << std::endl;
        for (const auto& log : logs) {
            std::cout << log << std::endl;
        }
    }
};

// 4. Authentication Middleware
class AuthMiddleware {
private:
    std::map<std::string, std::string> validTokens; // token -> username

public:
    AuthMiddleware() {
        // Pre-populate with some test tokens
        validTokens["abc123"] = "alice";
        validTokens["xyz789"] = "bob";
    }

    bool operator()(HttpRequest& req, HttpResponse& res) {
        // Check for Authorization header
        auto it = req.headers.find("Authorization");

        if (it == req.headers.end()) {
            res.statusCode = 401;
            res.body = R"({"error": "Missing authorization header"})";
            res.headers["Content-Type"] = "application/json";
            return false; // Stop pipeline
        }

        std::string token = it->second;

        // Remove "Bearer " prefix if present
        if (token.find("Bearer ") == 0) {
            token = token.substr(7);
        }

        // Validate token
        auto tokenIt = validTokens.find(token);
        if (tokenIt == validTokens.end()) {
            res.statusCode = 401;
            res.body = R"({"error": "Invalid token"})";
            res.headers["Content-Type"] = "application/json";
            return false;
        }

        // Add user info to request
        req.headers["X-User"] = tokenIt->second;
        std::cout << "[AUTH] User authenticated: " << tokenIt->second << std::endl;

        return true; // Continue to next middleware
    }

    void addToken(const std::string& token, const std::string& username) {
        validTokens[token] = username;
    }
};

// 5. CORS Middleware
class CORSMiddleware {
private:
    std::string allowedOrigin;
    std::vector<std::string> allowedMethods;
    std::vector<std::string> allowedHeaders;
    bool allowCredentials;

public:
    CORSMiddleware(const std::string& origin = "*")
        : allowedOrigin(origin), allowCredentials(true) {
        allowedMethods = {"GET", "POST", "PUT", "DELETE", "OPTIONS"};
        allowedHeaders = {"Content-Type", "Authorization", "X-Requested-With"};
    }

    bool operator()(HttpRequest& req, HttpResponse& res) {
        // Add CORS headers to response
        res.headers["Access-Control-Allow-Origin"] = allowedOrigin;
        res.headers["Access-Control-Allow-Credentials"] = allowCredentials ? "true" : "false";

        // Handle preflight request
        if (req.method == "OPTIONS") {
            res.headers["Access-Control-Allow-Methods"] = join(allowedMethods, ", ");
            res.headers["Access-Control-Allow-Headers"] = join(allowedHeaders, ", ");
            res.headers["Access-Control-Max-Age"] = "86400"; // 24 hours
            res.statusCode = 204; // No Content
            return false; // Stop pipeline
        }

        std::cout << "[CORS] Headers added for " << req.method << " " << req.path << std::endl;
        return true;
    }

private:
    std::string join(const std::vector<std::string>& vec, const std::string& delim) {
        std::string result;
        for (size_t i = 0; i < vec.size(); ++i) {
            if (i > 0) result += delim;
            result += vec[i];
        }
        return result;
    }
};

// 6. Content Type Middleware
class ContentTypeMiddleware {
public:
    bool operator()(HttpRequest& req, HttpResponse& res) {
        auto it = req.headers.find("Content-Type");

        if (it != req.headers.end()) {
            std::cout << "[CONTENT-TYPE] Request: " << it->second << std::endl;
        }

        // Set default response content type
        if (res.headers.find("Content-Type") == res.headers.end()) {
            res.headers["Content-Type"] = "application/json";
        }

        return true;
    }
};

// 7. Rate Limiting Middleware
class RateLimitMiddleware {
private:
    struct RequestCount {
        int count;
        std::chrono::system_clock::time_point resetTime;
    };

    std::map<std::string, RequestCount> requestCounts;
    int maxRequests;
    int windowSeconds;

public:
    RateLimitMiddleware(int max = 100, int window = 60)
        : maxRequests(max), windowSeconds(window) {}

    bool operator()(HttpRequest& req, HttpResponse& res) {
        // Get client identifier (IP address would be in real scenario)
        std::string clientId = req.headers["X-Client-ID"];
        if (clientId.empty()) {
            clientId = "unknown";
        }

        auto now = std::chrono::system_clock::now();
        auto it = requestCounts.find(clientId);

        if (it == requestCounts.end()) {
            // First request
            requestCounts[clientId] = {1, now + std::chrono::seconds(windowSeconds)};
            std::cout << "[RATE-LIMIT] " << clientId << ": 1/" << maxRequests << std::endl;
            return true;
        }

        // Check if window has expired
        if (now >= it->second.resetTime) {
            it->second.count = 1;
            it->second.resetTime = now + std::chrono::seconds(windowSeconds);
            std::cout << "[RATE-LIMIT] " << clientId << ": Window reset" << std::endl;
            return true;
        }

        // Increment count
        it->second.count++;

        if (it->second.count > maxRequests) {
            res.statusCode = 429;
            res.headers["Retry-After"] = std::to_string(windowSeconds);
            res.headers["X-RateLimit-Limit"] = std::to_string(maxRequests);
            res.headers["X-RateLimit-Remaining"] = "0";
            res.body = R"({"error": "Rate limit exceeded"})";
            res.headers["Content-Type"] = "application/json";
            std::cout << "[RATE-LIMIT] " << clientId << ": LIMIT EXCEEDED" << std::endl;
            return false;
        }

        int remaining = maxRequests - it->second.count;
        std::cout << "[RATE-LIMIT] " << clientId << ": " << it->second.count
                  << "/" << maxRequests << " (remaining: " << remaining << ")" << std::endl;

        res.headers["X-RateLimit-Limit"] = std::to_string(maxRequests);
        res.headers["X-RateLimit-Remaining"] = std::to_string(remaining);

        return true;
    }
};

// 8. Error Handling Middleware
class ErrorHandlingMiddleware {
public:
    bool operator()(HttpRequest& req, HttpResponse& res) {
        // This middleware wraps the handler to catch exceptions
        return true; // Always continue
    }

    void handleError(std::exception& e, HttpResponse& res) {
        res.statusCode = 500;
        res.body = R"({"error": ")" + std::string(e.what()) + R"("})";
        res.headers["Content-Type"] = "application/json";
        std::cout << "[ERROR] " << e.what() << std::endl;
    }
};

// 9. Compression Middleware
class CompressionMiddleware {
public:
    bool operator()(HttpRequest& req, HttpResponse& res) {
        // Check if client accepts compression
        auto it = req.headers.find("Accept-Encoding");

        if (it != req.headers.end()) {
            // Check for gzip support
            if (it->second.find("gzip") != std::string::npos) {
                res.headers["Content-Encoding"] = "gzip";
                std::cout << "[COMPRESSION] Gzip enabled" << std::endl;
                // In real implementation, compress response body here
            }
        }

        return true;
    }
};

// 10. Security Headers Middleware
class SecurityHeadersMiddleware {
public:
    bool operator()(HttpRequest& req, HttpResponse& res) {
        res.headers["X-Content-Type-Options"] = "nosniff";
        res.headers["X-Frame-Options"] = "DENY";
        res.headers["X-XSS-Protection"] = "1; mode=block";
        res.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
        res.headers["Content-Security-Policy"] = "default-src 'self'";

        std::cout << "[SECURITY] Security headers added" << std::endl;
        return true;
    }
};

// 11. Middleware Pipeline
class MiddlewarePipeline {
private:
    std::vector<MiddlewareFunc> middlewares;
    HandlerFunc finalHandler;

public:
    MiddlewarePipeline& use(MiddlewareFunc middleware) {
        middlewares.push_back(middleware);
        return *this;
    }

    void setHandler(HandlerFunc handler) {
        finalHandler = handler;
    }

    void process(HttpRequest& req, HttpResponse& res) {
        // Execute middlewares in sequence
        for (const auto& middleware : middlewares) {
            if (!middleware(req, res)) {
                // Middleware returned false, stop pipeline
                return;
            }
        }

        // All middlewares passed, execute final handler
        if (finalHandler) {
            finalHandler(req, res);
        }
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ HTTP Middleware Examples ===" << std::endl;

    // Create middlewares
    LoggingMiddleware logger;
    AuthMiddleware auth;
    CORSMiddleware cors;
    ContentTypeMiddleware contentType;
    RateLimitMiddleware rateLimiter(10, 60);
    CompressionMiddleware compression;
    SecurityHeadersMiddleware security;

    // 1. Basic Pipeline
    std::cout << "\n--- 1. Basic Pipeline ---" << std::endl;
    MiddlewarePipeline pipeline1;

    pipeline1.use(logger)
             .use(cors)
             .use(contentType)
             .setHandler([](HttpRequest& req, HttpResponse& res) {
                 res.body = R"({"message": "Hello, World!"})";
                 std::cout << "[HANDLER] Request processed" << std::endl;
             });

    HttpRequest req1{"GET", "/api/test", {{"X-Client-ID", "client1"}}};
    HttpResponse res1;

    pipeline1.process(req1, res1);
    std::cout << "Response: " << res1.statusCode << " - " << res1.body << std::endl;

    // 2. Authenticated Pipeline
    std::cout << "\n--- 2. Authenticated Pipeline ---" << std::endl;
    MiddlewarePipeline authPipeline;

    authPipeline.use(logger)
                .use(auth)
                .setHandler([](HttpRequest& req, HttpResponse& res) {
                    std::string user = req.headers["X-User"];
                    res.body = R"({"message": "Hello, )" + user + R"!("})";
                });

    HttpRequest authReq{"GET", "/api/profile", {{"Authorization", "Bearer abc123"}}};
    HttpResponse authRes;
    authPipeline.process(authReq, authRes);
    std::cout << "Response: " << authRes.statusCode << " - " << authRes.body << std::endl;

    // Failed auth
    HttpRequest invalidAuthReq{"GET", "/api/profile", {{"Authorization", "Bearer invalid"}}};
    HttpResponse invalidAuthRes;
    authPipeline.process(invalidAuthReq, invalidAuthRes);
    std::cout << "Response: " << invalidAuthRes.statusCode << " - " << invalidAuthRes.body << std::endl;

    // 3. Full Stack Pipeline
    std::cout << "\n--- 3. Full Stack Pipeline ---" << std::endl;
    MiddlewarePipeline fullPipeline;

    fullPipeline.use(security)
               .use(cors)
               .use(compression)
               .use(rateLimiter)
               .use(contentType)
               .setHandler([](HttpRequest& req, HttpResponse& res) {
                   res.body = R"({"status": "success", "data": {"id": 123}})";
               });

    HttpRequest apiReq{"GET", "/api/data", {{"X-Client-ID", "app1"}, {"Accept-Encoding", "gzip, deflate"}}};
    HttpResponse apiRes;

    fullPipeline.process(apiReq, apiRes);
    std::cout << "Response: " << apiRes.statusCode << std::endl;

    // 4. Rate Limiting Test
    std::cout << "\n--- 4. Rate Limiting Test ---" << std::endl;
    MiddlewarePipeline rateLimitPipeline;

    rateLimitPipeline.use(rateLimiter)
                    .setHandler([](HttpRequest& req, HttpResponse& res) {
                        res.body = R"({"message": "Request processed"})";
                    });

    for (int i = 1; i <= 15; i++) {
        HttpRequest rlReq{"GET", "/api/test", {{"X-Client-ID", "client2"}}};
        HttpResponse rlRes;
        rateLimitPipeline.process(rlReq, rlRes);

        if (rlRes.statusCode == 429) {
            std::cout << "Request " << i << ": Rate limited!" << std::endl;
            break;
        }
    }

    // Display logs
    logger.displayLogs();

    std::cout << "\n=== All HTTP Middleware Examples Completed ===" << std::endl;
    return 0;
}

💻 Servicio de Archivos Estáticos cpp

🟡 intermediate ⭐⭐⭐⭐

Servir archivos estáticos desde disco con detección de tipos MIME, encabezados de caché y soporte de solicitudes de rango

⏱️ 35 min 🏷️ cpp, web, static files, http, windows
Prerequisites: Intermediate C++, HTTP protocol, File I/O
// Windows C++ Static File Serving Examples
// Using Windows HTTP Server API

#include <iostream>
#include <string>
#include <map>
#include <fstream>
#include <sstream>
#include <windows.h>
#include <http.h>

#pragma comment(lib, "httpapi.lib")

// 1. MIME Type Detector
class MIMEDetector {
private:
    std::map<std::string, std::string> mimeTypes;

public:
    MIMEDetector() {
        // Text types
        mimeTypes[".html"] = "text/html";
        mimeTypes[".htm"] = "text/html";
        mimeTypes[".css"] = "text/css";
        mimeTypes[".js"] = "application/javascript";
        mimeTypes[".json"] = "application/json";
        mimeTypes[".xml"] = "application/xml";
        mimeTypes[".txt"] = "text/plain";
        mimeTypes[".md"] = "text/markdown";

        // Image types
        mimeTypes[".jpg"] = "image/jpeg";
        mimeTypes[".jpeg"] = "image/jpeg";
        mimeTypes[".png"] = "image/png";
        mimeTypes[".gif"] = "image/gif";
        mimeTypes[".svg"] = "image/svg+xml";
        mimeTypes[".ico"] = "image/x-icon";
        mimeTypes[".webp"] = "image/webp";
        mimeTypes[".bmp"] = "image/bmp";

        // Font types
        mimeTypes[".woff"] = "font/woff";
        mimeTypes[".woff2"] = "font/woff2";
        mimeTypes[".ttf"] = "font/ttf";
        mimeTypes[".eot"] = "application/vnd.ms-fontobject";

        // Video types
        mimeTypes[".mp4"] = "video/mp4";
        mimeTypes[".webm"] = "video/webm";
        mimeTypes[".avi"] = "video/x-msvideo";

        // Audio types
        mimeTypes[".mp3"] = "audio/mpeg";
        mimeTypes[".wav"] = "audio/wav";
        mimeTypes[".ogg"] = "audio/ogg";

        // Document types
        mimeTypes[".pdf"] = "application/pdf";
        mimeTypes[".doc"] = "application/msword";
        mimeTypes[".docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        mimeTypes[".xls"] = "application/vnd.ms-excel";
        mimeTypes[".xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        // Archive types
        mimeTypes[".zip"] = "application/zip";
        mimeTypes[".rar"] = "application/x-rar-compressed";
        mimeTypes[".tar"] = "application/x-tar";
        mimeTypes[".gz"] = "application/gzip";
    }

    std::string getMIMEType(const std::string& filePath) const {
        size_t dotPos = filePath.find_last_of('.');
        if (dotPos != std::string::npos) {
            std::string ext = filePath.substr(dotPos);
            auto it = mimeTypes.find(ext);
            if (it != mimeTypes.end()) {
                return it->second;
            }
        }
        return "application/octet-stream"; // Default MIME type
    }

    void addMIMEType(const std::string& extension, const std::string& mimeType) {
        mimeTypes[extension] = mimeType;
    }
};

// 2. File Information
struct FileInfo {
    std::string path;
    std::string name;
    size_t size;
    FILETIME lastModified;
    bool exists;
};

// 3. File Server
class StaticFileServer {
private:
    std::string rootDirectory;
    MIMEDetector mimeDetector;
    std::map<std::string, std::string> customHeaders;

public:
    StaticFileServer(const std::string& root) : rootDirectory(root) {
        // Set default headers
        customHeaders["Server"] = "CppFileServer/1.0";
        customHeaders["X-Content-Type-Options"] = "nosniff";
    }

    void setRootDirectory(const std::string& path) {
        rootDirectory = path;
    }

    void addHeader(const std::string& name, const std::string& value) {
        customHeaders[name] = value;
    }

    // Get file information
    FileInfo getFileInfo(const std::string& relativePath) {
        FileInfo info;
        std::string fullPath = rootDirectory + "\" + relativePath;

        DWORD attrs = GetFileAttributesA(fullPath.c_str());
        info.exists = (attrs != INVALID_FILE_ATTRIBUTES);

        if (info.exists) {
            info.path = fullPath;
            info.name = getFileName(fullPath);

            WIN32_FILE_ATTRIBUTE_DATA fileData;
            if (GetFileAttributesExA(fullPath.c_str(), GetFileExInfoStandard, &fileData)) {
                LARGE_INTEGER size;
                size.HighPart = fileData.nFileSizeHigh;
                size.LowPart = fileData.nFileSizeLow;
                info.size = static_cast<size_t>(size.QuadPart);
                info.lastModified = fileData.ftLastWriteTime;
            }
        }

        return info;
    }

    // Read file content
    std::vector<char> readFile(const std::string& path) {
        std::ifstream file(path, std::ios::binary);
        if (!file) {
            return {};
        }

        file.seekg(0, std::ios::end);
        size_t fileSize = file.tellg();
        file.seekg(0, std::ios::beg);

        std::vector<char> content(fileSize);
        file.read(content.data(), fileSize);

        return content;
    }

    // Generate ETag
    std::string generateETag(const FileInfo& info) {
        // Use file size and last modified time
        std::stringstream ss;
        ss << """ << info.size << "-";

        // Convert FILETIME to string
        ULARGE_INTEGER uli;
        uli.LowPart = info.lastModified.dwLowDateTime;
        uli.HighPart = info.lastModified.dwHighDateTime;

        ss << std::hex << uli.QuadPart << std::dec << """;
        return ss.str();
    }

    // Format file time to HTTP date
    std::string fileTimeToHTTPDate(const FILETIME& ft) {
        FileTimeToLocalFileTime(&ft, const_cast<FILETIME*>(&ft));

        SYSTEMTIME st;
        FileTimeToSystemTime(&ft, &st);

        char buffer[100];
        sprintf_s(buffer, "%s, %02d %s %04d %02d:%02d:%02d GMT",
            getDayName(st.wDayOfWeek).c_str(),
            st.wDay,
            getMonthName(st.wMonth).c_str(),
            st.wYear,
            st.wHour,
            st.wMinute,
            st.wSecond);

        return buffer;
    }

    // Serve static file
    struct FileResponse {
        int statusCode;
        std::map<std::string, std::string> headers;
        std::vector<char> body;
        std::string errorMessage;
    };

    FileResponse serveFile(const std::string& relativePath,
                           const std::string& ifNoneMatch = "",
                           const std::string& ifModifiedSince = "") {
        FileResponse response;
        response.statusCode = 200;

        // Security check - prevent directory traversal
        if (relativePath.find("..") != std::string::npos) {
            response.statusCode = 403;
            response.errorMessage = "Access denied";
            return response;
        }

        // Handle directory - look for index.html
        std::string requestPath = relativePath;
        if (requestPath.empty() || requestPath.back() == '/') {
            requestPath += "index.html";
        }

        FileInfo info = getFileInfo(requestPath);

        if (!info.exists) {
            response.statusCode = 404;
            response.errorMessage = "File not found";
            return response;
        }

        // Generate ETag
        std::string etag = generateETag(info);

        // Check ETag for conditional request
        if (!ifNoneMatch.empty() && ifNoneMatch == etag) {
            response.statusCode = 304; // Not Modified
            return response;
        }

        // Add headers
        response.headers["Content-Type"] = mimeDetector.getMIMEType(info.name);
        response.headers["Content-Length"] = std::to_string(info.size);
        response.headers["Last-Modified"] = fileTimeToHTTPDate(info.lastModified);
        response.headers["ETag"] = etag;
        response.headers["Cache-Control"] = "public, max-age=3600";

        // Add custom headers
        for (const auto& header : customHeaders) {
            response.headers[header.first] = header.second;
        }

        // Read file
        response.body = readFile(info.path);

        if (response.body.empty() && info.size > 0) {
            response.statusCode = 500;
            response.errorMessage = "Failed to read file";
        }

        return response;
    }

    // Serve with range support (for video streaming)
    FileResponse serveFileRange(const std::string& relativePath,
                                 size_t rangeStart, size_t rangeEnd) {
        FileResponse response;
        response.statusCode = 206; // Partial Content

        FileInfo info = getFileInfo(relativePath);
        if (!info.exists) {
            response.statusCode = 404;
            return response;
        }

        // Validate range
        if (rangeEnd >= info.size) {
            rangeEnd = info.size - 1;
        }

        size_t contentLength = rangeEnd - rangeStart + 1;

        // Add headers
        response.headers["Content-Type"] = mimeDetector.getMIMEType(info.name);
        response.headers["Content-Length"] = std::to_string(contentLength);
        response.headers["Content-Range"] = "bytes " + std::to_string(rangeStart) +
                                           "-" + std::to_string(rangeEnd) +
                                           "/" + std::to_string(info.size);
        response.headers["Accept-Ranges"] = "bytes";

        // Read partial file
        std::ifstream file(info.path, std::ios::binary);
        if (file) {
            file.seekg(rangeStart);
            response.body.resize(contentLength);
            file.read(response.body.data(), contentLength);
        }

        return response;
    }

    // List directory contents
    std::vector<std::string> listDirectory(const std::string& relativePath) {
        std::vector<std::string> entries;
        std::string fullPath = rootDirectory + "\" + relativePath;
        std::string searchPath = fullPath + "\*";

        WIN32_FIND_DATAA fd;
        HANDLE hFind = FindFirstFileA(searchPath.c_str(), &fd);

        if (hFind != INVALID_HANDLE_VALUE) {
            do {
                std::string name = fd.cFileName;
                if (name != "." && name != "..") {
                    entries.push_back(name);
                }
            } while (FindNextFileA(hFind, &fd));
            FindClose(hFind);
        }

        return entries;
    }

private:
    std::string getFileName(const std::string& path) {
        size_t pos = path.find_last_of("\/");
        if (pos != std::string::npos) {
            return path.substr(pos + 1);
        }
        return path;
    }

    std::string getDayName(int day) {
        static const char* days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return days[day];
    }

    std::string getMonthName(int month) {
        static const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return months[month - 1];
    }
};

// 4. Cache Control Manager
class CacheManager {
public:
    static std::string getCacheControl(const std::string& extension) {
        // Static assets - long cache
        if (extension == ".js" || extension == ".css" ||
            extension == ".png" || extension == ".jpg" ||
            extension == ".jpeg" || extension == ".gif" ||
            extension == ".svg" || extension == ".ico" ||
            extension == ".woff" || extension == ".woff2") {
            return "public, max-age=31536000, immutable";
        }

        // HTML files - shorter cache for updates
        if (extension == ".html" || extension == ".htm") {
            return "public, max-age=3600, must-revalidate";
        }

        // Default
        return "public, max-age=86400";
    }
};

// 5. Gzip Compression Support
class CompressionHandler {
public:
    static bool shouldCompress(const std::string& mimeType) {
        // Compress text-based content
        return mimeType.find("text/") == 0 ||
               mimeType == "application/javascript" ||
               mimeType == "application/json" ||
               mimeType == "application/xml";
    }

    static std::vector<char> compressGzip(const std::vector<char>& data) {
        // In real implementation, use zlib or similar
        // This is a placeholder
        std::cout << "[COMPRESSION] Gzip compression enabled" << std::endl;
        return data; // Return uncompressed for demo
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ Static File Serving Examples ===" << std::endl;

    StaticFileServer server("./public");

    // 1. Basic file serving
    std::cout << "\n--- 1. Basic File Serving ---" << std::endl;

    auto response1 = server.serveFile("index.html");
    std::cout << "File: index.html" << std::endl;
    std::cout << "Status: " << response1.statusCode << std::endl;
    if (response1.statusCode == 200) {
        std::cout << "Content-Type: " << response1.headers["Content-Type"] << std::endl;
        std::cout << "Content-Length: " << response1.headers["Content-Length"] << std::endl;
        std::cout << "ETag: " << response1.headers["ETag"] << std::endl;
    } else {
        std::cout << "Error: " << response1.errorMessage << std::endl;
    }

    // 2. MIME type detection
    std::cout << "\n--- 2. MIME Type Detection ---" << std::endl;
    MIMEDetector detector;

    std::vector<std::string> testFiles = {
        "index.html", "style.css", "app.js", "image.png",
        "photo.jpg", "data.json", "font.woff2", "video.mp4"
    };

    for (const auto& file : testFiles) {
        std::cout << file << " -> " << detector.getMIMEType(file) << std::endl;
    }

    // 3. Cache control
    std::cout << "\n--- 3. Cache Control Headers ---" << std::endl;
    std::cout << ".js files: " << CacheManager::getCacheControl(".js") << std::endl;
    std::cout << ".css files: " << CacheManager::getCacheControl(".css") << std::endl;
    std::cout << ".html files: " << CacheManager::getCacheControl(".html") << std::endl;
    std::cout << ".png files: " << CacheManager::getCacheControl(".png") << std::endl;

    // 4. Range requests
    std::cout << "\n--- 4. Range Request Support ---" << std::endl;
    auto rangeResponse = server.serveFileRange("video.mp4", 0, 1023);
    std::cout << "Range: bytes 0-1023/..." << std::endl;
    std::cout << "Status: " << rangeResponse.statusCode << std::endl;
    std::cout << "Content-Range: " << rangeResponse.headers["Content-Range"] << std::endl;

    // 5. ETag validation
    std::cout << "\n--- 5. ETag Validation ---" << std::endl;
    auto fileResponse = server.serveFile("index.html");
    std::string etag = fileResponse.headers["ETag"];
    std::cout << "Generated ETag: " << etag << std::endl;

    // Simulate conditional request
    auto cachedResponse = server.serveFile("index.html", etag);
    std::cout << "Conditional request status: " << cachedResponse.statusCode << " (304 = Not Modified)" << std::endl;

    // 6. Directory listing
    std::cout << "\n--- 6. Directory Listing ---" << std::endl;
    auto entries = server.listDirectory(".");
    std::cout << "Files in root directory:" << std::endl;
    for (const auto& entry : entries) {
        std::cout << "  - " << entry << std::endl;
    }

    // 7. Custom headers
    std::cout << "\n--- 7. Custom Headers ---" << std::endl;
    server.addHeader("X-Frame-Options", "DENY");
    server.addHeader("X-XSS-Protection", "1; mode=block");

    auto headerResponse = server.serveFile("page.html");
    std::cout << "Response headers for page.html:" << std::endl;
    for (const auto& header : headerResponse.headers) {
        std::cout << "  " << header.first << ": " << header.second << std::endl;
    }

    // 8. Compression check
    std::cout << "\n--- 8. Compression ---" << std::endl;
    std::vector<std::string> mimeTypes = {
        "text/html", "application/json", "image/png", "video/mp4"
    };

    for (const auto& mime : mimeTypes) {
        bool shouldCompress = CompressionHandler::shouldCompress(mime);
        std::cout << mime << " - Compress: " << (shouldCompress ? "Yes" : "No") << std::endl;
    }

    std::cout << "\n=== All Static File Serving Examples Completed ===" << std::endl;
    return 0;
}