From 3f778eecc705990598f1033e6245522f42e2fcb5 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 12 Apr 2020 14:01:40 +0200 Subject: Refactor path concept --- response.cpp | 151 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 49 deletions(-) (limited to 'response.cpp') 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 + #include #include +#include #include 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> GetRequestParamFunctions{ +std::unordered_map> 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::bind(GetServerParam, _1, std::ref(server)))}; + auto GetRequestParamFunction {std::function(std::bind(GetRequestParam, _1, std::ref(req_ctx)))}; + auto SetResponseHeaderFunction{std::function(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::bind(GetServerParam, _1, std::ref(server)))}; - auto GetRequestParamFunction {std::function(std::bind(GetRequestParam, _1, std::ref(req), std::ref(server)))}; - auto SetResponseHeaderFunction{std::function(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; } -- cgit v1.2.3