/* * Copyright (C) 2007 Martin Willi * HSR 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 . * * 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 #include #include #include #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; }