2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
27 #include <boost/utility.hpp>
28 #include <yahttp/yahttp.hpp>
30 #include "namespaces.hh"
35 class HttpRequest : public YaHTTP::Request {
37 HttpRequest(const string& logprefix="") : YaHTTP::Request(), accept_json(false), accept_html(false), complete(false), logprefix(logprefix) { };
45 // checks password _only_.
46 bool compareAuthorization(const string &expected_password);
47 bool compareHeader(const string &header_name, const string &expected_value);
50 class HttpResponse: public YaHTTP::Response {
52 HttpResponse() : YaHTTP::Response() { };
53 HttpResponse(const YaHTTP::Response &resp) : YaHTTP::Response(resp) { };
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);
64 HttpException(int status) : d_response()
66 d_response.status = status;
69 HttpException(int status, const string& msg) : d_response()
71 d_response.setErrorResult(msg, status);
74 HttpResponse response()
80 HttpResponse d_response;
83 class HttpBadRequestException : public HttpException {
85 HttpBadRequestException() : HttpException(400) { };
86 HttpBadRequestException(const string& msg) : HttpException(400, msg) { };
89 class HttpUnauthorizedException : public HttpException {
91 HttpUnauthorizedException(string const &scheme) : HttpException(401)
93 d_response.headers["WWW-Authenticate"] = scheme + " realm=\"PowerDNS\"";
97 class HttpForbiddenException : public HttpException {
99 HttpForbiddenException() : HttpException(403) { };
100 HttpForbiddenException(const string& msg) : HttpException(403, msg) { };
103 class HttpNotFoundException : public HttpException {
105 HttpNotFoundException() : HttpException(404) { };
106 HttpNotFoundException(const string& msg) : HttpException(404, msg) { };
109 class HttpMethodNotAllowedException : public HttpException {
111 HttpMethodNotAllowedException() : HttpException(405) { };
112 HttpMethodNotAllowedException(const string& msg) : HttpException(405, msg) { };
115 class HttpConflictException : public HttpException {
117 HttpConflictException() : HttpException(409) { };
118 HttpConflictException(const string& msg) : HttpException(409, msg) { };
121 class HttpInternalServerErrorException : public HttpException {
123 HttpInternalServerErrorException() : HttpException(500) { };
124 HttpInternalServerErrorException(const string& msg) : HttpException(500, msg) { };
127 class ApiException : public runtime_error
130 ApiException(const string& what) : runtime_error(what) {
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();
142 virtual ~Server() { };
144 ComboAddress d_local;
146 std::shared_ptr<Socket> accept() {
147 return std::shared_ptr<Socket>(d_server_socket.accept());
151 Socket d_server_socket;
154 class WebServer : public boost::noncopyable
157 WebServer(const string &listenaddress, int port);
158 virtual ~WebServer() { };
160 void setApiKey(const string &apikey) {
161 if (d_registerApiHandlerCalled) {
162 throw PDNSException("registerApiHandler has been called, can not change apikey");
167 void setPassword(const string &password) {
168 if (d_registerWebHandlerCalled) {
169 throw PDNSException("registerWebHandler has been called, can not change password");
171 d_webserverPassword = password;
174 void setACL(const NetmaskGroup &nmg) {
181 void serveConnection(std::shared_ptr<Socket> client) const;
182 void handleRequest(HttpRequest& request, HttpResponse& resp) const;
184 typedef boost::function<void(HttpRequest* req, HttpResponse* resp)> HandlerFunction;
185 void registerApiHandler(const string& url, HandlerFunction handler);
186 void registerWebHandler(const string& url, HandlerFunction handler);
188 enum class LogLevel : uint8_t {
189 None = 0, // No logs from requests at all
190 Normal = 10, // A "common log format"-like line e.g. '127.0.0.1 "GET /apache_pb.gif HTTP/1.0" 200 2326'
191 Detailed = 20, // The full request headers and body, and the full response headers and body
194 void setLogLevel(const string& level) {
195 if (level == "none") {
196 d_loglevel = LogLevel::None;
200 if (level == "normal") {
201 d_loglevel = LogLevel::Normal;
205 if (level == "detailed") {
206 d_loglevel = LogLevel::Detailed;
210 throw PDNSException("Unknown webserver log level: " + level);
213 void setLogLevel(const LogLevel level) {
217 LogLevel getLogLevel() {
222 void registerBareHandler(const string& url, HandlerFunction handler);
223 void logRequest(const HttpRequest& req, const ComboAddress& remote) const;
224 void logResponse(const HttpResponse& resp, const ComboAddress& remote, const string& logprefix) const;
226 virtual std::shared_ptr<Server> createServer() {
227 return std::make_shared<Server>(d_listenaddress, d_port);
230 string d_listenaddress;
233 std::shared_ptr<Server> d_server;
235 std::string d_apikey;
236 bool d_registerApiHandlerCalled{false};
238 std::string d_webserverPassword;
239 bool d_registerWebHandlerCalled{false};
243 const string d_logprefix = "[webserver] ";
245 // Describes the amount of logging the webserver does
246 WebServer::LogLevel d_loglevel{WebServer::LogLevel::Detailed};
249 #endif /* WEBSERVER_HH */