From: Christian Hofstaedtler Date: Sun, 20 Oct 2013 16:34:44 +0000 (+0200) Subject: webserver: first batch of new API URLs X-Git-Tag: rec-3.6.0-rc1~354^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c67bf8c5d1a5406d8adaaae7b863267079691764;p=pdns webserver: first batch of new API URLs Note that return data is still in old format. --- diff --git a/pdns/json.cc b/pdns/json.cc index 59e44386a..c2132e1a0 100644 --- a/pdns/json.cc +++ b/pdns/json.cc @@ -85,7 +85,7 @@ string returnJSONError(const string& error) return makeStringFromDocument(doc); } -string makeLogGrepJSON(map& varmap, const string& fname, const string& prefix) +string makeLogGrepJSON(const string& q, const string& fname, const string& prefix) { FILE* ptr = fopen(fname.c_str(), "r"); if(!ptr) { @@ -94,7 +94,7 @@ string makeLogGrepJSON(map& varmap, const string& fname, const s boost::shared_ptr fp(ptr, fclose); string line; - string needle=varmap["needle"]; + string needle = q; trim_right(needle); boost::replace_all(needle, "%20", " "); diff --git a/pdns/json.hh b/pdns/json.hh index 11a574245..3945b05c5 100644 --- a/pdns/json.hh +++ b/pdns/json.hh @@ -27,5 +27,5 @@ std::string returnJSONObject(const std::map& items); std::string returnJSONError(const std::string& error); -std::string makeLogGrepJSON(std::map& varmap, const std::string& fname, const std::string& prefix=""); +std::string makeLogGrepJSON(const std::string& q, const std::string& fname, const std::string& prefix=""); std::string makeStringFromDocument(const rapidjson::Document& doc); diff --git a/pdns/json_ws.cc b/pdns/json_ws.cc index 53397e5f2..d51fbb6b6 100644 --- a/pdns/json_ws.cc +++ b/pdns/json_ws.cc @@ -225,7 +225,7 @@ string JWebserver::handleRequest(const string &method, const string &uri, const content += returnJSONObject(stats); } else if(command == "log-grep") { - content += makeLogGrepJSON(varmap, ::arg()["experimental-logfile"], " pdns_recursor["); + content += makeLogGrepJSON(varmap["needle"], ::arg()["experimental-logfile"], " pdns_recursor["); } else { // if(command == "stats") { stats = getAllStatsMap(); diff --git a/pdns/ws.cc b/pdns/ws.cc index 2758a7cba..ccf141a2f 100644 --- a/pdns/ws.cc +++ b/pdns/ws.cc @@ -366,6 +366,72 @@ static string createOrUpdateZone(const string& zonename, bool onlyCreate, varmap return getZone(zonename); } +static string apiServerConfig(HttpRequest* req) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + vector items = ::arg().list(); + Document doc; + doc.SetArray(); + BOOST_FOREACH(const string& var, items) { + Value kv, key, value; + kv.SetArray(); + key.SetString(var.c_str(), var.length()); + kv.PushBack(key, doc.GetAllocator()); + + if(var.find("password") != string::npos) + value="*****"; + else + value.SetString(::arg()[var].c_str(), ::arg()[var].length(), doc.GetAllocator()); + + kv.PushBack(value, doc.GetAllocator()); + doc.PushBack(kv, doc.GetAllocator()); + } + return makeStringFromDocument(doc); +} + +static string apiServerSearchLog(HttpRequest* req) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + return makeLogGrepJSON(req->queryArgs["q"], ::arg()["experimental-logfile"], " pdns["); +} + +static string apiServerZones(HttpRequest* req) { + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + UeberBackend B; + vector domains; + B.getAllDomains(&domains); + + Document doc; + doc.SetObject(); + + Value jdomains; + jdomains.SetArray(); + + BOOST_FOREACH(const DomainInfo& di, domains) { + Value jdi; + jdi.SetObject(); + jdi.AddMember("name", di.zone.c_str(), doc.GetAllocator()); + jdi.AddMember("kind", di.getKindString(), doc.GetAllocator()); + Value masters; + masters.SetArray(); + BOOST_FOREACH(const string& master, di.masters) { + Value value(master.c_str(), doc.GetAllocator()); + masters.PushBack(value, doc.GetAllocator()); + } + jdi.AddMember("masters", masters, doc.GetAllocator()); + jdi.AddMember("serial", di.serial, doc.GetAllocator()); + jdi.AddMember("notified_serial", di.notified_serial, doc.GetAllocator()); + jdi.AddMember("last_check", (unsigned int) di.last_check, doc.GetAllocator()); + jdomains.PushBack(jdi, doc.GetAllocator()); + } + doc.AddMember("domains", jdomains, doc.GetAllocator()); + return makeStringFromDocument(doc); +} + static string jsonDispatch(HttpRequest* req, const string& command) { if(command=="get") { if(req->queryArgs.empty()) { @@ -398,24 +464,7 @@ static string jsonDispatch(HttpRequest* req, const string& command) { return makeStringFromDocument(doc); } else if(command=="config") { - vector items = ::arg().list(); - Document doc; - doc.SetArray(); - BOOST_FOREACH(const string& var, items) { - Value kv, key, value; - kv.SetArray(); - key.SetString(var.c_str(), var.length()); - kv.PushBack(key, doc.GetAllocator()); - - if(var.find("password") != string::npos) - value="*****"; - else - value.SetString(::arg()[var].c_str(), ::arg()[var].length(), doc.GetAllocator()); - - kv.PushBack(value, doc.GetAllocator()); - doc.PushBack(kv, doc.GetAllocator()); - } - return makeStringFromDocument(doc); + return apiServerConfig(req); } else if(command == "flush-cache") { extern PacketCache PC; @@ -565,45 +614,16 @@ static string jsonDispatch(HttpRequest* req, const string& command) { } } else if(command=="log-grep") { - return makeLogGrepJSON(req->queryArgs, ::arg()["experimental-logfile"], " pdns["); + return makeLogGrepJSON(req->queryArgs["needle"], ::arg()["experimental-logfile"], " pdns["); } else if(command=="domains") { - UeberBackend B; - vector domains; - B.getAllDomains(&domains); - - Document doc; - doc.SetObject(); - - Value jdomains; - jdomains.SetArray(); - - BOOST_FOREACH(const DomainInfo& di, domains) { - Value jdi; - jdi.SetObject(); - jdi.AddMember("name", di.zone.c_str(), doc.GetAllocator()); - jdi.AddMember("kind", di.getKindString(), doc.GetAllocator()); - Value masters; - masters.SetArray(); - BOOST_FOREACH(const string& master, di.masters) { - Value value(master.c_str(), doc.GetAllocator()); - masters.PushBack(value, doc.GetAllocator()); - } - jdi.AddMember("masters", masters, doc.GetAllocator()); - jdi.AddMember("serial", di.serial, doc.GetAllocator()); - jdi.AddMember("notified_serial", di.notified_serial, doc.GetAllocator()); - jdi.AddMember("last_check", (unsigned int) di.last_check, doc.GetAllocator()); - jdomains.PushBack(jdi, doc.GetAllocator()); - } - doc.AddMember("domains", jdomains, doc.GetAllocator()); - return makeStringFromDocument(doc); + return apiServerZones(req); } return returnJSONError("No or unknown command given"); } -string StatWebServer::jsonstat(HttpRequest* req, bool *custom) -{ +static string apiWrapper(boost::function handler, HttpRequest* req, bool *custom) { *custom=1; // indicates we build the response string ret="HTTP/1.1 200 OK\r\n" "Server: PowerDNS/"VERSION"\r\n" @@ -613,23 +633,18 @@ string StatWebServer::jsonstat(HttpRequest* req, bool *custom) "\r\n" ; string callback; - string command; if(req->queryArgs.count("callback")) { callback=req->queryArgs["callback"]; req->queryArgs.erase("callback"); } - if(req->queryArgs.count("command")) { - command=req->queryArgs["command"]; - req->queryArgs.erase("command"); - } + req->queryArgs.erase("_"); // jQuery cache buster - req->queryArgs.erase("_"); if(!callback.empty()) ret += callback+"("; - ret += jsonDispatch(req, command); + ret += handler(req); if(!callback.empty()) { ret += ");"; @@ -637,6 +652,23 @@ string StatWebServer::jsonstat(HttpRequest* req, bool *custom) return ret; } +void StatWebServer::registerApiHandler(const string& url, boost::function handler) { + WebServer::HandlerFunction f = boost::bind(&apiWrapper, handler, _1, _2); + d_ws->registerHandler(url, f); +} + +string StatWebServer::jsonstat(HttpRequest* req) +{ + string command; + + if(req->queryArgs.count("command")) { + command=req->queryArgs["command"]; + req->queryArgs.erase("command"); + } + + return jsonDispatch(req, command); +} + string StatWebServer::cssfunction(HttpRequest* req, bool *custom) { *custom=1; // indicates we build the response @@ -682,8 +714,13 @@ void StatWebServer::launch() try { 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)); + if(::arg().mustDo("experimental-json-interface")) { + registerApiHandler("/servers/localhost/config", &apiServerConfig); + registerApiHandler("/servers/localhost/search-log", &apiServerSearchLog); + registerApiHandler("/servers/localhost/zones", &apiServerZones); + // legacy dispatch + registerApiHandler("/jsonstat", boost::bind(&StatWebServer::jsonstat, this, _1)); + } d_ws->go(); } catch(...) { diff --git a/pdns/ws.hh b/pdns/ws.hh index d01f965de..85ae97570 100644 --- a/pdns/ws.hh +++ b/pdns/ws.hh @@ -84,12 +84,14 @@ public: StatWebServer(); void go(); static string makePercentage(const double& val); + private: static void *threadHelper(void *); static void *statThreadHelper(void *p); string indexfunction(HttpRequest* req, bool *custom); string cssfunction(HttpRequest* req, bool *custom); - string jsonstat(HttpRequest* req, bool *custom); + string jsonstat(HttpRequest* req); + void registerApiHandler(const string& url, boost::function handler); void printvars(ostringstream &ret); void printargs(ostringstream &ret); void launch();