]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
6edbf68a PL |
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 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
731f58b8 | 25 | #include "utility.hh" |
12c86877 | 26 | #include "webserver.hh" |
12c86877 | 27 | #include "misc.hh" |
d4c53d8c | 28 | #include <thread> |
519f5484 | 29 | #include "threadname.hh" |
12c86877 BH |
30 | #include <vector> |
31 | #include "logger.hh" | |
32 | #include <stdio.h> | |
33 | #include "dns.hh" | |
2db9c30e | 34 | #include "base64.hh" |
33196945 | 35 | #include "json.hh" |
3f9a8002 | 36 | #include "uuid-utils.hh" |
583ea80d | 37 | #include <yahttp/router.hpp> |
12c86877 | 38 | |
5938c49f CH |
39 | json11::Json HttpRequest::json() |
40 | { | |
41 | string err; | |
42 | if(this->body.empty()) { | |
dc0db7b8 | 43 | g_log<<Logger::Debug<<logprefix<<"JSON document expected in request body, but body was empty" << endl; |
5938c49f CH |
44 | throw HttpBadRequestException(); |
45 | } | |
46 | json11::Json doc = json11::Json::parse(this->body, err); | |
47 | if (doc.is_null()) { | |
dc0db7b8 | 48 | g_log<<Logger::Debug<<logprefix<<"parsing of JSON document failed:" << err << endl; |
5938c49f CH |
49 | throw HttpBadRequestException(); |
50 | } | |
51 | return doc; | |
52 | } | |
53 | ||
bbef8f04 CH |
54 | bool HttpRequest::compareAuthorization(const string &expected_password) |
55 | { | |
56 | // validate password | |
57 | YaHTTP::strstr_map_t::iterator header = headers.find("authorization"); | |
58 | bool auth_ok = false; | |
59 | if (header != headers.end() && toLower(header->second).find("basic ") == 0) { | |
60 | string cookie = header->second.substr(6); | |
61 | ||
62 | string plain; | |
63 | B64Decode(cookie, plain); | |
64 | ||
65 | vector<string> cparts; | |
66 | stringtok(cparts, plain, ":"); | |
67 | ||
68 | // this gets rid of terminating zeros | |
69 | auth_ok = (cparts.size()==2 && (0==strcmp(cparts[1].c_str(), expected_password.c_str()))); | |
70 | } | |
71 | return auth_ok; | |
72 | } | |
73 | ||
74 | bool HttpRequest::compareHeader(const string &header_name, const string &expected_value) | |
75 | { | |
76 | YaHTTP::strstr_map_t::iterator header = headers.find(header_name); | |
77 | if (header == headers.end()) | |
78 | return false; | |
79 | ||
80 | // this gets rid of terminating zeros | |
81 | return (0==strcmp(header->second.c_str(), expected_value.c_str())); | |
82 | } | |
83 | ||
84 | ||
5938c49f CH |
85 | void HttpResponse::setBody(const json11::Json& document) |
86 | { | |
87 | document.dump(this->body); | |
88 | } | |
89 | ||
dd079764 | 90 | void HttpResponse::setErrorResult(const std::string& message, const int status_) |
692829aa CH |
91 | { |
92 | setBody(json11::Json::object { { "error", message } }); | |
dd079764 | 93 | this->status = status_; |
692829aa CH |
94 | } |
95 | ||
dd079764 | 96 | void HttpResponse::setSuccessResult(const std::string& message, const int status_) |
692829aa CH |
97 | { |
98 | setBody(json11::Json::object { { "result", message } }); | |
dd079764 | 99 | this->status = status_; |
692829aa CH |
100 | } |
101 | ||
bbef8f04 | 102 | static void bareHandlerWrapper(WebServer::HandlerFunction handler, YaHTTP::Request* req, YaHTTP::Response* resp) |
12c86877 | 103 | { |
583ea80d CH |
104 | // wrapper to convert from YaHTTP::* to our subclasses |
105 | handler(static_cast<HttpRequest*>(req), static_cast<HttpResponse*>(resp)); | |
106 | } | |
232f0877 | 107 | |
bbef8f04 | 108 | void WebServer::registerBareHandler(const string& url, HandlerFunction handler) |
583ea80d | 109 | { |
bbef8f04 | 110 | YaHTTP::THandlerFunction f = boost::bind(&bareHandlerWrapper, handler, _1, _2); |
583ea80d | 111 | YaHTTP::Router::Any(url, f); |
232f0877 CH |
112 | } |
113 | ||
7f7481be AT |
114 | static bool optionsHandler(HttpRequest* req, HttpResponse* resp) { |
115 | if (req->method == "OPTIONS") { | |
116 | resp->headers["access-control-allow-origin"] = "*"; | |
117 | resp->headers["access-control-allow-headers"] = "Content-Type, X-API-Key"; | |
118 | resp->headers["access-control-allow-methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"; | |
119 | resp->headers["access-control-max-age"] = "3600"; | |
120 | resp->status = 200; | |
121 | resp->headers["content-type"]= "text/plain"; | |
122 | resp->body = ""; | |
123 | return true; | |
124 | } | |
125 | return false; | |
126 | } | |
127 | ||
c563cbe5 | 128 | void WebServer::apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp, bool allowPassword) { |
7f7481be AT |
129 | if (optionsHandler(req, resp)) return; |
130 | ||
131 | resp->headers["access-control-allow-origin"] = "*"; | |
132 | ||
7579a7b9 | 133 | if (d_apikey.empty()) { |
a53cd863 | 134 | g_log<<Logger::Error<<req->logprefix<<"HTTP API Request \"" << req->url.path << "\": Authentication failed, API Key missing in config" << endl; |
53255086 | 135 | throw HttpUnauthorizedException("X-API-Key"); |
bbef8f04 | 136 | } |
7579a7b9 CH |
137 | |
138 | bool auth_ok = req->compareHeader("x-api-key", d_apikey) || req->getvars["api-key"] == d_apikey; | |
c563cbe5 CH |
139 | |
140 | if (!auth_ok && allowPassword) { | |
141 | if (!d_webserverPassword.empty()) { | |
142 | auth_ok = req->compareAuthorization(d_webserverPassword); | |
143 | } else { | |
144 | auth_ok = true; | |
145 | } | |
146 | } | |
147 | ||
bbef8f04 | 148 | if (!auth_ok) { |
a53cd863 | 149 | g_log<<Logger::Error<<req->logprefix<<"HTTP Request \"" << req->url.path << "\": Authentication by API Key failed" << endl; |
53255086 | 150 | throw HttpUnauthorizedException("X-API-Key"); |
bbef8f04 CH |
151 | } |
152 | ||
3ae143b0 CH |
153 | resp->headers["Content-Type"] = "application/json"; |
154 | ||
7fe2a2dc CH |
155 | // security headers |
156 | resp->headers["X-Content-Type-Options"] = "nosniff"; | |
157 | resp->headers["X-Frame-Options"] = "deny"; | |
158 | resp->headers["X-Permitted-Cross-Domain-Policies"] = "none"; | |
159 | resp->headers["X-XSS-Protection"] = "1; mode=block"; | |
160 | resp->headers["Content-Security-Policy"] = "default-src 'self'; style-src 'self' 'unsafe-inline'"; | |
3ae143b0 | 161 | |
583ea80d | 162 | req->getvars.erase("_"); // jQuery cache buster |
3ae143b0 CH |
163 | |
164 | try { | |
583ea80d | 165 | resp->status = 200; |
3ae143b0 CH |
166 | handler(req, resp); |
167 | } catch (ApiException &e) { | |
692829aa | 168 | resp->setErrorResult(e.what(), 422); |
6ec5e728 CH |
169 | return; |
170 | } catch (JsonException &e) { | |
692829aa | 171 | resp->setErrorResult(e.what(), 422); |
3ae143b0 CH |
172 | return; |
173 | } | |
174 | ||
37663c3b CH |
175 | if (resp->status == 204) { |
176 | // No Content -> no Content-Type. | |
177 | resp->headers.erase("Content-Type"); | |
178 | } | |
3ae143b0 CH |
179 | } |
180 | ||
c563cbe5 CH |
181 | void WebServer::registerApiHandler(const string& url, HandlerFunction handler, bool allowPassword) { |
182 | HandlerFunction f = boost::bind(&WebServer::apiWrapper, this, handler, _1, _2, allowPassword); | |
bbef8f04 CH |
183 | registerBareHandler(url, f); |
184 | } | |
185 | ||
7579a7b9 CH |
186 | void WebServer::webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) { |
187 | if (!d_webserverPassword.empty()) { | |
188 | bool auth_ok = req->compareAuthorization(d_webserverPassword); | |
bbef8f04 | 189 | if (!auth_ok) { |
a53cd863 | 190 | g_log<<Logger::Debug<<req->logprefix<<"HTTP Request \"" << req->url.path << "\": Web Authentication failed" << endl; |
53255086 | 191 | throw HttpUnauthorizedException("Basic"); |
bbef8f04 CH |
192 | } |
193 | } | |
194 | ||
195 | handler(req, resp); | |
196 | } | |
197 | ||
198 | void WebServer::registerWebHandler(const string& url, HandlerFunction handler) { | |
7579a7b9 | 199 | HandlerFunction f = boost::bind(&WebServer::webWrapper, this, handler, _1, _2); |
bbef8f04 | 200 | registerBareHandler(url, f); |
3ae143b0 CH |
201 | } |
202 | ||
b184a9dc | 203 | static void *WebServerConnectionThreadStart(const WebServer* webServer, std::shared_ptr<Socket> client) { |
519f5484 | 204 | setThreadName("pdns-r/webhndlr"); |
b184a9dc | 205 | webServer->serveConnection(client); |
d4c53d8c | 206 | return nullptr; |
232f0877 CH |
207 | } |
208 | ||
b184a9dc | 209 | void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp) const |
80d59cd1 | 210 | { |
80d59cd1 CH |
211 | // set default headers |
212 | resp.headers["Content-Type"] = "text/html; charset=utf-8"; | |
33196945 | 213 | |
12c86877 | 214 | try { |
825fa717 | 215 | if (!req.complete) { |
dc0db7b8 | 216 | g_log<<Logger::Debug<<req.logprefix<<"Incomplete request" << endl; |
825fa717 CH |
217 | throw HttpBadRequestException(); |
218 | } | |
219 | ||
dc0db7b8 | 220 | g_log<<Logger::Debug<<req.logprefix<<"Handling request \"" << req.url.path << "\"" << endl; |
825fa717 | 221 | |
80d59cd1 CH |
222 | YaHTTP::strstr_map_t::iterator header; |
223 | ||
224 | if ((header = req.headers.find("accept")) != req.headers.end()) { | |
225 | // json wins over html | |
226 | if (header->second.find("application/json") != std::string::npos) { | |
227 | req.accept_json = true; | |
228 | } else if (header->second.find("text/html") != std::string::npos) { | |
229 | req.accept_html = true; | |
230 | } | |
12c86877 BH |
231 | } |
232 | ||
583ea80d CH |
233 | YaHTTP::THandlerFunction handler; |
234 | if (!YaHTTP::Router::Route(&req, handler)) { | |
dc0db7b8 | 235 | g_log<<Logger::Debug<<req.logprefix<<"No route found for \"" << req.url.path << "\"" << endl; |
33196945 | 236 | throw HttpNotFoundException(); |
12c86877 | 237 | } |
12c86877 | 238 | |
0f67eeda | 239 | try { |
583ea80d | 240 | handler(&req, &resp); |
dc0db7b8 | 241 | g_log<<Logger::Debug<<req.logprefix<<"Result for \"" << req.url.path << "\": " << resp.status << ", body length: " << resp.body.size() << endl; |
0f67eeda | 242 | } |
4d706054 | 243 | catch(HttpException&) { |
583ea80d CH |
244 | throw; |
245 | } | |
0f67eeda | 246 | catch(PDNSException &e) { |
a53cd863 | 247 | g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Exception: " << e.reason << endl; |
0f67eeda CH |
248 | throw HttpInternalServerErrorException(); |
249 | } | |
250 | catch(std::exception &e) { | |
a53cd863 | 251 | g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": STL Exception: " << e.what() << endl; |
0f67eeda CH |
252 | throw HttpInternalServerErrorException(); |
253 | } | |
254 | catch(...) { | |
a53cd863 | 255 | g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Unknown Exception" << endl; |
0f67eeda CH |
256 | throw HttpInternalServerErrorException(); |
257 | } | |
12c86877 | 258 | } |
33196945 | 259 | catch(HttpException &e) { |
80d59cd1 | 260 | resp = e.response(); |
a53cd863 PL |
261 | // TODO rm this logline? |
262 | g_log<<Logger::Debug<<req.logprefix<<"Error result for \"" << req.url.path << "\": " << resp.status << endl; | |
80d59cd1 | 263 | string what = YaHTTP::Utility::status2text(resp.status); |
02c04144 | 264 | if(req.accept_html) { |
80d59cd1 CH |
265 | resp.headers["Content-Type"] = "text/html; charset=utf-8"; |
266 | resp.body = "<!html><title>" + what + "</title><h1>" + what + "</h1>"; | |
02c04144 | 267 | } else if (req.accept_json) { |
80d59cd1 | 268 | resp.headers["Content-Type"] = "application/json"; |
8204102e PL |
269 | if (resp.body.empty()) { |
270 | resp.setErrorResult(what, resp.status); | |
271 | } | |
33196945 | 272 | } else { |
80d59cd1 CH |
273 | resp.headers["Content-Type"] = "text/plain; charset=utf-8"; |
274 | resp.body = what; | |
33196945 | 275 | } |
12c86877 | 276 | } |
33196945 | 277 | |
80d59cd1 | 278 | // always set these headers |
41ea0e50 | 279 | resp.headers["Server"] = "PowerDNS/" VERSION; |
80d59cd1 CH |
280 | resp.headers["Connection"] = "close"; |
281 | ||
ac9908c2 CH |
282 | if (req.method == "HEAD") { |
283 | resp.body = ""; | |
284 | } else { | |
335da0ba | 285 | resp.headers["Content-Length"] = std::to_string(resp.body.size()); |
ac9908c2 | 286 | } |
80d59cd1 CH |
287 | } |
288 | ||
612ad9ec PL |
289 | void WebServer::logRequest(const HttpRequest& req, const ComboAddress& remote) const { |
290 | if (d_loglevel >= WebServer::LogLevel::Detailed) { | |
291 | auto logprefix = req.logprefix; | |
292 | g_log<<Logger::Notice<<logprefix<<"Request details:"<<endl; | |
293 | ||
294 | bool first = true; | |
295 | for (const auto& r : req.getvars) { | |
296 | if (first) { | |
297 | first = false; | |
298 | g_log<<Logger::Notice<<logprefix<<" GET params:"<<endl; | |
299 | } | |
300 | g_log<<Logger::Notice<<logprefix<<" "<<r.first<<": "<<r.second<<endl; | |
301 | } | |
302 | ||
303 | first = true; | |
304 | for (const auto& r : req.postvars) { | |
305 | if (first) { | |
306 | first = false; | |
307 | g_log<<Logger::Notice<<logprefix<<" POST params:"<<endl; | |
308 | } | |
309 | g_log<<Logger::Notice<<logprefix<<" "<<r.first<<": "<<r.second<<endl; | |
310 | } | |
311 | ||
312 | first = true; | |
313 | for (const auto& h : req.headers) { | |
314 | if (first) { | |
315 | first = false; | |
316 | g_log<<Logger::Notice<<logprefix<<" Headers:"<<endl; | |
317 | } | |
318 | g_log<<Logger::Notice<<logprefix<<" "<<h.first<<": "<<h.second<<endl; | |
319 | } | |
320 | ||
321 | if (req.body.empty()) { | |
322 | g_log<<Logger::Notice<<logprefix<<" No body"<<endl; | |
323 | } else { | |
324 | g_log<<Logger::Notice<<logprefix<<" Full body: "<<endl; | |
325 | g_log<<Logger::Notice<<logprefix<<" "<<req.body<<endl; | |
326 | } | |
327 | } | |
328 | } | |
329 | ||
330 | void WebServer::logResponse(const HttpResponse& resp, const ComboAddress& remote, const string& logprefix) const { | |
331 | if (d_loglevel >= WebServer::LogLevel::Detailed) { | |
332 | g_log<<Logger::Notice<<logprefix<<"Response details:"<<endl; | |
333 | bool first = true; | |
334 | for (const auto& h : resp.headers) { | |
335 | if (first) { | |
336 | first = false; | |
337 | g_log<<Logger::Notice<<logprefix<<" Headers:"<<endl; | |
338 | } | |
339 | g_log<<Logger::Notice<<logprefix<<" "<<h.first<<": "<<h.second<<endl; | |
340 | } | |
341 | if (resp.body.empty()) { | |
342 | g_log<<Logger::Notice<<logprefix<<" No body"<<endl; | |
343 | } else { | |
344 | g_log<<Logger::Notice<<logprefix<<" Full body: "<<endl; | |
345 | g_log<<Logger::Notice<<logprefix<<" "<<resp.body<<endl; | |
346 | } | |
347 | } | |
348 | } | |
349 | ||
a53cd863 | 350 | void WebServer::serveConnection(std::shared_ptr<Socket> client) const { |
f024c7bc | 351 | const string logprefix = d_logprefix + to_string(getUniqueID()) + " "; |
80d59cd1 | 352 | |
9b960272 PL |
353 | HttpRequest req(logprefix); |
354 | HttpResponse resp; | |
214b034e | 355 | resp.max_response_size=d_maxbodysize; |
9b960272 PL |
356 | ComboAddress remote; |
357 | string reply; | |
358 | ||
80d59cd1 | 359 | try { |
a53cd863 PL |
360 | YaHTTP::AsyncRequestLoader yarl; |
361 | yarl.initialize(&req); | |
214b034e | 362 | req.max_request_size=d_maxbodysize; |
a53cd863 PL |
363 | int timeout = 5; |
364 | client->setNonBlocking(); | |
365 | ||
366 | try { | |
367 | while(!req.complete) { | |
368 | int bytes; | |
bfde2d10 | 369 | char buf[16000]; |
a53cd863 PL |
370 | bytes = client->readWithTimeout(buf, sizeof(buf), timeout); |
371 | if (bytes > 0) { | |
372 | string data = string(buf, bytes); | |
373 | req.complete = yarl.feed(data); | |
374 | } else { | |
375 | // read error OR EOF | |
376 | break; | |
377 | } | |
378 | } | |
379 | yarl.finalize(); | |
380 | } catch (YaHTTP::ParseError &e) { | |
381 | // request stays incomplete | |
9fc86908 | 382 | g_log<<Logger::Warning<<logprefix<<"Unable to parse request: "<<e.what()<<endl; |
a53cd863 PL |
383 | } |
384 | ||
a53cd863 PL |
385 | if (d_loglevel >= WebServer::LogLevel::None) { |
386 | client->getRemote(remote); | |
387 | } | |
388 | ||
612ad9ec | 389 | logRequest(req, remote); |
80d59cd1 | 390 | |
a53cd863 PL |
391 | WebServer::handleRequest(req, resp); |
392 | ostringstream ss; | |
393 | resp.write(ss); | |
9b960272 | 394 | reply = ss.str(); |
a53cd863 | 395 | |
612ad9ec | 396 | logResponse(resp, remote, logprefix); |
a53cd863 | 397 | |
a53cd863 | 398 | client->writenWithTimeout(reply.c_str(), reply.size(), timeout); |
b2cb8982 | 399 | } |
a53cd863 PL |
400 | catch(PDNSException &e) { |
401 | g_log<<Logger::Error<<logprefix<<"HTTP Exception: "<<e.reason<<endl; | |
b2cb8982 | 402 | } |
a53cd863 PL |
403 | catch(std::exception &e) { |
404 | if(strstr(e.what(), "timeout")==0) | |
405 | g_log<<Logger::Error<<logprefix<<"HTTP STL Exception: "<<e.what()<<endl; | |
406 | } | |
407 | catch(...) { | |
408 | g_log<<Logger::Error<<logprefix<<"Unknown exception"<<endl; | |
b2cb8982 | 409 | } |
9b960272 | 410 | |
a35306f9 | 411 | if (d_loglevel >= WebServer::LogLevel::Normal) { |
64c08e25 | 412 | g_log<<Logger::Notice<<logprefix<<remote<<" \""<<req.method<<" "<<req.url.path<<" HTTP/"<<req.versionStr(req.version)<<"\" "<<resp.status<<" "<<reply.size()<<endl; |
9b960272 | 413 | } |
33196945 CH |
414 | } |
415 | ||
8a70e507 CHB |
416 | WebServer::WebServer(const string &listenaddress, int port) : |
417 | d_listenaddress(listenaddress), | |
418 | d_port(port), | |
214b034e PD |
419 | d_server(nullptr), |
420 | d_maxbodysize(2*1024*1024) | |
12c86877 | 421 | { |
825fa717 CH |
422 | } |
423 | ||
424 | void WebServer::bind() | |
425 | { | |
96d299db | 426 | try { |
825fa717 | 427 | d_server = createServer(); |
a53cd863 | 428 | g_log<<Logger::Warning<<d_logprefix<<"Listening for HTTP requests on "<<d_server->d_local.toStringWithPort()<<endl; |
96d299db | 429 | } |
825fa717 | 430 | catch(NetworkError &e) { |
a53cd863 | 431 | g_log<<Logger::Error<<d_logprefix<<"Listening on HTTP socket failed: "<<e.what()<<endl; |
690984d4 | 432 | d_server = nullptr; |
96d299db | 433 | } |
12c86877 BH |
434 | } |
435 | ||
436 | void WebServer::go() | |
437 | { | |
96d299db BH |
438 | if(!d_server) |
439 | return; | |
12c86877 | 440 | try { |
3ae143b0 | 441 | while(true) { |
17d60ab0 | 442 | try { |
b184a9dc | 443 | auto client = d_server->accept(); |
8a781bb5 RG |
444 | if (!client) { |
445 | continue; | |
446 | } | |
0010aefa | 447 | if (client->acl(d_acl)) { |
b184a9dc | 448 | std::thread webHandler(WebServerConnectionThreadStart, this, client); |
d4c53d8c | 449 | webHandler.detach(); |
17d60ab0 RG |
450 | } else { |
451 | ComboAddress remote; | |
b184a9dc | 452 | if (client->getRemote(remote)) |
a53cd863 | 453 | g_log<<Logger::Error<<d_logprefix<<"Webserver closing socket: remote ("<< remote.toString() <<") does not match the set ACL("<<d_acl.toString()<<")"<<endl; |
17d60ab0 RG |
454 | } |
455 | } | |
456 | catch(PDNSException &e) { | |
a53cd863 | 457 | g_log<<Logger::Error<<d_logprefix<<"PDNSException while accepting a connection in main webserver thread: "<<e.reason<<endl; |
17d60ab0 RG |
458 | } |
459 | catch(std::exception &e) { | |
a53cd863 | 460 | g_log<<Logger::Error<<d_logprefix<<"STL Exception while accepting a connection in main webserver thread: "<<e.what()<<endl; |
17d60ab0 RG |
461 | } |
462 | catch(...) { | |
a53cd863 | 463 | g_log<<Logger::Error<<d_logprefix<<"Unknown exception while accepting a connection in main webserver thread"<<endl; |
69e7f117 | 464 | } |
12c86877 BH |
465 | } |
466 | } | |
69e7f117 | 467 | catch(PDNSException &e) { |
a53cd863 | 468 | g_log<<Logger::Error<<d_logprefix<<"PDNSException in main webserver thread: "<<e.reason<<endl; |
69e7f117 | 469 | } |
adc10f99 | 470 | catch(std::exception &e) { |
a53cd863 | 471 | g_log<<Logger::Error<<d_logprefix<<"STL Exception in main webserver thread: "<<e.what()<<endl; |
12c86877 BH |
472 | } |
473 | catch(...) { | |
a53cd863 | 474 | g_log<<Logger::Error<<d_logprefix<<"Unknown exception in main webserver thread"<<endl; |
12c86877 | 475 | } |
5bd2ea7b | 476 | _exit(1); |
3ae143b0 | 477 | } |