rec_channel.o rec_channel_rec.o selectmplexer.o sillyrecords.o \
dns_random.o ext/polarssl-1.3.2/library/aes.o ext/polarssl-1.3.2/library/padlock.o dnslabeltext.o \
lua-pdns.o lua-recursor.o randomhelper.o recpacketcache.o dns.o \
-reczones.o base32.o nsecrecords.o json.o ws-recursor.o version.o responsestats.o \
-session.o webserver.o ext/yahttp/yahttp/reqresp.o
+reczones.o base32.o nsecrecords.o json.o ws-recursor.o ws-api.o \
+version.o responsestats.o session.o webserver.o ext/yahttp/yahttp/reqresp.o
REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \
unix_utility.o logger.o qtype.o
packetcache.cc statbag.cc pdnsexception.hh arguments.hh distributor.hh \
dns.hh dnsbackend.hh dnsbackend.cc dnspacket.hh dynmessenger.hh lock.hh logger.hh \
nameserver.hh packetcache.hh packethandler.hh qtype.hh statbag.hh \
-ueberbackend.hh pdns.conf-dist ws-auth.hh ws-auth.cc webserver.cc webserver.hh \
+ueberbackend.hh pdns.conf-dist \
+ws-auth.hh ws-auth.cc ws-api.cc ws-api.hh webserver.cc webserver.hh \
session.cc session.hh misc.cc misc.hh receiver.cc ueberbackend.cc \
dynlistener.cc dynlistener.hh dynhandler.cc dynhandler.hh \
resolver.hh resolver.cc slavecommunicator.cc mastercommunicator.cc communicator.cc communicator.hh dnsproxy.cc \
rec_channel_rec.cc selectmplexer.cc epollmplexer.cc sillyrecords.cc htimer.cc htimer.hh \
dns_random.cc \
lua-pdns.cc lua-pdns.hh lua-recursor.cc lua-recursor.hh randomhelper.cc \
-recpacketcache.cc recpacketcache.hh dns.cc nsecrecords.cc base32.cc cachecleaner.hh ws-recursor.cc ws-recursor.hh \
-json.cc json.hh version.hh version.cc responsestats.cc webserver.cc webserver.hh session.cc session.hh
+recpacketcache.cc recpacketcache.hh dns.cc nsecrecords.cc base32.cc cachecleaner.hh \
+ws-recursor.cc ws-recursor.hh ws-api.cc ws-api.hh webserver.cc webserver.hh \
+session.cc session.hh json.cc json.hh version.hh version.cc responsestats.cc
pdns_recursor_LDFLAGS= $(LUA_LIBS)
pdns_recursor_LDADD= $(POLARSSL_LIBS) $(YAHTTP_LIBS)
mplexer.hh \
dns_random.hh lua-pdns.hh lua-recursor.hh namespaces.hh \
recpacketcache.hh base32.hh cachecleaner.hh json.hh version.hh \
+ws-recursor.hh ws-api.hh \
responsestats.hh webserver.hh session.hh"
CFILES="syncres.cc misc.cc unix_utility.cc qtype.cc \
selectmplexer.cc epollmplexer.cc kqueuemplexer.cc portsmplexer.cc pdns_hw.cc \
sillyrecords.cc lua-pdns.cc lua-recursor.cc randomhelper.cc \
devpollmplexer.cc recpacketcache.cc dns.cc reczones.cc base32.cc nsecrecords.cc \
-dnslabeltext.cc json.cc ws-recursor.cc ws-recursor.hh version.cc dns_random.cc \
+dnslabeltext.cc json.cc ws-recursor.cc ws-api.cc version.cc dns_random.cc \
responsestats.cc webserver.cc session.cc"
cd docs
#include "json.hh"
#include "namespaces.hh"
-#include <stdio.h>
-#include <boost/circular_buffer.hpp>
-#include <boost/tokenizer.hpp>
-#include "namespaces.hh"
#include "misc.hh"
#include <boost/foreach.hpp>
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
-#include "config.h"
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-
-#ifndef HAVE_STRCASESTR
-/*
- * strcasestr() locates the first occurrence in the string s1 of the
- * sequence of characters (excluding the terminating null character)
- * in the string s2, ignoring case. strcasestr() returns a pointer
- * to the located string, or a null pointer if the string is not found.
- * If s2 is empty, the function returns s1.
- */
+using namespace rapidjson;
-static char *
-strcasestr(const char *s1, const char *s2)
+int intFromJson(const Value& container, const char* key)
{
- int *cm = __trans_lower;
- const uchar_t *us1 = (const uchar_t *)s1;
- const uchar_t *us2 = (const uchar_t *)s2;
- const uchar_t *tptr;
- int c;
-
- if (us2 == NULL || *us2 == '\0')
- return ((char *)us1);
-
- c = cm[*us2];
- while (*us1 != '\0') {
- if (c == cm[*us1++]) {
- tptr = us1;
- while (cm[c = *++us2] == cm[*us1++] && c != '\0')
- continue;
- if (c == '\0')
- return ((char *)tptr - 1);
- us1 = tptr;
- us2 = (const uchar_t *)s2;
- c = cm[*us2];
- }
- }
+ const Value& val = container[key];
+ if (val.IsInt()) {
+ return val.GetInt();
+ } else if (val.IsString()) {
+ return atoi(val.GetString());
+ } else {
+ throw JsonException("Key '" + string(key) + "' not an Integer or not present");
+ }
+}
- return (NULL);
+int intFromJson(const Value& container, const char* key, const int default_value)
+{
+ const Value& val = container[key];
+ if (val.IsInt()) {
+ return val.GetInt();
+ } else if (val.IsString()) {
+ return atoi(val.GetString());
+ } else {
+ // TODO: check if value really isn't present
+ return default_value;
+ }
}
-#endif // HAVE_STRCASESTR
+string stringFromJson(const Value& container, const char* key)
+{
+ const Value& val = container[key];
+ if (val.IsString()) {
+ return val.GetString();
+ } else {
+ throw JsonException("Key '" + string(key) + "' not present or not a String");
+ }
+}
-using namespace rapidjson;
+string stringFromJson(const Value& container, const char* key, const string& default_value)
+{
+ const Value& val = container[key];
+ if (val.IsString()) {
+ return val.GetString();
+ } else {
+ // TODO: check if value really isn't present
+ return default_value;
+ }
+}
string makeStringFromDocument(const Document& doc)
{
return string(output.GetString(), output.Size());
}
-string returnJSONObject(const map<string, string>& items)
+string returnJsonObject(const map<string, string>& items)
{
Document doc;
doc.SetObject();
return makeStringFromDocument(doc);
}
-string returnJSONError(const string& error)
+string returnJsonError(const string& error)
{
Document doc;
doc.SetObject();
doc.AddMember("error", jerror, doc.GetAllocator());
return makeStringFromDocument(doc);
}
-
-string makeLogGrepJSON(const string& q, const string& fname, const string& prefix)
-{
- FILE* ptr = fopen(fname.c_str(), "r");
- if(!ptr) {
- return "[]";
- }
- boost::shared_ptr<FILE> fp(ptr, fclose);
-
- string line;
- string needle = q;
- trim_right(needle);
-
- boost::replace_all(needle, "%20", " ");
- boost::replace_all(needle, "%22", "\"");
-
- boost::tokenizer<boost::escaped_list_separator<char> > t(needle, boost::escaped_list_separator<char>("\\", " ", "\""));
- vector<string> matches(t.begin(), t.end());
- matches.push_back(prefix);
-
- boost::circular_buffer<string> lines(200);
- while(stringfgets(fp.get(), line)) {
- vector<string>::const_iterator iter;
- for(iter = matches.begin(); iter != matches.end(); ++iter) {
- if(!strcasestr(line.c_str(), iter->c_str()))
- break;
- }
- if(iter == matches.end()) {
- trim_right(line);
- lines.push_front(line);
- }
- }
-
- Document doc;
- doc.SetArray();
- if(!lines.empty()) {
- BOOST_FOREACH(const string& line, lines) {
- doc.PushBack(line.c_str(), doc.GetAllocator());
- }
- }
- return makeStringFromDocument(doc);
-}
#include <string>
#include <map>
+#include <stdexcept>
#include "rapidjson/document.h"
-std::string returnJSONObject(const std::map<std::string, std::string>& items);
-std::string returnJSONError(const std::string& error);
-std::string makeLogGrepJSON(const std::string& q, const std::string& fname, const std::string& prefix="");
+std::string returnJsonObject(const std::map<std::string, std::string>& items);
+std::string returnJsonError(const std::string& error);
std::string makeStringFromDocument(const rapidjson::Document& doc);
+int intFromJson(const rapidjson::Value& container, const char* key);
+int intFromJson(const rapidjson::Value& container, const char* key, const int default_value);
+std::string stringFromJson(const rapidjson::Value& container, const char* key);
+std::string stringFromJson(const rapidjson::Value& container, const char* key, const std::string& default_value);
+
+class JsonException : public std::runtime_error
+{
+public:
+ JsonException(const std::string& what) : std::runtime_error(what) {
+ }
+};
Session client;
};
+void HttpRequest::json(rapidjson::Document& document)
+{
+ if(document.Parse<0>(this->body.c_str()).HasParseError()) {
+ throw HttpBadRequestException();
+ }
+}
+
int WebServer::B64Decode(const std::string& strInput, std::string& strOutput)
{
return ::B64Decode(strInput, strOutput);
try {
handler(req, resp);
} catch (ApiException &e) {
- string what = e.what();
- resp->body = returnJSONError(what);
+ resp->body = returnJsonError(e.what());
+ resp->status = 422;
+ return;
+ } catch (JsonException &e) {
+ resp->body = returnJsonError(e.what());
resp->status = 422;
return;
}
resp.body = "<!html><title>" + what + "</title><h1>" + what + "</h1>";
} else if (req.accept_json) {
resp.headers["Content-Type"] = "application/json";
- resp.body = returnJSONError(what);
+ resp.body = returnJsonError(what);
} else {
resp.headers["Content-Type"] = "text/plain; charset=utf-8";
resp.body = what;
#include <list>
#include <boost/utility.hpp>
#include <yahttp/yahttp.hpp>
-
+#include "rapidjson/document.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
#include "namespaces.hh"
+
class Server;
class Session;
map<string,string> path_parameters;
bool accept_json;
bool accept_html;
+ void json(rapidjson::Document& document);
};
class HttpResponse: public YaHTTP::Response {
--- /dev/null
+/*
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#include <boost/foreach.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/circular_buffer.hpp>
+#include "namespaces.hh"
+#include "ws-api.hh"
+#include "json.hh"
+#include "config.h"
+#include "version.hh"
+#include "arguments.hh"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifndef HAVE_STRCASESTR
+
+/*
+ * strcasestr() locates the first occurrence in the string s1 of the
+ * sequence of characters (excluding the terminating null character)
+ * in the string s2, ignoring case. strcasestr() returns a pointer
+ * to the located string, or a null pointer if the string is not found.
+ * If s2 is empty, the function returns s1.
+ */
+
+static char *
+strcasestr(const char *s1, const char *s2)
+{
+ int *cm = __trans_lower;
+ const uchar_t *us1 = (const uchar_t *)s1;
+ const uchar_t *us2 = (const uchar_t *)s2;
+ const uchar_t *tptr;
+ int c;
+
+ if (us2 == NULL || *us2 == '\0')
+ return ((char *)us1);
+
+ c = cm[*us2];
+ while (*us1 != '\0') {
+ if (c == cm[*us1++]) {
+ tptr = us1;
+ while (cm[c = *++us2] == cm[*us1++] && c != '\0')
+ continue;
+ if (c == '\0')
+ return ((char *)tptr - 1);
+ us1 = tptr;
+ us2 = (const uchar_t *)s2;
+ c = cm[*us2];
+ }
+ }
+
+ return (NULL);
+}
+
+#endif // HAVE_STRCASESTR
+
+using namespace rapidjson;
+
+static void fillServerDetail(Value& out, Value::AllocatorType& allocator)
+{
+ Value jdaemonType(productTypeApiType().c_str(), allocator);
+ out.SetObject();
+ out.AddMember("type", "Server", allocator);
+ out.AddMember("id", "localhost", allocator);
+ out.AddMember("url", "/servers/localhost", allocator);
+ out.AddMember("daemon_type", jdaemonType, allocator);
+ out.AddMember("version", VERSION, allocator);
+ out.AddMember("config_url", "/servers/localhost/config{/config_setting}", allocator);
+ out.AddMember("zones_url", "/servers/localhost/zones{/zone}", allocator);
+}
+
+void apiServer(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ Document doc;
+ doc.SetArray();
+ Value server;
+ fillServerDetail(server, doc.GetAllocator());
+ doc.PushBack(server, doc.GetAllocator());
+ resp->body = makeStringFromDocument(doc);
+}
+
+void apiServerDetail(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ Document doc;
+ fillServerDetail(doc, doc.GetAllocator());
+ resp->body = makeStringFromDocument(doc);
+}
+
+void apiServerConfig(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ vector<string> items = ::arg().list();
+ string value;
+ Document doc;
+ doc.SetArray();
+ BOOST_FOREACH(const string& item, items) {
+ Value jitem;
+ jitem.SetObject();
+ jitem.AddMember("type", "ConfigSetting", doc.GetAllocator());
+
+ Value jname(item.c_str(), doc.GetAllocator());
+ jitem.AddMember("name", jname, doc.GetAllocator());
+
+ if(item.find("password") != string::npos)
+ value = "***";
+ else
+ value = ::arg()[item];
+
+ Value jvalue(value.c_str(), doc.GetAllocator());
+ jitem.AddMember("value", jvalue, doc.GetAllocator());
+
+ doc.PushBack(jitem, doc.GetAllocator());
+ }
+ resp->body = makeStringFromDocument(doc);
+}
+
+static string logGrep(const string& q, const string& fname, const string& prefix)
+{
+ FILE* ptr = fopen(fname.c_str(), "r");
+ if(!ptr) {
+ return "[]";
+ }
+ boost::shared_ptr<FILE> fp(ptr, fclose);
+
+ string line;
+ string needle = q;
+ trim_right(needle);
+
+ boost::replace_all(needle, "%20", " ");
+ boost::replace_all(needle, "%22", "\"");
+
+ boost::tokenizer<boost::escaped_list_separator<char> > t(needle, boost::escaped_list_separator<char>("\\", " ", "\""));
+ vector<string> matches(t.begin(), t.end());
+ matches.push_back(prefix);
+
+ boost::circular_buffer<string> lines(200);
+ while(stringfgets(fp.get(), line)) {
+ vector<string>::const_iterator iter;
+ for(iter = matches.begin(); iter != matches.end(); ++iter) {
+ if(!strcasestr(line.c_str(), iter->c_str()))
+ break;
+ }
+ if(iter == matches.end()) {
+ trim_right(line);
+ lines.push_front(line);
+ }
+ }
+
+ Document doc;
+ doc.SetArray();
+ if(!lines.empty()) {
+ BOOST_FOREACH(const string& line, lines) {
+ doc.PushBack(line.c_str(), doc.GetAllocator());
+ }
+ }
+ return makeStringFromDocument(doc);
+}
+
+void apiServerSearchLog(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ string prefix;
+ switch (versionGetProduct()) {
+ case ProductAuthoritative:
+ prefix = " pdns[";
+ break;
+ case ProductRecursor:
+ prefix = " pdns_recursor[";
+ break;
+ }
+ resp->body = logGrep(req->parameters["q"], ::arg()["experimental-logfile"], prefix);
+}
+
+void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ map<string,string> items;
+ productServerStatisticsFetch(items);
+
+ Document doc;
+ doc.SetArray();
+ typedef map<string, string> items_t;
+ BOOST_FOREACH(const items_t::value_type& item, items) {
+ Value jitem;
+ jitem.SetObject();
+ jitem.AddMember("type", "StatisticItem", doc.GetAllocator());
+
+ Value jname(item.first.c_str(), doc.GetAllocator());
+ jitem.AddMember("name", jname, doc.GetAllocator());
+
+ Value jvalue(item.second.c_str(), doc.GetAllocator());
+ jitem.AddMember("value", jvalue, doc.GetAllocator());
+
+ doc.PushBack(jitem, doc.GetAllocator());
+ }
+
+ resp->body = makeStringFromDocument(doc);
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#include <map>
+#include "rapidjson/document.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
+#include "webserver.hh"
+
+void apiServer(HttpRequest* req, HttpResponse* resp);
+void apiServerDetail(HttpRequest* req, HttpResponse* resp);
+void apiServerConfig(HttpRequest* req, HttpResponse* resp);
+void apiServerSearchLog(HttpRequest* req, HttpResponse* resp);
+void apiServerStatistics(HttpRequest* req, HttpResponse* resp);
+
+// To be provided by product code.
+void productServerStatisticsFetch(std::map<string,string>& out);
/*
- Copyright (C) 2002 - 2012 PowerDNS.COM BV
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
+ it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation
Additionally, the license of this program contains a special
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
+#include "ws-api.hh"
#include "version.hh"
using namespace rapidjson;
extern StatBag S;
-typedef map<string,string> varmap_t;
-
AuthWebServer::AuthWebServer()
{
d_start=time(0);
resp->body = ret.str();
}
-static void parseJsonBody(HttpRequest* req, rapidjson::Document& document) {
- if(document.Parse<0>(req->body.c_str()).HasParseError()) {
- throw HttpBadRequestException();
- }
-}
-
-static int intFromJson(const Value& container, const char* key) {
- const Value& val = container[key];
- if (val.IsInt()) {
- return val.GetInt();
- } else if (val.IsString()) {
- return atoi(val.GetString());
- } else {
- throw ApiException("Key '" + string(key) + "' not an Integer or not present");
- }
-}
-
-static int intFromJson(const Value& container, const char* key, const int default_value) {
- const Value& val = container[key];
- if (val.IsInt()) {
- return val.GetInt();
- } else if (val.IsString()) {
- return atoi(val.GetString());
- } else {
- // TODO: check if value really isn't present
- return default_value;
- }
-}
-
-static string stringFromJson(const Value& container, const char* key) {
- const Value& val = container[key];
- if (val.IsString()) {
- return val.GetString();
- } else {
- throw ApiException("Key '" + string(key) + "' not present or not a String");
- }
-}
-
-static string stringFromJson(const Value& container, const char* key, const string default_value) {
- const Value& val = container[key];
- if (val.IsString()) {
- return val.GetString();
- } else {
- // TODO: check if value really isn't present
- return default_value;
- }
-}
-
static string getZone(const string& zonename) {
UeberBackend B;
DomainInfo di;
if(!B.getDomainInfo(zonename, di))
- return returnJSONError("Could not find domain '"+zonename+"'");
+ return returnJsonError("Could not find domain '"+zonename+"'");
Document doc;
doc.SetObject();
return makeStringFromDocument(doc);
}
-static void fillServerDetail(Value& out, Value::AllocatorType& allocator) {
- Value jdaemonType(productTypeApiType().c_str(), allocator);
- out.SetObject();
- out.AddMember("type", "Server", allocator);
- out.AddMember("id", "localhost", allocator);
- out.AddMember("url", "/servers/localhost", allocator);
- out.AddMember("daemon_type", jdaemonType, allocator);
- out.AddMember("version", VERSION, allocator);
- out.AddMember("config_url", "/servers/localhost/config{/config_setting}", allocator);
- out.AddMember("zones_url", "/servers/localhost/zones{/zone}", allocator);
-}
-
-static void apiServer(HttpRequest* req, HttpResponse* resp) {
- if(req->method != "GET")
- throw HttpMethodNotAllowedException();
-
- vector<string> items = ::arg().list();
- Document doc;
- doc.SetArray();
- Value server;
- fillServerDetail(server, doc.GetAllocator());
- doc.PushBack(server, doc.GetAllocator());
- resp->body = makeStringFromDocument(doc);
-}
-
-static void apiServerDetail(HttpRequest* req, HttpResponse* resp) {
- if(req->method != "GET")
- throw HttpMethodNotAllowedException();
-
- vector<string> items = ::arg().list();
- Document doc;
- fillServerDetail(doc, doc.GetAllocator());
- resp->body = makeStringFromDocument(doc);
-}
-
-static void apiServerConfig(HttpRequest* req, HttpResponse* resp) {
- if(req->method != "GET")
- throw HttpMethodNotAllowedException();
-
- vector<string> items = ::arg().list();
- string value;
- Document doc;
- doc.SetArray();
- BOOST_FOREACH(const string& item, items) {
- Value jitem;
- jitem.SetObject();
- jitem.AddMember("type", "ConfigSetting", doc.GetAllocator());
-
- Value jname(item.c_str(), doc.GetAllocator());
- jitem.AddMember("name", jname, doc.GetAllocator());
-
- if(item.find("password") != string::npos)
- value = "***";
- else
- value = ::arg()[item];
-
- Value jvalue(value.c_str(), doc.GetAllocator());
- jitem.AddMember("value", jvalue, doc.GetAllocator());
-
- doc.PushBack(jitem, doc.GetAllocator());
- }
- resp->body = makeStringFromDocument(doc);
-}
-
-static void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
- if(req->method != "GET")
- throw HttpMethodNotAllowedException();
-
+void productServerStatisticsFetch(map<string,string>& out)
+{
vector<string> items = S.getEntries();
- string value;
- Document doc;
- doc.SetArray();
BOOST_FOREACH(const string& item, items) {
- Value jitem;
- jitem.SetObject();
- jitem.AddMember("type", "StatisticItem", doc.GetAllocator());
-
- Value jname(item.c_str(), doc.GetAllocator());
- jitem.AddMember("name", jname, doc.GetAllocator());
-
- value = lexical_cast<string>(S.read(item));
-
- Value jvalue(value.c_str(), doc.GetAllocator());
- jitem.AddMember("value", jvalue, doc.GetAllocator());
-
- doc.PushBack(jitem, doc.GetAllocator());
+ out[item] = lexical_cast<string>(S.read(item));
}
// add uptime
- // TODO: this is a hack. should we move this elsewhere?
- {
- Value jitem;
- jitem.SetObject();
- jitem.AddMember("type", "StatisticItem", doc.GetAllocator());
- jitem.AddMember("name", "uptime", doc.GetAllocator());
- value = lexical_cast<string>(time(0) - s_starttime);
- Value jvalue(value.c_str(), doc.GetAllocator());
- jitem.AddMember("value", jvalue, doc.GetAllocator());
- doc.PushBack(jitem, doc.GetAllocator());
- }
-
- resp->body = makeStringFromDocument(doc);
-}
-
-static void apiServerSearchLog(HttpRequest* req, HttpResponse* resp) {
- if(req->method != "GET")
- throw HttpMethodNotAllowedException();
-
- resp->body = makeLogGrepJSON(req->parameters["q"], ::arg()["experimental-logfile"], " pdns[");
+ out["uptime"] = lexical_cast<string>(time(0) - s_starttime);
}
static void apiServerZones(HttpRequest* req, HttpResponse* resp) {
if (req->method == "POST") {
DomainInfo di;
Document document;
- parseJsonBody(req, document);
+ req->json(document);
string zonename = stringFromJson(document, "name");
// TODO: better validation of zonename
if(zonename.empty())
throw ApiException("Could not find domain '"+zonename+"'");
Document document;
- parseJsonBody(req, document);
+ req->json(document);
string master;
const Value &masters = document["masters"];
throw ApiException("Could not find domain '"+zonename+"'");
Document document;
- parseJsonBody(req, document);
+ req->json(document);
string qname, changetype;
QType qtype;
map<string, string> object;
object["number"]=lexical_cast<string>(number);
//cerr<<"Flushed cache for '"<<parameters["domain"]<<"', cleaned "<<number<<" records"<<endl;
- resp->body = returnJSONObject(object);
+ resp->body = returnJsonObject(object);
return;
}
else if(command == "pdns-control") {
throw HttpMethodNotAllowedException();
// cout<<"post: "<<post<<endl;
rapidjson::Document document;
- if(document.Parse<0>(req->body.c_str()).HasParseError()) {
- resp->status = 400;
- resp->body = returnJSONError("Unable to parse JSON");
- return;
- }
+ req->json(document);
// cout<<"Parameters: '"<<document["parameters"].GetString()<<"'\n";
vector<string> parameters;
stringtok(parameters, document["parameters"].GetString(), " \t");
resp->status = 404;
m["error"]="No such function "+toUpper(parameters[0]);
}
- resp->body = returnJSONObject(m);
+ resp->body = returnJsonObject(m);
return;
}
else if(command=="log-grep") {
- resp->body = makeLogGrepJSON(req->parameters["needle"], ::arg()["experimental-logfile"], " pdns[");
+ // legacy parameter name hack
+ req->parameters["q"] = req->parameters["needle"];
+ apiServerSearchLog(req, resp);
return;
}
- resp->body = returnJSONError("No or unknown command given");
+ resp->body = returnJsonError("No or unknown command given");
resp->status = 404;
return;
}
Copyright (C) 2003 - 2012 PowerDNS.COM BV
This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
+ it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation
Additionally, the license of this program contains a special
#include "arguments.hh"
#include "misc.hh"
#include "syncres.hh"
-#include "config.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "webserver.hh"
+#include "ws-api.hh"
using namespace rapidjson;
+void productServerStatisticsFetch(map<string,string>& out)
+{
+ map<string,string> stats = getAllStatsMap();
+ out.swap(stats);
+}
+
RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm)
{
RecursorControlParser rcp; // inits
// legacy dispatch
d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2));
+ d_ws->registerApiHandler("/servers/localhost/config", &apiServerConfig);
+ d_ws->registerApiHandler("/servers/localhost/search-log", &apiServerSearchLog);
+ d_ws->registerApiHandler("/servers/localhost/statistics", &apiServerStatistics);
+ d_ws->registerApiHandler("/servers/localhost", &apiServerDetail);
+ d_ws->registerApiHandler("/servers", &apiServer);
d_ws->go();
}
resp->body = makeStringFromDocument(doc);
return;
} else {
- resp->body = returnJSONError("Could not find domain '"+arg_zone+"'");
+ resp->body = returnJsonError("Could not find domain '"+arg_zone+"'");
return;
}
}
int count = broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, canon));
count+=broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, canon));
stats["number"]=lexical_cast<string>(count);
- resp->body = returnJSONObject(stats);
+ resp->body = returnJsonObject(stats);
return;
}
else if(command == "config") {
BOOST_FOREACH(const string& var, items) {
stats[var] = ::arg()[var];
}
- resp->body = returnJSONObject(stats);
+ resp->body = returnJsonObject(stats);
return;
}
else if(command == "log-grep") {
- resp->body = makeLogGrepJSON(req->parameters["needle"], ::arg()["experimental-logfile"], " pdns_recursor[");
+ // legacy parameter name hack
+ req->parameters["q"] = req->parameters["needle"];
+ apiServerSearchLog(req, resp);
return;
}
else if(command == "stats") {
stats = getAllStatsMap();
- resp->body = returnJSONObject(stats);
+ resp->body = returnJsonObject(stats);
return;
} else {
resp->status = 404;
- resp->body = returnJSONError("Not found");
+ resp->body = returnJsonError("Not found");
}
}
#include <boost/utility.hpp>
#include "namespaces.hh"
#include "mplexer.hh"
-#include "webserver.hh"
+
+class AsyncWebServer;
+class HttpRequest;
+class HttpResponse;
class RecursorWebServer : public boost::noncopyable
{