]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/webserver.cc
add OpenSSL exception to PowerDNS, Netherlabs, van Dijk and Hubert copyrights
[thirdparty/pdns.git] / pdns / webserver.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
ac7ba905 3 Copyright (C) 2002-2012 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
f782fe38
MH
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12c86877
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
731f58b8 22#include "utility.hh"
12c86877
BH
23#include "webserver.hh"
24#include "session.hh"
25#include "misc.hh"
26#include <vector>
27#include "logger.hh"
28#include <stdio.h>
29#include "dns.hh"
2db9c30e 30#include "base64.hh"
33196945 31#include "json.hh"
12c86877
BH
32
33
34map<string,WebServer::HandlerFunction *>WebServer::d_functions;
35void *WebServer::d_that;
36string WebServer::d_password;
37
12c86877
BH
38int WebServer::B64Decode(const std::string& strInput, std::string& strOutput)
39{
2db9c30e 40 return ::B64Decode(strInput, strOutput);
12c86877
BH
41}
42
12c86877
BH
43void WebServer::registerHandler(const string&s, HandlerFunction *ptr)
44{
45 d_functions[s]=ptr;
46}
47
48void WebServer::setCaller(void *that)
49{
50 d_that=that;
51}
52
53void *WebServer::serveConnection(void *p)
33196945 54try {
6b70b8c7 55 pthread_detach(pthread_self());
12c86877 56 Session *client=static_cast<Session *>(p);
33196945
CH
57 bool want_html=false;
58 bool want_json=false;
59
12c86877
BH
60 try {
61 string line;
9761df50 62 client->setTimeout(5);
12c86877
BH
63 client->getLine(line);
64 stripLine(line);
8ef98963 65 if(line.empty())
33196945 66 throw HttpBadRequestException();
12c86877
BH
67 // L<<"page: "<<line<<endl;
68
69 vector<string> parts;
70 stringtok(parts,line);
71
a2ce158c
BH
72 string method, uri;
73 if(parts.size()>1) {
74 method=parts[0];
12c86877 75 uri=parts[1];
a2ce158c 76 }
12c86877
BH
77
78 vector<string>variables;
79
80 parts.clear();
81 stringtok(parts,uri,"?");
82
83 // L<<"baseUrl: '"<<parts[0]<<"'"<<endl;
84
85 vector<string>urlParts;
86 stringtok(urlParts,parts[0],"/");
87 string baseUrl;
88 if(urlParts.empty())
89 baseUrl="";
90 else
91 baseUrl=urlParts[0];
92
93 // L<<"baseUrl real: '"<<baseUrl<<"'"<<endl;
94
95 if(parts.size()>1) {
96 stringtok(variables,parts[1],"&");
97 }
98
99 map<string,string>varmap;
100
101 for(vector<string>::const_iterator i=variables.begin();
4957a608 102 i!=variables.end();++i) {
12c86877
BH
103
104 parts.clear();
105 stringtok(parts,*i,"=");
106 if(parts.size()>1)
4957a608 107 varmap[parts[0]]=parts[1];
12c86877 108 else
4957a608 109 varmap[parts[0]]="";
12c86877 110
12c86877
BH
111 }
112
113 bool authOK=0;
a2ce158c 114 int postlen = 0;
12c86877
BH
115 // read & ignore other lines
116 do {
117 client->getLine(line);
118 stripLine(line);
119
33196945
CH
120 if(line.empty())
121 break;
122
123 size_t colon = line.find(":");
124 if(colon==std::string::npos)
125 throw HttpBadRequestException();
126
127 string header = toLower(line.substr(0, colon));
128 string value = line.substr(line.find_first_not_of(' ', colon+1));
129
130 if(header == "authorization" && toLower(value).find("basic ") == 0) {
131 string cookie=value.substr(6);
4957a608
BH
132 string plain;
133
134 B64Decode(cookie,plain);
135 vector<string>cparts;
136 stringtok(cparts,plain,":");
33196945 137 // L<<Logger::Error<<"Entered password: '"<<cparts[1].c_str()<<"', should be '"<<d_password.c_str()<<"'"<<endl;
4957a608
BH
138 if(cparts.size()==2 && !strcmp(cparts[1].c_str(),d_password.c_str())) { // this gets rid of terminating zeros
139 authOK=1;
140 }
12c86877 141 }
33196945
CH
142 else if(header == "content-length" && method=="POST") {
143 postlen = atoi(value.c_str());
a2ce158c
BH
144// cout<<"Got a post: "<<postlen<<" bytes"<<endl;
145 }
33196945
CH
146 else if(header == "accept") {
147 // json wins over html
148 if(value.find("application/json")!=std::string::npos) {
149 want_json=true;
150 } else if(value.find("text/html")!=std::string::npos) {
151 want_html=true;
152 }
153 }
a2ce158c
BH
154 else
155 ; // cerr<<"Ignoring line: "<<line<<endl;
156
33196945 157 } while(true);
12c86877 158
a2ce158c
BH
159 string post;
160 if(postlen)
161 post = client->get(postlen);
162
163 // cout<<"Post: '"<<post<<"'"<<endl;
164
33196945
CH
165 if(!d_password.empty() && !authOK)
166 throw HttpUnauthorizedException();
12c86877
BH
167
168 HandlerFunction *fptr;
f1f85f12 169 if(d_functions.count(baseUrl) && (fptr=d_functions[baseUrl])) {
117d4c45 170 bool custom=false;
a2ce158c 171 string ret=(*fptr)(method, post, varmap, d_that, &custom);
12c86877
BH
172
173 if(!custom) {
4957a608
BH
174 client->putLine("HTTP/1.1 200 OK\n");
175 client->putLine("Connection: close\n");
e24e563c 176 client->putLine("Content-Type: text/html; charset=utf-8\n\n");
12c86877
BH
177 }
178 client->putLine(ret);
179 }
180 else {
33196945 181 throw HttpNotFoundException();
12c86877 182 }
12c86877
BH
183
184 }
33196945
CH
185 catch(HttpException &e) {
186 client->putLine(e.statusLine());
187 client->putLine("Connection: close\n");
188 client->putLine(e.headers());
189 if(want_html) {
190 client->putLine("Content-Type: text/html; charset=utf-8\n\n");
191 client->putLine("<!html><title>" + e.what() + "</title><h1>" + e.what() + "</h1>");
192 } else if (want_json) {
193 client->putLine("Content-Type: application/json\n\n");
194 client->putLine(returnJSONError(e.what()));
195 } else {
196 client->putLine("Content-Type: text/plain; charset=utf-8\n\n");
197 client->putLine(e.what());
198 }
12c86877 199 }
33196945
CH
200
201 client->close();
202 delete client;
203 client=0;
204
12c86877
BH
205 return 0;
206}
33196945
CH
207catch(SessionTimeoutException &e) {
208 // L<<Logger::Error<<"Timeout in webserver"<<endl;
209}
210catch(PDNSException &e) {
211 L<<Logger::Error<<"Exception in webserver: "<<e.reason<<endl;
212}
213catch(std::exception &e) {
214 L<<Logger::Error<<"STL Exception in webserver: "<<e.what()<<endl;
215}
216catch(...) {
217 L<<Logger::Error<<"Unknown exception in webserver"<<endl;
218}
219
12c86877
BH
220
221WebServer::WebServer(const string &listenaddress, int port, const string &password)
222{
223 d_listenaddress=listenaddress;
224 d_port=port;
225 d_password=password;
96d299db
BH
226 d_server = 0; // on exception, this class becomes a NOOP later on
227 try {
228 d_server = new Server(d_port, d_listenaddress);
229 }
230 catch(SessionException &e) {
231 L<<Logger::Error<<"Fatal error in webserver: "<<e.reason<<endl;
232 }
12c86877
BH
233}
234
235void WebServer::go()
236{
96d299db
BH
237 if(!d_server)
238 return;
12c86877 239 try {
12c86877
BH
240 Session *client;
241 pthread_t tid;
242
96a2625e 243 L<<Logger::Error<<"Launched webserver on " << d_server->d_local.toStringWithPort() <<endl;
12c86877 244
96d299db 245 while((client=d_server->accept())) {
12c86877
BH
246 pthread_create(&tid, 0 , &serveConnection, (void *)client);
247 }
248 }
249 catch(SessionTimeoutException &e) {
96a2625e 250 // L<<Logger::Error<<"Timeout in webserver"<<endl;
12c86877 251 }
1270deb0
CH
252 catch(PDNSException &e) {
253 L<<Logger::Error<<"Exception in main webserver thread: "<<e.reason<<endl;
254 }
adc10f99 255 catch(std::exception &e) {
12c86877
BH
256 L<<Logger::Error<<"STL Exception in main webserver thread: "<<e.what()<<endl;
257 }
258 catch(...) {
259 L<<Logger::Error<<"Unknown exception in main webserver thread"<<endl;
260 }
261 exit(1);
262
263}