]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/webserver.cc
pkcs11signers: Use emplace_back for attributes
[thirdparty/pdns.git] / pdns / webserver.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "utility.hh"
26 #include "webserver.hh"
27 #include "misc.hh"
28 #include <thread>
29 #include "threadname.hh"
30 #include <utility>
31 #include <vector>
32 #include "logger.hh"
33 #include <stdio.h>
34 #include "dns.hh"
35 #include "base64.hh"
36 #include "json.hh"
37 #include "uuid-utils.hh"
38 #include <yahttp/router.hpp>
39
40 json11::Json HttpRequest::json()
41 {
42 string err;
43 if(this->body.empty()) {
44 SLOG(g_log<<Logger::Debug<<logprefix<<"JSON document expected in request body, but body was empty" << endl,
45 d_slog->info(Logr::Debug, "JSON document expected in request body, but body was empty"));
46 throw HttpBadRequestException();
47 }
48 json11::Json doc = json11::Json::parse(this->body, err);
49 if (doc.is_null()) {
50 SLOG(g_log<<Logger::Debug<<logprefix<<"parsing of JSON document failed:" << err << endl,
51 d_slog->error(Logr::Debug, err, "parsing of JSON document failed"));
52 throw HttpBadRequestException();
53 }
54 return doc;
55 }
56
57 bool HttpRequest::compareAuthorization(const CredentialsHolder& credentials) const
58 {
59 // validate password
60 auto header = headers.find("authorization");
61 bool auth_ok = false;
62 if (header != headers.end() && toLower(header->second).find("basic ") == 0) {
63 string cookie = header->second.substr(6);
64
65 string plain;
66 B64Decode(cookie, plain);
67
68 vector<string> cparts;
69 stringtok(cparts, plain, ":");
70
71 auth_ok = (cparts.size() == 2 && credentials.matches(cparts[1].c_str()));
72 }
73 return auth_ok;
74 }
75
76 bool HttpRequest::compareHeader(const string &header_name, const string &expected_value) const
77 {
78 auto header = headers.find(header_name);
79 if (header == headers.end()) {
80 return false;
81 }
82
83 // this gets rid of terminating zeros
84 return (0==strcmp(header->second.c_str(), expected_value.c_str()));
85 }
86
87 bool HttpRequest::compareHeader(const string &header_name, const CredentialsHolder& credentials) const
88 {
89 auto header = headers.find(header_name);
90 if (header == headers.end()) {
91 return false;
92 }
93
94 return credentials.matches(header->second);
95 }
96
97 void HttpResponse::setPlainBody(const string& document)
98 {
99 this->headers["Content-Type"] = "text/plain; charset=utf-8";
100
101 this->body = document;
102 }
103
104 void HttpResponse::setYamlBody(const string& document)
105 {
106 this->headers["Content-Type"] = "application/x-yaml";
107
108 this->body = document;
109 }
110
111 void HttpResponse::setJsonBody(const string& document)
112 {
113 this->headers["Content-Type"] = "application/json";
114
115 this->body = document;
116 }
117
118 void HttpResponse::setJsonBody(const json11::Json& document)
119 {
120 this->headers["Content-Type"] = "application/json";
121
122 document.dump(this->body);
123 }
124
125 void HttpResponse::setErrorResult(const std::string& message, const int status_)
126 {
127 setJsonBody(json11::Json::object { { "error", message } });
128 this->status = status_;
129 }
130
131 void HttpResponse::setSuccessResult(const std::string& message, const int status_)
132 {
133 setJsonBody(json11::Json::object { { "result", message } });
134 this->status = status_;
135 }
136
137 static void bareHandlerWrapper(const WebServer::HandlerFunction& handler, YaHTTP::Request* req, YaHTTP::Response* resp)
138 {
139 // wrapper to convert from YaHTTP::* to our subclasses
140 handler(static_cast<HttpRequest*>(req), static_cast<HttpResponse*>(resp));
141 }
142
143 void WebServer::registerBareHandler(const string& url, const HandlerFunction& handler)
144 {
145 YaHTTP::THandlerFunction f = [=](YaHTTP::Request* req, YaHTTP::Response* resp){return bareHandlerWrapper(handler, req, resp);};
146 YaHTTP::Router::Any(url, f);
147 }
148
149 static bool optionsHandler(HttpRequest* req, HttpResponse* resp) {
150 if (req->method == "OPTIONS") {
151 resp->headers["access-control-allow-origin"] = "*";
152 resp->headers["access-control-allow-headers"] = "Content-Type, X-API-Key";
153 resp->headers["access-control-allow-methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS";
154 resp->headers["access-control-max-age"] = "3600";
155 resp->status = 200;
156 resp->headers["content-type"]= "text/plain";
157 resp->body = "";
158 return true;
159 }
160 return false;
161 }
162
163 void WebServer::apiWrapper(const WebServer::HandlerFunction& handler, HttpRequest* req, HttpResponse* resp, bool allowPassword) {
164 if (optionsHandler(req, resp)) return;
165
166 resp->headers["access-control-allow-origin"] = "*";
167
168 if (!d_apikey) {
169 SLOG(g_log<<Logger::Error<<req->logprefix<<"HTTP API Request \"" << req->url.path << "\": Authentication failed, API Key missing in config" << endl,
170 d_slog->info(Logr::Error, "Authentication failed, API Key missing in config", "urlpath", Logging::Loggable(req->url.path)));
171 throw HttpUnauthorizedException("X-API-Key");
172 }
173
174 bool auth_ok = req->compareHeader("x-api-key", *d_apikey) || d_apikey->matches(req->getvars["api-key"]);
175
176 if (!auth_ok && allowPassword) {
177 if (d_webserverPassword) {
178 auth_ok = req->compareAuthorization(*d_webserverPassword);
179 } else {
180 auth_ok = true;
181 }
182 }
183
184 if (!auth_ok) {
185 SLOG(g_log<<Logger::Error<<req->logprefix<<"HTTP Request \"" << req->url.path << "\": Authentication by API Key failed" << endl,
186 d_slog->info(Logr::Error, "Authentication by API Key failed", "urlpath", Logging::Loggable(req->url.path)));
187 throw HttpUnauthorizedException("X-API-Key");
188 }
189
190 // security headers
191 resp->headers["X-Content-Type-Options"] = "nosniff";
192 resp->headers["X-Frame-Options"] = "deny";
193 resp->headers["X-Permitted-Cross-Domain-Policies"] = "none";
194 resp->headers["X-XSS-Protection"] = "1; mode=block";
195 resp->headers["Content-Security-Policy"] = "default-src 'self'; style-src 'self' 'unsafe-inline'";
196
197 req->getvars.erase("_"); // jQuery cache buster
198
199 try {
200 resp->status = 200;
201 handler(req, resp);
202 } catch (ApiException &e) {
203 resp->setErrorResult(e.what(), 422);
204 return;
205 } catch (JsonException &e) {
206 resp->setErrorResult(e.what(), 422);
207 return;
208 }
209
210 if (resp->status == 204) {
211 // No Content -> no Content-Type.
212 resp->headers.erase("Content-Type");
213 }
214 }
215
216 void WebServer::registerApiHandler(const string& url, const HandlerFunction& handler, bool allowPassword) {
217 auto f = [=](HttpRequest *req, HttpResponse* resp){apiWrapper(handler, req, resp, allowPassword);};
218 registerBareHandler(url, f);
219 }
220
221 void WebServer::webWrapper(const WebServer::HandlerFunction& handler, HttpRequest* req, HttpResponse* resp) {
222 if (d_webserverPassword) {
223 bool auth_ok = req->compareAuthorization(*d_webserverPassword);
224 if (!auth_ok) {
225 SLOG(g_log<<Logger::Debug<<req->logprefix<<"HTTP Request \"" << req->url.path << "\": Web Authentication failed" << endl,
226 d_slog->info(Logr::Debug, "HTTP Request: Web Authentication failed", "urlpath", Logging::Loggable(req->url.path)));
227 throw HttpUnauthorizedException("Basic");
228 }
229 }
230
231 handler(req, resp);
232 }
233
234 void WebServer::registerWebHandler(const string& url, const HandlerFunction& handler) {
235 auto f = [=](HttpRequest *req, HttpResponse *resp){webWrapper(handler, req, resp);};
236 registerBareHandler(url, f);
237 }
238
239 static void *WebServerConnectionThreadStart(const WebServer* webServer, std::shared_ptr<Socket> client) {
240 setThreadName("rec/webhndlr");
241 const std::string msg = "Exception while serving a connection in main webserver thread";
242 try {
243 webServer->serveConnection(client);
244 }
245 catch(PDNSException &e) {
246 SLOG(g_log<<Logger::Error<<"PDNSException while serving a connection in main webserver thread: "<<e.reason<<endl,
247 webServer->d_slog->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException")));
248 }
249 catch(std::exception &e) {
250 SLOG(g_log<<Logger::Error<<"STL Exception while serving a connection in main webserver thread: "<<e.what()<<endl,
251 webServer->d_slog->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception")));
252 }
253 catch(...) {
254 SLOG(g_log<<Logger::Error<<"Unknown exception while serving a connection in main webserver thread"<<endl,
255 webServer->d_slog->info(Logr::Error, msg));
256 }
257 return nullptr;
258 }
259
260 void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp) const
261 {
262 // set default headers
263 resp.headers["Content-Type"] = "text/html; charset=utf-8";
264
265 #ifdef RECURSOR
266 auto log = req.d_slog->withValues("urlpath", Logging::Loggable(req.url.path));
267 #endif
268
269 try {
270 if (!req.complete) {
271 SLOG(g_log<<Logger::Debug<<req.logprefix<<"Incomplete request" << endl,
272 d_slog->info(Logr::Debug, "Incomplete request"));
273 throw HttpBadRequestException();
274 }
275 SLOG(g_log<<Logger::Debug<<req.logprefix<<"Handling request \"" << req.url.path << "\"" << endl,
276 log->info(Logr::Debug, "Handling request"));
277
278 YaHTTP::strstr_map_t::iterator header;
279
280 if ((header = req.headers.find("accept")) != req.headers.end()) {
281 // yaml wins over json, json wins over html
282 if (header->second.find("application/x-yaml") != std::string::npos) {
283 req.accept_yaml = true;
284 } else if (header->second.find("text/x-yaml") != std::string::npos) {
285 req.accept_yaml = true;
286 } else if (header->second.find("application/json") != std::string::npos) {
287 req.accept_json = true;
288 } else if (header->second.find("text/html") != std::string::npos) {
289 req.accept_html = true;
290 }
291 }
292
293 YaHTTP::THandlerFunction handler;
294 if (!YaHTTP::Router::Route(&req, handler)) {
295 SLOG(g_log<<Logger::Debug<<req.logprefix<<"No route found for \"" << req.url.path << "\"" << endl,
296 log->info(Logr::Debug, "No route found"));
297 throw HttpNotFoundException();
298 }
299
300 const string msg = "HTTP ISE Exception";
301 try {
302 handler(&req, &resp);
303 SLOG(g_log<<Logger::Debug<<req.logprefix<<"Result for \"" << req.url.path << "\": " << resp.status << ", body length: " << resp.body.size() << endl,
304 log->info(Logr::Debug, "Result", "status", Logging::Loggable(resp.status), "bodyLength", Logging::Loggable(resp.body.size())));
305 }
306 catch(HttpException&) {
307 throw;
308 }
309 catch(PDNSException &e) {
310 SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Exception: " << e.reason << endl,
311 log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException")));
312 throw HttpInternalServerErrorException();
313 }
314 catch(std::exception &e) {
315 SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": STL Exception: " << e.what() << endl,
316 log->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception")));
317 throw HttpInternalServerErrorException();
318 }
319 catch(...) {
320 SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Unknown Exception" << endl,
321 log->info(Logr::Error, msg));
322 throw HttpInternalServerErrorException();
323 }
324 }
325 catch(HttpException &e) {
326 resp = e.response();
327 #ifdef RECURSOR
328 // An HttpException does not initialize d_slog
329 if (!resp.d_slog) {
330 resp.setSLog(log);
331 }
332 #endif
333 // TODO rm this logline?
334 SLOG(g_log<<Logger::Debug<<req.logprefix<<"Error result for \"" << req.url.path << "\": " << resp.status << endl,
335 d_slog->error(Logr::Debug, resp.status, "Error result", "urlpath", Logging::Loggable(req.url.path)));
336 string what = YaHTTP::Utility::status2text(resp.status);
337 if (req.accept_json) {
338 resp.headers["Content-Type"] = "application/json";
339 if (resp.body.empty()) {
340 resp.setErrorResult(what, resp.status);
341 }
342 } else if (req.accept_html) {
343 resp.headers["Content-Type"] = "text/html; charset=utf-8";
344 resp.body = "<!html><title>" + what + "</title><h1>" + what + "</h1>";
345 } else {
346 resp.headers["Content-Type"] = "text/plain; charset=utf-8";
347 resp.body = what;
348 }
349 }
350
351 // always set these headers
352 resp.headers["Connection"] = "close";
353
354 if (req.method == "HEAD") {
355 resp.body = "";
356 } else {
357 resp.headers["Content-Length"] = std::to_string(resp.body.size());
358 }
359 }
360
361 #ifdef RECURSOR
362 // Helper to log key-value maps used by YaHTTP
363 template<>
364 std::string Logging::IterLoggable<YaHTTP::strstr_map_t::const_iterator>::to_string() const
365 {
366 std::ostringstream oss;
367 bool first = true;
368 for (auto i = _t1; i != _t2; i++) {
369 if (!first) {
370 oss << '\n';
371 }
372 else {
373 first = false;
374 }
375 oss << i->first << ": " << i->second;
376 }
377 return oss.str();
378 }
379 #endif
380
381 void WebServer::logRequest(const HttpRequest& req, [[maybe_unused]] const ComboAddress& remote) const {
382 if (d_loglevel >= WebServer::LogLevel::Detailed) {
383 #ifdef RECURSOR
384 if (!g_slogStructured) {
385 #endif
386 auto logprefix = req.logprefix;
387 g_log<<Logger::Notice<<logprefix<<"Request details:"<<endl;
388
389 bool first = true;
390 for (const auto& r : req.getvars) {
391 if (first) {
392 first = false;
393 g_log<<Logger::Notice<<logprefix<<" GET params:"<<endl;
394 }
395 g_log<<Logger::Notice<<logprefix<<" "<<r.first<<": "<<r.second<<endl;
396 }
397
398 first = true;
399 for (const auto& r : req.postvars) {
400 if (first) {
401 first = false;
402 g_log<<Logger::Notice<<logprefix<<" POST params:"<<endl;
403 }
404 g_log<<Logger::Notice<<logprefix<<" "<<r.first<<": "<<r.second<<endl;
405 }
406
407 first = true;
408 for (const auto& h : req.headers) {
409 if (first) {
410 first = false;
411 g_log<<Logger::Notice<<logprefix<<" Headers:"<<endl;
412 }
413 g_log<<Logger::Notice<<logprefix<<" "<<h.first<<": "<<h.second<<endl;
414 }
415
416 if (req.body.empty()) {
417 g_log<<Logger::Notice<<logprefix<<" No body"<<endl;
418 } else {
419 g_log<<Logger::Notice<<logprefix<<" Full body: "<<endl;
420 g_log<<Logger::Notice<<logprefix<<" "<<req.body<<endl;
421 }
422 #ifdef RECURSOR
423 }
424 else {
425 req.d_slog->info(Logr::Info, "Request details", "getParams", Logging::IterLoggable(req.getvars.cbegin(), req.getvars.cend()),
426 "postParams", Logging::IterLoggable(req.postvars.cbegin(), req.postvars.cend()),
427 "body", Logging::Loggable(req.body),
428 "address", Logging::Loggable(remote));
429 }
430 #endif
431 }
432 }
433
434 void WebServer::logResponse(const HttpResponse& resp, const ComboAddress& /* remote */, const string& logprefix) const {
435 if (d_loglevel >= WebServer::LogLevel::Detailed) {
436 #ifdef RECURSOR
437 if (!g_slogStructured) {
438 #endif
439 g_log<<Logger::Notice<<logprefix<<"Response details:"<<endl;
440 bool first = true;
441 for (const auto& h : resp.headers) {
442 if (first) {
443 first = false;
444 g_log<<Logger::Notice<<logprefix<<" Headers:"<<endl;
445 }
446 g_log<<Logger::Notice<<logprefix<<" "<<h.first<<": "<<h.second<<endl;
447 }
448 if (resp.body.empty()) {
449 g_log<<Logger::Notice<<logprefix<<" No body"<<endl;
450 } else {
451 g_log<<Logger::Notice<<logprefix<<" Full body: "<<endl;
452 g_log<<Logger::Notice<<logprefix<<" "<<resp.body<<endl;
453 }
454 #ifdef RECURSOR
455 }
456 else {
457 resp.d_slog->info(Logr::Info, "Response details", "headers", Logging::IterLoggable(resp.headers.cbegin(), resp.headers.cend()),
458 "body", Logging::Loggable(resp.body));
459 }
460 #endif
461 }
462 }
463
464 void WebServer::serveConnection(const std::shared_ptr<Socket>& client) const {
465 const auto unique = getUniqueID();
466 const string logprefix = d_logprefix + to_string(unique) + " ";
467
468 HttpRequest req(logprefix);
469
470 HttpResponse resp;
471 #ifdef RECURSOR
472 auto log = d_slog->withValues("uniqueid", Logging::Loggable(to_string(unique)));
473 req.setSLog(log);
474 resp.setSLog(log);
475 #endif
476 resp.max_response_size=d_maxbodysize;
477 ComboAddress remote;
478 string reply;
479
480 try {
481 YaHTTP::AsyncRequestLoader yarl;
482 yarl.initialize(&req);
483 req.max_request_size=d_maxbodysize;
484 int timeout = 5;
485 client->setNonBlocking();
486
487 try {
488 while(!req.complete) {
489 int bytes;
490 char buf[16000];
491 bytes = client->readWithTimeout(buf, sizeof(buf), timeout);
492 if (bytes > 0) {
493 string data = string(buf, bytes);
494 req.complete = yarl.feed(data);
495 } else {
496 // read error OR EOF
497 break;
498 }
499 }
500 yarl.finalize();
501 } catch (YaHTTP::ParseError &e) {
502 // request stays incomplete
503 SLOG(g_log<<Logger::Warning<<logprefix<<"Unable to parse request: "<<e.what()<<endl,
504 d_slog->error(Logr::Warning, e.what(), "Unable to parse request"));
505 }
506
507 // Uses of `remote` below guarded by d_loglevel
508 if (d_loglevel > WebServer::LogLevel::None) {
509 client->getRemote(remote);
510 }
511
512 logRequest(req, remote);
513
514 WebServer::handleRequest(req, resp);
515 ostringstream ss;
516 resp.write(ss);
517 reply = ss.str();
518
519 logResponse(resp, remote, logprefix);
520
521 client->writenWithTimeout(reply.c_str(), reply.size(), timeout);
522 }
523 catch(PDNSException &e) {
524 SLOG(g_log<<Logger::Error<<logprefix<<"HTTP Exception: "<<e.reason<<endl,
525 d_slog->error(Logr::Error, e.reason, "HTTP Exception", "exception", Logging::Loggable("PDNSException")));
526 }
527 catch(std::exception &e) {
528 if(strstr(e.what(), "timeout")==nullptr)
529 SLOG(g_log<<Logger::Error<<logprefix<<"HTTP STL Exception: "<<e.what()<<endl,
530 d_slog->error(Logr::Error, e.what(), "HTTP Exception", "exception", Logging::Loggable("std::exception")));
531 }
532 catch(...) {
533 SLOG(g_log<<Logger::Error<<logprefix<<"Unknown exception"<<endl,
534 d_slog->info(Logr::Error, "HTTP Exception"));
535 }
536
537 if (d_loglevel >= WebServer::LogLevel::Normal) {
538 SLOG(g_log<<Logger::Notice<<logprefix<<remote<<" \""<<req.method<<" "<<YaHTTP::Utility::encodeURL(req.url.path)<<" HTTP/"<<req.versionStr(req.version)<<"\" "<<resp.status<<" "<<reply.size()<<endl,
539 d_slog->info(Logr::Info, "Request", "remote", Logging::Loggable(remote), "method", Logging::Loggable(req.method),
540 "urlpath", Logging::Loggable(req.url.path), "HTTPVersion", Logging::Loggable(req.versionStr(req.version)),
541 "status", Logging::Loggable(resp.status), "respsize", Logging::Loggable(reply.size())));
542 }
543 }
544
545 WebServer::WebServer(string listenaddress, int port) :
546 d_listenaddress(std::move(listenaddress)),
547 d_port(port),
548 d_server(nullptr),
549 d_maxbodysize(2*1024*1024)
550 {
551 }
552
553 void WebServer::bind()
554 {
555 try {
556 d_server = createServer();
557 SLOG(g_log<<Logger::Warning<<d_logprefix<<"Listening for HTTP requests on "<<d_server->d_local.toStringWithPort()<<endl,
558 d_slog->info(Logr::Info, "Listening for HTTP requests", "address", Logging::Loggable(d_server->d_local)));
559 }
560 catch(NetworkError &e) {
561 SLOG(g_log<<Logger::Error<<d_logprefix<<"Listening on HTTP socket failed: "<<e.what()<<endl,
562 d_slog->error(Logr::Error, e.what(), "Listening on HTTP socket failed", "exception", Logging::Loggable("NetworkError")));
563 d_server = nullptr;
564 }
565 }
566
567 void WebServer::go()
568 {
569 if(!d_server)
570 return;
571 const string msg = "Exception in main webserver thread";
572 try {
573 while(true) {
574 const string acceptmsg = "Exception while accepting a connection in main webserver thread";
575 try {
576 auto client = d_server->accept();
577 if (!client) {
578 continue;
579 }
580 if (client->acl(d_acl)) {
581 std::thread webHandler(WebServerConnectionThreadStart, this, client);
582 webHandler.detach();
583 } else {
584 ComboAddress remote;
585 if (client->getRemote(remote))
586 g_log<<Logger::Error<<d_logprefix<<"Webserver closing socket: remote ("<< remote.toString() <<") does not match the set ACL("<<d_acl.toString()<<")"<<endl;
587 }
588 }
589 catch(PDNSException &e) {
590 SLOG(g_log<<Logger::Error<<d_logprefix<<"PDNSException while accepting a connection in main webserver thread: "<<e.reason<<endl,
591 d_slog->error(Logr::Error, e.reason, acceptmsg, Logging::Loggable("PDNSException")));
592 }
593 catch(std::exception &e) {
594 SLOG(g_log<<Logger::Error<<d_logprefix<<"STL Exception while accepting a connection in main webserver thread: "<<e.what()<<endl,
595 d_slog->error(Logr::Error, e.what(), acceptmsg, Logging::Loggable("std::exception")));
596 }
597 catch(...) {
598 SLOG(g_log<<Logger::Error<<d_logprefix<<"Unknown exception while accepting a connection in main webserver thread"<<endl,
599 d_slog->info(Logr::Error, msg));
600 }
601 }
602 }
603 catch(PDNSException &e) {
604 SLOG(g_log<<Logger::Error<<d_logprefix<<"PDNSException in main webserver thread: "<<e.reason<<endl,
605 d_slog->error(Logr::Error, e.reason, msg, Logging::Loggable("PDNSException")));
606 }
607 catch(std::exception &e) {
608 SLOG(g_log<<Logger::Error<<d_logprefix<<"STL Exception in main webserver thread: "<<e.what()<<endl,
609 d_slog->error(Logr::Error, e.what(), msg, Logging::Loggable("std::exception")));
610 }
611 catch(...) {
612 SLOG(g_log<<Logger::Error<<d_logprefix<<"Unknown exception in main webserver thread"<<endl,
613 d_slog->info(Logr::Error, msg));
614 }
615 _exit(1);
616 }