]>
Commit | Line | Data |
---|---|---|
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 |
33 | class WebServer; |
34 | ||
80d59cd1 CH |
35 | class HttpRequest : public YaHTTP::Request { |
36 | public: | |
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 | ||
50 | class HttpResponse: public YaHTTP::Response { | |
51 | public: | |
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 |
61 | class HttpException |
62 | { | |
63 | public: | |
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 |
79 | protected: |
80 | HttpResponse d_response; | |
33196945 CH |
81 | }; |
82 | ||
83 | class HttpBadRequestException : public HttpException { | |
84 | public: | |
80d59cd1 | 85 | HttpBadRequestException() : HttpException(400) { }; |
8204102e | 86 | HttpBadRequestException(const string& msg) : HttpException(400, msg) { }; |
33196945 CH |
87 | }; |
88 | ||
89 | class HttpUnauthorizedException : public HttpException { | |
90 | public: | |
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 |
97 | class HttpForbiddenException : public HttpException { |
98 | public: | |
99 | HttpForbiddenException() : HttpException(403) { }; | |
8204102e | 100 | HttpForbiddenException(const string& msg) : HttpException(403, msg) { }; |
53255086 PL |
101 | }; |
102 | ||
33196945 CH |
103 | class HttpNotFoundException : public HttpException { |
104 | public: | |
80d59cd1 | 105 | HttpNotFoundException() : HttpException(404) { }; |
8204102e | 106 | HttpNotFoundException(const string& msg) : HttpException(404, msg) { }; |
33196945 CH |
107 | }; |
108 | ||
109 | class HttpMethodNotAllowedException : public HttpException { | |
110 | public: | |
80d59cd1 | 111 | HttpMethodNotAllowedException() : HttpException(405) { }; |
8204102e | 112 | HttpMethodNotAllowedException(const string& msg) : HttpException(405, msg) { }; |
33196945 CH |
113 | }; |
114 | ||
331d3062 CH |
115 | class HttpConflictException : public HttpException { |
116 | public: | |
117 | HttpConflictException() : HttpException(409) { }; | |
f7b99555 | 118 | HttpConflictException(const string& msg) : HttpException(409, msg) { }; |
331d3062 CH |
119 | }; |
120 | ||
0f67eeda CH |
121 | class HttpInternalServerErrorException : public HttpException { |
122 | public: | |
123 | HttpInternalServerErrorException() : HttpException(500) { }; | |
8204102e | 124 | HttpInternalServerErrorException(const string& msg) : HttpException(500, msg) { }; |
0f67eeda CH |
125 | }; |
126 | ||
3ae143b0 CH |
127 | class ApiException : public runtime_error |
128 | { | |
129 | public: | |
130 | ApiException(const string& what) : runtime_error(what) { | |
131 | } | |
132 | }; | |
02c04144 | 133 | |
a7650f23 CH |
134 | class Server |
135 | { | |
136 | public: | |
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 | ||
150 | protected: | |
151 | Socket d_server_socket; | |
152 | }; | |
153 | ||
3ae143b0 | 154 | class WebServer : public boost::noncopyable |
12c86877 BH |
155 | { |
156 | public: | |
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 | 219 | protected: |
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 */ |