]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ws-api.cc
2 Copyright (C) 2002 - 2014 PowerDNS.COM BV
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2
6 as published by the Free Software Foundation
8 Additionally, the license of this program contains a special
9 exception which allows to distribute the program in binary form when
10 it is linked against OpenSSL.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <boost/foreach.hpp>
22 #include <boost/tokenizer.hpp>
23 #include <boost/circular_buffer.hpp>
24 #include "namespaces.hh"
29 #include "arguments.hh"
33 #include <sys/types.h>
36 extern string s_programname
;
38 #ifndef HAVE_STRCASESTR
41 * strcasestr() locates the first occurrence in the string s1 of the
42 * sequence of characters (excluding the terminating null character)
43 * in the string s2, ignoring case. strcasestr() returns a pointer
44 * to the located string, or a null pointer if the string is not found.
45 * If s2 is empty, the function returns s1.
49 strcasestr(const char *s1
, const char *s2
)
51 int *cm
= __trans_lower
;
52 const uchar_t
*us1
= (const uchar_t
*)s1
;
53 const uchar_t
*us2
= (const uchar_t
*)s2
;
57 if (us2
== NULL
|| *us2
== '\0')
61 while (*us1
!= '\0') {
62 if (c
== cm
[*us1
++]) {
64 while (cm
[c
= *++us2
] == cm
[*us1
++] && c
!= '\0')
67 return ((char *)tptr
- 1);
69 us2
= (const uchar_t
*)s2
;
77 #endif // HAVE_STRCASESTR
79 using namespace rapidjson
;
81 static void fillServerDetail(Value
& out
, Value::AllocatorType
& allocator
)
83 Value
jdaemonType(productTypeApiType().c_str(), allocator
);
85 out
.AddMember("type", "Server", allocator
);
86 out
.AddMember("id", "localhost", allocator
);
87 out
.AddMember("url", "/servers/localhost", allocator
);
88 out
.AddMember("daemon_type", jdaemonType
, allocator
);
89 out
.AddMember("version", VERSION
, allocator
);
90 out
.AddMember("config_url", "/servers/localhost/config{/config_setting}", allocator
);
91 out
.AddMember("zones_url", "/servers/localhost/zones{/zone}", allocator
);
94 void apiServer(HttpRequest
* req
, HttpResponse
* resp
) {
95 if(req
->method
!= "GET")
96 throw HttpMethodNotAllowedException();
101 fillServerDetail(server
, doc
.GetAllocator());
102 doc
.PushBack(server
, doc
.GetAllocator());
106 void apiServerDetail(HttpRequest
* req
, HttpResponse
* resp
) {
107 if(req
->method
!= "GET")
108 throw HttpMethodNotAllowedException();
111 fillServerDetail(doc
, doc
.GetAllocator());
115 void apiServerConfig(HttpRequest
* req
, HttpResponse
* resp
) {
116 if(req
->method
!= "GET")
117 throw HttpMethodNotAllowedException();
119 vector
<string
> items
= ::arg().list();
123 BOOST_FOREACH(const string
& item
, items
) {
126 jitem
.AddMember("type", "ConfigSetting", doc
.GetAllocator());
128 Value
jname(item
.c_str(), doc
.GetAllocator());
129 jitem
.AddMember("name", jname
, doc
.GetAllocator());
131 if(item
.find("password") != string::npos
)
134 value
= ::arg()[item
];
136 Value
jvalue(value
.c_str(), doc
.GetAllocator());
137 jitem
.AddMember("value", jvalue
, doc
.GetAllocator());
139 doc
.PushBack(jitem
, doc
.GetAllocator());
144 static string
logGrep(const string
& q
, const string
& fname
, const string
& prefix
)
146 FILE* ptr
= fopen(fname
.c_str(), "r");
148 throw ApiException("Opening \"" + fname
+ "\" failed: " + stringerror());
150 boost::shared_ptr
<FILE> fp(ptr
, fclose
);
156 boost::replace_all(needle
, "%20", " ");
157 boost::replace_all(needle
, "%22", "\"");
159 boost::tokenizer
<boost::escaped_list_separator
<char> > t(needle
, boost::escaped_list_separator
<char>("\\", " ", "\""));
160 vector
<string
> matches(t
.begin(), t
.end());
161 matches
.push_back(prefix
);
163 boost::circular_buffer
<string
> lines(200);
164 while(stringfgets(fp
.get(), line
)) {
165 vector
<string
>::const_iterator iter
;
166 for(iter
= matches
.begin(); iter
!= matches
.end(); ++iter
) {
167 if(!strcasestr(line
.c_str(), iter
->c_str()))
170 if(iter
== matches
.end()) {
172 lines
.push_front(line
);
179 BOOST_FOREACH(const string
& line
, lines
) {
180 doc
.PushBack(line
.c_str(), doc
.GetAllocator());
183 return makeStringFromDocument(doc
);
186 void apiServerSearchLog(HttpRequest
* req
, HttpResponse
* resp
) {
187 if(req
->method
!= "GET")
188 throw HttpMethodNotAllowedException();
190 string prefix
= " " + s_programname
+ "[";
191 resp
->body
= logGrep(req
->getvars
["q"], ::arg()["experimental-logfile"], prefix
);
194 void apiServerStatistics(HttpRequest
* req
, HttpResponse
* resp
) {
195 if(req
->method
!= "GET")
196 throw HttpMethodNotAllowedException();
198 map
<string
,string
> items
;
199 productServerStatisticsFetch(items
);
203 typedef map
<string
, string
> items_t
;
204 BOOST_FOREACH(const items_t::value_type
& item
, items
) {
207 jitem
.AddMember("type", "StatisticItem", doc
.GetAllocator());
209 Value
jname(item
.first
.c_str(), doc
.GetAllocator());
210 jitem
.AddMember("name", jname
, doc
.GetAllocator());
212 Value
jvalue(item
.second
.c_str(), doc
.GetAllocator());
213 jitem
.AddMember("value", jvalue
, doc
.GetAllocator());
215 doc
.PushBack(jitem
, doc
.GetAllocator());
221 string
apiZoneIdToName(const string
& id
) {
226 throw HttpBadRequestException();
228 std::size_t lastpos
= 0, pos
= 0;
229 while ((pos
= id
.find('=', lastpos
)) != string::npos
) {
230 ss
<< id
.substr(lastpos
, pos
-lastpos
);
233 if (id
[pos
+1] >= '0' && id
[pos
+1] <= '9') {
235 } else if (id
[pos
+1] >= 'A' && id
[pos
+1] <= 'F') {
236 c
= id
[pos
+1] - 'A' + 10;
238 throw HttpBadRequestException();
243 if (id
[pos
+2] >= '0' && id
[pos
+2] <= '9') {
244 c
+= id
[pos
+2] - '0';
245 } else if (id
[pos
+2] >= 'A' && id
[pos
+2] <= 'F') {
246 c
+= id
[pos
+2] - 'A' + 10;
248 throw HttpBadRequestException();
256 ss
<< id
.substr(lastpos
, pos
-lastpos
);
261 // strip trailing dot
262 if (zonename
.substr(zonename
.size()-1) == ".") {
263 zonename
.resize(zonename
.size()-1);
268 string
apiZoneNameToId(const string
& name
) {
271 for(string::const_iterator iter
= name
.begin(); iter
!= name
.end(); ++iter
) {
272 if ((*iter
>= 'A' && *iter
<= 'Z') ||
273 (*iter
>= 'a' && *iter
<= 'z') ||
274 (*iter
>= '0' && *iter
<= '9') ||
275 (*iter
== '.') || (*iter
== '-')) {
278 ss
<< (boost::format("=%02X") % (int)(*iter
));
282 string id
= ss
.str();
285 if (id
.substr(id
.size()-1) != ".") {
289 // special handling for the root zone, as a dot on it's own doesn't work
292 id
= (boost::format("=%02x") % (int)('.')).str();