22 #include <webview/request_dispatcher.h> 23 #include <webview/request_processor.h> 24 #include <webview/url_manager.h> 25 #include <webview/page_reply.h> 26 #include <webview/error_reply.h> 27 #include <webview/user_verifier.h> 28 #include <webview/access_log.h> 30 #include <core/threading/mutex.h> 31 #include <core/threading/mutex_locker.h> 32 #include <core/exception.h> 33 #include <utils/misc/string_urlescape.h> 34 #include <utils/time/time.h> 36 #include <sys/types.h> 37 #include <sys/socket.h> 39 #include <microhttpd.h> 43 #include <microhttpd.h> 45 #define UNAUTHORIZED_REPLY \ 47 " <head><title>Access denied</title></head>\n" \ 49 " <h1>Access denied</h1>\n" \ 50 " <p>Authentication is required to access Fawkes Webview</p>\n" \ 78 __url_manager = url_manager;
79 __page_header_generator = headergen;
80 __page_footer_generator = footergen;
81 __active_requests = 0;
82 __active_requests_mutex =
new Mutex();
83 __last_request_completion_time =
new Time();
88 WebRequestDispatcher::~WebRequestDispatcher()
90 if (__realm) free(__realm);
91 delete __active_requests_mutex;
92 delete __last_request_completion_time;
104 WebRequestDispatcher::setup_basic_auth(
const char *realm,
107 #if MHD_VERSION >= 0x00090400 108 if (__realm) free(__realm);
110 __user_verifier = NULL;
111 if (realm && verifier) {
112 __realm = strdup(realm);
113 __user_verifier = verifier;
116 throw Exception(
"libmicrohttpd >= 0.9.4 is required for basic authentication, " 117 "which was not available at compile time.");
126 WebRequestDispatcher::setup_access_log(
const char *filename)
139 WebRequestDispatcher::uri_log_cb(
void *cls,
const char * uri)
142 return rd->log_uri(uri);
157 WebRequestDispatcher::process_request_cb(
void *callback_data,
158 struct MHD_Connection * connection,
162 const char *upload_data,
163 size_t *upload_data_size,
167 return rd->process_request(connection, url, method, version,
168 upload_data, upload_data_size, session_data);
179 WebRequestDispatcher::request_completed_cb(
void *cls,
180 struct MHD_Connection *connection,
void **con_cls,
181 enum MHD_RequestTerminationCode toe)
185 rd->request_completed(request, toe);
202 ssize_t bytes = dreply->
next_chunk(pos, buf, max);
224 struct MHD_Response *
225 WebRequestDispatcher::prepare_static_response(StaticWebReply *sreply)
227 struct MHD_Response *response;
228 WebPageReply *wpreply =
dynamic_cast<WebPageReply *
>(sreply);
230 wpreply->pack(__active_baseurl,
231 __page_header_generator, __page_footer_generator);
235 if (sreply->body_length() > 0) {
236 response = MHD_create_response_from_buffer(sreply->body_length(),
237 (
void*) sreply->body().c_str(),
238 MHD_RESPMEM_MUST_COPY);
240 response = MHD_create_response_from_buffer(0, (
void*)
"",
241 MHD_RESPMEM_PERSISTENT);
244 WebRequest *request = sreply->get_request();
246 request->set_reply_code(sreply->code());
247 request->increment_reply_size(sreply->body_length());
250 const WebReply::HeaderMap &headers = sreply->headers();
251 WebReply::HeaderMap::const_iterator i;
252 for (i = headers.begin(); i != headers.end(); ++i) {
253 MHD_add_response_header(response, i->first.c_str(), i->second.c_str());
265 WebRequestDispatcher::queue_dynamic_reply(
struct MHD_Connection * connection,
267 DynamicWebReply *dreply)
269 dreply->set_request(request);
270 request->set_reply_code(dreply->code());
272 struct MHD_Response *response;
273 response = MHD_create_response_from_callback(dreply->size(),
274 dreply->chunk_size(),
279 const WebReply::HeaderMap &headers = dreply->headers();
280 WebReply::HeaderMap::const_iterator i;
281 for (i = headers.begin(); i != headers.end(); ++i) {
282 MHD_add_response_header(response, i->first.c_str(), i->second.c_str());
285 int ret = MHD_queue_response (connection, dreply->code(), response);
286 MHD_destroy_response (response);
298 WebRequestDispatcher::queue_static_reply(
struct MHD_Connection * connection,
300 StaticWebReply *sreply)
302 sreply->set_request(request);
304 struct MHD_Response *response = prepare_static_response(sreply);
306 int rv = MHD_queue_response(connection, sreply->code(), response);
307 MHD_destroy_response(response);
317 WebRequestDispatcher::queue_basic_auth_fail(
struct MHD_Connection * connection,
320 StaticWebReply sreply(WebReply::HTTP_UNAUTHORIZED, UNAUTHORIZED_REPLY);
321 #if MHD_VERSION >= 0x00090400 322 sreply.set_request(request);
323 struct MHD_Response *response = prepare_static_response(&sreply);
325 int rv = MHD_queue_basic_auth_fail_response(connection, __realm, response);
326 MHD_destroy_response(response);
328 sreply.add_header(MHD_HTTP_HEADER_WWW_AUTHENTICATE,
329 (std::string(
"Basic realm=") + __realm).c_str());
331 int rv = queue_static_reply(connection, request, &sreply);
357 post_iterator(
void *cls,
enum MHD_ValueKind kind,
const char *key,
358 const char *filename,
const char *content_type,
359 const char *transfer_encoding,
const char *data, uint64_t off,
362 WebRequest *request =
static_cast<WebRequest *
>(cls);
365 if (filename)
return MHD_NO;
367 request->set_post_value(key, data+off, size);
377 WebRequestDispatcher::log_uri(
const char *uri)
379 return new WebRequest(uri);
393 WebRequestDispatcher::process_request(
struct MHD_Connection * connection,
397 const char *upload_data,
398 size_t *upload_data_size,
401 WebRequest *request =
static_cast<WebRequest *
>(*session_data);
403 if ( ! request->is_setup() ) {
406 request->setup(url, method, version, connection);
408 __active_requests_mutex->lock();
409 __active_requests += 1;
410 __active_requests_mutex->unlock();
412 if (0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
414 MHD_create_post_processor(connection, 1024, &post_iterator, request);
420 #if MHD_VERSION >= 0x00090400 422 char *user, *pass = NULL;
423 user = MHD_basic_auth_get_username_password(connection, &pass);
424 if ( (user == NULL) || (pass == NULL) ||
425 ! __user_verifier->verify_user(user, pass))
427 return queue_basic_auth_fail(connection, request);
429 request->user_ = user;
433 std::string surl = url;
436 MutexLocker lock(__url_manager->mutex());
437 WebRequestProcessor *proc = __url_manager->find_processor(surl);
440 if (0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
441 if (MHD_post_process(request->pp_, upload_data, *upload_data_size) == MHD_NO) {
442 request->set_raw_post_data(upload_data, *upload_data_size);
444 if (0 != *upload_data_size) {
445 *upload_data_size = 0;
448 MHD_destroy_post_processor(request->pp_);
452 WebReply *reply = proc->process_request(request);
454 StaticWebReply *sreply =
dynamic_cast<StaticWebReply *
>(reply);
455 DynamicWebReply *dreply =
dynamic_cast<DynamicWebReply *
>(reply);
457 ret = queue_static_reply(connection, request, sreply);
460 ret = queue_dynamic_reply(connection, request, dreply);
462 WebErrorPageReply ereply(WebReply::HTTP_INTERNAL_SERVER_ERROR);
463 ret = queue_static_reply(connection, request, &ereply);
467 WebErrorPageReply ereply(WebReply::HTTP_NOT_FOUND);
468 ret = queue_static_reply(connection, request, &ereply);
472 WebPageReply preply(
"Fawkes",
"<h1>Welcome to Fawkes.</h1><hr />");
473 ret = queue_static_reply(connection, request, &preply);
475 WebErrorPageReply ereply(WebReply::HTTP_NOT_FOUND);
476 ret = queue_static_reply(connection, request, &ereply);
484 WebRequestDispatcher::request_completed(WebRequest *request, MHD_RequestTerminationCode term_code)
486 __active_requests_mutex->lock();
487 if (__active_requests > 0) __active_requests -= 1;
488 __last_request_completion_time->stamp();
489 __active_requests_mutex->unlock();
490 if (__access_log) __access_log->log(request);
497 WebRequestDispatcher::active_requests()
const 500 return __active_requests;
507 WebRequestDispatcher::last_request_completion_time()
const 510 return *__last_request_completion_time;
virtual size_t next_chunk(size_t pos, char *buffer, size_t buf_max_size)=0
Get data of next chunk.
WebRequest * get_request() const
Get associated request.
Fawkes library namespace.
static ssize_t dynamic_reply_data_cb(void *reply, uint64_t pos, char *buf, size_t max)
Callback based chunk-wise data.
static void dynamic_reply_free_cb(void *reply)
Callback to free dynamic web reply.
A class for handling time.
Interface for user verification.
Webview access_log writer.
Base class for exceptions in Fawkes.
Web request meta data carrier.
void increment_reply_size(size_t increment_by)
Increment reply bytes counter.
Mutex mutual exclusion lock.