diff options
Diffstat (limited to 'plugins/static-files/static-files.cpp')
-rw-r--r-- | plugins/static-files/static-files.cpp | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/plugins/static-files/static-files.cpp b/plugins/static-files/static-files.cpp index 358e239..ad85f22 100644 --- a/plugins/static-files/static-files.cpp +++ b/plugins/static-files/static-files.cpp @@ -1,8 +1,49 @@ #include "static-files.h" +#include <filesystem> +#include <fstream> #include <iostream> +#include <string> 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<char*>(bytes.data()), fileSize); + + return bytes; + + } else { + throw std::runtime_error("Opening "s + filename.string() + " for reading"); + } +} + +std::string extend_index_html(std::string path) +{ + if (path.size() == 0 || (path.size() && path.back() == '/')) + path.append("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<plugin_interface_setter_type>& SetResponseHeader) +{ + SetResponseHeader("status", status); + SetResponseHeader("content_type", "text/html"); + return status + " " + message; +} + +} std::string static_files_plugin::name() { @@ -26,9 +67,32 @@ std::string static_files_plugin::generate_page( ) { try { - return "Static Files "s + GetServerParam("path"s); + // Make sure we can handle the method + std::string method {GetRequestParam("method")}; + if (method != "GET" && method != "HEAD") + return HttpStatus("400", "Unknown HTTP method", SetResponseHeader); + + // Request path must be absolute and not contain "..". + std::string rel_target{GetRequestParam("rel_target")}; + if (rel_target.find("..") != std::string::npos) { + std::string target{GetRequestParam("target")}; + return HttpStatus("400", "Illegal request: "s + target, SetResponseHeader); + } + + // Build the path to the requested file + std::string doc_root{GetRequestParam("doc_root")}; + std::string path {fs::path{doc_root} / extend_index_html(rel_target)}; + + try { + return getFile(path); + } catch (const std::runtime_error& ex) { + return HttpStatus("404", "Not found: "s + GetRequestParam("target"), SetResponseHeader); + } catch (const std::exception& ex) { + return HttpStatus("500", "Internal Server Error: "s + ex.what(), SetResponseHeader); + } + } catch (const std::exception& ex) { - return "Error: "s + ex.what(); + return HttpStatus("500", "Unknown Error: "s + ex.what(), SetResponseHeader); } } |