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();
90 if (__realm) free(__realm);
91 delete __active_requests_mutex;
92 delete __last_request_completion_time;
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.");
142 return rd->log_uri(uri);
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);
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;
230 wpreply->
pack(__active_baseurl,
231 __page_header_generator, __page_footer_generator);
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);
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,
272 struct MHD_Response *response;
273 response = MHD_create_response_from_callback(dreply->
size(),
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,
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,
321 #if MHD_VERSION >= 0x00090400 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,
365 if (filename)
return MHD_NO;
377 WebRequestDispatcher::log_uri(
const char *uri)
393 WebRequestDispatcher::process_request(
struct MHD_Connection * connection,
397 const char *upload_data,
398 size_t *upload_data_size,
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) ||
427 return queue_basic_auth_fail(connection, request);
429 request->user_ = user;
433 std::string surl = url;
440 if (0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
441 if (MHD_post_process(request->pp_, upload_data, *upload_data_size) == MHD_NO) {
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);
457 ret = queue_static_reply(connection, request, sreply);
460 ret = queue_dynamic_reply(connection, request, dreply);
463 ret = queue_static_reply(connection, request, &ereply);
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);
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);
500 return __active_requests;
510 return *__last_request_completion_time;
const HeaderMap & headers() const
get headers.
void set_request(WebRequest *request)
Set associated request.
virtual size_t next_chunk(size_t pos, char *buffer, size_t buf_max_size)=0
Get data of next chunk.
virtual size_t chunk_size()
Chunksize.
unsigned int active_requests() const
Get number of active requests.
void set_reply_code(WebReply::Code code)
Set HTTP code of the final reply.
WebRequest * get_request() const
Get associated request.
virtual size_t size()=0
Total size of the web reply.
Fawkes library namespace.
void unlock()
Unlock the mutex.
static ssize_t dynamic_reply_data_cb(void *reply, uint64_t pos, char *buf, size_t max)
Callback based chunk-wise data.
void add_header(std::string header, std::string content)
Add a HTTP header.
static void dynamic_reply_free_cb(void *reply)
Callback to free dynamic web reply.
Abstract web request processor.
static void request_completed_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
Process request completion.
A class for handling time.
static int process_request_cb(void *callback_data, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **session_data)
Process request callback for libmicrohttpd.
WebRequestDispatcher(WebUrlManager *url_manager, WebPageHeaderGenerator *headergen=0, WebPageFooterGenerator *footergen=0)
Constructor.
~WebRequestDispatcher()
Destructor.
Mutex * mutex()
Get internal mutex.
virtual const std::string & body()
Get body.
void setup_basic_auth(const char *realm, WebUserVerifier *verifier)
Setup basic authentication.
Interface for user verification.
Code code() const
Get response code.
Webview access_log writer.
void set_post_value(const char *key, const char *data, size_t size)
Set a POST value.
Base class for exceptions in Fawkes.
std::map< std::string, std::string > HeaderMap
Map of headers.
Web request meta data carrier.
void increment_reply_size(size_t increment_by)
Increment reply bytes counter.
Time last_request_completion_time() const
Get time when last request was completed.
virtual bool verify_user(const char *user, const char *password)=0
Verify a user.
WebRequestProcessor * find_processor(std::string &url) const
Lock mutex and find processor.
static void * uri_log_cb(void *cls, const char *uri)
Callback for new requests.
void set_raw_post_data(const char *data, size_t data_size)
Set raw post data.
void setup_access_log(const char *filename)
Setup access log.
void lock()
Lock this mutex.
Time & stamp()
Set this time to the current time.
Mutex mutual exclusion lock.
void log(const WebRequest *request)
Log a request.
virtual void pack()
Pack the data.
virtual std::string::size_type body_length()
Get length of body.