From: Christian Hofstaedtler Date: Sun, 20 Oct 2013 16:01:40 +0000 (+0200) Subject: webserver: bundle all request data into class HttpRequest X-Git-Tag: rec-3.6.0-rc1~354^2~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=02c041443d453b43586c9c30df30c5c4e1d0bafa;p=pdns webserver: bundle all request data into class HttpRequest Now, pathArgs could actually be used by handlers. --- diff --git a/pdns/webserver.cc b/pdns/webserver.cc index 9d3ba539c..af667ccc2 100644 --- a/pdns/webserver.cc +++ b/pdns/webserver.cc @@ -42,7 +42,7 @@ int WebServer::B64Decode(const std::string& strInput, std::string& strOutput) // url is supposed to start with a slash. // url can contain variable names, marked as ; such variables -// are parsed out during routing and are put into the "urlArgs" map. +// are parsed out during routing and are put into the "pathArgs" map. // route() makes no assumptions about the contents of variables except // that the following URL segment can't be part of the variable. // @@ -79,13 +79,13 @@ void WebServer::registerHandler(const string& url, HandlerFunction handler) d_handlers.push_back(reg); } -bool WebServer::route(const std::string& url, std::map& urlArgs, HandlerFunction** handler) +bool WebServer::route(const std::string& url, std::map& pathArgs, HandlerFunction** handler) { for (std::list::iterator reg=d_handlers.begin(); reg != d_handlers.end(); ++reg) { bool matches = true; size_t lastpos = 0, pos = 0; string lastParam; - urlArgs.clear(); + pathArgs.clear(); for (std::list::iterator urlPart = reg->urlParts.begin(), param = reg->paramNames.begin(); urlPart != reg->urlParts.end() && param != reg->paramNames.end(); urlPart++, param++) { @@ -97,7 +97,7 @@ bool WebServer::route(const std::string& url, std::map } if (!lastParam.empty()) { // store - urlArgs[lastParam] = url.substr(lastpos, pos-lastpos); + pathArgs[lastParam] = url.substr(lastpos, pos-lastpos); } lastpos = pos + urlPart->size(); lastParam = *param; @@ -106,7 +106,7 @@ bool WebServer::route(const std::string& url, std::map if (matches) { if (!lastParam.empty()) { // store trailing parameter - urlArgs[lastParam] = url.substr(lastpos, pos-lastpos); + pathArgs[lastParam] = url.substr(lastpos, pos-lastpos); } else if (lastpos != url.size()) { matches = false; continue; @@ -129,8 +129,7 @@ static void *WebServerConnectionThreadStart(void *p) { void WebServer::serveConnection(Session* client) try { - bool want_html=false; - bool want_json=false; + HttpRequest req; try { string line; @@ -142,36 +141,31 @@ try { // L<<"page: "< parts; - stringtok(parts,line); - - string method, uri; + stringtok(parts, line); + if(parts.size()>1) { - method=parts[0]; - uri=parts[1]; + req.method = parts[0]; + req.uri = parts[1]; } parts.clear(); - stringtok(parts,uri,"?"); - - string baseUrl=parts[0]; + stringtok(parts,req.uri,"?"); + req.path = parts[0]; - vectorvariables; + vector variables; if(parts.size()>1) { stringtok(variables,parts[1],"&"); } - mapvarmap; - for(vector::const_iterator i=variables.begin(); i!=variables.end();++i) { parts.clear(); stringtok(parts,*i,"="); if(parts.size()>1) - varmap[parts[0]]=parts[1]; + req.queryArgs[parts[0]]=parts[1]; else - varmap[parts[0]]=""; - + req.queryArgs[parts[0]]=""; } bool authOK=0; @@ -203,16 +197,16 @@ try { authOK=1; } } - else if(header == "content-length" && method=="POST") { + else if(header == "content-length" && req.method=="POST") { postlen = atoi(value.c_str()); // cout<<"Got a post: "<get(postlen); + req.body = client->get(postlen); - // cout<<"Post: '"< urlArgs; - if (route(baseUrl, urlArgs, &handler)) { + if (route(req.path, req.pathArgs, &handler)) { bool custom=false; - string ret=(*handler)(method, post, varmap, &custom); + string ret=(*handler)(&req, &custom); if(!custom) { client->putLine("HTTP/1.1 200 OK\n"); @@ -250,10 +240,10 @@ try { client->putLine(e.statusLine()); client->putLine("Connection: close\n"); client->putLine(e.headers()); - if(want_html) { + if(req.accept_html) { client->putLine("Content-Type: text/html; charset=utf-8\n\n"); client->putLine("" + e.what() + "

" + e.what() + "

