first revision of new manager webapp
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file context.h
|
||||
*
|
||||
* @brief Interface of context_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONTEXT_H_
|
||||
#define CONTEXT_H_
|
||||
|
||||
typedef struct context_t context_t;
|
||||
|
||||
/**
|
||||
* @brief Constructor function for a context
|
||||
*/
|
||||
typedef context_t *(*context_constructor_t)(void *param);
|
||||
|
||||
/**
|
||||
* @brief Custom session context
|
||||
*
|
||||
*/
|
||||
struct context_t {
|
||||
|
||||
/**
|
||||
* @brief Destroy the context_t.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (context_t *this);
|
||||
};
|
||||
|
||||
#endif /* CONTEXT_H_ */
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file controller.h
|
||||
*
|
||||
* @brief Interface controller_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONTROLLER_H_
|
||||
#define CONTROLLER_H_
|
||||
|
||||
#include "request.h"
|
||||
#include "response.h"
|
||||
#include "context.h"
|
||||
|
||||
typedef struct controller_t controller_t;
|
||||
|
||||
/**
|
||||
* @brief Controller action handle function
|
||||
*
|
||||
* @param request http request
|
||||
* @param response http response
|
||||
*/
|
||||
typedef void *(*controller_handler_t)(controller_t *this, request_t *request, response_t *response);
|
||||
|
||||
/**
|
||||
* @brief Constructor function for a controller
|
||||
*
|
||||
* @param context session specific context
|
||||
* @param param user supplied param
|
||||
*/
|
||||
typedef controller_t *(*controller_constructor_t)(context_t* context, void *param);
|
||||
|
||||
/**
|
||||
* @brief Controller interface, to be implemented by users controllers.
|
||||
*
|
||||
*/
|
||||
struct controller_t {
|
||||
|
||||
/**
|
||||
* @brief Get the name of the controller.
|
||||
*
|
||||
* @return name of the controller
|
||||
*/
|
||||
char* (*get_name)(controller_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the controllers handler function for an action name.
|
||||
*
|
||||
* @param name name of the action
|
||||
* @return controllers handler
|
||||
*/
|
||||
controller_handler_t (*get_handler)(controller_t *this, char *name);
|
||||
|
||||
/**
|
||||
* @brief Destroy the controller instance.
|
||||
*/
|
||||
void (*destroy) (controller_t *this);
|
||||
};
|
||||
|
||||
#endif /* CONTROLLER_H_ */
|
||||
@@ -0,0 +1,348 @@
|
||||
/**
|
||||
* @file dispatcher.c
|
||||
*
|
||||
* @brief Implementation of dispatcher_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "dispatcher.h"
|
||||
|
||||
#include "request.h"
|
||||
#include "session.h"
|
||||
|
||||
#include <fcgiapp.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
typedef struct private_dispatcher_t private_dispatcher_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_dispatcher_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
dispatcher_t public;
|
||||
|
||||
/**
|
||||
* fcgi socket fd
|
||||
*/
|
||||
int fd;
|
||||
|
||||
/**
|
||||
* thread list
|
||||
*/
|
||||
pthread_t *threads;
|
||||
|
||||
/**
|
||||
* number of threads in "threads"
|
||||
*/
|
||||
int thread_count;
|
||||
|
||||
/**
|
||||
* session locking mutex
|
||||
*/
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
/**
|
||||
* List of sessions
|
||||
*/
|
||||
linked_list_t *sessions;
|
||||
|
||||
/**
|
||||
* session timeout
|
||||
*/
|
||||
time_t timeout;
|
||||
|
||||
/**
|
||||
* List of controllers controller_constructor_t
|
||||
*/
|
||||
linked_list_t *controllers;
|
||||
|
||||
/**
|
||||
* constructor function to create session context (in constructor_entry_t)
|
||||
*/
|
||||
context_constructor_t context_constructor;
|
||||
|
||||
/**
|
||||
* user param to context constructor
|
||||
*/
|
||||
void *param;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/** constructor function */
|
||||
controller_constructor_t constructor;
|
||||
/** parameter to constructor */
|
||||
void *param;
|
||||
} constructor_entry_t;
|
||||
|
||||
typedef struct {
|
||||
/** session instance */
|
||||
session_t *session;
|
||||
/** condvar to wait for session */
|
||||
pthread_cond_t cond;
|
||||
/** number of threads waiting for session */
|
||||
int waiting;
|
||||
/** last use of the session */
|
||||
time_t used;
|
||||
} session_entry_t;
|
||||
|
||||
/**
|
||||
* create a session and instanciate controllers
|
||||
*/
|
||||
static session_t* load_session(private_dispatcher_t *this)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
constructor_entry_t *entry;
|
||||
session_t *session;
|
||||
context_t *context = NULL;
|
||||
controller_t *controller;
|
||||
|
||||
if (this->context_constructor)
|
||||
{
|
||||
context = this->context_constructor(this->param);
|
||||
}
|
||||
session = session_create(context);
|
||||
|
||||
iterator = this->controllers->create_iterator(this->controllers, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&entry))
|
||||
{
|
||||
controller = entry->constructor(context, entry->param);
|
||||
session->add_controller(session, controller);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new session entry
|
||||
*/
|
||||
static session_entry_t *session_entry_create(private_dispatcher_t *this)
|
||||
{
|
||||
session_entry_t *entry;
|
||||
|
||||
entry = malloc_thing(session_entry_t);
|
||||
entry->waiting = 1;
|
||||
pthread_cond_init(&entry->cond, NULL);
|
||||
entry->session = load_session(this);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void session_entry_destroy(session_entry_t *entry)
|
||||
{
|
||||
entry->session->destroy(entry->session);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dispatcher_t.add_controller.
|
||||
*/
|
||||
static void add_controller(private_dispatcher_t *this,
|
||||
controller_constructor_t constructor, void *param)
|
||||
{
|
||||
constructor_entry_t *entry = malloc_thing(constructor_entry_t);
|
||||
|
||||
entry->constructor = constructor;
|
||||
entry->param = param;
|
||||
this->controllers->insert_last(this->controllers, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch
|
||||
*/
|
||||
static void dispatch(private_dispatcher_t *this)
|
||||
{
|
||||
FCGX_Request fcgi_req;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
if (FCGX_InitRequest(&fcgi_req, this->fd, 0) == 0)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
request_t *request;
|
||||
response_t *response;
|
||||
session_entry_t *current, *found = NULL;
|
||||
iterator_t *iterator;
|
||||
time_t now;
|
||||
char *sid;
|
||||
int accepted;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
accepted = FCGX_Accept_r(&fcgi_req);
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
|
||||
if (accepted != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* prepare */
|
||||
response = response_create(&fcgi_req);
|
||||
request = request_create(&fcgi_req);
|
||||
sid = request->get_cookie(request, "SID");
|
||||
now = time(NULL);
|
||||
|
||||
/* find session */
|
||||
iterator = this->sessions->create_iterator_locked(this->sessions, &this->mutex);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
if (sid && streq(current->session->get_sid(current->session), sid))
|
||||
{
|
||||
found = current;
|
||||
found->waiting++;
|
||||
}
|
||||
else if (current->waiting == 0 &&
|
||||
current->used + this->timeout > now)
|
||||
{
|
||||
iterator->remove(iterator);
|
||||
session_entry_destroy(current);
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (found)
|
||||
{ /* wait until session is unused */
|
||||
pthread_mutex_lock(&this->mutex);
|
||||
while (found->waiting > 1)
|
||||
{
|
||||
pthread_cond_wait(&found->cond, &this->mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&this->mutex);
|
||||
}
|
||||
else
|
||||
{ /* create a new session if not found */
|
||||
found = session_entry_create(this);
|
||||
pthread_mutex_lock(&this->mutex);
|
||||
this->sessions->insert_first(this->sessions, found);
|
||||
pthread_mutex_unlock(&this->mutex);
|
||||
}
|
||||
|
||||
/* start processing */
|
||||
found->session->process(found->session, request, response);
|
||||
found->used = time(NULL);
|
||||
|
||||
/* release session */
|
||||
pthread_mutex_lock(&this->mutex);
|
||||
found->waiting--;
|
||||
pthread_cond_signal(&found->cond);
|
||||
pthread_mutex_unlock(&this->mutex);
|
||||
|
||||
/* cleanup */
|
||||
request->destroy(request);
|
||||
response->destroy(response);
|
||||
|
||||
/*
|
||||
FCGX_FPrintF(fcgi_req.out, "<ul>");
|
||||
char **env = fcgi_req.envp;
|
||||
while (*env)
|
||||
{
|
||||
FCGX_FPrintF(fcgi_req.out, "<li>%s</li>", *env);
|
||||
env++;
|
||||
}
|
||||
FCGX_FPrintF(fcgi_req.out, "</ul>");
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dispatcher_t.run.
|
||||
*/
|
||||
static void run(private_dispatcher_t *this, int threads)
|
||||
{
|
||||
this->thread_count = threads;
|
||||
this->threads = malloc(sizeof(pthread_t) * threads);
|
||||
while (threads)
|
||||
{
|
||||
if (pthread_create(&this->threads[threads - 1],
|
||||
NULL, (void*)dispatch, this) == 0)
|
||||
{
|
||||
threads--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dispatcher_t.waitsignal.
|
||||
*/
|
||||
static void waitsignal(private_dispatcher_t *this)
|
||||
{
|
||||
sigset_t set;
|
||||
int sig;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGINT);
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &set, NULL);
|
||||
sigwait(&set, &sig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dispatcher_t.destroy
|
||||
*/
|
||||
static void destroy(private_dispatcher_t *this)
|
||||
{
|
||||
FCGX_ShutdownPending();
|
||||
while (this->thread_count--)
|
||||
{
|
||||
pthread_cancel(this->threads[this->thread_count]);
|
||||
pthread_join(this->threads[this->thread_count], NULL);
|
||||
}
|
||||
this->sessions->destroy_function(this->sessions, (void*)session_entry_destroy);
|
||||
this->controllers->destroy_function(this->controllers, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
dispatcher_t *dispatcher_create(context_constructor_t constructor, void *param)
|
||||
{
|
||||
private_dispatcher_t *this = malloc_thing(private_dispatcher_t);
|
||||
|
||||
this->public.add_controller = (void(*)(dispatcher_t*, controller_constructor_t, void*))add_controller;
|
||||
this->public.run = (void(*)(dispatcher_t*, int threads))run;
|
||||
this->public.waitsignal = (void(*)(dispatcher_t*))waitsignal;
|
||||
this->public.destroy = (void(*)(dispatcher_t*))destroy;
|
||||
|
||||
this->sessions = linked_list_create();
|
||||
this->controllers = linked_list_create();
|
||||
this->context_constructor = constructor;
|
||||
pthread_mutex_init(&this->mutex, NULL);
|
||||
this->param = param;
|
||||
this->fd = 0;
|
||||
this->timeout = 180;
|
||||
|
||||
FCGX_Init();
|
||||
|
||||
#ifdef FCGI_SOCKET
|
||||
unlink(FCGI_SOCKET);
|
||||
this->fd = FCGX_OpenSocket(FCGI_SOCKET, 10);
|
||||
#endif /* FCGI_SOCKET */
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file dispatcher.h
|
||||
*
|
||||
* @brief Interface of dispatcher_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef DISPATCHER_H_
|
||||
#define DISPATCHER_H_
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
typedef struct dispatcher_t dispatcher_t;
|
||||
|
||||
/**
|
||||
* @brief Dispatcher, accepts connections using multiple threads.
|
||||
*
|
||||
* The dispatcher creates a session for each client (using SID cookies). In
|
||||
* each session, a session context is created using the context constructor.
|
||||
* Each controller is instanciated in the session using the controller
|
||||
* constructor added with add_controller.
|
||||
*/
|
||||
struct dispatcher_t {
|
||||
|
||||
/**
|
||||
* @brief Register a controller to the dispatcher.
|
||||
*
|
||||
* @param constructor constructor function to the conntroller
|
||||
* @param param param to pass to constructor
|
||||
*/
|
||||
void (*add_controller)(dispatcher_t *this,
|
||||
controller_constructor_t constructor, void *param);
|
||||
|
||||
/**
|
||||
* @brief Start with dispatching.
|
||||
*
|
||||
* @param thread number of dispatching threads
|
||||
*/
|
||||
void (*run)(dispatcher_t *this, int threads);
|
||||
|
||||
/**
|
||||
* @brief Wait for a relevant signal action.
|
||||
*/
|
||||
void (*waitsignal)(dispatcher_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroy the dispatcher_t.
|
||||
*/
|
||||
void (*destroy) (dispatcher_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a dispatcher.
|
||||
*
|
||||
* The context constructor is invoked to create a session context for
|
||||
* each session.
|
||||
*
|
||||
* @param constructor construction function for session context
|
||||
* @param param parameter to supply to context constructor
|
||||
*/
|
||||
dispatcher_t *dispatcher_create(context_constructor_t constructor, void *param);
|
||||
|
||||
#endif /* DISPATCHER_H_ */
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file enumerator.h
|
||||
*
|
||||
* @brief Interface of enumerator_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ENUMERATOR_H_
|
||||
#define ENUMERATOR_H_
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct enumerator_t enumerator_t;
|
||||
|
||||
/**
|
||||
* @brief Enumerate is simpler, but more flexible than iterator.
|
||||
*/
|
||||
struct enumerator_t {
|
||||
|
||||
/**
|
||||
* @brief Enumerate collection.
|
||||
*
|
||||
* @param ... variable argument list of pointers, NULL terminated
|
||||
* @return TRUE if pointers returned
|
||||
*/
|
||||
bool (*enumerate)(enumerator_t *this, ...);
|
||||
|
||||
/**
|
||||
* @brief Destroy a enumerator instance.
|
||||
*/
|
||||
void (*destroy)(enumerator_t *this);
|
||||
};
|
||||
|
||||
#endif /* ENUMERATOR_H_ */
|
||||
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* @file request.c
|
||||
*
|
||||
* @brief Implementation of request_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "request.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *value;
|
||||
} name_value_t;
|
||||
|
||||
/**
|
||||
* destroy a name value pair
|
||||
*/
|
||||
static void name_value_destroy(name_value_t *this)
|
||||
{
|
||||
free(this->name);
|
||||
free(this->value);
|
||||
free(this);
|
||||
}
|
||||
|
||||
typedef struct private_request_t private_request_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_request_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
request_t public;
|
||||
|
||||
/**
|
||||
* the associated fcgi request
|
||||
*/
|
||||
FCGX_Request *req;
|
||||
|
||||
/**
|
||||
* list of cookies (name_value_t)
|
||||
*/
|
||||
linked_list_t *cookies;
|
||||
|
||||
/**
|
||||
* list of post data (name_value_t)
|
||||
*/
|
||||
linked_list_t *posts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of request_t.get_cookie.
|
||||
*/
|
||||
static char* get_cookie(private_request_t *this, char *name)
|
||||
{
|
||||
char *value = NULL;
|
||||
name_value_t *cookie;
|
||||
iterator_t *iterator;
|
||||
|
||||
iterator = this->cookies->create_iterator(this->cookies, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&cookie))
|
||||
{
|
||||
if (streq(cookie->name, name))
|
||||
{
|
||||
value = cookie->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of request_t.get_path.
|
||||
*/
|
||||
static char* get_path(private_request_t *this)
|
||||
{
|
||||
char * path = FCGX_GetParam("PATH_INFO", this->req->envp);
|
||||
return path ? path : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of request_t.get_post_data.
|
||||
*/
|
||||
static char* get_post_data(private_request_t *this, char *name)
|
||||
{
|
||||
char *value = NULL;
|
||||
name_value_t *data;
|
||||
iterator_t *iterator;
|
||||
|
||||
iterator = this->posts->create_iterator(this->posts, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&data))
|
||||
{
|
||||
if (streq(data->name, name))
|
||||
{
|
||||
value = data->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert 2 digit hex string to a integer
|
||||
*/
|
||||
static char hex2char(char *hex)
|
||||
{
|
||||
static char hexdig[] = "00112233445566778899AaBbCcDdEeFf";
|
||||
|
||||
return (strchr(hexdig, hex[1]) - hexdig)/2 +
|
||||
((strchr(hexdig, hex[0]) - hexdig)/2 * 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* unescape a string up to the delimiter, and return a clone
|
||||
*/
|
||||
static char *unescape(char **pos, char delimiter)
|
||||
{
|
||||
char *ptr, *res, *end, code[3] = {'\0','\0','\0'};
|
||||
|
||||
if (**pos == '\0')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ptr = strchr(*pos, delimiter);
|
||||
if (ptr)
|
||||
{
|
||||
res = strndup(*pos, ptr - *pos);
|
||||
*pos = ptr + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = strdup(*pos);
|
||||
*pos = "";
|
||||
}
|
||||
end = res + strlen(res) + 1;
|
||||
/* replace '+' with ' ' */
|
||||
ptr = res;
|
||||
while ((ptr = strchr(ptr, '+')))
|
||||
{
|
||||
*ptr = ' ';
|
||||
}
|
||||
/* replace %HH with its ascii value */
|
||||
ptr = res;
|
||||
while ((ptr = strchr(ptr, '%')))
|
||||
{
|
||||
if (ptr > end - 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
strncpy(code, ptr + 1, 2);
|
||||
*ptr = hex2char(code);
|
||||
memmove(ptr + 1, ptr + 3, end - (ptr + 3));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the http POST data
|
||||
*/
|
||||
static void parse_post(private_request_t *this)
|
||||
{
|
||||
char buf[4096], *pos, *name, *value;
|
||||
name_value_t *data;
|
||||
int len;
|
||||
|
||||
if (!streq(FCGX_GetParam("REQUEST_METHOD", this->req->envp), "POST") ||
|
||||
!streq(FCGX_GetParam("CONTENT_TYPE", this->req->envp),
|
||||
"application/x-www-form-urlencoded"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
len = FCGX_GetStr(buf, sizeof(buf) - 1, this->req->in);
|
||||
if (len != atoi(FCGX_GetParam("CONTENT_LENGTH", this->req->envp)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
buf[len] = 0;
|
||||
|
||||
pos = buf;
|
||||
while (TRUE)
|
||||
{
|
||||
name = unescape(&pos, '=');
|
||||
if (name)
|
||||
{
|
||||
value = unescape(&pos, '&');
|
||||
if (value)
|
||||
{
|
||||
data = malloc_thing(name_value_t);
|
||||
data->name = name;
|
||||
data->value = value;
|
||||
this->posts->insert_last(this->posts, data);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the requests cookies
|
||||
*/
|
||||
static void parse_cookies(private_request_t *this)
|
||||
{
|
||||
char *str, *pos;
|
||||
name_value_t *cookie;
|
||||
|
||||
str = FCGX_GetParam("HTTP_COOKIE", this->req->envp);
|
||||
while (str)
|
||||
{
|
||||
if (*str == ' ')
|
||||
{
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
pos = strchr(str, '=');
|
||||
if (pos == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cookie = malloc_thing(name_value_t);
|
||||
cookie->name = strndup(str, pos - str);
|
||||
cookie->value = NULL;
|
||||
str = pos + 1;
|
||||
if (str)
|
||||
{
|
||||
pos = strchr(str, ';');
|
||||
if (pos)
|
||||
{
|
||||
cookie->value = strndup(str, pos - str);
|
||||
}
|
||||
else
|
||||
{
|
||||
cookie->value = strdup(str);
|
||||
}
|
||||
}
|
||||
this->cookies->insert_last(this->cookies, cookie);
|
||||
if (pos == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
str = pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of request_t.destroy
|
||||
*/
|
||||
static void destroy(private_request_t *this)
|
||||
{
|
||||
this->cookies->destroy_function(this->cookies, (void*)name_value_destroy);
|
||||
this->posts->destroy_function(this->posts, (void*)name_value_destroy);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
request_t *request_create(FCGX_Request *request)
|
||||
{
|
||||
private_request_t *this = malloc_thing(private_request_t);
|
||||
|
||||
this->public.get_path = (char*(*)(request_t*))get_path;
|
||||
this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie;
|
||||
this->public.get_post_data = (char*(*)(request_t*, char *name))get_post_data;
|
||||
this->public.destroy = (void(*)(request_t*))destroy;
|
||||
|
||||
this->req = request;
|
||||
this->cookies = linked_list_create();
|
||||
this->posts = linked_list_create();
|
||||
|
||||
parse_cookies(this);
|
||||
parse_post(this);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file request.h
|
||||
*
|
||||
* @brief Interface of request_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_H_
|
||||
#define REQUEST_H_
|
||||
|
||||
|
||||
#include <fcgiapp.h>
|
||||
|
||||
typedef struct request_t request_t;
|
||||
|
||||
/**
|
||||
* @brief A HTTP request, encapsulates FCGX_Request.
|
||||
*
|
||||
*/
|
||||
struct request_t {
|
||||
|
||||
/**
|
||||
* @brief Get a cookie the client sent in the request.
|
||||
*
|
||||
* @param name name of the cookie
|
||||
* @return cookie value, NULL if no such cookie found
|
||||
*/
|
||||
char* (*get_cookie)(request_t *this, char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the request path relative to the application.
|
||||
*
|
||||
* @return path
|
||||
*/
|
||||
char* (*get_path)(request_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get a post variable included in the request.
|
||||
*
|
||||
* @param name name of the POST variable
|
||||
* @return value, NULL if not found
|
||||
*/
|
||||
char* (*get_post_data)(request_t *this, char *name);
|
||||
|
||||
/**
|
||||
* @brief Destroy the request_t.
|
||||
*/
|
||||
void (*destroy) (request_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a request from the fastcgi struct.
|
||||
*
|
||||
* @param request the FCGI request
|
||||
*/
|
||||
request_t *request_create(FCGX_Request *request);
|
||||
|
||||
#endif /* REQUEST_H_ */
|
||||
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* @file response.c
|
||||
*
|
||||
* @brief Implementation of response_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "response.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *value;
|
||||
} name_value_t;
|
||||
|
||||
/**
|
||||
* create name value pair
|
||||
*/
|
||||
static name_value_t *name_value_create(char *name, char *value)
|
||||
{
|
||||
name_value_t *this = malloc_thing(name_value_t);
|
||||
|
||||
this->name = strdup(name);
|
||||
this->value = strdup(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy a name value pair
|
||||
*/
|
||||
static void name_value_destroy(name_value_t *this)
|
||||
{
|
||||
free(this->name);
|
||||
free(this->value);
|
||||
free(this);
|
||||
}
|
||||
|
||||
typedef struct private_response_t private_response_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_response_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
response_t public;
|
||||
|
||||
/**
|
||||
* the associated fcgi request
|
||||
*/
|
||||
FCGX_Request *req;
|
||||
|
||||
/**
|
||||
* Content type
|
||||
*/
|
||||
char *content_type;
|
||||
|
||||
/**
|
||||
* list of cookies (name_value_t)
|
||||
*/
|
||||
linked_list_t *cookies;
|
||||
|
||||
/**
|
||||
* list of custom headers (name_value_t)
|
||||
*/
|
||||
linked_list_t *headers;
|
||||
|
||||
/**
|
||||
* headers already written?
|
||||
*/
|
||||
bool started;
|
||||
};
|
||||
|
||||
/**
|
||||
* write the headers, if not already written
|
||||
*/
|
||||
static void write_headers(private_response_t *this)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
name_value_t *current;
|
||||
|
||||
FCGX_FPrintF(this->req->out, "Content-type: %s\n", this->content_type);
|
||||
iterator = this->cookies->create_iterator(this->cookies, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
FCGX_FPrintF(this->req->out, "Set-Cookie: %s=%s; path=%s\n",
|
||||
current->name, current->value,
|
||||
FCGX_GetParam("SCRIPT_NAME", this->req->envp));
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
iterator = this->cookies->create_iterator(this->headers, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
FCGX_FPrintF(this->req->out, "%s: %s\n",
|
||||
current->name, current->value);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
FCGX_PutChar('\n', this->req->out);
|
||||
this->started = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.print.
|
||||
*/
|
||||
static void print_(private_response_t *this, char *str)
|
||||
{
|
||||
if (!this->started)
|
||||
{
|
||||
write_headers(this);
|
||||
}
|
||||
FCGX_PutS(str, this->req->out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.printf.
|
||||
*/
|
||||
static void printf_(private_response_t *this, char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!this->started)
|
||||
{
|
||||
write_headers(this);
|
||||
}
|
||||
|
||||
va_start(args, format);
|
||||
FCGX_VFPrintF(this->req->out, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.add_header.
|
||||
*/
|
||||
static void add_header(private_response_t *this, char *name, char *value)
|
||||
{
|
||||
this->headers->insert_last(this->headers, name_value_create(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.set_content_type.
|
||||
*/
|
||||
static void set_content_type(private_response_t *this, char *type)
|
||||
{
|
||||
free(this->content_type);
|
||||
this->content_type = strdup(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.add_cookie.
|
||||
*/
|
||||
static void add_cookie(private_response_t *this, char *name, char *value)
|
||||
{
|
||||
this->cookies->insert_last(this->cookies, name_value_create(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.redirect.
|
||||
*/
|
||||
static void redirect(private_response_t *this, char *location)
|
||||
{
|
||||
FCGX_FPrintF(this->req->out, "Status: 303 See Other\n");
|
||||
FCGX_FPrintF(this->req->out, "Location: %s%s%s\n\n",
|
||||
FCGX_GetParam("SCRIPT_NAME", this->req->envp),
|
||||
*location == '/' ? "" : "/", location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of response_t.destroy
|
||||
*/
|
||||
static void destroy(private_response_t *this)
|
||||
{
|
||||
this->headers->destroy_function(this->headers, (void*)name_value_destroy);
|
||||
this->cookies->destroy_function(this->cookies, (void*)name_value_destroy);
|
||||
free(this->content_type);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
response_t *response_create(FCGX_Request *request)
|
||||
{
|
||||
private_response_t *this = malloc_thing(private_response_t);
|
||||
|
||||
this->public.print = (void(*)(response_t*, char *str))print_;
|
||||
this->public.printf = (void(*)(response_t*, char *format, ...))printf_;
|
||||
this->public.add_header = (void(*)(response_t*, char *name, char *value))add_header;
|
||||
this->public.set_content_type = (void(*)(response_t*, char *type))set_content_type;
|
||||
this->public.add_cookie = (void(*)(response_t*, char *name, char *value))add_cookie;
|
||||
this->public.redirect = (void(*)(response_t*, char *location))redirect;
|
||||
this->public.destroy = (void(*)(response_t*))destroy;
|
||||
|
||||
this->req = request;
|
||||
this->headers = linked_list_create();
|
||||
this->cookies = linked_list_create();
|
||||
this->content_type = strdup("text/html");
|
||||
this->started = FALSE;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file response.h
|
||||
*
|
||||
* @brief Interface of response_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RESPONSE_H_
|
||||
#define RESPONSE_H_
|
||||
|
||||
|
||||
#include <fcgiapp.h>
|
||||
|
||||
typedef struct response_t response_t;
|
||||
|
||||
/**
|
||||
* @brief A HTTP response, wraps response functionality around FCGX_Request.
|
||||
*
|
||||
*/
|
||||
struct response_t {
|
||||
|
||||
/**
|
||||
* @brief Write a string to the client.
|
||||
*
|
||||
* @param str string to write
|
||||
*/
|
||||
void (*print)(response_t *this, char *str);
|
||||
|
||||
/**
|
||||
* @brief Write a printf like format string to client.
|
||||
*
|
||||
* @param format printf like format string
|
||||
* @param ... variable argument list
|
||||
*/
|
||||
void (*printf)(response_t *this, char *format, ...);
|
||||
|
||||
/**
|
||||
* @brief Add a custom header to the response.
|
||||
*
|
||||
* @param name name of the header
|
||||
* @param value value of the header
|
||||
*/
|
||||
void (*add_header)(response_t *this, char *name, char *value);
|
||||
|
||||
/**
|
||||
* @brief Set the content type (Content-Type header).
|
||||
*
|
||||
* @param type content type (e.g. text/html)
|
||||
*/
|
||||
void (*set_content_type)(response_t *this, char *type);
|
||||
|
||||
/**
|
||||
* @brief Add a cookie to the response (Set-Cookie header).
|
||||
*
|
||||
* @param name name of the cookie to set
|
||||
* @param value value of the cookie
|
||||
*/
|
||||
void (*add_cookie)(response_t *this, char *name, char *value);
|
||||
|
||||
/**
|
||||
* @brief Redirect the client to another location.
|
||||
*
|
||||
* @param location location to redirect to
|
||||
*/
|
||||
void (*redirect)(response_t *this, char *location);
|
||||
|
||||
/**
|
||||
* @brief Destroy a response_t.
|
||||
*/
|
||||
void (*destroy) (response_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a response.
|
||||
*
|
||||
* @param request the FCGI request structure
|
||||
*/
|
||||
response_t *response_create(FCGX_Request *request);
|
||||
|
||||
#endif /* RESPONSE_H_ */
|
||||
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @file session.c
|
||||
*
|
||||
* @brief Implementation of session_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "session.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcgiapp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/randomizer.h>
|
||||
|
||||
typedef struct private_session_t private_session_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_session_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
session_t public;
|
||||
|
||||
/**
|
||||
* session ID
|
||||
*/
|
||||
char *sid;
|
||||
|
||||
/**
|
||||
* list of controller instances controller_t
|
||||
*/
|
||||
linked_list_t *controllers;
|
||||
|
||||
/**
|
||||
* user defined session context
|
||||
*/
|
||||
context_t *context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of session_t.load_controller.
|
||||
*/
|
||||
static void add_controller(private_session_t *this, controller_t *controller)
|
||||
{
|
||||
this->controllers->insert_last(this->controllers, controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a session ID and a cookie
|
||||
*/
|
||||
static void create_sid(private_session_t *this, response_t *response)
|
||||
{
|
||||
char buf[16];
|
||||
chunk_t chunk = chunk_from_buf(buf);
|
||||
randomizer_t *randomizer = randomizer_create();
|
||||
|
||||
randomizer->get_pseudo_random_bytes(randomizer, sizeof(buf), buf);
|
||||
asprintf(&this->sid, "%#B", &chunk);
|
||||
response->add_cookie(response, "SID", this->sid);
|
||||
randomizer->destroy(randomizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of session_t.process.
|
||||
*/
|
||||
static void process(private_session_t *this,
|
||||
request_t *request, response_t *response)
|
||||
{
|
||||
char *pos, *path, *controller, *action;
|
||||
iterator_t *iterator;
|
||||
bool handled = FALSE;
|
||||
controller_handler_t handler;
|
||||
controller_t *current;
|
||||
|
||||
if (this->sid == NULL)
|
||||
{
|
||||
create_sid(this, response);
|
||||
}
|
||||
|
||||
path = request->get_path(request);
|
||||
if (*path == '/') path++;
|
||||
pos = strchr(path, '/');
|
||||
if (pos == NULL)
|
||||
{
|
||||
controller = strdup(path);
|
||||
action = strdup("");
|
||||
}
|
||||
else
|
||||
{
|
||||
controller = strndup(path, pos - path);
|
||||
path = pos + 1;
|
||||
pos = strchr(path, '/');
|
||||
if (pos == NULL)
|
||||
{
|
||||
action = strdup(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
action = strndup(path, pos - path);
|
||||
}
|
||||
}
|
||||
iterator = this->controllers->create_iterator(this->controllers, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
if (streq(current->get_name(current), controller))
|
||||
{
|
||||
handler = current->get_handler(current, action);
|
||||
if (handler)
|
||||
{
|
||||
handler(current, request, response);
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
free(controller);
|
||||
free(action);
|
||||
if (!handled)
|
||||
{
|
||||
response->add_header(response, "Status", "400 Not Found");
|
||||
response->printf(response, "<html><body><h1>Not Found</h1></body></html>\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of session_t.get_sid.
|
||||
*/
|
||||
static char* get_sid(private_session_t *this)
|
||||
{
|
||||
return this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of session_t.destroy
|
||||
*/
|
||||
static void destroy(private_session_t *this)
|
||||
{
|
||||
this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy));
|
||||
if (this->context) this->context->destroy(this->context);
|
||||
free(this->sid);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
session_t *session_create(context_t *context)
|
||||
{
|
||||
private_session_t *this = malloc_thing(private_session_t);
|
||||
|
||||
this->public.add_controller = (void(*)(session_t*, controller_t*))add_controller;
|
||||
this->public.process = (void(*)(session_t*, request_t*,response_t*))process;
|
||||
this->public.get_sid = (char*(*)(session_t*))get_sid;
|
||||
this->public.destroy = (void(*)(session_t*))destroy;
|
||||
|
||||
this->sid = NULL;
|
||||
this->controllers = linked_list_create();
|
||||
this->context = context;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file session.h
|
||||
*
|
||||
* @brief Interface of session_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SESSION_H_
|
||||
#define SESSION_H_
|
||||
|
||||
#include "request.h"
|
||||
#include "response.h"
|
||||
#include "controller.h"
|
||||
|
||||
typedef struct session_t session_t;
|
||||
|
||||
/**
|
||||
* @brief A session, identified by a session ID.
|
||||
*
|
||||
*/
|
||||
struct session_t {
|
||||
|
||||
/**
|
||||
* @brief Get the session ID of the session.
|
||||
*
|
||||
* @return session ID
|
||||
*/
|
||||
char* (*get_sid)(session_t *this);
|
||||
|
||||
/**
|
||||
* @brief Add a controller instance to the session.
|
||||
*
|
||||
* @param controller controller to add
|
||||
*/
|
||||
void (*add_controller)(session_t *this, controller_t *controller);
|
||||
|
||||
/**
|
||||
* @brief Process a request in this session.
|
||||
*
|
||||
* @param request request to process
|
||||
* @param response response to send
|
||||
*/
|
||||
void (*process)(session_t *this, request_t *request, response_t *response);
|
||||
|
||||
/**
|
||||
* @brief Destroy the session_t.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (session_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a session.
|
||||
*
|
||||
* @param context user defined session context instance
|
||||
*/
|
||||
session_t *session_create(context_t *context);
|
||||
|
||||
#endif /* SESSION_H_ */
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @file template.c
|
||||
*
|
||||
* @brief Implementation of template_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "template.h"
|
||||
|
||||
#include <ClearSilver/ClearSilver.h>
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct private_template_t private_template_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_template_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
template_t public;
|
||||
|
||||
/**
|
||||
* template file
|
||||
*/
|
||||
char *file;
|
||||
|
||||
/**
|
||||
* clearsilver HDF dataset
|
||||
*/
|
||||
HDF *hdf;
|
||||
};
|
||||
|
||||
/**
|
||||
* clearsilver cs_render callback function
|
||||
*/
|
||||
static NEOERR* render_cb(response_t *response, char *str)
|
||||
{
|
||||
response->print(response, str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of template_t.render.
|
||||
*/
|
||||
static void render(private_template_t *this, response_t *response)
|
||||
{
|
||||
NEOERR* err;
|
||||
CSPARSE *parse;
|
||||
|
||||
hdf_remove_tree(this->hdf, "");
|
||||
|
||||
err = cs_init(&parse, this->hdf);
|
||||
if (!err)
|
||||
{
|
||||
err = cs_parse_file(parse, this->file);
|
||||
if (!err)
|
||||
{
|
||||
err = cs_render(parse, response, (CSOUTFUNC)render_cb);
|
||||
if (!err)
|
||||
{
|
||||
cs_destroy(&parse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cs_destroy(&parse);
|
||||
}
|
||||
nerr_log_error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of template_t.set.
|
||||
*/
|
||||
static void set(private_template_t *this, char *key, char *value)
|
||||
{
|
||||
hdf_set_value(this->hdf, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of template_t.setf.
|
||||
*/
|
||||
static void setf(private_template_t *this, char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
hdf_set_valuevf(this->hdf, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of template_t.destroy
|
||||
*/
|
||||
static void destroy(private_template_t *this)
|
||||
{
|
||||
hdf_destroy(&this->hdf);
|
||||
free(this->file);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
template_t *template_create(char *file)
|
||||
{
|
||||
private_template_t *this = malloc_thing(private_template_t);
|
||||
|
||||
this->public.render = (void(*)(template_t*,response_t*))render;
|
||||
this->public.set = (void(*)(template_t*, char *, char*))set;
|
||||
this->public.setf = (void(*)(template_t*, char *format, ...))setf;
|
||||
this->public.destroy = (void(*)(template_t*))destroy;
|
||||
|
||||
this->file = strdup(file);
|
||||
this->hdf = NULL;
|
||||
|
||||
hdf_init(&this->hdf);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file template.h
|
||||
*
|
||||
* @brief Interface of template_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TEMPLATE_H_
|
||||
#define TEMPLATE_H_
|
||||
|
||||
#include "response.h"
|
||||
|
||||
typedef struct template_t template_t;
|
||||
|
||||
/**
|
||||
* @brief Template engine based on ClearSilver.
|
||||
*
|
||||
*/
|
||||
struct template_t {
|
||||
|
||||
/**
|
||||
* @brief Set a template value.
|
||||
*
|
||||
* @param key key to set
|
||||
* @param value value to set key to
|
||||
*/
|
||||
void (*set)(template_t *this, char *key, char *value);
|
||||
|
||||
/**
|
||||
* @brief Set a template value using format strings.
|
||||
*
|
||||
* Format string is in the form "key=value", where printf like format
|
||||
* substitution occurs over the whole string.
|
||||
*
|
||||
* @param format printf like format string
|
||||
* @param ... variable argument list
|
||||
*/
|
||||
void (*setf)(template_t *this, char *format, ...);
|
||||
|
||||
/**
|
||||
* @brief Render a template to a response object.
|
||||
*
|
||||
* @param response response to render to
|
||||
* @return rendered template string
|
||||
*/
|
||||
void (*render)(template_t *this, response_t *response);
|
||||
|
||||
/**
|
||||
* @brief Destroy the template_t.
|
||||
*/
|
||||
void (*destroy) (template_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a template from a file.
|
||||
*
|
||||
* @param file template file
|
||||
*/
|
||||
template_t *template_create(char *file);
|
||||
|
||||
#endif /* TEMPLATE_H_ */
|
||||
Reference in New Issue
Block a user