23 #include <webview/request_dispatcher.h>
24 #include <webview/request_processor.h>
25 #include <webview/url_manager.h>
26 #include <webview/page_reply.h>
27 #include <webview/error_reply.h>
28 #include <webview/user_verifier.h>
30 #include <core/threading/mutex_locker.h>
31 #include <core/exception.h>
32 #include <utils/misc/string_urlescape.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
37 #include <microhttpd.h>
41 #define UNAUTHORIZED_REPLY \
43 " <head><title>Access denied</title></head>\n" \
45 " <h1>Access denied</h1>\n" \
46 " <p>Authentication is required to access Fawkes Webview</p>\n" \
73 __url_manager = url_manager;
74 __page_header_generator = headergen;
75 __page_footer_generator = footergen;
80 WebRequestDispatcher::~WebRequestDispatcher()
82 if (__realm) free(__realm);
93 WebRequestDispatcher::setup_basic_auth(
const char *realm,
96 #if MHD_VERSION >= 0x00090400
97 if (__realm) free(__realm);
99 __user_verifier = NULL;
100 if (realm && verifier) {
101 __realm = strdup(realm);
102 __user_verifier = verifier;
105 throw Exception(
"libmicrohttpd >= 0.9.4 is required for basic authentication, "
106 "which was not available at compile time.");
122 WebRequestDispatcher::process_request_cb(
void *callback_data,
123 struct MHD_Connection * connection,
127 const char *upload_data,
128 size_t *upload_data_size,
132 return rd->process_request(connection, url, method, version,
133 upload_data, upload_data_size, session_data);
145 #if MHD_VERSION >= 0x00090200
150 # if MHD_VERSION <= 0x00040000
177 struct MHD_Response *
178 WebRequestDispatcher::prepare_static_response(StaticWebReply *sreply)
180 struct MHD_Response *response;
181 WebPageReply *wpreply =
dynamic_cast<WebPageReply *
>(sreply);
183 wpreply->pack(__active_baseurl,
184 __page_header_generator, __page_footer_generator);
188 if (sreply->body_length() > 0) {
189 response = MHD_create_response_from_data(sreply->body_length(),
190 (
void*) sreply->body().c_str(),
194 response = MHD_create_response_from_data(0, (
void*)
"",
199 const WebReply::HeaderMap &headers = sreply->headers();
200 WebReply::HeaderMap::const_iterator i;
201 for (i = headers.begin(); i != headers.end(); ++i) {
202 MHD_add_response_header(response, i->first.c_str(), i->second.c_str());
214 WebRequestDispatcher::queue_static_reply(
struct MHD_Connection * connection,
215 StaticWebReply *sreply)
217 struct MHD_Response *response = prepare_static_response(sreply);
219 int rv = MHD_queue_response(connection, sreply->code(), response);
220 MHD_destroy_response(response);
230 WebRequestDispatcher::queue_basic_auth_fail(
struct MHD_Connection * connection)
232 StaticWebReply sreply(WebReply::HTTP_UNAUTHORIZED, UNAUTHORIZED_REPLY);
233 #if MHD_VERSION >= 0x00090400
234 struct MHD_Response *response = prepare_static_response(&sreply);
236 int rv = MHD_queue_basic_auth_fail_response(connection, __realm, response);
237 MHD_destroy_response(response);
239 sreply.add_header(MHD_HTTP_HEADER_WWW_AUTHENTICATE,
240 (std::string(
"Basic realm=") + __realm).c_str());
242 int rv = queue_static_reply(connection, &sreply);
259 WebRequestDispatcher::process_request(
struct MHD_Connection * connection,
263 const char *upload_data,
264 size_t *upload_data_size,
267 std::string surl = url;
271 if ((0 != strcmp(method,
"GET")) && (0 != strcmp(method,
"POST")))
274 MutexLocker lock(__url_manager->mutex());
275 WebRequestProcessor *proc = __url_manager->find_processor(surl);
278 char *urlc = strdup(url);
280 std::string urls = urlc;
283 if (! proc->handles_session_data()) {
284 if ( *session_data == NULL) {
287 *session_data = &dummy;
290 *session_data = NULL;
292 if ( *session_data == NULL) {
293 WebReply *reply = proc->process_request(urls.c_str(), method, version,
294 upload_data, upload_data_size,
296 if ((reply != NULL) || (*session_data == NULL)) {
304 #if MHD_VERSION >= 0x00090400
306 char *user, *pass = NULL;
307 user = MHD_basic_auth_get_username_password(connection, &pass);
308 if ( (user == NULL) || (pass == NULL) ||
309 ! __user_verifier->verify_user(user, pass))
311 return queue_basic_auth_fail(connection);
316 WebReply *reply = proc->process_request(urls.c_str(), method, version,
317 upload_data, upload_data_size,
320 StaticWebReply *sreply =
dynamic_cast<StaticWebReply *
>(reply);
321 DynamicWebReply *dreply =
dynamic_cast<DynamicWebReply *
>(reply);
323 ret = queue_static_reply(connection, sreply);
326 struct MHD_Response *response;
327 response = MHD_create_response_from_callback(dreply->size(),
328 dreply->chunk_size(),
332 ret = MHD_queue_response (connection, dreply->code(), response);
333 MHD_destroy_response (response);
335 WebErrorPageReply ereply(WebReply::HTTP_INTERNAL_SERVER_ERROR);
336 ret = queue_static_reply(connection, &ereply);
340 if (proc->handles_session_data()) {
343 WebErrorPageReply ereply(WebReply::HTTP_NOT_FOUND);
344 ret = queue_static_reply(connection, &ereply);
349 WebPageReply preply(
"Fawkes",
"<h1>Welcome to Fawkes.</h1><hr />");
350 ret = queue_static_reply(connection, &preply);
352 WebErrorPageReply ereply(WebReply::HTTP_NOT_FOUND);
353 ret = queue_static_reply(connection, &ereply);
virtual size_t next_chunk(size_t pos, char *buffer, size_t buf_max_size)=0
Get data of next chunk.
Fawkes library namespace.
static void dynamic_reply_free_cb(void *reply)
Callback to free dynamic web reply.
Interface for user verification.
Base class for exceptions in Fawkes.
static int dynamic_reply_data_cb(void *reply, size_t pos, char *buf, int max)
Callback based chunk-wise data.
void hex_unescape(char *s)
Remove URL hex escapes from s in place.