summaryrefslogtreecommitdiffhomepage
path: root/plugins/webbox/webbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/webbox/webbox.cpp')
-rw-r--r--plugins/webbox/webbox.cpp164
1 files changed, 69 insertions, 95 deletions
diff --git a/plugins/webbox/webbox.cpp b/plugins/webbox/webbox.cpp
index c58bd0c..53322b5 100644
--- a/plugins/webbox/webbox.cpp
+++ b/plugins/webbox/webbox.cpp
@@ -3,6 +3,8 @@
#include "file.h"
#include "stringutil.h"
+#include "libcommon/mime.h"
+
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -127,6 +129,9 @@ namespace {
std::function<std::string(const std::string& key)>& m_GetRequestParam; // request including body (POST...)
std::function<void(const std::string& key, const std::string& value)>& m_SetResponseHeader; // to be added to result string
+ std::string m_pathInfo; // path inside webbox, derived from request
+ fs::path m_path; // local filesystem path
+
std::unordered_map<std::string, std::string> paramHash;
std::string webboxPath;
@@ -150,14 +155,27 @@ namespace {
{
if (webboxStaticHtml == "")
webboxStaticHtml = STATIC_HTML_DOC_ROOT;
+
+ m_pathInfo = urlDecode(GetRequestParam("rel_target"));
+ size_t pos {m_pathInfo.find('?')};
+ if (pos != m_pathInfo.npos) {
+ m_pathInfo = m_pathInfo.substr(0, pos);
+ }
+
+ if (m_pathInfo.find("..") != m_pathInfo.npos) {
+ throw std::runtime_error("Bad path: "s + m_pathInfo);
+ }
+
+ m_path = webboxPath;
+ if (!m_pathInfo.empty())
+ m_path /= m_pathInfo;
}
};
- // Used to return errors by generating response page and HTTP status code
- std::string HttpStatus(std::string status, std::string message, CommandParameters& commandParameters)
+ std::string HttpStatus(std::string status, std::string message, std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader)
{
- commandParameters.m_SetResponseHeader("status", status);
- commandParameters.m_SetResponseHeader("content_type", "text/html");
+ SetResponseHeader("status", status);
+ SetResponseHeader("content_type", "text/html");
auto it{status_map.find(status)};
std::string description{"(Unknown)"};
@@ -167,6 +185,12 @@ namespace {
return "<html><body><h1>"s + status + " "s + description + "</h1><p>"s + message + "</p></body></html>";
}
+ // Used to return errors by generating response page and HTTP status code
+ std::string HttpStatus(std::string status, std::string message, CommandParameters& commandParameters)
+ {
+ return HttpStatus(status, message, commandParameters.m_SetResponseHeader);
+ }
+
} // anonymous namespace
class Command
@@ -186,21 +210,6 @@ public:
return HttpStatus("403", "Bad request method", p);
}
- // Set parameters from FastCGI request environment
- m_pathInfo = urlDecode(p.m_GetRequestParam("rel_target"));
- size_t pos {m_pathInfo.find('?')};
- if (pos != m_pathInfo.npos) {
- m_pathInfo = m_pathInfo.substr(0, pos);
- }
-
- if (m_pathInfo.find("..") != m_pathInfo.npos) {
- return HttpStatus("403", "Bad path: "s + m_pathInfo, p);
- }
-
- m_path = p.webboxPath;
- if (!m_pathInfo.empty())
- m_path /= m_pathInfo;
-
return this->start(p);
}
@@ -220,9 +229,6 @@ protected:
std::string m_requestMethod;
bool m_isWriteCommand; // if true, command must be prevented if p.webboxReadOnly
- // calculated during start of execute()
- std::string m_pathInfo; // path inside webbox, derived from request
- fs::path m_path; // local filesystem path
};
class GetCommand: public Command
@@ -306,13 +312,13 @@ protected:
pt::ptree list;
pt::ptree entry;
- if (m_pathInfo != ""s) { // Add ".." if not in top directory of this webbox
+ if (p.m_pathInfo != ""s) { // Add ".." if not in top directory of this webbox
entry.put_value("..");
entry.put("<xmlattr>.type", "dir");
list.push_back(pt::ptree::value_type("listentry", entry));
}
- fs::directory_iterator dir(m_path);
+ fs::directory_iterator dir(p.m_path);
std::vector<std::string> files;
std::vector<std::string> dirs;
@@ -412,7 +418,7 @@ protected:
std::string dirname = tree.get<std::string>("dirname");
try {
- if (fs::create_directory(m_path / dirname))
+ if (fs::create_directory(p.m_path / dirname))
return "Successfully created directory";
else
return "Error creating directory";
@@ -449,7 +455,7 @@ protected:
for (const auto& element: elements) {
if (element.first == "file"s) {
std::string filename{element.second.data()};
- fs::path path {m_path / filename};
+ fs::path path {p.m_path / filename};
auto filesize {fs::file_size(path)};
@@ -514,7 +520,7 @@ protected:
return HttpStatus("400", "No files found", p);
try {
- fs::current_path(m_path);
+ fs::current_path(p.m_path);
} catch (const std::exception& ex) {
return HttpStatus("500", "Change path error: "s + ex.what(), p);
}
@@ -566,7 +572,7 @@ protected:
if (element.first == "file"s) {
std::string filename{element.second.data()};
- fs::path path{m_path / filename};
+ fs::path path{p.m_path / filename};
if (fs::is_directory(path)) {
try {
@@ -624,10 +630,10 @@ protected:
auto elements {tree.get_child("request")};
for (const auto& element: elements) {
if (element.first == "target") {
- targetDir = m_path / element.second.data();
+ targetDir = p.m_path / element.second.data();
} else if (element.first == "file") {
std::string filename{element.second.data()};
- fs::path old_path{m_path / filename};
+ fs::path old_path{p.m_path / filename};
fs::path new_path{targetDir / filename};
try {
fs::rename(old_path, new_path);
@@ -674,8 +680,8 @@ protected:
std::string oldname{tree.get<std::string>("request.oldname")};
std::string newname{tree.get<std::string>("request.newname")};
- fs::path oldpath{m_path / oldname};
- fs::path newpath{m_path / newname};
+ fs::path oldpath{p.m_path / oldname};
+ fs::path newpath{p.m_path / newname};
try {
fs::rename(oldpath, newpath);
@@ -753,7 +759,7 @@ protected:
} else {
filecontent = filecontent.substr(start + "\r\n\r\n"s.size());
- fs::path path{ m_path / filename};
+ fs::path path{ p.m_path / filename};
try {
File::setFile(path, filecontent);
} catch (const std::exception& ex) {
@@ -784,54 +790,18 @@ protected:
virtual std::string start(CommandParameters& p)
{
try {
- std::string result{File::getFile(m_path)};
+ std::string result{File::getFile(p.m_path)};
- p.m_SetResponseHeader("content_disposition", "attachment; filename=\""s + m_path.filename().string() + "\""s);
+ p.m_SetResponseHeader("content_disposition", "attachment; filename=\""s + p.m_path.filename().string() + "\""s);
p.m_SetResponseHeader("content_type", "application/octet-stream");
return result;
} catch (const std::exception& ex) {
- return HttpStatus("404", "Bad file: "s + m_path.filename().string(), p);
+ return HttpStatus("404", "Bad file: "s + p.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:
@@ -846,7 +816,7 @@ protected:
{
// redirect to xyz/ if xyz was requested
std::string target = p.m_GetRequestParam("target");
- if (m_pathInfo == "" && !target.empty() && target.back() != '/') {
+ if (p.m_pathInfo == "" && !target.empty() && target.back() != '/') {
p.m_SetResponseHeader("location", target + "/");
return HttpStatus("301", "Use correct index: /"s, p);
}
@@ -854,20 +824,20 @@ protected:
try {
fs::path file_path;
- if (m_pathInfo == "/" || m_pathInfo == "") {
+ if (p.m_pathInfo == "/" || p.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 if (boost::algorithm::starts_with(p.m_pathInfo, STATIC_HTML_TARGET)) {
+ file_path = p.webboxStaticHtml / p.m_pathInfo.substr(STATIC_HTML_TARGET.size());
} else {
- return HttpStatus("500", "Bad request: "s + m_pathInfo, p);
+ return HttpStatus("500", "Bad request: "s + p.m_pathInfo, p);
}
- p.m_SetResponseHeader("content_type", mime_type(file_path));
+ p.m_SetResponseHeader("content_type", mime_type(file_path.string()));
std::string result{File::getFile(file_path)};
return result;
} catch (const std::exception& ex) {
- return HttpStatus("500", "Server error: "s + m_pathInfo, p);
+ return HttpStatus("500", "Server error: "s + p.m_pathInfo, p);
}
}
};
@@ -908,23 +878,27 @@ std::string webbox_plugin::generate_page(
{
// 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")};
- if (it != commandParameters.paramHash.end())
- commandName = it->second;
+ try {
+ CommandParameters commandParameters(GetServerParam, GetRequestParam, SetResponseHeader);
+
+ std::string commandName;
+
+ auto it {commandParameters.paramHash.find("command")};
+ if (it != commandParameters.paramHash.end())
+ commandName = it->second;
- auto commands_it{m_commands.find(commandName)};
- if (commands_it != m_commands.end()) {
- try {
- return commands_it->second->execute(commandParameters);
- } catch (const std::exception& ex) {
- return HttpStatus("500", "Processing command: "s + commandName + ", "s + ex.what(), commandParameters);
- }
- } else
- return HttpStatus("400", "Bad command: "s + commandName, commandParameters);
+ auto commands_it{m_commands.find(commandName)};
+ if (commands_it != m_commands.end()) {
+ try {
+ return commands_it->second->execute(commandParameters);
+ } catch (const std::exception& ex) {
+ return HttpStatus("500", "Processing command: "s + commandName + ", "s + ex.what(), commandParameters);
+ }
+ } else
+ return HttpStatus("400", "Bad command: "s + commandName, commandParameters);
+ } catch (const std::exception& ex) {
+ return HttpStatus("500", ex.what(), SetResponseHeader);
+ }
}
void webbox_plugin::registerCommand(std::shared_ptr<Command> command)