]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/webserver.hh
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / webserver.hh
CommitLineData
12c86877 1/*
12471842
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 */
12c86877
BH
22#ifndef WEBSERVER_HH
23#define WEBSERVER_HH
24#include <map>
25#include <string>
232f0877 26#include <list>
3ae143b0
CH
27#include <boost/utility.hpp>
28#include <yahttp/yahttp.hpp>
5938c49f 29#include "json11.hpp"
10f4eea8 30#include "namespaces.hh"
825fa717 31#include "sstuff.hh"
12c86877 32
bbef8f04
CH
33class WebServer;
34
80d59cd1
CH
35class HttpRequest : public YaHTTP::Request {
36public:
a53cd863 37 HttpRequest(const string& logprefix="") : YaHTTP::Request(), accept_json(false), accept_html(false), complete(false), logprefix(logprefix) { };
80d59cd1 38
80d59cd1
CH
39 bool accept_json;
40 bool accept_html;
825fa717 41 bool complete;
a53cd863 42 string logprefix;
5938c49f 43 json11::Json json();
bbef8f04
CH
44
45 // checks password _only_.
46 bool compareAuthorization(const string &expected_password);
47 bool compareHeader(const string &header_name, const string &expected_value);
80d59cd1
CH
48};
49
50class HttpResponse: public YaHTTP::Response {
51public:
52 HttpResponse() : YaHTTP::Response() { };
80d59cd1 53 HttpResponse(const YaHTTP::Response &resp) : YaHTTP::Response(resp) { };
669822d0 54
5938c49f 55 void setBody(const json11::Json& document);
692829aa
CH
56 void setErrorResult(const std::string& message, const int status);
57 void setSuccessResult(const std::string& message, const int status = 200);
80d59cd1
CH
58};
59
60
33196945
CH
61class HttpException
62{
63public:
80d59cd1 64 HttpException(int status) : d_response()
33196945 65 {
80d59cd1 66 d_response.status = status;
33196945
CH
67 };
68
8204102e
PL
69 HttpException(int status, const string& msg) : d_response()
70 {
71 d_response.setErrorResult(msg, status);
72 };
73
80d59cd1
CH
74 HttpResponse response()
75 {
76 return d_response;
33196945
CH
77 }
78
80d59cd1
CH
79protected:
80 HttpResponse d_response;
33196945
CH
81};
82
83class HttpBadRequestException : public HttpException {
84public:
80d59cd1 85 HttpBadRequestException() : HttpException(400) { };
8204102e 86 HttpBadRequestException(const string& msg) : HttpException(400, msg) { };
33196945
CH
87};
88
89class HttpUnauthorizedException : public HttpException {
90public:
53255086 91 HttpUnauthorizedException(string const &scheme) : HttpException(401)
80d59cd1 92 {
53255086 93 d_response.headers["WWW-Authenticate"] = scheme + " realm=\"PowerDNS\"";
33196945
CH
94 }
95};
96
53255086
PL
97class HttpForbiddenException : public HttpException {
98public:
99 HttpForbiddenException() : HttpException(403) { };
8204102e 100 HttpForbiddenException(const string& msg) : HttpException(403, msg) { };
53255086
PL
101};
102
33196945
CH
103class HttpNotFoundException : public HttpException {
104public:
80d59cd1 105 HttpNotFoundException() : HttpException(404) { };
8204102e 106 HttpNotFoundException(const string& msg) : HttpException(404, msg) { };
33196945
CH
107};
108
109class HttpMethodNotAllowedException : public HttpException {
110public:
80d59cd1 111 HttpMethodNotAllowedException() : HttpException(405) { };
8204102e 112 HttpMethodNotAllowedException(const string& msg) : HttpException(405, msg) { };
33196945
CH
113};
114
331d3062
CH
115class HttpConflictException : public HttpException {
116public:
117 HttpConflictException() : HttpException(409) { };
f7b99555 118 HttpConflictException(const string& msg) : HttpException(409, msg) { };
331d3062
CH
119};
120
0f67eeda
CH
121class HttpInternalServerErrorException : public HttpException {
122public:
123 HttpInternalServerErrorException() : HttpException(500) { };
8204102e 124 HttpInternalServerErrorException(const string& msg) : HttpException(500, msg) { };
0f67eeda
CH
125};
126
3ae143b0
CH
127class ApiException : public runtime_error
128{
129public:
130 ApiException(const string& what) : runtime_error(what) {
131 }
132};
02c04144 133
a7650f23
CH
134class Server
135{
136public:
93f4e5ce 137 Server(const string &localaddress, int port) : d_local(localaddress.empty() ? "0.0.0.0" : localaddress, port), d_server_socket(d_local.sin4.sin_family, SOCK_STREAM, 0) {
a7650f23
CH
138 d_server_socket.setReuseAddr();
139 d_server_socket.bind(d_local);
140 d_server_socket.listen();
141 }
690984d4 142 virtual ~Server() { };
a7650f23
CH
143
144 ComboAddress d_local;
145
d4c53d8c
RG
146 std::shared_ptr<Socket> accept() {
147 return std::shared_ptr<Socket>(d_server_socket.accept());
a7650f23
CH
148 }
149
150protected:
151 Socket d_server_socket;
152};
153
3ae143b0 154class WebServer : public boost::noncopyable
12c86877
BH
155{
156public:
bbef8f04 157 WebServer(const string &listenaddress, int port);
690984d4 158 virtual ~WebServer() { };
29997a3c
PL
159
160 void setApiKey(const string &apikey) {
29997a3c
PL
161 d_apikey = apikey;
162 }
163
0c3b088c 164 void setPassword(const string &password) {
0c3b088c
PL
165 d_webserverPassword = password;
166 }
167
214b034e
PD
168 void setMaxBodySize(ssize_t s) { // in megabytes
169 d_maxbodysize = s * 1024 * 1024;
170 }
171
0010aefa
PL
172 void setACL(const NetmaskGroup &nmg) {
173 d_acl = nmg;
174 }
175
825fa717 176 void bind();
12c86877 177 void go();
232f0877 178
b184a9dc
RG
179 void serveConnection(std::shared_ptr<Socket> client) const;
180 void handleRequest(HttpRequest& request, HttpResponse& resp) const;
232f0877 181
80d59cd1 182 typedef boost::function<void(HttpRequest* req, HttpResponse* resp)> HandlerFunction;
c563cbe5 183 void registerApiHandler(const string& url, HandlerFunction handler, bool allowPassword=false);
bbef8f04 184 void registerWebHandler(const string& url, HandlerFunction handler);
232f0877 185
a53cd863
PL
186 enum class LogLevel : uint8_t {
187 None = 0, // No logs from requests at all
a35306f9 188 Normal = 10, // A "common log format"-like line e.g. '127.0.0.1 "GET /apache_pb.gif HTTP/1.0" 200 2326'
a53cd863
PL
189 Detailed = 20, // The full request headers and body, and the full response headers and body
190 };
191
60986c4b
PL
192 void setLogLevel(const string& level) {
193 if (level == "none") {
194 d_loglevel = LogLevel::None;
195 return;
196 }
197
a35306f9
PL
198 if (level == "normal") {
199 d_loglevel = LogLevel::Normal;
60986c4b
PL
200 return;
201 }
202
203 if (level == "detailed") {
204 d_loglevel = LogLevel::Detailed;
205 return;
206 }
207
208 throw PDNSException("Unknown webserver log level: " + level);
209 }
210
a53cd863
PL
211 void setLogLevel(const LogLevel level) {
212 d_loglevel = level;
213 };
214
215 LogLevel getLogLevel() {
216 return d_loglevel;
217 };
b2cb8982 218
3ae143b0 219protected:
bbef8f04 220 void registerBareHandler(const string& url, HandlerFunction handler);
612ad9ec
PL
221 void logRequest(const HttpRequest& req, const ComboAddress& remote) const;
222 void logResponse(const HttpResponse& resp, const ComboAddress& remote, const string& logprefix) const;
232f0877 223
690984d4
RG
224 virtual std::shared_ptr<Server> createServer() {
225 return std::make_shared<Server>(d_listenaddress, d_port);
825fa717
CH
226 }
227
12c86877
BH
228 string d_listenaddress;
229 int d_port;
232f0877 230 string d_password;
690984d4 231 std::shared_ptr<Server> d_server;
29997a3c
PL
232
233 std::string d_apikey;
c563cbe5 234 void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp, bool allowPassword);
0c3b088c 235 std::string d_webserverPassword;
7579a7b9 236 void webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp);
0010aefa 237
214b034e
PD
238 ssize_t d_maxbodysize; // in bytes
239
0010aefa 240 NetmaskGroup d_acl;
b2cb8982
PL
241
242 const string d_logprefix = "[webserver] ";
a53cd863
PL
243
244 // Describes the amount of logging the webserver does
245 WebServer::LogLevel d_loglevel{WebServer::LogLevel::Detailed};
12c86877 246};
3ae143b0 247
12c86877 248#endif /* WEBSERVER_HH */