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