"); - } else if (want_json) { + } else if (req.accept_json) { client->putLine("Content-Type: application/json\n\n"); client->putLine(returnJSONError(e.what())); } else { diff --git a/pdns/webserver.hh b/pdns/webserver.hh index 48fcda1cc..bdf49f2ab 100644 --- a/pdns/webserver.hh +++ b/pdns/webserver.hh @@ -78,6 +78,21 @@ public: HttpMethodNotAllowedException() : HttpException(405, "Method Not Allowed") { }; }; +class HttpRequest { +public: + HttpRequest() : accept_json(false), accept_html(false) { }; + + string method; + string post; + string uri; + string path; + string body; + map pathArgs; + map queryArgs; + bool accept_json; + bool accept_html; +}; + class WebServer { public: @@ -86,7 +101,7 @@ public: void serveConnection(Session* client); - typedef boost::function&varmap, bool *custom)> HandlerFunction; + typedef boost::function HandlerFunction; struct HandlerRegistration { std::list urlParts; std::list paramNames; diff --git a/pdns/ws.cc b/pdns/ws.cc index 711f21e34..2758a7cba 100644 --- a/pdns/ws.cc +++ b/pdns/ws.cc @@ -186,17 +186,16 @@ string StatWebServer::makePercentage(const double& val) return (boost::format("%.01f%%") % val).str(); } -string StatWebServer::indexfunction(const string& method, const string& post, const map &varmap, bool *custom) +string StatWebServer::indexfunction(HttpRequest* req, bool *custom) { - maprvarmap=varmap; - if(!rvarmap["resetring"].empty()){ + if(!req->queryArgs["resetring"].empty()){ *custom=true; - S.resetRing(rvarmap["resetring"]); + S.resetRing(req->queryArgs["resetring"]); return "HTTP/1.1 301 Moved Permanently\nLocation: /\nConnection: close\n\n"; } - if(!rvarmap["resizering"].empty()){ + if(!req->queryArgs["resizering"].empty()){ *custom=true; - S.resizeRing(rvarmap["resizering"], atoi(rvarmap["size"].c_str())); + S.resizeRing(req->queryArgs["resizering"], atoi(req->queryArgs["size"].c_str())); return "HTTP/1.1 301 Moved Permanently\nLocation: /\nConnection: close\n\n"; } @@ -251,7 +250,7 @@ string StatWebServer::indexfunction(const string& method, const string& post, co "
"<
"<queryArgs["ring"].empty()) { vectorentries=S.listRings(); for(vector::const_iterator i=entries.begin();i!=entries.end();++i) printtable(ret,*i,S.getRingTitle(*i)); @@ -261,7 +260,7 @@ string StatWebServer::indexfunction(const string& method, const string& post, co printargs(ret); } else - printtable(ret,rvarmap["ring"],S.getRingTitle(rvarmap["ring"]),100); + printtable(ret,req->queryArgs["ring"],S.getRingTitle(req->queryArgs["ring"]),100); ret<<""<"<© 2013 PowerDNS.COM BV."<queryArgs.empty()) { vector entries = S.getEntries(); BOOST_FOREACH(string& ent, entries) { - varmap[ent]; + req->queryArgs[ent]; } - varmap["version"]; - varmap["uptime"]; + req->queryArgs["version"]; + req->queryArgs["uptime"]; } string variable, value; Document doc; doc.SetObject(); - for(varmap_t::const_iterator iter = varmap.begin(); iter != varmap.end() ; ++iter) { + for(varmap_t::const_iterator iter = req->queryArgs.begin(); iter != req->queryArgs.end() ; ++iter) { variable = iter->first; if(variable == "version") { value = VERSION; @@ -421,22 +420,22 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v else if(command == "flush-cache") { extern PacketCache PC; int number; - if(varmap["domain"].empty()) + if(req->queryArgs["domain"].empty()) number = PC.purge(); else - number = PC.purge(varmap["domain"]); + number = PC.purge(req->queryArgs["domain"]); map object; object["number"]=lexical_cast(number); - //cerr<<"Flushed cache for '"<method!="POST") throw HttpMethodNotAllowedException(); // cout<<"post: "<(post.c_str()).HasParseError()) + if(document.Parse<0>(req->body.c_str()).HasParseError()) return returnJSONError("Unable to parse JSON"); // cout<<"Parameters: '"< parameters; @@ -456,7 +455,7 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v } else if(command == "zone-rest") { // http://jsonstat?command=zone-rest&rest=/powerdns.nl/www.powerdns.nl/a vector parts; - stringtok(parts, varmap["rest"], "/"); + stringtok(parts, req->queryArgs["rest"], "/"); if(parts.size() != 3) return returnJSONError("Could not parse rest parameter"); UeberBackend B; @@ -472,7 +471,7 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v PC.purge(qname); // cerr<<"domain id: "<method == "GET") { B.lookup(qtype, parts[1], 0, sd.domain_id); DNSResourceRecord rr; @@ -494,13 +493,13 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v ret+="]}"; return ret; } - else if(method=="DELETE") { + else if(req->method=="DELETE") { sd.db->replaceRRSet(sd.domain_id, qname, qtype, vector()); } - else if(method=="POST") { + else if(req->method=="POST") { rapidjson::Document document; - if(document.Parse<0>(post.c_str()).HasParseError()) + if(document.Parse<0>(req->body.c_str()).HasParseError()) return returnJSONError("Unable to parse JSON"); DNSResourceRecord rr; @@ -534,24 +533,24 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v sd.db->startTransaction(qname); sd.db->replaceRRSet(sd.domain_id, qname, qtype, rrset); sd.db->commitTransaction(); - return post; + return req->body; } } else if(command == "zone") { - string zonename = varmap["zone"]; + string zonename = req->queryArgs["zone"]; if (zonename.empty()) return returnJSONError("Must give zone parameter"); - if(method == "GET") { + if(req->method == "GET") { // get current zone return getZone(zonename); - } else if (method == "POST") { + } else if (req->method == "POST") { // create - return createOrUpdateZone(zonename, true, varmap); - } else if (method == "PUT") { + return createOrUpdateZone(zonename, true, req->queryArgs); + } else if (req->method == "PUT") { // update or create - return createOrUpdateZone(zonename, false, varmap); - } else if (method == "DELETE") { + return createOrUpdateZone(zonename, false, req->queryArgs); + } else if (req->method == "DELETE") { // delete UeberBackend B; DomainInfo di; @@ -566,7 +565,7 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v } } else if(command=="log-grep") { - return makeLogGrepJSON(varmap, ::arg()["experimental-logfile"], " pdns["); + return makeLogGrepJSON(req->queryArgs, ::arg()["experimental-logfile"], " pdns["); } else if(command=="domains") { UeberBackend B; @@ -603,7 +602,7 @@ static string jsonDispatch(const string& method, const string& post, varmap_t& v return returnJSONError("No or unknown command given"); } -string StatWebServer::jsonstat(const string& method, const string& post, const map &varmap, bool *custom) +string StatWebServer::jsonstat(HttpRequest* req, bool *custom) { *custom=1; // indicates we build the response string ret="HTTP/1.1 200 OK\r\n" @@ -613,25 +612,24 @@ string StatWebServer::jsonstat(const string& method, const string& post, const m "Content-Type: application/json\r\n" "\r\n" ; - varmap_t ourvarmap=varmap; string callback; string command; - if(ourvarmap.count("callback")) { - callback=ourvarmap["callback"]; - ourvarmap.erase("callback"); + if(req->queryArgs.count("callback")) { + callback=req->queryArgs["callback"]; + req->queryArgs.erase("callback"); } - if(ourvarmap.count("command")) { - command=ourvarmap["command"]; - ourvarmap.erase("command"); + if(req->queryArgs.count("command")) { + command=req->queryArgs["command"]; + req->queryArgs.erase("command"); } - ourvarmap.erase("_"); + req->queryArgs.erase("_"); if(!callback.empty()) ret += callback+"("; - ret += jsonDispatch(method, post, ourvarmap, command); + ret += jsonDispatch(req, command); if(!callback.empty()) { ret += ");"; @@ -639,7 +637,7 @@ string StatWebServer::jsonstat(const string& method, const string& post, const m return ret; } -string StatWebServer::cssfunction(const string& method, const string& post, const map &varmap, bool *custom) +string StatWebServer::cssfunction(HttpRequest* req, bool *custom) { *custom=1; // indicates we build the response ostringstream ret; @@ -682,10 +680,10 @@ string StatWebServer::cssfunction(const string& method, const string& post, cons void StatWebServer::launch() { try { - d_ws->registerHandler("/", boost::bind(&StatWebServer::indexfunction, this, _1, _2, _3, _4)); - d_ws->registerHandler("/style.css", boost::bind(&StatWebServer::cssfunction, this, _1, _2, _3, _4)); + d_ws->registerHandler("/", boost::bind(&StatWebServer::indexfunction, this, _1, _2)); + d_ws->registerHandler("/style.css", boost::bind(&StatWebServer::cssfunction, this, _1, _2)); if(::arg().mustDo("experimental-json-interface")) - d_ws->registerHandler("/jsonstat", boost::bind(&StatWebServer::jsonstat, this, _1, _2, _3, _4)); + d_ws->registerHandler("/jsonstat", boost::bind(&StatWebServer::jsonstat, this, _1, _2)); d_ws->go(); } catch(...) { diff --git a/pdns/ws.hh b/pdns/ws.hh index 907ae5547..d01f965de 100644 --- a/pdns/ws.hh +++ b/pdns/ws.hh @@ -76,6 +76,7 @@ private: }; class WebServer; +class HttpRequest; class StatWebServer { @@ -86,9 +87,9 @@ public: private: static void *threadHelper(void *); static void *statThreadHelper(void *p); - string indexfunction(const string& method, const string& post, const map &varmap, bool *custom); - string cssfunction(const string& method, const string& post, const map &varmap, bool *custom); - string jsonstat(const string& method, const string& post, const map &varmap, bool *custom); + string indexfunction(HttpRequest* req, bool *custom); + string cssfunction(HttpRequest* req, bool *custom); + string jsonstat(HttpRequest* req, bool *custom); void printvars(ostringstream &ret); void printargs(ostringstream &ret); void launch();