diff options
Diffstat (limited to 'src/libfast/fast_session.c')
-rw-r--r-- | src/libfast/fast_session.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/src/libfast/fast_session.c b/src/libfast/fast_session.c new file mode 100644 index 000000000..56d4a0443 --- /dev/null +++ b/src/libfast/fast_session.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include "fast_session.h" + +#include <string.h> +#include <fcgiapp.h> +#include <stdio.h> + +#include <collections/linked_list.h> + +#define COOKIE_LEN 16 + +typedef struct private_fast_session_t private_fast_session_t; + +/** + * private data of the task manager + */ +struct private_fast_session_t { + + /** + * public functions + */ + fast_session_t public; + + /** + * session ID + */ + char sid[COOKIE_LEN * 2 + 1]; + + /** + * have we sent the session cookie? + */ + bool cookie_sent; + + /** + * list of controller instances controller_t + */ + linked_list_t *controllers; + + /** + * list of filter instances filter_t + */ + linked_list_t *filters; + + /** + * user defined session context + */ + fast_context_t *context; +}; + +METHOD(fast_session_t, add_controller, void, + private_fast_session_t *this, fast_controller_t *controller) +{ + this->controllers->insert_last(this->controllers, controller); +} + +METHOD(fast_session_t, add_filter, void, + private_fast_session_t *this, fast_filter_t *filter) +{ + this->filters->insert_last(this->filters, filter); +} + +/** + * Create a session ID and a cookie + */ +static bool create_sid(private_fast_session_t *this) +{ + char buf[COOKIE_LEN]; + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + return FALSE; + } + if (!rng->get_bytes(rng, sizeof(buf), buf)) + { + rng->destroy(rng); + return FALSE; + } + rng->destroy(rng); + chunk_to_hex(chunk_create(buf, sizeof(buf)), this->sid, FALSE); + return TRUE; +} + +/** + * run all registered filters + */ +static bool run_filter(private_fast_session_t *this, fast_request_t *request, + char *p0, char *p1, char *p2, char *p3, char *p4, char *p5) +{ + enumerator_t *enumerator; + fast_filter_t *filter; + + enumerator = this->filters->create_enumerator(this->filters); + while (enumerator->enumerate(enumerator, &filter)) + { + if (!filter->run(filter, request, p0, p1, p2, p3, p4, p5)) + { + enumerator->destroy(enumerator); + return FALSE; + } + } + enumerator->destroy(enumerator); + return TRUE; +} + +METHOD(fast_session_t, process, void, + private_fast_session_t *this, fast_request_t *request) +{ + char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; + enumerator_t *enumerator; + bool handled = FALSE; + fast_controller_t *current; + int i = 0; + + if (!this->cookie_sent) + { + request->add_cookie(request, "SID", this->sid); + this->cookie_sent = TRUE; + } + + start = request->get_path(request); + if (start) + { + if (*start == '/') + { + start++; + } + while ((pos = strchr(start, '/')) != NULL && i < 5) + { + param[i++] = strndupa(start, pos - start); + start = pos + 1; + } + param[i] = strdupa(start); + + if (run_filter(this, request, param[0], param[1], param[2], param[3], + param[4], param[5])) + { + enumerator = this->controllers->create_enumerator(this->controllers); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->get_name(current), param[0])) + { + current->handle(current, request, param[1], param[2], + param[3], param[4], param[5]); + handled = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } + else + { + handled = TRUE; + } + } + if (!handled) + { + if (this->controllers->get_first(this->controllers, + (void**)¤t) == SUCCESS) + { + request->streamf(request, + "Status: 301 Moved permanently\nLocation: %s/%s\n\n", + request->get_base(request), current->get_name(current)); + } + } +} + +METHOD(fast_session_t, get_sid, char*, + private_fast_session_t *this) +{ + return this->sid; +} + +METHOD(fast_session_t, destroy, void, + private_fast_session_t *this) +{ + this->controllers->destroy_offset(this->controllers, + offsetof(fast_controller_t, destroy)); + this->filters->destroy_offset(this->filters, + offsetof(fast_filter_t, destroy)); + DESTROY_IF(this->context); + free(this); +} + +/* + * see header file + */ +fast_session_t *fast_session_create(fast_context_t *context) +{ + private_fast_session_t *this; + + INIT(this, + .public = { + .add_controller = _add_controller, + .add_filter = _add_filter, + .process = _process, + .get_sid = _get_sid, + .destroy = _destroy, + }, + .controllers = linked_list_create(), + .filters = linked_list_create(), + .context = context, + ); + if (!create_sid(this)) + { + destroy(this); + return NULL; + } + + return &this->public; +} |