From c0ccf16c69d43a89674640c61d13ec2c02b128d6 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 10 Apr 2020 15:36:59 +0200 Subject: First working plugin: static-files --- plugins/static-files/static-files.cpp | 68 +++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) (limited to 'plugins') 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 +#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"); + } +} + +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& 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); } } -- cgit v1.2.3