summaryrefslogtreecommitdiffhomepage
path: root/response.cpp
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-04-12 14:01:40 +0200
committerRoland Reichwein <mail@reichwein.it>2020-04-12 14:01:40 +0200
commit3f778eecc705990598f1033e6245522f42e2fcb5 (patch)
treedfa2af27ef4e6b6a299ecb014a684c272db77992 /response.cpp
parent77a68fbe16246245937c5d692bb8c89dc14d7800 (diff)
Refactor path concept
Diffstat (limited to 'response.cpp')
-rw-r--r--response.cpp151
1 files changed, 102 insertions, 49 deletions
diff --git a/response.cpp b/response.cpp
index 4d6aaaf..1ee8932 100644
--- a/response.cpp
+++ b/response.cpp
@@ -1,14 +1,59 @@
#include "response.h"
#include "file.h"
+#include <boost/algorithm/string/predicate.hpp>
+
#include <functional>
#include <iostream>
+#include <string>
#include <unordered_map>
using namespace std::placeholders;
namespace {
+class RequestContext
+{
+private:
+ request_type& m_req;
+ std::string m_host;
+ std::string m_target;
+ Server& m_server;
+ const Path& m_path;
+
+public:
+ RequestContext(request_type& req, Server& server)
+ : m_req(req)
+ , m_host(req["host"])
+ , m_target(req.target())
+ , m_server(server)
+ , m_path(server.GetConfig().GetPath(server.GetSocket(), m_host, m_target))
+ {
+ }
+
+ const Path& GetPath() const {return m_path;}
+
+ std::string GetPluginName() const {return m_path.params.at("plugin");} // can throw std::out_of_range
+
+ std::string GetPluginPath() const {return m_path.requested;}
+
+ std::string GetDocRoot() const {return m_path.params.at("target");} // can throw std::out_of_range
+
+ std::string GetRelativePath() const { // can throw std::runtime_error
+ if (!boost::starts_with(m_target, m_path.requested))
+ throw std::runtime_error("Mismatch of target ("s + m_target + ") and plugin path(" + m_path.requested + ")"s);
+ return m_target.substr(m_path.requested.size());
+ }
+
+ std::string GetPluginParam(const std::string& key) const {return m_path.params.at(key);} // can throw std::out_of_range
+
+ plugin_type GetPlugin() const {return m_server.GetPlugin(m_path.params.at("plugin"));}; // can throw std::out_of_range
+
+ request_type& GetReq() const {return m_req;}
+
+ std::string GetTarget() const {return m_target;}
+};
+
std::string extend_index_html(std::string path)
{
if (path.size() && path.back() == '/')
@@ -23,39 +68,47 @@ std::string GetServerParam(const std::string& key, Server& server)
throw std::runtime_error("Unsupported server param: "s + key);
}
-std::unordered_map<std::string, std::function<std::string(request_type&, Server&)>> GetRequestParamFunctions{
+std::unordered_map<std::string, std::function<std::string(RequestContext&)>> GetRequestParamFunctions{
// following are the supported fields:
- {"target", [](request_type& req, Server& server){return std::string{req.target()};}},
-
- {"rel_target", [](request_type& req, Server& server){
- std::string host{req["host"]};
- std::string target{req.target()};
- return server.GetConfig().GetRelativePath(server.GetSocket(), host, target);
- }},
-
- {"doc_root", [](request_type& req, Server& server) {
- std::string host{req["host"]};
- std::string target{req.target()};
- return server.GetConfig().DocRoot(server.GetSocket(), host, target);
- }},
-
- {"method", [](request_type& req, Server& server){
- if (req.method() == http::verb::get)
- return "GET";
- else if (req.method() == http::verb::post)
- return "POST";
- else if (req.method() == http::verb::head)
- return "HEAD";
- else
- return "";
- }},
+ {"target", [](RequestContext& req_ctx) {return req_ctx.GetTarget();}},
+
+ {"rel_target", [](RequestContext& req_ctx) {return req_ctx.GetRelativePath();}},
+
+ {"doc_root", [](RequestContext& req_ctx) { return req_ctx.GetDocRoot();}},
+
+ {"body", [](RequestContext& req_ctx) { return req_ctx.GetReq().body(); }},
+
+ {"method", [](RequestContext& req_ctx) { return std::string{req_ctx.GetReq().method_string()};}},
};
-std::string GetRequestParam(const std::string& key, request_type& req, Server& server)
+std::string GetRequestParam(const std::string& key, RequestContext& req_ctx)
{
- auto it = GetRequestParamFunctions.find(key);
- if (it != GetRequestParamFunctions.end())
- return it->second(req, server);
+ // first, look up functions from GetRequestParamFunctions
+ {
+ auto it = GetRequestParamFunctions.find(key);
+ if (it != GetRequestParamFunctions.end())
+ return it->second(req_ctx);
+ }
+
+ // second, look up plugin parameters
+ {
+ try {
+ return req_ctx.GetPluginParam(key);
+ } catch(const std::out_of_range& ex) {
+ // not found
+ };
+ }
+
+ // third, look up req parameters
+ {
+ try {
+ return std::string{req_ctx.GetReq()[key]};
+ } catch(...){
+ // not found
+ }
+ }
+
+ // otherwise: error
throw std::runtime_error("Unsupported request param: "s + key);
}
@@ -129,27 +182,27 @@ response_type generate_response(request_type& req, Server& server)
res.set(http::field::content_type, mime_type(extend_index_html(std::string(req.target()))));
res.keep_alive(req.keep_alive());
- std::string host{req["host"]};
- std::string target{req.target()};
- std::string plugin_name { server.GetConfig().GetPlugin(server.GetSocket(), host, target)};
- if (plugin_name == "") {
- return HttpStatus("400", "Bad request: Host "s + host + ":"s + target + " unknown"s, res);
+ try {
+ RequestContext req_ctx{req, server}; // can throw std::out_of_range
+
+ plugin_type plugin{req_ctx.GetPlugin()};
+
+ auto GetServerParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetServerParam, _1, std::ref(server)))};
+ auto GetRequestParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetRequestParam, _1, std::ref(req_ctx)))};
+ auto SetResponseHeaderFunction{std::function<void(const std::string& key, const std::string& value)>(std::bind(SetResponseHeader, _1, _2, std::ref(res)))};
+
+ std::string res_data { plugin->generate_page(GetServerParamFunction, GetRequestParamFunction, SetResponseHeaderFunction)};
+ if (req.method() == http::verb::head) {
+ res.content_length(res_data.size());
+ } else {
+ res.body() = res_data;
+ res.prepare_payload();
+ }
+
+ return res;
+ } catch(const std::out_of_range& ex) {
+ return HttpStatus("400", "Bad request: Host "s + std::string{req["host"]} + ":"s + std::string{req.target()} + " unknown"s, res);
}
- plugin_type plugin{server.GetPlugin(plugin_name)};
-
- auto GetServerParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetServerParam, _1, std::ref(server)))};
- auto GetRequestParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetRequestParam, _1, std::ref(req), std::ref(server)))};
- auto SetResponseHeaderFunction{std::function<void(const std::string& key, const std::string& value)>(std::bind(SetResponseHeader, _1, _2, std::ref(res)))};
-
- std::string res_data { plugin->generate_page(GetServerParamFunction, GetRequestParamFunction, SetResponseHeaderFunction)};
- if (req.method() == http::verb::head) {
- res.content_length(res_data.size());
- } else {
- res.body() = res_data;
- res.prepare_payload();
- }
-
- return res;
}