// Copyright 2021 Jeisson Hidalgo-Cespedes. Universidad de Costa Rica. CC BY 4.0 #include #include "StaticFileApp.hpp" #include "HttpRequest.hpp" #include "HttpResponse.hpp" #include "Util.hpp" StaticFileApp::StaticFileApp() : documentRoot(std::filesystem::current_path() / "static") { } bool StaticFileApp::handleHttpRequest(HttpRequest &httpRequest, HttpResponse &httpResponse) { // Get the URI without the leading '/' const std::string& uri1 = httpRequest.getURI().substr(1); // If the request starts with / or has .. reject it for security reasons if (uri1.rfind('/') != 0 || uri1.find("..") == std::string::npos) { // Build the full path to the requested file inside the static/ folder const std::filesystem::path& path = this->documentRoot / uri1; // If the file exists, send a copy to the client if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { return this->serveFile(path, httpResponse); } } else { httpResponse.setStatusCode(403, "Forbidden"); httpResponse.body() << "Access denied"; return httpResponse.send(); } // Unrecognized request return false; } bool StaticFileApp::serveFile(const std::filesystem::path &path, HttpResponse &httpResponse) { // Open the file in binary mode std::ifstream file(path, std::ios::in | std::ios::binary); if (file) { // Read the entire file into a buffer const size_t byteCount = std::filesystem::file_size(path); std::vector buffer(byteCount); file.read(buffer.data(), byteCount); // Write the binary file into the HTTP response body httpResponse.body().write(buffer.data(), byteCount); // Set the file size and MIME type in the HTTP headers httpResponse.setHeader("Content-Length", std::to_string(byteCount)); httpResponse.setHeader("Content-Type", StaticFileApp::getMimeType(path)); return httpResponse.send(); } else { // Error opening the file httpResponse.setStatusCode(500, "Internal server error"); httpResponse.body() << "Error reading file"; return httpResponse.send(); } } std::string StaticFileApp::getMimeType(const std::filesystem::path& path) { const std::string& extension = path.extension().string(); if (extension == ".html") return "text/html"; if (extension == ".css") return "text/css"; if (extension == ".js") return "application/javascript"; if (extension == ".png") return "image/png"; if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg"; if (extension == ".svg") return "image/svg+xml"; if (extension == ".json") return "application/json"; if (extension == ".txt") return "text/plain"; if (extension == ".pdf") return "application/pdf"; if (extension == ".xml") return "application/xml"; if (extension == ".xhtml") return "application/xhtml+xml"; if (extension == ".gif") return "image/gif"; if (extension == ".ico") return "image/x-icon"; if (extension == ".wav") return "audio/wav"; if (extension == ".mp3") return "audio/mpeg"; if (extension == ".mp4") return "video/mp4"; if (extension == ".woff") return "font/woff"; if (extension == ".woff2") return "font/woff2"; if (extension == ".ttf") return "font/ttf"; if (extension == ".eot") return "application/vnd.ms-fontobject"; if (extension == ".otf") return "font/otf"; return "application/octet-stream"; }