]> granicus.if.org Git - pdns/commitdiff
-- libjson-cpp is now a dependency, remotebackend is mandatory for building from...
authorBert Hubert <bert.hubert@netherlabs.nl>
Fri, 30 Nov 2012 16:10:12 +0000 (16:10 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Fri, 30 Nov 2012 16:10:12 +0000 (16:10 +0000)
teach our appalling webserver about different methods, allow it to read POSTed forms, teach it to parse JSON restful requests on our database!

git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2939 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/webserver.cc
pdns/webserver.hh
pdns/ws.cc
pdns/ws.hh

index 8e94d90278d51eca8569b26079ced43d5670f959..ae0190466a24ff29a581a83d611a339fb20d041e 100644 (file)
@@ -62,9 +62,11 @@ void *WebServer::serveConnection(void *p)
     vector<string> parts;
     stringtok(parts,line);
     
-    string uri;
-    if(parts.size()>1)
+    string method, uri;
+    if(parts.size()>1) {
+      method=parts[0];
       uri=parts[1];
+    }
 
     vector<string>variables;
 
@@ -102,7 +104,7 @@ void *WebServer::serveConnection(void *p)
     }
 
     bool authOK=0;
-
+    int postlen = 0;
     // read & ignore other lines
     do {
       client->getLine(line);
@@ -121,8 +123,21 @@ void *WebServer::serveConnection(void *p)
           authOK=1;
         }
       }
+      else if(boost::starts_with(line, "Content-Length: ") && method=="POST") {
+       postlen = atoi(line.c_str() + strlen("Content-Length: "));
+//     cout<<"Got a post: "<<postlen<<" bytes"<<endl;
+      }
+      else
+       ; // cerr<<"Ignoring line: "<<line<<endl;
+      
     }while(!line.empty());
 
