#include "weblog.h" #include #include #include #include #include using namespace std::string_literals; namespace fs = std::filesystem; namespace { // Return a reasonable mime type based on the extension of a file. std::string mime_type(fs::path path) { using boost::algorithm::iequals; auto const ext = [&path] { size_t pos = path.string().rfind("."); if (pos == std::string::npos) return std::string{}; return path.string().substr(pos); }(); if(iequals(ext, ".htm")) return "text/html"; // TODO: unordered_map if(iequals(ext, ".html")) return "text/html"; if(iequals(ext, ".php")) return "text/html"; if(iequals(ext, ".css")) return "text/css"; if(iequals(ext, ".txt")) return "text/plain"; if(iequals(ext, ".js")) return "application/javascript"; if(iequals(ext, ".json")) return "application/json"; if(iequals(ext, ".xml")) return "application/xml"; if(iequals(ext, ".swf")) return "application/x-shockwave-flash"; if(iequals(ext, ".flv")) return "video/x-flv"; if(iequals(ext, ".png")) return "image/png"; if(iequals(ext, ".jpe")) return "image/jpeg"; if(iequals(ext, ".jpeg")) return "image/jpeg"; if(iequals(ext, ".jpg")) return "image/jpeg"; if(iequals(ext, ".gif")) return "image/gif"; if(iequals(ext, ".bmp")) return "image/bmp"; if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon"; if(iequals(ext, ".tiff")) return "image/tiff"; if(iequals(ext, ".tif")) return "image/tiff"; if(iequals(ext, ".svg")) return "image/svg+xml"; if(iequals(ext, ".svgz")) return "image/svg+xml"; return "application/text"; } 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"); } } bool is_index_page(std::string& path) { return (path.size() == 0 || path.back() == '/'); } std::string generateIndexPage(std::function& SetResponseHeader) { return "

Blog

"; } // 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 weblog_plugin::name() { return "weblog"; } weblog_plugin::weblog_plugin() { //std::cout << "Plugin constructor" << std::endl; } weblog_plugin::~weblog_plugin() { //std::cout << "Plugin destructor" << std::endl; } std::string weblog_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); // Request path must not contain "..". std::string rel_target{GetRequestParam("rel_target")}; std::string target{GetRequestParam("target")}; 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); } SetResponseHeader("content_type", "text/html"); if (is_index_page(rel_target)) return generateIndexPage(SetResponseHeader); return HttpStatus("404", "Bad path specification: "s + rel_target, SetResponseHeader); } catch (const std::exception& ex) { return HttpStatus("500", "Unknown Error: "s + ex.what(), SetResponseHeader); } }