#include <string.h>
#include <ctype.h>
#include <sys/types.h>
+#include <iomanip>
#ifndef HAVE_STRCASESTR
resp->setBody(doc);
}
+
+string apiZoneIdToName(const string& id) {
+ string zonename;
+ ostringstream ss;
+
+ if(id.empty())
+ throw HttpBadRequestException();
+
+ std::size_t lastpos = 0, pos = 0;
+ while ((pos = id.find('=', lastpos)) != string::npos) {
+ ss << id.substr(lastpos, pos-lastpos);
+ if ((id[pos+1] >= '0' && id[pos+1] <= '9') &&
+ (id[pos+2] >= '0' && id[pos+2] <= '9')) {
+ char c = ((id[pos+1] - '0')*10) + (id[pos+2] - '0');
+ ss << c;
+ } else {
+ throw HttpBadRequestException();
+ }
+
+ lastpos = pos+3;
+ }
+ if (lastpos < pos) {
+ ss << id.substr(lastpos, pos-lastpos);
+ }
+
+ zonename = ss.str();
+
+ // strip trailing dot
+ if (zonename.substr(zonename.size()-1) == ".") {
+ zonename = zonename.substr(0, zonename.size()-1);
+ }
+ return zonename;
+}
+
+string apiZoneNameToId(const string& name) {
+ ostringstream ss;
+
+ for(string::const_iterator iter = name.begin(); iter != name.end(); ++iter) {
+ if ((*iter >= 'A' && *iter <= 'Z') ||
+ (*iter >= 'a' && *iter <= 'z') ||
+ (*iter >= '0' && *iter <= '9') ||
+ (*iter == '.') || (*iter == '-')) {
+ ss << *iter;
+ } else {
+ ss << "=" << std::setfill('0') << std::setw(2) << (int)(*iter);
+ }
+ }
+
+ // add trailing dot
+ string id = ss.str() + ".";
+
+ // special handling for the root zone, as a dot on it's own doesn't work
+ // everywhere.
+ if (id == ".") {
+ id = (boost::format("=%d") % (int)('.')).str();
+ }
+ return id;
+}
void apiServerSearchLog(HttpRequest* req, HttpResponse* resp);
void apiServerStatistics(HttpRequest* req, HttpResponse* resp);
+// helpers
+string apiZoneIdToName(const string& id);
+string apiZoneNameToId(const string& name);
+
// To be provided by product code.
void productServerStatisticsFetch(std::map<string,string>& out);
#include "rapidjson/writer.h"
#include "ws-api.hh"
#include "version.hh"
+#include <iomanip>
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif // HAVE_CONFIG_H
using namespace rapidjson;
doc.SetObject();
// id is the canonical lookup key, which doesn't actually match the name (in some cases)
- doc.AddMember("id", di.zone.c_str(), doc.GetAllocator());
- string url = (boost::format("/servers/localhost/zones/%s") % di.zone).str();
+ string zoneId = apiZoneNameToId(di.zone);
+ Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
+ doc.AddMember("id", jzoneId, doc.GetAllocator());
+ string url = "/servers/localhost/zones/" + zoneId;
Value jurl(url.c_str(), doc.GetAllocator()); // copy
doc.AddMember("url", jurl, doc.GetAllocator());
doc.AddMember("name", di.zone.c_str(), doc.GetAllocator());
Value jdi;
jdi.SetObject();
// id is the canonical lookup key, which doesn't actually match the name (in some cases)
- jdi.AddMember("id", di.zone.c_str(), doc.GetAllocator());
- string url = (boost::format("/servers/localhost/zones/%s") % di.zone).str();
+ string zoneId = apiZoneNameToId(di.zone);
+ Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
+ jdi.AddMember("id", jzoneId, doc.GetAllocator());
+ string url = "/servers/localhost/zones/" + zoneId;
Value jurl(url.c_str(), doc.GetAllocator()); // copy
jdi.AddMember("url", jurl, doc.GetAllocator());
jdi.AddMember("name", di.zone.c_str(), doc.GetAllocator());
}
static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp) {
- string zonename = req->path_parameters["id"];
+ string zonename = apiZoneIdToName(req->path_parameters["id"]);
if(req->method == "PUT") {
// update domain settings
UeberBackend B;
DomainInfo di;
- string zonename = req->path_parameters["id"];
+ string zonename = apiZoneIdToName(req->path_parameters["id"]);
if(!B.getDomainInfo(zonename, di))
throw ApiException("Could not find domain '"+zonename+"'");
#include <map>
#include <time.h>
#include <pthread.h>
-#include <sstream>
-#include <iomanip>
-#include <unistd.h>
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif // HAVE_CONFIG_H
-
#include "misc.hh"
#include "namespaces.hh"
if k in payload:
self.assertEquals(data[k], payload[k])
- @unittest.expectedFailure
def test_CreateZoneWithSymbols(self):
payload, data = self.create_zone(name='foo/bar.'+unique_zone_name())
name = payload['name']
- expected_id = name.replace('/', '\\047')
+ expected_id = (name.replace('/', '=47')) + '.'
for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'):
self.assertIn(k, data)
if k in payload:
self.assertEquals(data[k], payload[k])
self.assertEquals(data['id'], expected_id)
+ def test_GetZoneWithSymbols(self):
+ payload, data = self.create_zone(name='foo/bar.'+unique_zone_name())
+ name = payload['name']
+ zone_id = (name.replace('/', '=47')) + '.'
+ r = self.session.get(self.url("/servers/localhost/zones/" + zone_id))
+ for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'):
+ self.assertIn(k, data)
+ if k in payload:
+ self.assertEquals(data[k], payload[k])
+
def test_GetZone(self):
r = self.session.get(self.url("/servers/localhost/zones"))
domains = r.json()