+    string post;
+    if(postlen) 
+      post = client->get(postlen);
+  
+ //   cout<<"Post: '"<<post<<"'"<<endl;
+
     if(!d_password.empty() && !authOK) {
       client->putLine("HTTP/1.1 401 OK\n");
       client->putLine("WWW-Authenticate: Basic realm=\"PowerDNS\"\n");
@@ -138,7 +153,7 @@ void *WebServer::serveConnection(void *p)
     HandlerFunction *fptr;
     if(d_functions.count(baseUrl) && (fptr=d_functions[baseUrl])) {
       bool custom=false;
-      string ret=(*fptr)(varmap, d_that, &custom);
+      string ret=(*fptr)(method, post, varmap, d_that, &custom);
 
       if(!custom) {
         client->putLine("HTTP/1.1 200 OK\n");
index 878fbecdeecf208efa16340c6f9914838bdacae8..bde1e7634c72c334de90ba900290687558d2808f 100644 (file)
@@ -1,6 +1,6 @@
 /*
     PowerDNS Versatile Database Driven Nameserver
-    Copyright (C) 2002  PowerDNS.COM BV
+    Copyright (C) 2002-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
@@ -32,7 +32,7 @@ public:
   void go();
   static void* serveConnection(void *);
   void setCaller(void *that);
-  typedef string HandlerFunction(const map<string,string>&varmap, void *that, bool *custom);
+  typedef string HandlerFunction(const string& method, const string& post, const map<string,string>&varmap, void *that, bool *custom);
   void registerHandler(const string &, HandlerFunction *ptr);
 private:
   static char B64Decode1(char cInChar);
index 9220e46bc3faa549989cd17cf4af4d935478db31..fb9caac0728a99d71c4cd46d9b8b85f72f5e1b9f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002 - 2007  PowerDNS.COM BV
+    Copyright (C) 2002 - 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 
@@ -28,6 +28,7 @@
 #include <boost/format.hpp>
 #include <boost/foreach.hpp>
 #include "namespaces.hh"
+#include <jsoncpp/json/json.h>
 
 extern StatBag S;
 
@@ -152,7 +153,7 @@ string StatWebServer::makePercentage(const double& val)
   return (boost::format("%.01f%%") % val).str();
 }
 
-string StatWebServer::indexfunction(const map<string,string> &varmap, void *ptr, bool *custom)
+string StatWebServer::indexfunction(const string& method, const string& post, const map<string,string> &varmap, void *ptr, bool *custom)
 {
   StatWebServer *sws=static_cast<StatWebServer *>(ptr);
   map<string,string>rvarmap=varmap;
@@ -231,11 +232,10 @@ string StatWebServer::indexfunction(const map<string,string> &varmap, void *ptr,
 }
 
 
-string StatWebServer::jsonstat(const map<string,string> &varmap, void *ptr, bool *custom)
+string StatWebServer::jsonstat(const string& method, const string& post, const map<string,string> &varmap, void *ptr, bool *custom)
 {
-  *custom=1;
+  *custom=1; // indicates we build the response
   string ret="HTTP/1.1 200 OK\r\n"
-  "Date: Wed, 30 Nov 2011 22:01:15 GMT\r\n" // XXX FIXME real date!
   "Server: PowerDNS/"VERSION"\r\n"
   "Connection: close\r\n"
   "Access-Control-Allow-Origin: *\r\n"
@@ -353,6 +353,95 @@ string StatWebServer::jsonstat(const map<string,string> &varmap, void *ptr, bool
 
     ret += "]";
   }
+  if(command == "zone-rest") { // http://jsonstat?command=zone-rest&rest=/powerdns.nl/www.powerdns.nl/a
+    vector<string> parts;
+    stringtok(parts, ourvarmap["rest"], "/");
+    if(parts.size() != 3) 
+      return ret+"{\"error\": \"Could not parse rest parameter\"}";
+    UeberBackend B;
+    SOAData sd;
+    sd.db = (DNSBackend*)-1;
+    if(!B.getSOA(parts[0], sd) || !sd.db) {
+      map<string, string> err;
+      err["error"]= "Could not find domain '"+ourvarmap["zone"]+"'";
+      return ret+returnJSONObject(err);
+    }
+    
+    QType qtype;
+    qtype=parts[2];
+    string qname=parts[1];
+    extern PacketCache PC;
+    PC.purge(qname);
+    // cerr<<"domain id: "<<sd.domain_id<<", lookup name: '"<<parts[1]<<"', for type: '"<<qtype.getName()<<"'"<<endl;
+    
+    if(method == "GET" ) {
+      B.lookup(qtype, parts[1], 0, sd.domain_id);
+      
+      DNSResourceRecord rr;
+      ret+="{ \"records\": [";
+      map<string, string> object;
+      bool first=1;
+      
+      while(B.get(rr)) {
+       if(!first) ret += ", ";
+         first=false;
+       object.clear();
+       object["name"] = rr.qname;
+       object["type"] = rr.qtype.getName();
+       object["ttl"] = lexical_cast<string>(rr.ttl);
+       object["priority"] = lexical_cast<string>(rr.priority);
+       object["content"] = rr.content;
+       ret+=returnJSONObject(object);
+      }
+      ret+="]}";
+    }
+    else if(method=="DELETE") {
+      sd.db->replaceRRSet(sd.domain_id, qname, qtype, vector<DNSResourceRecord>());
+      
+    }
+    else if(method=="POST") {
+      Json::Value root;   // will contains the root value after parsing.
+      Json::Reader reader;
+      if(!reader.parse(post, root )) {
+       return ret+"{\"error\": \"Unable to parse JSON\"";
+      }
+      
+      const Json::Value records=root["records"];
+      
+      DNSResourceRecord rr;
+      vector<DNSResourceRecord> rrset;
+      for(unsigned int i = 0 ; i < records.size(); ++i) {
+       const Json::Value& record = records[i];
+       rr.qname=record["name"].asString();
+       rr.content=record["content"].asString();
+       rr.qtype=record["type"].asString();
+       rr.domain_id = sd.domain_id;
+       rr.auth=0;
+       rr.ttl=atoi(record["ttl"].asString().c_str());
+       rr.priority=atoi(record["priority"].asString().c_str());
+       
+       rrset.push_back(rr);
+       
+       if(rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) 
+         rr.content = lexical_cast<string>(rr.priority)+" "+rr.content;
+         
+       try {
+         shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
+         string tmp=drc->serialize(rr.qname);
+       }
+       catch(std::exception& e) 
+       {
+         map<string, string> err;
+         err["error"]= "Following record had a problem: "+rr.qname+" IN " +rr.qtype.getName()+ " " + rr.content+": "+e.what();
+         return ret+returnJSONObject(err);
+       }
+      }
+      // but now what
+      sd.db->startTransaction(qname);
+      sd.db->replaceRRSet(sd.domain_id, qname, qtype, rrset);
+      sd.db->commitTransaction();
+    }  
+  }
   if(command=="log-grep") {
     ret += makeLogGrepJSON(ourvarmap, ::arg()["logfile"], " pdns[");
   }
index 63f1fc9968132c7bee8b32411915aff53f64c64f..e5c6ff72612676185c1f16d8ba0e1dac75caa88c 100644 (file)
@@ -86,8 +86,8 @@ public:
 private:
   static void *threadHelper(void *);
   static void *statThreadHelper(void *p);
-  static string indexfunction(const map<string,string> &varmap, void *ptr, bool *custom);
-  static string jsonstat(const map<string,string> &varmap, void *ptr, bool *custom);
+  static string indexfunction(const string& method, const string& post, const map<string,string> &varmap, void *ptr, bool *custom);
+  static string jsonstat(const string& method, const string& post, const map<string,string> &varmap, void *ptr, bool *custom);
   void printvars(ostringstream &ret);
   void printargs(ostringstream &ret);
   void launch();