From 5b32a4415c9776dd6cae859c8d718b5e68f01d81 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 10 May 2020 16:51:20 +0200 Subject: Move webbox to root to make index --- README.txt | 7 ---- plugins/fcgi/fcgi.cpp | 11 ----- plugins/webbox/html/index.html | 9 ++-- plugins/webbox/html/webbox.js | 33 +++++++++------ plugins/webbox/webbox.cpp | 94 +++++++++++++++++++++++++++++++++++++++++- webserver.conf | 12 ++++-- 6 files changed, 125 insertions(+), 41 deletions(-) diff --git a/README.txt b/README.txt index d8783af..66d4168 100644 --- a/README.txt +++ b/README.txt @@ -172,16 +172,9 @@ Configuration example: Plugin: webbox ~~~~~~~~~~~~~~ -This plugin needs a combination of static-files (for statically served parts) -and webbox plugins (for dynamic contents). - Configuration example: - static-files - /usr/lib/webbox/html - - webbox /home/rr/testbox Testbox1 diff --git a/plugins/fcgi/fcgi.cpp b/plugins/fcgi/fcgi.cpp index f9d8a4d..a97f1c0 100644 --- a/plugins/fcgi/fcgi.cpp +++ b/plugins/fcgi/fcgi.cpp @@ -314,16 +314,6 @@ namespace { return status + " " + message; } - void DumpAppValues(const std::unordered_map& app_values) - { - std::cout << "App properties:" << std::endl; - if (app_values.size() == 0) - std::cout << " (empty)" << std::endl; - else for (auto&[key, value]: app_values) { - std::cout << " " << key << "=" << value << std::endl; - } - } - } // anonymous namespace std::string fcgi_plugin::fcgiQuery(FCGIContext& context) @@ -448,7 +438,6 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context) std::cerr << "FCGI STDERR: " << r.getContent() << std::endl; } else if (r.getType() == FCGI_GET_VALUES_RESULT) { FCGI_DecodeEnv(r.getContent(), app_values); - //DumpAppValues(app_values); } else throw std::runtime_error("Unhandled FCGI type: "s + std::to_string(r.getType())); } catch (const std::length_error& ex) { diff --git a/plugins/webbox/html/index.html b/plugins/webbox/html/index.html index e9ea819..cc1cf12 100644 --- a/plugins/webbox/html/index.html +++ b/plugins/webbox/html/index.html @@ -4,22 +4,23 @@ Webbox - - + + +
- +
Webbox
- +
diff --git a/plugins/webbox/html/webbox.js b/plugins/webbox/html/webbox.js index 9a38051..602f76d 100644 --- a/plugins/webbox/html/webbox.js +++ b/plugins/webbox/html/webbox.js @@ -4,6 +4,13 @@ var numberOfSelectedRows = 0; var username = "notaname"; var password = "password"; +function relativePath(path) { + if (path.startsWith("/")) + return path.substr(1); + else + return path; +} + function clearContents() { var result = ""; // empty list @@ -35,9 +42,9 @@ function loadContents(dir) { for (var i = 0; i < listElements.length; i++) { var type = listElements[i].getAttribute("type"); if (type == "file") { - type = ""; + type = ""; } else if (type == "dir") { - type = ""; + type = ""; } else { type = ""; } @@ -57,7 +64,7 @@ function loadContents(dir) { } - xhr.open("GET", "bin" + dir + "?command=list", true); + xhr.open("GET", relativePath(dir) + "?command=list", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(); } @@ -329,7 +336,7 @@ function initMainpage() { initMainpage2(); } - xhrTitle.open("GET", "bin?command=server-info", true); + xhrTitle.open("GET", "?command=server-info", true); xhrTitle.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhrTitle.send(); @@ -350,7 +357,7 @@ function initMainpage2() { document.getElementsByClassName("footer")[0].innerHTML = xhrFooter.responseText; } - xhrFooter.open("GET", "bin?command=version", true); + xhrFooter.open("GET", "?command=version", true); xhrFooter.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhrFooter.send(); @@ -431,7 +438,7 @@ function download(filename) { filesElement.appendChild(fileElement); } - xhr.open("POST", "bin" + currentDir + "?command=download-zip", true); + xhr.open("POST", relativePath(currentDir) + "?command=download-zip", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.responseType = 'blob'; @@ -458,7 +465,7 @@ function download(filename) { dir += "/" } progressOn(); - xhr.open("GET", "bin" + dir + filename, true); + xhr.open("GET", relativePath(dir) + filename, true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.responseType = 'blob'; xhr.send(); @@ -493,7 +500,7 @@ function createDir() { dirElement.appendChild(document.createTextNode(document.getElementById("newdir").value)); - xhr.open("POST", "bin" + currentDir + "?command=newdir", true); + xhr.open("POST", relativePath(currentDir) + "?command=newdir", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -557,7 +564,7 @@ function onUploadFile() { formData.append("uploadfile", uploadfile.files[i]); } - xhr.open("POST", "bin" + currentDir + "?command=upload", true); + xhr.open("POST", relativePath(currentDir) + "?command=upload", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(formData); } @@ -607,7 +614,7 @@ function deleteItems() { filesElement.appendChild(fileElement); } - xhr.open("POST", "bin" + currentDir + "?command=delete", true); + xhr.open("POST", relativePath(currentDir) + "?command=delete", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -672,7 +679,7 @@ function move() { filesElement.appendChild(fileElement); } - xhr.open("POST", "bin" + currentDir + "?command=move", true); + xhr.open("POST", relativePath(currentDir) + "?command=move", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -736,7 +743,7 @@ function rename() { newnameElement.appendChild(document.createTextNode(document.getElementById("renamenew").value)); filesElement.appendChild(newnameElement); - xhr.open("POST", "bin" + currentDir + "?command=rename", true); + xhr.open("POST", relativePath(currentDir) + "?command=rename", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -784,7 +791,7 @@ function info() { filesElement.appendChild(fileElement); } - xhr.open("POST", "bin" + currentDir + "?command=info", true); + xhr.open("POST", relativePath(currentDir) + "?command=info", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); diff --git a/plugins/webbox/webbox.cpp b/plugins/webbox/webbox.cpp index 7d15ee9..c58bd0c 100644 --- a/plugins/webbox/webbox.cpp +++ b/plugins/webbox/webbox.cpp @@ -30,6 +30,11 @@ namespace { static const std::string PROGRAMVERSION{"Webbox 2.0"}; static const std::string DOWNLOAD_FILENAME{"webbox-download.zip"}; + // STATIC_HTML_TARGET: no leading slash because comparision is done with relative path; + // trailing slash because of path comparison + static const std::string STATIC_HTML_TARGET{"webbox-html/"}; + static const fs::path STATIC_HTML_DOC_ROOT{"/usr/lib/webbox/html"}; + // TODO: separate out class Tempfile { @@ -109,6 +114,8 @@ namespace { result[urlDecode(i.substr(0, pos))] = urlDecode(i.substr(pos + 1)); } } + } else if (s == "/" || s == "" || boost::algorithm::starts_with(s, STATIC_HTML_TARGET)) { + result["command"] = "static-html"; } return result; @@ -125,6 +132,7 @@ namespace { std::string webboxPath; std::string webboxName; bool webboxReadOnly; + fs::path webboxStaticHtml; CommandParameters( std::function& GetServerParam, @@ -138,7 +146,10 @@ namespace { , webboxPath(m_GetRequestParam("doc_root")) , webboxName(m_GetRequestParam("WEBBOX_NAME")) , webboxReadOnly(m_GetRequestParam("WEBBOX_READONLY") == "1") + , webboxStaticHtml(m_GetRequestParam("WEBBOX_STATIC_HTML")) { + if (webboxStaticHtml == "") + webboxStaticHtml = STATIC_HTML_DOC_ROOT; } }; @@ -780,7 +791,83 @@ protected: return result; } catch (const std::exception& ex) { - return HttpStatus("500", "Bad file: "s + m_path.filename().string(), p); + return HttpStatus("404", "Bad file: "s + m_path.filename().string(), p); + } + } +}; + +// Return a reasonable mime type based on the extension of a file. +static 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"; +} + +class StaticHtmlCommand: public GetCommand +{ +public: + StaticHtmlCommand() + { + m_commandName = "static-html"; + m_isWriteCommand = false; + } + +protected: + virtual std::string start(CommandParameters& p) + { + // redirect to xyz/ if xyz was requested + std::string target = p.m_GetRequestParam("target"); + if (m_pathInfo == "" && !target.empty() && target.back() != '/') { + p.m_SetResponseHeader("location", target + "/"); + return HttpStatus("301", "Use correct index: /"s, p); + } + + try { + + fs::path file_path; + if (m_pathInfo == "/" || m_pathInfo == "") { + file_path = p.webboxStaticHtml / "index.html"; + } else if (boost::algorithm::starts_with(m_pathInfo, STATIC_HTML_TARGET)) { + file_path = p.webboxStaticHtml / m_pathInfo.substr(STATIC_HTML_TARGET.size()); + } else { + return HttpStatus("500", "Bad request: "s + m_pathInfo, p); + } + + p.m_SetResponseHeader("content_type", mime_type(file_path)); + std::string result{File::getFile(file_path)}; + return result; + + } catch (const std::exception& ex) { + return HttpStatus("500", "Server error: "s + m_pathInfo, p); } } }; @@ -805,6 +892,7 @@ webbox_plugin::webbox_plugin() registerCommand(std::make_shared()); registerCommand(std::make_shared()); registerCommand(std::make_shared()); + registerCommand(std::make_shared()); } webbox_plugin::~webbox_plugin() @@ -818,8 +906,10 @@ std::string webbox_plugin::generate_page( std::function& SetResponseHeader // to be added to result string ) { - CommandParameters commandParameters(GetServerParam, GetRequestParam, SetResponseHeader); + // Queries under STATIC_HTML_TARGET will be served statically from STATIC_HTML_DOC_ROOT + CommandParameters commandParameters(GetServerParam, GetRequestParam, SetResponseHeader); + std::string commandName; auto it {commandParameters.paramHash.find("command")}; diff --git a/webserver.conf b/webserver.conf index efc1a69..4901578 100644 --- a/webserver.conf +++ b/webserver.conf @@ -23,16 +23,20 @@ - static-files - /home/ernie/code/webserver/plugins/webbox/html - - webbox /home/ernie/testbox Testbox1 0 + /home/ernie/code/webserver/plugins/webbox/html + + webbox + /home/ernie/testbox + Testbox1 + 1 + /home/ernie/code/webserver/plugins/webbox/html + weblog /home/ernie/testblog -- cgit v1.2.3