#include "static-files.h" #include "libcommon/mime.h" #include "libcommon/url.h" #include #include #include #include #include using namespace std::string_literals; namespace fs = std::filesystem; namespace { std::string getFile(const fs::path& filename) { std::ifstream file(filename.string(), std::ios::in | std::ios::binary | std::ios::ate); if (file.is_open()) { std::ifstream::pos_type fileSize = file.tellg(); file.seekg(0, std::ios::beg); std::string bytes(fileSize, ' '); file.read(reinterpret_cast(bytes.data()), fileSize); return bytes; } else { throw std::runtime_error("Opening "s + filename.string() + " for reading"); } } fs::path extend_index_html(fs::path path) { if (path.string().size() == 0 || path.string().back() == '/') return path / "index.html"; return path; } // Used to return errors by generating response page and HTTP status code std::string HttpStatus(std::string status, std::string message, std::function& SetResponseHeader) { SetResponseHeader("status", status); SetResponseHeader("content_type", "text/html"); return status + " " + message; } } std::string static_files_plugin::name() { return "static-files"; } static_files_plugin::static_files_plugin() { //std::cout << "Plugin constructor" << std::endl; } static_files_plugin::~static_files_plugin() { //std::cout << "Plugin destructor" << std::endl; } std::string static_files_plugin::generate_page( std::function& GetServerParam, std::function& GetRequestParam, // request including body (POST...) std::function& SetResponseHeader // to be added to result string ) { try { // Make sure we can handle the method std::string method {GetRequestParam("method")}; if (method != "GET" && method != "HEAD") return HttpStatus("400", "Unknown HTTP method", SetResponseHeader); std::string target{GetRequestParam("target")}; size_t pos{target.find('?')}; if (pos != target.npos) target = target.substr(0, pos); std::string rel_target{urlDecode(GetRequestParam("rel_target"))}; pos = rel_target.find('?'); if (pos != rel_target.npos) rel_target = rel_target.substr(0, pos); // Request path must not contain "..". if (rel_target.find("..") != std::string::npos) { return HttpStatus("400", "Illegal request: "s + target, SetResponseHeader); } // Build the path to the requested file std::string doc_root{GetRequestParam("doc_root")}; fs::path path {fs::path{doc_root} / rel_target}; if (target.size() && target.back() != '/' && fs::is_directory(path)) { std::string location{GetRequestParam("location") + "/"s}; SetResponseHeader("location", location); return HttpStatus("301", "Correcting directory path", SetResponseHeader); } path = {extend_index_html(path)}; SetResponseHeader("content_type", mime_type(path.string())); try { return getFile(path); } catch (const std::runtime_error& ex) { return HttpStatus("404", "Not found: "s + target, SetResponseHeader); } catch (const std::exception& ex) { return HttpStatus("500", "Internal Server Error: "s + ex.what(), SetResponseHeader); } } catch (const std::exception& ex) { return HttpStatus("500", "Unknown Error: "s + ex.what(), SetResponseHeader); } } bool static_files_plugin::has_own_authentication() { return false; }