From def52539028cb024b4e9e9767796face08d645f6 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Thu, 14 May 2020 18:21:04 +0200 Subject: Webbox: Support subdirectory via URL. This makes webbox viable as index page --- TODO | 6 ++++ debian/changelog | 2 +- plugins/webbox/TODO | 14 --------- plugins/webbox/html/webbox.js | 69 ++++++++++++++++++++++++++++++------------- plugins/webbox/webbox.cpp | 31 +++++++++++++------ 5 files changed, 77 insertions(+), 45 deletions(-) delete mode 100644 plugins/webbox/TODO diff --git a/TODO b/TODO index 3142cf9..584b690 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,9 @@ Speed up config.GetPath weblog: link consistency check (cron?) Integrate into Debian: WNPP support alternative SSL libs: mbedtls, gnutls, wolfssl, botan, (matrixssl, libressl, cryptlib: not in debian) +webbox: gallery +webbox: google pagespeed insights https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.kneipenband.com%2Fwebbox%2F&tab=mobile +webbox: chromecast +webbox: player +webbox: i18n +webbox: list: more info if appropriate, number of files, limit(?) diff --git a/debian/changelog b/debian/changelog index 2c671ff..77207a7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,7 +4,7 @@ webserver (1.5) unstable; urgency=medium * Bugfix: Path matching * Minor fixes - -- Roland Reichwein Fri, 08 May 2020 11:39:09 +0200 + -- Roland Reichwein Thu, 14 May 2020 18:20:34 +0200 webserver (1.4) unstable; urgency=medium diff --git a/plugins/webbox/TODO b/plugins/webbox/TODO deleted file mode 100644 index 2ce1274..0000000 --- a/plugins/webbox/TODO +++ /dev/null @@ -1,14 +0,0 @@ -Prio 1 (for next version) -====== - -provide index for nested directories, also if requested via url -gallery - -Prio 2 (for future versions) -====== - -google pagespeed insights https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.kneipenband.com%2Fwebbox%2F&tab=mobile -chromecast -player -i18n -list: more info if appropriate, number of files, limit(?) diff --git a/plugins/webbox/html/webbox.js b/plugins/webbox/html/webbox.js index f1c01f5..b262f6f 100644 --- a/plugins/webbox/html/webbox.js +++ b/plugins/webbox/html/webbox.js @@ -1,4 +1,5 @@ var currentDir = "/"; +var rootDir = "/"; var listElements; var numberOfSelectedRows = 0; var username = "notaname"; @@ -11,6 +12,24 @@ function relativePath(path) { return path; } +function absolutePath(path) { + var result = rootDir + "/" + relativePath(path); + + if (rootDir.startsWith("//")) { + rootDir = rootDir.substr(1); + } + + if (rootDir != "/" && rootDir.endsWith("/")) { + rootDir = rootDir.substr(0, rootDir.length - 1); + } + + return result; +} + +function setRootDir(dir) { + rootDir = dir; +} + function clearContents() { var result = ""; // empty list @@ -50,15 +69,10 @@ function loadContents(dir) { full_path = full_path.substr(1); } - // make relative path - while (full_path.substr(0, 1) == "/") { - full_path = full_path.substr(1); - } - var name_td; if (type == "file") { type = ""; - name_td = ""; + name_td = ""; } else if (type == "dir") { type = ""; name_td = ""; @@ -87,7 +101,7 @@ function loadContents(dir) { } - xhr.open("GET", relativePath(dir) + "?command=list", true); + xhr.open("GET", absolutePath(dir) + "?command=list", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(); } @@ -337,6 +351,12 @@ function initMainpage() { var readOnly = serverInfo.getElementsByTagName("readonly")[0].textContent; prepareReadOnly(readOnly); + var rootDir = serverInfo.getElementsByTagName("rootdir")[0].textContent; + setRootDir(rootDir); + + // fill file list initially + setCurrentDir(serverInfo.getElementsByTagName("currentdir")[0].textContent); + // if successful: continue loading initMainpage2(); } @@ -349,8 +369,6 @@ function initMainpage() { // deferred initialization after successful login function initMainpage2() { - // fill file list initially - setCurrentDir("/"); // load footer var xhrFooter = new XMLHttpRequest(); @@ -404,6 +422,13 @@ function addDirectoryLinks(path) { } function setCurrentDir(newDir) { + if (newDir.endsWith("/")) { + newDir = newDir.substr(0, newDir.length - 1); + } + if (!newDir.startsWith("/")) { + newDir = "/" + newDir; + } + currentDir = newDir; loadContents(newDir); @@ -462,7 +487,7 @@ function download(filename) { filesElement.appendChild(fileElement); } - xhr.open("POST", relativePath(currentDir) + "?command=download-zip", true); + xhr.open("POST", absolutePath(currentDir) + "?command=download-zip", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.responseType = 'blob'; @@ -489,7 +514,7 @@ function download(filename) { dir += "/" } progressOn(); - xhr.open("GET", relativePath(dir) + filename, true); + xhr.open("GET", absolutePath(dir) + filename, true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.responseType = 'blob'; xhr.send(); @@ -524,7 +549,7 @@ function createDir() { dirElement.appendChild(document.createTextNode(document.getElementById("newdir").value)); - xhr.open("POST", relativePath(currentDir) + "?command=newdir", true); + xhr.open("POST", absolutePath(currentDir) + "?command=newdir", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -588,7 +613,7 @@ function onUploadFile() { formData.append("uploadfile", uploadfile.files[i]); } - xhr.open("POST", relativePath(currentDir) + "?command=upload", true); + xhr.open("POST", absolutePath(currentDir) + "?command=upload", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.send(formData); } @@ -638,7 +663,7 @@ function deleteItems() { filesElement.appendChild(fileElement); } - xhr.open("POST", relativePath(currentDir) + "?command=delete", true); + xhr.open("POST", absolutePath(currentDir) + "?command=delete", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -703,7 +728,7 @@ function copy() { filesElement.appendChild(fileElement); } - xhr.open("POST", relativePath(currentDir) + "?command=copy", true); + xhr.open("POST", absolutePath(currentDir) + "?command=copy", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -768,7 +793,7 @@ function move() { filesElement.appendChild(fileElement); } - xhr.open("POST", relativePath(currentDir) + "?command=move", true); + xhr.open("POST", absolutePath(currentDir) + "?command=move", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -832,7 +857,7 @@ function rename() { newnameElement.appendChild(document.createTextNode(document.getElementById("renamenew").value)); filesElement.appendChild(newnameElement); - xhr.open("POST", relativePath(currentDir) + "?command=rename", true); + xhr.open("POST", absolutePath(currentDir) + "?command=rename", true); xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); xhr.setRequestHeader("Content-type", "text/xml"); xhr.send(xmlDocument); @@ -878,12 +903,14 @@ function info() { var filesElement = xmlDocument.getElementsByTagName("files")[0]; for (var i = 0; i < files.length; i++) { - var fileElement = xmlDocument.createElement("file"); - fileElement.appendChild(document.createTextNode(files[i])); - filesElement.appendChild(fileElement); + if (files[i] != "..") { + var fileElement = xmlDocument.createElement("file"); + fileElement.appendChild(document.createTextNode(files[i])); + filesElement.appendChild(fileElement); + } } - xhr.open("POST", relativePath(currentDir) + "?command=info", true); + xhr.open("POST", absolutePath(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 4abb2bf..09ac7c5 100644 --- a/plugins/webbox/webbox.cpp +++ b/plugins/webbox/webbox.cpp @@ -32,7 +32,7 @@ namespace { static const std::string DOWNLOAD_FILENAME{"webbox-download.zip"}; - // STATIC_HTML_TARGET: no leading slash because comparision is done with relative path; + // STATIC_HTML_TARGET: no leading slash because comparison 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"}; @@ -75,7 +75,7 @@ namespace { return result; } - std::unordered_map ParseQueryString(std::string s) + std::unordered_map ParseQueryString(const std::string& s, const std::string& webboxPath) { std::unordered_map result; @@ -88,7 +88,10 @@ namespace { result[urlDecode(i.substr(0, pos))] = urlDecode(i.substr(pos + 1)); } } - } else if (s == "/" || s == "" || boost::algorithm::starts_with(s, STATIC_HTML_TARGET)) { + } else if (s.empty() || s.back() == '/' || boost::algorithm::starts_with(s, STATIC_HTML_TARGET) || + boost::algorithm::contains(s, "/"s + STATIC_HTML_TARGET) || + (s.back() != '/' && fs::exists(webboxPath + "/" + s) && fs::is_directory(webboxPath + "/" + s))) + { result["command"] = "static-html"; } @@ -104,12 +107,13 @@ namespace { std::string m_pathInfo; // path inside webbox, derived from request fs::path m_path; // local filesystem path - std::unordered_map paramHash; - std::string webboxPath; std::string webboxName; bool webboxReadOnly; fs::path webboxStaticHtml; + std::string m_rootdir; + + std::unordered_map paramHash; CommandParameters( std::function& GetServerParam, @@ -119,11 +123,12 @@ namespace { : m_GetServerParam(GetServerParam) , m_GetRequestParam(GetRequestParam) , m_SetResponseHeader(SetResponseHeader) - , paramHash(ParseQueryString(GetRequestParam("rel_target"))) // rel_target contains query string , webboxPath(m_GetRequestParam("doc_root")) , webboxName(m_GetRequestParam("WEBBOX_NAME")) , webboxReadOnly(m_GetRequestParam("WEBBOX_READONLY") == "1") , webboxStaticHtml(m_GetRequestParam("WEBBOX_STATIC_HTML")) + , m_rootdir(m_GetRequestParam("plugin_path")) + , paramHash(ParseQueryString(GetRequestParam("rel_target"), webboxPath)) // rel_target contains query string { if (webboxStaticHtml == "") webboxStaticHtml = STATIC_HTML_DOC_ROOT; @@ -327,6 +332,7 @@ protected: // Retrieve from Server: // Title // ReadOnly flag +// Root directory: Where in the HTTP URL is the webbox root located, e.g. /webbox1 class ServerInfoCommand: public GetCommand { public: @@ -344,6 +350,8 @@ protected: pt::ptree tree; tree.put("serverinfo.title", p.webboxName); tree.put("serverinfo.readonly", p.webboxReadOnly ? "1" : "0"); + tree.put("serverinfo.rootdir", p.m_rootdir); + tree.put("serverinfo.currentdir", p.m_pathInfo); std::ostringstream ss; pt::xml_parser::write_xml(ss, tree); return ss.str(); @@ -400,6 +408,7 @@ protected: } }; +// Info about single or multiple files class InfoCommand: public PostCommand { public: @@ -838,8 +847,10 @@ protected: virtual std::string start(CommandParameters& p) { // redirect to xyz/ if xyz was requested - std::string target = p.m_GetRequestParam("target"); - if (p.m_pathInfo == "" && !target.empty() && target.back() != '/') { + std::string target { p.m_GetRequestParam("target") }; + if (!target.empty() && target.back() != '/' && + (p.m_pathInfo.empty() || (fs::exists(p.webboxPath + "/" + p.m_pathInfo) && fs::is_directory(p.webboxPath + "/" + p.m_pathInfo)))) + { p.m_SetResponseHeader("location", target + "/"); return HttpStatus("301", "Use correct index: /"s, p); } @@ -847,10 +858,12 @@ protected: try { fs::path file_path; - if (p.m_pathInfo == "/" || p.m_pathInfo == "") { + if (p.m_pathInfo.empty() || p.m_pathInfo.back() == '/') { file_path = p.webboxStaticHtml / "index.html"; } else if (boost::algorithm::starts_with(p.m_pathInfo, STATIC_HTML_TARGET)) { file_path = p.webboxStaticHtml / p.m_pathInfo.substr(STATIC_HTML_TARGET.size()); + } else if (boost::algorithm::contains(p.m_pathInfo, "/"s + STATIC_HTML_TARGET)) { + file_path = p.webboxStaticHtml / p.m_pathInfo.substr(p.m_pathInfo.find("/"s + STATIC_HTML_TARGET) + STATIC_HTML_TARGET.size() + 1); } else { return HttpStatus("500", "Bad request: "s + p.m_pathInfo, p); } -- cgit v1.2.3
" + filename + "
" + filename + "
" + filename + "