From 6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Sun, 25 Aug 2013 15:37:26 +0200 Subject: Imported Upstream version 5.1.0 --- src/libfast/Makefile.am | 14 +- src/libfast/Makefile.in | 93 +++++--- src/libfast/context.h | 42 ---- src/libfast/controller.h | 77 ------- src/libfast/dispatcher.c | 456 ------------------------------------- src/libfast/dispatcher.h | 137 ------------ src/libfast/fast_context.h | 42 ++++ src/libfast/fast_controller.h | 78 +++++++ src/libfast/fast_dispatcher.c | 460 ++++++++++++++++++++++++++++++++++++++ src/libfast/fast_dispatcher.h | 137 ++++++++++++ src/libfast/fast_filter.h | 64 ++++++ src/libfast/fast_request.c | 509 ++++++++++++++++++++++++++++++++++++++++++ src/libfast/fast_request.h | 217 ++++++++++++++++++ src/libfast/fast_session.c | 228 +++++++++++++++++++ src/libfast/fast_session.h | 77 +++++++ src/libfast/fast_smtp.c | 187 ++++++++++++++++ src/libfast/fast_smtp.h | 56 +++++ src/libfast/filter.h | 63 ------ src/libfast/request.c | 499 ----------------------------------------- src/libfast/request.h | 217 ------------------ src/libfast/session.c | 227 ------------------- src/libfast/session.h | 77 ------- src/libfast/smtp.c | 188 ---------------- src/libfast/smtp.h | 56 ----- 24 files changed, 2127 insertions(+), 2074 deletions(-) delete mode 100644 src/libfast/context.h delete mode 100644 src/libfast/controller.h delete mode 100644 src/libfast/dispatcher.c delete mode 100644 src/libfast/dispatcher.h create mode 100644 src/libfast/fast_context.h create mode 100644 src/libfast/fast_controller.h create mode 100644 src/libfast/fast_dispatcher.c create mode 100644 src/libfast/fast_dispatcher.h create mode 100644 src/libfast/fast_filter.h create mode 100644 src/libfast/fast_request.c create mode 100644 src/libfast/fast_request.h create mode 100644 src/libfast/fast_session.c create mode 100644 src/libfast/fast_session.h create mode 100644 src/libfast/fast_smtp.c create mode 100644 src/libfast/fast_smtp.h delete mode 100644 src/libfast/filter.h delete mode 100644 src/libfast/request.c delete mode 100644 src/libfast/request.h delete mode 100644 src/libfast/session.c delete mode 100644 src/libfast/session.h delete mode 100644 src/libfast/smtp.c delete mode 100644 src/libfast/smtp.h (limited to 'src/libfast') diff --git a/src/libfast/Makefile.am b/src/libfast/Makefile.am index df5b650ce..edc2ab1ca 100644 --- a/src/libfast/Makefile.am +++ b/src/libfast/Makefile.am @@ -1,15 +1,21 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I/usr/include/ClearSilver + +AM_CFLAGS = \ + -rdynamic + ipseclib_LTLIBRARIES = libfast.la libfast_la_SOURCES = \ - dispatcher.c request.c session.c smtp.c + fast_dispatcher.c fast_request.c fast_session.c fast_smtp.c if USE_DEV_HEADERS fast_includedir = ${dev_headers}/fast nobase_fast_include_HEADERS = \ - context.h controller.h dispatcher.h filter.h request.h session.h smtp.h + fast_context.h fast_controller.h fast_dispatcher.h fast_filter.h \ + fast_request.h fast_session.h fast_smtp.h endif libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ -lfcgi $(clearsilver_LIBS) $(PTHREADLIB) -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I/usr/include/ClearSilver -AM_CFLAGS = -rdynamic diff --git a/src/libfast/Makefile.in b/src/libfast/Makefile.in index cadf76d8f..d5b511e56 100644 --- a/src/libfast/Makefile.in +++ b/src/libfast/Makefile.in @@ -64,7 +64,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ $(top_srcdir)/m4/macros/with.m4 \ $(top_srcdir)/m4/macros/enable-disable.m4 \ $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -105,21 +105,38 @@ am__DEPENDENCIES_1 = libfast_la_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -am_libfast_la_OBJECTS = dispatcher.lo request.lo session.lo smtp.lo +am_libfast_la_OBJECTS = fast_dispatcher.lo fast_request.lo \ + fast_session.lo fast_smtp.lo libfast_la_OBJECTS = $(am_libfast_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libfast_la_SOURCES) DIST_SOURCES = $(libfast_la_SOURCES) am__can_run_installinfo = \ @@ -127,8 +144,9 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -am__nobase_fast_include_HEADERS_DIST = context.h controller.h \ - dispatcher.h filter.h request.h session.h smtp.h +am__nobase_fast_include_HEADERS_DIST = fast_context.h \ + fast_controller.h fast_dispatcher.h fast_filter.h \ + fast_request.h fast_session.h fast_smtp.h HEADERS = $(nobase_fast_include_HEADERS) ETAGS = etags CTAGS = ctags @@ -136,6 +154,7 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ @@ -148,6 +167,8 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECK_CFLAGS = @CHECK_CFLAGS@ CHECK_LIBS = @CHECK_LIBS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ @@ -163,6 +184,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ GREP = @GREP@ @@ -171,6 +193,7 @@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ @@ -217,6 +240,7 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOCKLIB = @SOCKLIB@ STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ @@ -245,6 +269,7 @@ charon_natt_port = @charon_natt_port@ charon_plugins = @charon_plugins@ charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ @@ -322,19 +347,25 @@ top_srcdir = @top_srcdir@ urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I/usr/include/ClearSilver + +AM_CFLAGS = \ + -rdynamic + ipseclib_LTLIBRARIES = libfast.la libfast_la_SOURCES = \ - dispatcher.c request.c session.c smtp.c + fast_dispatcher.c fast_request.c fast_session.c fast_smtp.c @USE_DEV_HEADERS_TRUE@fast_includedir = ${dev_headers}/fast @USE_DEV_HEADERS_TRUE@nobase_fast_include_HEADERS = \ -@USE_DEV_HEADERS_TRUE@ context.h controller.h dispatcher.h filter.h request.h session.h smtp.h +@USE_DEV_HEADERS_TRUE@ fast_context.h fast_controller.h fast_dispatcher.h fast_filter.h \ +@USE_DEV_HEADERS_TRUE@ fast_request.h fast_session.h fast_smtp.h libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ -lfcgi $(clearsilver_LIBS) $(PTHREADLIB) -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I/usr/include/ClearSilver -AM_CFLAGS = -rdynamic all: all-am .SUFFIXES: @@ -402,7 +433,7 @@ clean-ipseclibLTLIBRARIES: rm -f "$${dir}/so_locations"; \ done libfast.la: $(libfast_la_OBJECTS) $(libfast_la_DEPENDENCIES) $(EXTRA_libfast_la_DEPENDENCIES) - $(LINK) -rpath $(ipseclibdir) $(libfast_la_OBJECTS) $(libfast_la_LIBADD) $(LIBS) + $(AM_V_CCLD)$(LINK) -rpath $(ipseclibdir) $(libfast_la_OBJECTS) $(libfast_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -410,31 +441,31 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatcher.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smtp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fast_dispatcher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fast_request.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fast_session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fast_smtp.Plo@am__quote@ .c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo diff --git a/src/libfast/context.h b/src/libfast/context.h deleted file mode 100644 index 4f8d11d2c..000000000 --- a/src/libfast/context.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 . - * - * 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. - */ - -/** - * @defgroup context context - * @{ @ingroup libfast - */ - -#ifndef CONTEXT_H_ -#define CONTEXT_H_ - -typedef struct context_t context_t; - -/** - * Constructor function for a user specific context. - */ -typedef context_t *(*context_constructor_t)(void *param); - -/** - * User specific session context, to extend. - */ -struct context_t { - - /** - * Destroy the context_t. - */ - void (*destroy) (context_t *this); -}; - -#endif /** CONTEXT_H_ @}*/ diff --git a/src/libfast/controller.h b/src/libfast/controller.h deleted file mode 100644 index 7a7efc706..000000000 --- a/src/libfast/controller.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 . - * - * 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. - */ - -/** - * @defgroup controller controller - * @{ @ingroup libfast - */ - -#ifndef CONTROLLER_H_ -#define CONTROLLER_H_ - -#include "request.h" -#include "context.h" - -typedef struct controller_t controller_t; - -/** - * Constructor function for a controller. - * - * @param context session specific context, implements context_t - * @param param user supplied param, as registered to the dispatcher - */ -typedef controller_t *(*controller_constructor_t)(context_t* context, void *param); - -/** - * Controller interface, to be implemented by users controllers. - * - * Controller instances get created per session, so each session has an - * associated set of private controller instances. - * The controller handle function is called for each incoming request. - */ -struct controller_t { - - /** - * Get the name of the controller. - * - * @return name of the controller - */ - char* (*get_name)(controller_t *this); - - /** - * Handle a HTTP request for that controller. - * - * Request URLs are parsed in the form - * controller_name/p1/p2/p3/p4/p5 with a maximum of 5 parameters. Each - * parameter not found in the request URL is set to NULL. - * - * @param request HTTP request - * @param p1 first parameter - * @param p2 second parameter - * @param p3 third parameter - * @param p4 forth parameter - * @param p5 fifth parameter - * @return - */ - void (*handle)(controller_t *this, request_t *request, - char *p1, char *p2, char *p3, char *p4, char *p5); - - /** - * Destroy the controller instance. - */ - void (*destroy) (controller_t *this); -}; - -#endif /** CONTROLLER_H_ @}*/ diff --git a/src/libfast/dispatcher.c b/src/libfast/dispatcher.c deleted file mode 100644 index e5a02c63b..000000000 --- a/src/libfast/dispatcher.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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 . - * - * 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 -#include -#include - -#include -#include -#include -#include -#include -#include - -/** Intervall to check for expired sessions, in seconds */ -#define CLEANUP_INTERVAL 30 - -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 - */ - thread_t **threads; - - /** - * number of threads in "threads" - */ - int thread_count; - - /** - * session locking mutex - */ - mutex_t *mutex; - - /** - * Hahstable with active sessions - */ - hashtable_t *sessions; - - /** - * session timeout - */ - time_t timeout; - - /** - * timestamp of last session cleanup round - */ - time_t last_cleanup; - - /** - * running in debug mode? - */ - bool debug; - - /** - * List of controllers controller_constructor_t - */ - linked_list_t *controllers; - - /** - * List of filters filter_constructor_t - */ - linked_list_t *filters; - - /** - * constructor function to create session context (in controller_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; -} controller_entry_t; - -typedef struct { - /** constructor function */ - filter_constructor_t constructor; - /** parameter to constructor */ - void *param; -} filter_entry_t; - -typedef struct { - /** session instance */ - session_t *session; - /** condvar to wait for session */ - condvar_t *cond; - /** client host address, to prevent session hijacking */ - char *host; - /** TRUE if session is in use */ - bool in_use; - /** last use of the session */ - time_t used; - /** has the session been closed by the handler? */ - bool closed; -} session_entry_t; - -/** - * create a session and instanciate controllers - */ -static session_t* load_session(private_dispatcher_t *this) -{ - enumerator_t *enumerator; - controller_entry_t *centry; - filter_entry_t *fentry; - session_t *session; - context_t *context = NULL; - controller_t *controller; - filter_t *filter; - - if (this->context_constructor) - { - context = this->context_constructor(this->param); - } - session = session_create(context); - - enumerator = this->controllers->create_enumerator(this->controllers); - while (enumerator->enumerate(enumerator, ¢ry)) - { - controller = centry->constructor(context, centry->param); - session->add_controller(session, controller); - } - enumerator->destroy(enumerator); - - enumerator = this->filters->create_enumerator(this->filters); - while (enumerator->enumerate(enumerator, &fentry)) - { - filter = fentry->constructor(context, fentry->param); - session->add_filter(session, filter); - } - enumerator->destroy(enumerator); - - return session; -} - -/** - * create a new session entry - */ -static session_entry_t *session_entry_create(private_dispatcher_t *this, - char *host) -{ - session_entry_t *entry; - session_t *session; - - session = load_session(this); - if (!session) - { - return NULL; - } - INIT(entry, - .cond = condvar_create(CONDVAR_TYPE_DEFAULT), - .session = session, - .host = strdup(host), - .used = time_monotonic(NULL), - ); - return entry; -} - -/** - * destroy a session - */ -static void session_entry_destroy(session_entry_t *entry) -{ - entry->session->destroy(entry->session); - entry->cond->destroy(entry->cond); - free(entry->host); - free(entry); -} - -METHOD(dispatcher_t, add_controller, void, - private_dispatcher_t *this, controller_constructor_t constructor, - void *param) -{ - controller_entry_t *entry; - - INIT(entry, - .constructor = constructor, - .param = param, - ); - this->controllers->insert_last(this->controllers, entry); -} - -METHOD(dispatcher_t, add_filter, void, - private_dispatcher_t *this, filter_constructor_t constructor, void *param) -{ - filter_entry_t *entry; - - INIT(entry, - .constructor = constructor, - .param = param, - ); - this->filters->insert_last(this->filters, entry); -} - -/** - * Hashtable hash function - */ -static u_int session_hash(char *sid) -{ - return chunk_hash(chunk_create(sid, strlen(sid))); -} - -/** - * Hashtable equals function - */ -static bool session_equals(char *sid1, char *sid2) -{ - return streq(sid1, sid2); -} - -/** - * Cleanup unused sessions - */ -static void cleanup_sessions(private_dispatcher_t *this, time_t now) -{ - if (this->last_cleanup < now - CLEANUP_INTERVAL) - { - char *sid; - session_entry_t *entry; - enumerator_t *enumerator; - linked_list_t *remove; - - this->last_cleanup = now; - remove = linked_list_create(); - enumerator = this->sessions->create_enumerator(this->sessions); - while (enumerator->enumerate(enumerator, &sid, &entry)) - { - /* check all sessions for timeout or close flag */ - if (!entry->in_use && - (entry->used < now - this->timeout || entry->closed)) - { - remove->insert_last(remove, sid); - } - } - enumerator->destroy(enumerator); - - while (remove->remove_last(remove, (void**)&sid) == SUCCESS) - { - entry = this->sessions->remove(this->sessions, sid); - if (entry) - { - session_entry_destroy(entry); - } - } - remove->destroy(remove); - } -} - -/** - * Actual dispatching code - */ -static void dispatch(private_dispatcher_t *this) -{ - thread_cancelability(FALSE); - - while (TRUE) - { - request_t *request; - session_entry_t *found = NULL; - time_t now; - char *sid; - - thread_cancelability(TRUE); - request = request_create(this->fd, this->debug); - thread_cancelability(FALSE); - - if (request == NULL) - { - continue; - } - now = time_monotonic(NULL); - sid = request->get_cookie(request, "SID"); - - this->mutex->lock(this->mutex); - if (sid) - { - found = this->sessions->get(this->sessions, sid); - } - if (found && !streq(found->host, request->get_host(request))) - { - found = NULL; - } - if (found) - { - /* wait until session is unused */ - while (found->in_use) - { - found->cond->wait(found->cond, this->mutex); - } - } - else - { /* create a new session if not found */ - found = session_entry_create(this, request->get_host(request)); - if (!found) - { - request->destroy(request); - this->mutex->unlock(this->mutex); - continue; - } - sid = found->session->get_sid(found->session); - this->sessions->put(this->sessions, sid, found); - } - found->in_use = TRUE; - this->mutex->unlock(this->mutex); - - /* start processing */ - found->session->process(found->session, request); - found->used = time_monotonic(NULL); - - /* release session */ - this->mutex->lock(this->mutex); - found->in_use = FALSE; - found->closed = request->session_closed(request); - found->cond->signal(found->cond); - cleanup_sessions(this, now); - this->mutex->unlock(this->mutex); - - request->destroy(request); - } -} - -METHOD(dispatcher_t, run, void, - private_dispatcher_t *this, int threads) -{ - this->thread_count = threads; - this->threads = malloc(sizeof(thread_t*) * threads); - while (threads) - { - this->threads[threads - 1] = thread_create((thread_main_t)dispatch, - this); - if (this->threads[threads - 1]) - { - threads--; - } - } -} - -METHOD(dispatcher_t, waitsignal, void, - 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); -} - -METHOD(dispatcher_t, destroy, void, - private_dispatcher_t *this) -{ - char *sid; - session_entry_t *entry; - enumerator_t *enumerator; - - FCGX_ShutdownPending(); - while (this->thread_count--) - { - thread_t *thread = this->threads[this->thread_count]; - thread->cancel(thread); - thread->join(thread); - } - enumerator = this->sessions->create_enumerator(this->sessions); - while (enumerator->enumerate(enumerator, &sid, &entry)) - { - session_entry_destroy(entry); - } - enumerator->destroy(enumerator); - this->sessions->destroy(this->sessions); - this->controllers->destroy_function(this->controllers, free); - this->filters->destroy_function(this->filters, free); - this->mutex->destroy(this->mutex); - free(this->threads); - free(this); -} - -/* - * see header file - */ -dispatcher_t *dispatcher_create(char *socket, bool debug, int timeout, - context_constructor_t constructor, void *param) -{ - private_dispatcher_t *this; - - INIT(this, - .public = { - .add_controller = _add_controller, - .add_filter = _add_filter, - .run = _run, - .waitsignal = _waitsignal, - .destroy = _destroy, - }, - .sessions = hashtable_create((void*)session_hash, - (void*)session_equals, 4096), - .controllers = linked_list_create(), - .filters = linked_list_create(), - .context_constructor = constructor, - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .param = param, - .timeout = timeout, - .last_cleanup = time_monotonic(NULL), - .debug = debug, - ); - - FCGX_Init(); - - if (socket) - { - unlink(socket); - this->fd = FCGX_OpenSocket(socket, 10); - } - return &this->public; -} - diff --git a/src/libfast/dispatcher.h b/src/libfast/dispatcher.h deleted file mode 100644 index 16223fe76..000000000 --- a/src/libfast/dispatcher.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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 . - * - * 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. - */ - -/** - * @defgroup libfast libfast - * @{ - * FastCGI Application Server w/ templates. - * - * Libfast is a framework to write web applications in an MVC fashion. It uses - * the ClearSilver template engine and communicates through FastCGI with - * the webserver. It is multithreaded and really fast. - * - * The application has a global context and a session context. The global - * context is accessed from all sessions simultaneously and therefore - * needs to be threadsave. Often a database wrapper is the global context. - * The session context is instanciated per session. Sessions are managed - * automatically through session cookies. The session context is kept alive - * until the session times out. It must implement the context_t interface and - * a #context_constructor_t is needed to create instances. To each session, - * a set of controllers gets instanciated. The controller instances are per - * session, so you can hold private data for each user. - * Controllers need to implement the controller_t interface and need a - * #controller_constructor_t function to create instances. - * - * A small example shows how to set up libfast: - * @code - dispatcher_t *dispatcher; - your_global_context_implementation_t *global; - - global = initialize_your_global_context(); - - dispatcher = dispatcher_create(NULL, FALSE, 180, - (context_constructor_t)your_session_context_create, global); - dispatcher->add_controller(dispatcher, your_controller1_create, param1); - dispatcher->add_controller(dispatcher, your_controller2_create, param2); - - dispatcher->run(dispatcher, 20); - - dispatcher->waitsignal(dispatcher); - - dispatcher->destroy(dispatcher); - global->destroy(); - @endcode - * @} - * - * @defgroup dispatcher dispatcher - * @{ @ingroup libfast - */ - -#ifndef DISPATCHER_H_ -#define DISPATCHER_H_ - -#include "controller.h" -#include "filter.h" - -typedef struct dispatcher_t dispatcher_t; - -/** - * 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 { - - /** - * Register a controller to the dispatcher. - * - * The first controller added serves as default controller. Client's - * get redirected to it if no other controller matches. - * - * @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); - - /** - * Add a filter to the dispatcher. - * - * @param constructor constructor to create filter in session - * @param param param to pass to constructor - */ - void (*add_filter)(dispatcher_t *this, - filter_constructor_t constructor, void *param); - - /** - * Start with dispatching. - * - * Instanciate a constant thread pool and start dispatching requests. - * - * @param threads number of dispatching threads - */ - void (*run)(dispatcher_t *this, int threads); - - /** - * Wait for a relevant signal action. - * - */ - void (*waitsignal)(dispatcher_t *this); - - /** - * Destroy the dispatcher_t. - */ - void (*destroy) (dispatcher_t *this); -}; - -/** - * Create a dispatcher. - * - * The context constructor is invoked to create a session context for - * each session. - * - * @param socket FastCGI socket path, NULL for dynamic - * @param debug no stripping, no compression, timing information - * @param timeout session timeout - * @param constructor construction function for session context - * @param param parameter to supply to context constructor - */ -dispatcher_t *dispatcher_create(char *socket, bool debug, int timeout, - context_constructor_t constructor, void *param); - -#endif /** DISPATCHER_H_ @}*/ diff --git a/src/libfast/fast_context.h b/src/libfast/fast_context.h new file mode 100644 index 000000000..4922703ca --- /dev/null +++ b/src/libfast/fast_context.h @@ -0,0 +1,42 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup fast_context fast_context + * @{ @ingroup libfast + */ + +#ifndef FAST_CONTEXT_H_ +#define FAST_CONTEXT_H_ + +typedef struct fast_context_t fast_context_t; + +/** + * Constructor function for a user specific context. + */ +typedef fast_context_t *(*fast_context_constructor_t)(void *param); + +/** + * User specific session context, to extend. + */ +struct fast_context_t { + + /** + * Destroy the fast_context_t. + */ + void (*destroy) (fast_context_t *this); +}; + +#endif /** FAST_CONTEXT_H_ @}*/ diff --git a/src/libfast/fast_controller.h b/src/libfast/fast_controller.h new file mode 100644 index 000000000..bbd0214fc --- /dev/null +++ b/src/libfast/fast_controller.h @@ -0,0 +1,78 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup fast_controller fast_controller + * @{ @ingroup libfast + */ + +#ifndef FAST_CONTROLLER_H_ +#define FAST_CONTROLLER_H_ + +#include "fast_request.h" +#include "fast_context.h" + +typedef struct fast_controller_t fast_controller_t; + +/** + * Constructor function for a controller. + * + * @param context session specific context, implements context_t + * @param param user supplied param, as registered to the dispatcher + */ +typedef fast_controller_t *(*fast_controller_constructor_t)( + fast_context_t* context, void *param); + +/** + * Controller interface, to be implemented by users controllers. + * + * Controller instances get created per session, so each session has an + * associated set of private controller instances. + * The controller handle function is called for each incoming request. + */ +struct fast_controller_t { + + /** + * Get the name of the controller. + * + * @return name of the controller + */ + char* (*get_name)(fast_controller_t *this); + + /** + * Handle a HTTP request for that controller. + * + * Request URLs are parsed in the form + * controller_name/p1/p2/p3/p4/p5 with a maximum of 5 parameters. Each + * parameter not found in the request URL is set to NULL. + * + * @param request HTTP request + * @param p1 first parameter + * @param p2 second parameter + * @param p3 third parameter + * @param p4 forth parameter + * @param p5 fifth parameter + * @return + */ + void (*handle)(fast_controller_t *this, fast_request_t *request, + char *p1, char *p2, char *p3, char *p4, char *p5); + + /** + * Destroy the controller instance. + */ + void (*destroy) (fast_controller_t *this); +}; + +#endif /** FAST_CONTROLLER_H_ @}*/ diff --git a/src/libfast/fast_dispatcher.c b/src/libfast/fast_dispatcher.c new file mode 100644 index 000000000..4daf91905 --- /dev/null +++ b/src/libfast/fast_dispatcher.c @@ -0,0 +1,460 @@ +/* + * 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 . + * + * 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 "fast_dispatcher.h" + +#include "fast_request.h" +#include "fast_session.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** Intervall to check for expired sessions, in seconds */ +#define CLEANUP_INTERVAL 30 + +typedef struct private_fast_dispatcher_t private_fast_dispatcher_t; + +/** + * private data of the task manager + */ +struct private_fast_dispatcher_t { + + /** + * public functions + */ + fast_dispatcher_t public; + + /** + * fcgi socket fd + */ + int fd; + + /** + * thread list + */ + thread_t **threads; + + /** + * number of threads in "threads" + */ + int thread_count; + + /** + * session locking mutex + */ + mutex_t *mutex; + + /** + * Hahstable with active sessions + */ + hashtable_t *sessions; + + /** + * session timeout + */ + time_t timeout; + + /** + * timestamp of last session cleanup round + */ + time_t last_cleanup; + + /** + * running in debug mode? + */ + bool debug; + + /** + * List of controllers controller_constructor_t + */ + linked_list_t *controllers; + + /** + * List of filters filter_constructor_t + */ + linked_list_t *filters; + + /** + * constructor function to create session context (in controller_entry_t) + */ + fast_context_constructor_t context_constructor; + + /** + * user param to context constructor + */ + void *param; +}; + +typedef struct { + /** constructor function */ + fast_controller_constructor_t constructor; + /** parameter to constructor */ + void *param; +} controller_entry_t; + +typedef struct { + /** constructor function */ + fast_filter_constructor_t constructor; + /** parameter to constructor */ + void *param; +} filter_entry_t; + +typedef struct { + /** session instance */ + fast_session_t *session; + /** condvar to wait for session */ + condvar_t *cond; + /** client host address, to prevent session hijacking */ + char *host; + /** TRUE if session is in use */ + bool in_use; + /** last use of the session */ + time_t used; + /** has the session been closed by the handler? */ + bool closed; +} session_entry_t; + +/** + * create a session and instanciate controllers + */ +static fast_session_t* load_session(private_fast_dispatcher_t *this) +{ + enumerator_t *enumerator; + controller_entry_t *centry; + filter_entry_t *fentry; + fast_session_t *session; + fast_context_t *context = NULL; + fast_controller_t *controller; + fast_filter_t *filter; + + if (this->context_constructor) + { + context = this->context_constructor(this->param); + } + session = fast_session_create(context); + if (!session) + { + return NULL; + } + + enumerator = this->controllers->create_enumerator(this->controllers); + while (enumerator->enumerate(enumerator, ¢ry)) + { + controller = centry->constructor(context, centry->param); + session->add_controller(session, controller); + } + enumerator->destroy(enumerator); + + enumerator = this->filters->create_enumerator(this->filters); + while (enumerator->enumerate(enumerator, &fentry)) + { + filter = fentry->constructor(context, fentry->param); + session->add_filter(session, filter); + } + enumerator->destroy(enumerator); + + return session; +} + +/** + * create a new session entry + */ +static session_entry_t *session_entry_create(private_fast_dispatcher_t *this, + char *host) +{ + session_entry_t *entry; + fast_session_t *session; + + session = load_session(this); + if (!session) + { + return NULL; + } + INIT(entry, + .cond = condvar_create(CONDVAR_TYPE_DEFAULT), + .session = session, + .host = strdup(host), + .used = time_monotonic(NULL), + ); + return entry; +} + +/** + * destroy a session + */ +static void session_entry_destroy(session_entry_t *entry) +{ + entry->session->destroy(entry->session); + entry->cond->destroy(entry->cond); + free(entry->host); + free(entry); +} + +METHOD(fast_dispatcher_t, add_controller, void, + private_fast_dispatcher_t *this, fast_controller_constructor_t constructor, + void *param) +{ + controller_entry_t *entry; + + INIT(entry, + .constructor = constructor, + .param = param, + ); + this->controllers->insert_last(this->controllers, entry); +} + +METHOD(fast_dispatcher_t, add_filter, void, + private_fast_dispatcher_t *this, fast_filter_constructor_t constructor, + void *param) +{ + filter_entry_t *entry; + + INIT(entry, + .constructor = constructor, + .param = param, + ); + this->filters->insert_last(this->filters, entry); +} + +/** + * Hashtable hash function + */ +static u_int session_hash(char *sid) +{ + return chunk_hash(chunk_create(sid, strlen(sid))); +} + +/** + * Hashtable equals function + */ +static bool session_equals(char *sid1, char *sid2) +{ + return streq(sid1, sid2); +} + +/** + * Cleanup unused sessions + */ +static void cleanup_sessions(private_fast_dispatcher_t *this, time_t now) +{ + if (this->last_cleanup < now - CLEANUP_INTERVAL) + { + char *sid; + session_entry_t *entry; + enumerator_t *enumerator; + linked_list_t *remove; + + this->last_cleanup = now; + remove = linked_list_create(); + enumerator = this->sessions->create_enumerator(this->sessions); + while (enumerator->enumerate(enumerator, &sid, &entry)) + { + /* check all sessions for timeout or close flag */ + if (!entry->in_use && + (entry->used < now - this->timeout || entry->closed)) + { + remove->insert_last(remove, sid); + } + } + enumerator->destroy(enumerator); + + while (remove->remove_last(remove, (void**)&sid) == SUCCESS) + { + entry = this->sessions->remove(this->sessions, sid); + if (entry) + { + session_entry_destroy(entry); + } + } + remove->destroy(remove); + } +} + +/** + * Actual dispatching code + */ +static void dispatch(private_fast_dispatcher_t *this) +{ + thread_cancelability(FALSE); + + while (TRUE) + { + fast_request_t *request; + session_entry_t *found = NULL; + time_t now; + char *sid; + + thread_cancelability(TRUE); + request = fast_request_create(this->fd, this->debug); + thread_cancelability(FALSE); + + if (request == NULL) + { + break; + } + now = time_monotonic(NULL); + sid = request->get_cookie(request, "SID"); + + this->mutex->lock(this->mutex); + if (sid) + { + found = this->sessions->get(this->sessions, sid); + } + if (found && !streq(found->host, request->get_host(request))) + { + found = NULL; + } + if (found) + { + /* wait until session is unused */ + while (found->in_use) + { + found->cond->wait(found->cond, this->mutex); + } + } + else + { /* create a new session if not found */ + found = session_entry_create(this, request->get_host(request)); + if (!found) + { + request->destroy(request); + this->mutex->unlock(this->mutex); + continue; + } + sid = found->session->get_sid(found->session); + this->sessions->put(this->sessions, sid, found); + } + found->in_use = TRUE; + this->mutex->unlock(this->mutex); + + /* start processing */ + found->session->process(found->session, request); + found->used = time_monotonic(NULL); + + /* release session */ + this->mutex->lock(this->mutex); + found->in_use = FALSE; + found->closed = request->session_closed(request); + found->cond->signal(found->cond); + cleanup_sessions(this, now); + this->mutex->unlock(this->mutex); + + request->destroy(request); + } +} + +METHOD(fast_dispatcher_t, run, void, + private_fast_dispatcher_t *this, int threads) +{ + this->thread_count = threads; + this->threads = malloc(sizeof(thread_t*) * threads); + while (threads) + { + this->threads[threads - 1] = thread_create((thread_main_t)dispatch, + this); + if (this->threads[threads - 1]) + { + threads--; + } + } +} + +METHOD(fast_dispatcher_t, waitsignal, void, + private_fast_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); +} + +METHOD(fast_dispatcher_t, destroy, void, + private_fast_dispatcher_t *this) +{ + char *sid; + session_entry_t *entry; + enumerator_t *enumerator; + + FCGX_ShutdownPending(); + while (this->thread_count--) + { + thread_t *thread = this->threads[this->thread_count]; + thread->cancel(thread); + thread->join(thread); + } + enumerator = this->sessions->create_enumerator(this->sessions); + while (enumerator->enumerate(enumerator, &sid, &entry)) + { + session_entry_destroy(entry); + } + enumerator->destroy(enumerator); + this->sessions->destroy(this->sessions); + this->controllers->destroy_function(this->controllers, free); + this->filters->destroy_function(this->filters, free); + this->mutex->destroy(this->mutex); + free(this->threads); + free(this); +} + +/* + * see header file + */ +fast_dispatcher_t *fast_dispatcher_create(char *socket, bool debug, int timeout, + fast_context_constructor_t constructor, void *param) +{ + private_fast_dispatcher_t *this; + + INIT(this, + .public = { + .add_controller = _add_controller, + .add_filter = _add_filter, + .run = _run, + .waitsignal = _waitsignal, + .destroy = _destroy, + }, + .sessions = hashtable_create((void*)session_hash, + (void*)session_equals, 4096), + .controllers = linked_list_create(), + .filters = linked_list_create(), + .context_constructor = constructor, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .param = param, + .timeout = timeout, + .last_cleanup = time_monotonic(NULL), + .debug = debug, + ); + + FCGX_Init(); + + if (socket) + { + unlink(socket); + this->fd = FCGX_OpenSocket(socket, 10); + } + return &this->public; +} diff --git a/src/libfast/fast_dispatcher.h b/src/libfast/fast_dispatcher.h new file mode 100644 index 000000000..6546385c6 --- /dev/null +++ b/src/libfast/fast_dispatcher.h @@ -0,0 +1,137 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup libfast libfast + * @{ + * FastCGI Application Server w/ templates. + * + * Libfast is a framework to write web applications in an MVC fashion. It uses + * the ClearSilver template engine and communicates through FastCGI with + * the webserver. It is multithreaded and really fast. + * + * The application has a global context and a session context. The global + * context is accessed from all sessions simultaneously and therefore + * needs to be threadsave. Often a database wrapper is the global context. + * The session context is instanciated per session. Sessions are managed + * automatically through session cookies. The session context is kept alive + * until the session times out. It must implement the context_t interface and + * a #fast_context_constructor_t is needed to create instances. To each session, + * a set of controllers gets instanciated. The controller instances are per + * session, so you can hold private data for each user. + * Controllers need to implement the controller_t interface and need a + * #fast_controller_constructor_t function to create instances. + * + * A small example shows how to set up libfast: + * @code + fast_fast_dispatcher_t *dispatcher; + your_global_context_implementation_t *global; + + global = initialize_your_global_context(); + + dispatcher = fast_dispatcher_create(NULL, FALSE, 180, + (context_constructor_t)your_session_context_create, global); + dispatcher->add_controller(dispatcher, your_controller1_create, param1); + dispatcher->add_controller(dispatcher, your_controller2_create, param2); + + dispatcher->run(dispatcher, 20); + + dispatcher->waitsignal(dispatcher); + + dispatcher->destroy(dispatcher); + global->destroy(); + @endcode + * @} + * + * @defgroup fast_dispatcher fast_dispatcher + * @{ @ingroup libfast + */ + +#ifndef FAST_DISPATCHER_H_ +#define FAST_DISPATCHER_H_ + +#include "fast_controller.h" +#include "fast_filter.h" + +typedef struct fast_dispatcher_t fast_dispatcher_t; + +/** + * 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 fast_dispatcher_t { + + /** + * Register a controller to the dispatcher. + * + * The first controller added serves as default controller. Client's + * get redirected to it if no other controller matches. + * + * @param constructor constructor function to the conntroller + * @param param param to pass to constructor + */ + void (*add_controller)(fast_dispatcher_t *this, + fast_controller_constructor_t constructor, + void *param); + + /** + * Add a filter to the dispatcher. + * + * @param constructor constructor to create filter in session + * @param param param to pass to constructor + */ + void (*add_filter)(fast_dispatcher_t *this, + fast_filter_constructor_t constructor, void *param); + + /** + * Start with dispatching. + * + * Instanciate a constant thread pool and start dispatching requests. + * + * @param threads number of dispatching threads + */ + void (*run)(fast_dispatcher_t *this, int threads); + + /** + * Wait for a relevant signal action. + */ + void (*waitsignal)(fast_dispatcher_t *this); + + /** + * Destroy the fast_dispatcher_t. + */ + void (*destroy) (fast_dispatcher_t *this); +}; + +/** + * Create a dispatcher. + * + * The context constructor is invoked to create a session context for + * each session. + * + * @param socket FastCGI socket path, NULL for dynamic + * @param debug no stripping, no compression, timing information + * @param timeout session timeout + * @param constructor construction function for session context + * @param param parameter to supply to context constructor + */ +fast_dispatcher_t *fast_dispatcher_create(char *socket, bool debug, int timeout, + fast_context_constructor_t constructor, void *param); + +#endif /** FAST_DISPATCHER_H_ @}*/ diff --git a/src/libfast/fast_filter.h b/src/libfast/fast_filter.h new file mode 100644 index 000000000..57367bd5a --- /dev/null +++ b/src/libfast/fast_filter.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 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 . + * + * 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. + */ + +/* + * @defgroup fast_filter fast_filter + * @{ @ingroup libfast + */ + +#ifndef FAST_FILTER_H_ +#define FAST_FILTER_H_ + +#include "fast_request.h" +#include "fast_context.h" +#include "fast_controller.h" + +typedef struct fast_filter_t fast_filter_t; + +/** + * Constructor function for a filter + * + * @param context session specific context + * @param param user supplied param + */ +typedef fast_filter_t *(*fast_filter_constructor_t)(fast_context_t* context, + void *param); + +/** + * Filter interface, to be implemented by users filters. + */ +struct fast_filter_t { + + /** + * Called before the controller handles the request. + * + * @param request HTTP request + * @param p1 first parameter + * @param p2 second parameter + * @param p3 third parameter + * @param p4 forth parameter + * @param p5 fifth parameter + * @return TRUE to continue request handling + */ + bool (*run)(fast_filter_t *this, fast_request_t *request, + char *p0, char *p1, char *p2, char *p3, char *p4, char *p5); + + /** + * Destroy the filter instance. + */ + void (*destroy) (fast_filter_t *this); +}; + +#endif /* FAST_FILTER_H_ @} */ diff --git a/src/libfast/fast_request.c b/src/libfast/fast_request.c new file mode 100644 index 000000000..0673750b7 --- /dev/null +++ b/src/libfast/fast_request.c @@ -0,0 +1,509 @@ +/* + * 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 . + * + * 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_request.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +typedef struct private_fast_request_t private_fast_request_t; + +/** + * private data of the task manager + */ +struct private_fast_request_t { + + /** + * public functions + */ + fast_request_t public; + + /** + * FastCGI request object + */ + FCGX_Request req; + + /** + * length of the req.envp array + */ + int req_env_len; + + /** + * ClearSilver CGI Kit context + */ + CGI *cgi; + + /** + * ClearSilver HDF dataset for this request + */ + HDF *hdf; + + /** + * close the session? + */ + bool closed; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * ClearSilver cgiwrap is not threadsave, so we use a private + * context for each thread. + */ +static thread_value_t *thread_this; + +/** + * control variable for pthread_once + */ +pthread_once_t once = PTHREAD_ONCE_INIT; + +/** + * fcgiwrap read callback + */ +static int read_cb(void *null, char *buf, int size) +{ + private_fast_request_t *this; + + this = (private_fast_request_t*)thread_this->get(thread_this); + + return FCGX_GetStr(buf, size, this->req.in); +} + +/** + * fcgiwrap writef callback + */ +static int writef_cb(void *null, const char *format, va_list args) +{ + private_fast_request_t *this; + + this = (private_fast_request_t*)thread_this->get(thread_this); + + FCGX_VFPrintF(this->req.out, format, args); + return 0; +} +/** + * fcgiwrap write callback + */ +static int write_cb(void *null, const char *buf, int size) +{ + private_fast_request_t *this; + + this = (private_fast_request_t*)thread_this->get(thread_this); + + return FCGX_PutStr(buf, size, this->req.out); +} + +/** + * fcgiwrap getenv callback + */ +static char *getenv_cb(void *null, const char *key) +{ + char *value; + private_fast_request_t *this; + + this = (private_fast_request_t*)thread_this->get(thread_this); + + value = FCGX_GetParam(key, this->req.envp); + return strdupnull(value); +} + +/** + * fcgiwrap getenv callback + */ +static int putenv_cb(void *null, const char *key, const char *value) +{ + /* not supported */ + return 1; +} + +/** + * fcgiwrap iterenv callback + */ +static int iterenv_cb(void *null, int num, char **key, char **value) +{ + private_fast_request_t *this; + + *key = NULL; + *value = NULL; + this = (private_fast_request_t*)thread_this->get(thread_this); + + if (num < this->req_env_len) + { + char *eq; + + eq = strchr(this->req.envp[num], '='); + if (eq) + { + *key = strndup(this->req.envp[num], eq - this->req.envp[num]); + *value = strdup(eq + 1); + } + if (*key == NULL || *value == NULL) + { + free(*key); + free(*value); + return 1; + } + } + return 0; +} + +METHOD(fast_request_t, get_cookie, char*, + private_fast_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Cookie.%s", name); +} + +METHOD(fast_request_t, get_path, char*, + private_fast_request_t *this) +{ + char *path = FCGX_GetParam("PATH_INFO", this->req.envp); + return path ? path : ""; +} + +METHOD(fast_request_t, get_host, char*, + private_fast_request_t *this) +{ + char *addr = FCGX_GetParam("REMOTE_ADDR", this->req.envp); + return addr ? addr : ""; +} + +METHOD(fast_request_t, get_user_agent, char*, + private_fast_request_t *this) +{ + char *agent = FCGX_GetParam("HTTP_USER_AGENT", this->req.envp); + return agent ? agent : ""; +} + +METHOD(fast_request_t, get_query_data, char*, + private_fast_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Query.%s", name); +} + +METHOD(fast_request_t, get_env_var, char*, + private_fast_request_t *this, char *name) +{ + return FCGX_GetParam(name, this->req.envp); +} + +METHOD(fast_request_t, read_data, int, + private_fast_request_t *this, char *buf, int len) +{ + return FCGX_GetStr(buf, len, this->req.in); +} + +METHOD(fast_request_t, get_base, char*, + private_fast_request_t *this) +{ + return FCGX_GetParam("SCRIPT_NAME", this->req.envp); +} + +METHOD(fast_request_t, add_cookie, void, + private_fast_request_t *this, char *name, char *value) +{ + thread_this->set(thread_this, this); + cgi_cookie_set(this->cgi, name, value, NULL, NULL, NULL, 0, 0); +} + +METHOD(fast_request_t, redirect, void, + private_fast_request_t *this, char *fmt, ...) +{ + va_list args; + + FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); + FCGX_FPrintF(this->req.out, "Location: %s%s", get_base(this), + *fmt == '/' ? "" : "/"); + va_start(args, fmt); + FCGX_VFPrintF(this->req.out, fmt, args); + va_end(args); + FCGX_FPrintF(this->req.out, "\n\n"); +} + +METHOD(fast_request_t, get_referer, char*, + private_fast_request_t *this) +{ + return FCGX_GetParam("HTTP_REFERER", this->req.envp); +} + +METHOD(fast_request_t, to_referer, void, + private_fast_request_t *this) +{ + char *referer; + + referer = get_referer(this); + if (referer) + { + FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); + FCGX_FPrintF(this->req.out, "Location: %s\n\n", referer); + } + else + { + redirect(this, "/"); + } +} + +METHOD(fast_request_t, session_closed, bool, + private_fast_request_t *this) +{ + return this->closed; +} + +METHOD(fast_request_t, close_session, void, + private_fast_request_t *this) +{ + this->closed = TRUE; +} + +METHOD(fast_request_t, serve, void, + private_fast_request_t *this, char *headers, chunk_t chunk) +{ + FCGX_FPrintF(this->req.out, "%s\n\n", headers); + + FCGX_PutStr(chunk.ptr, chunk.len, this->req.out); +} + +METHOD(fast_request_t, sendfile, bool, + private_fast_request_t *this, char *path, char *mime) +{ + struct stat sb; + chunk_t data; + void *addr; + int fd, written; + char buf[24]; + + fd = open(path, O_RDONLY); + if (fd == -1) + { + return FALSE; + } + if (fstat(fd, &sb) == -1) + { + close(fd); + return FALSE; + } + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + close(fd); + return FALSE; + } + + /* FCGX does not like large integers, print to a buffer using libc */ + snprintf(buf, sizeof(buf), "%lld", (int64_t)sb.st_size); + FCGX_FPrintF(this->req.out, "Content-Length: %s\n", buf); + if (mime) + { + FCGX_FPrintF(this->req.out, "Content-Type: %s\n", mime); + } + FCGX_FPrintF(this->req.out, "\n"); + + data = chunk_create(addr, sb.st_size); + + while (data.len) + { + written = FCGX_PutStr(data.ptr, data.len, this->req.out); + if (written == -1) + { + munmap(addr, sb.st_size); + close(fd); + return FALSE; + } + data = chunk_skip(data, written); + } + + munmap(addr, sb.st_size); + close(fd); + return TRUE; +} + +METHOD(fast_request_t, render, void, + private_fast_request_t *this, char *template) +{ + NEOERR* err; + + thread_this->set(thread_this, this); + err = cgi_display(this->cgi, template); + if (err) + { + cgi_neo_error(this->cgi, err); + nerr_log_error(err); + } +} + +METHOD(fast_request_t, streamf, int, + private_fast_request_t *this, char *format, ...) +{ + va_list args; + int written; + + va_start(args, format); + written = FCGX_VFPrintF(this->req.out, format, args); + va_end(args); + if (written >= 0 && + FCGX_FFlush(this->req.out) == -1) + { + return -1; + } + return written; +} + +METHOD(fast_request_t, set, void, + private_fast_request_t *this, char *key, char *value) +{ + hdf_set_value(this->hdf, key, value); +} + +METHOD(fast_request_t, setf, void, + private_fast_request_t *this, char *format, ...) +{ + va_list args; + + va_start(args, format); + hdf_set_valuevf(this->hdf, format, args); + va_end(args); +} + +METHOD(fast_request_t, get_ref, fast_request_t*, + private_fast_request_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(fast_request_t, destroy, void, + private_fast_request_t *this) +{ + if (ref_put(&this->ref)) + { + thread_this->set(thread_this, this); + cgi_destroy(&this->cgi); + FCGX_Finish_r(&this->req); + free(this); + } +} + +/** + * This initialization method is guaranteed to run only once + * for all threads. + */ +static void init(void) +{ + cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb, + getenv_cb, putenv_cb, iterenv_cb); + thread_this = thread_value_create(NULL); +} + +/* + * see header file + */ +fast_request_t *fast_request_create(int fd, bool debug) +{ + NEOERR* err; + private_fast_request_t *this; + bool failed = FALSE; + + INIT(this, + .public = { + .get_path = _get_path, + .get_base = _get_base, + .get_host = _get_host, + .get_user_agent = _get_user_agent, + .add_cookie = _add_cookie, + .get_cookie = _get_cookie, + .get_query_data = _get_query_data, + .get_env_var = _get_env_var, + .read_data = _read_data, + .session_closed = _session_closed, + .close_session = _close_session, + .redirect = _redirect, + .get_referer = _get_referer, + .to_referer = _to_referer, + .render = _render, + .streamf = _streamf, + .serve = _serve, + .sendfile = _sendfile, + .set = _set, + .setf = _setf, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .ref = 1, + ); + + thread_cleanup_push(free, this); + if (FCGX_InitRequest(&this->req, fd, 0) != 0 || + FCGX_Accept_r(&this->req) != 0) + { + failed = TRUE; + } + thread_cleanup_pop(failed); + if (failed) + { + return NULL; + } + + pthread_once(&once, init); + thread_this->set(thread_this, this); + + while (this->req.envp[this->req_env_len] != NULL) + { + this->req_env_len++; + } + + err = hdf_init(&this->hdf); + if (!err) + { + hdf_set_value(this->hdf, "base", get_base(this)); + hdf_set_value(this->hdf, "Config.NoCache", "true"); + if (!debug) + { + hdf_set_value(this->hdf, "Config.TimeFooter", "0"); + hdf_set_value(this->hdf, "Config.CompressionEnabled", "1"); + hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2"); + } + + err = cgi_init(&this->cgi, this->hdf); + if (!err) + { + err = cgi_parse(this->cgi); + if (!err) + { + return &this->public; + } + cgi_destroy(&this->cgi); + } + } + nerr_log_error(err); + FCGX_Finish_r(&this->req); + free(this); + return NULL; +} diff --git a/src/libfast/fast_request.h b/src/libfast/fast_request.h new file mode 100644 index 000000000..678cf54d5 --- /dev/null +++ b/src/libfast/fast_request.h @@ -0,0 +1,217 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup fast_request fast_request + * @{ @ingroup libfast + */ + +#ifndef FAST_REQUEST_H_ +#define FAST_REQUEST_H_ + +#include +#include + +typedef struct fast_request_t fast_request_t; + +/** + * A HTTP request, encapsulates FCGX_Request. + * + * The response is also handled through the request object. + */ +struct fast_request_t { + + /** + * Add a cookie to the reply (Set-Cookie header). + * + * @param name name of the cookie to set + * @param value value of the cookie + */ + void (*add_cookie)(fast_request_t *this, char *name, char *value); + + /** + * 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)(fast_request_t *this, char *name); + + /** + * Get the request path relative to the application. + * + * @return path + */ + char* (*get_path)(fast_request_t *this); + + /** + * Get the base path of the application. + * + * @return base path + */ + char* (*get_base)(fast_request_t *this); + + /** + * Get the remote host address of this request. + * + * @return host address as string + */ + char* (*get_host)(fast_request_t *this); + + /** + * Get the user agent string. + * + * @return user agent string + */ + char* (*get_user_agent)(fast_request_t *this); + + /** + * Get a post/get variable included in the request. + * + * @param name name of the POST/GET variable + * @return value, NULL if not found + */ + char* (*get_query_data)(fast_request_t *this, char *name); + + /** + * Get an arbitrary environment variable. + * + * @param name name of the environment variable + * @return value, NULL if not found + */ + char* (*get_env_var)(fast_request_t *this, char *name); + + /** + * Read raw POST/PUT data from HTTP request. + * + * @param buf buffer to read data into + * @param len size of the supplied buffer + * @return number of bytes read, < 0 on error + */ + int (*read_data)(fast_request_t *this, char *buf, int len); + + /** + * Close the session and it's context after handling. + */ + void (*close_session)(fast_request_t *this); + + /** + * Has the session been closed by close_session()? + * + * @return TRUE if session has been closed + */ + bool (*session_closed)(fast_request_t *this); + + /** + * Redirect the client to another location. + * + * @param fmt location format string + * @param ... variable argument for fmt + */ + void (*redirect)(fast_request_t *this, char *fmt, ...); + + /** + * Get the HTTP referer. + * + * @return HTTP referer + */ + char* (*get_referer)(fast_request_t *this); + + /** + * Redirect back to the referer. + */ + void (*to_referer)(fast_request_t *this); + + /** + * Set a template value. + * + * @param key key to set + * @param value value to set key to + */ + void (*set)(fast_request_t *this, char *key, char *value); + + /** + * 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)(fast_request_t *this, char *format, ...); + + /** + * Render a template. + * + * The render() function additionally sets a HDF variable "base" + * which points to the root of the web application and allows to point to + * other targets without to worry about path location. + * + * @param template clearsilver template file location + */ + void (*render)(fast_request_t *this, char *template); + + /** + * Stream a format string to the client. + * + * Stream is not closed and may be called multiple times to allow + * server-push functionality. + * + * @param format printf like format string + * @param ... argmuent list to format string + * @return number of streamed bytes, < 0 if stream closed + */ + int (*streamf)(fast_request_t *this, char *format, ...); + + /** + * Serve a request with headers and a body. + * + * @param headers HTTP headers, \n separated + * @param chunk body to write to output + */ + void (*serve)(fast_request_t *this, char *headers, chunk_t chunk); + + /** + * Send a file from the file system. + * + * @param path path to file to serve + * @param mime mime type of file to send, or NULL + * @return TRUE if file served successfully + */ + bool (*sendfile)(fast_request_t *this, char *path, char *mime); + + /** + * Increase the reference count to the stream. + * + * @return this with increased refcount + */ + fast_request_t* (*get_ref)(fast_request_t *this); + + /** + * Destroy the fast_request_t. + */ + void (*destroy) (fast_request_t *this); +}; + +/** + * Create a request from the fastcgi struct. + * + * @param fd file descripter opened with FCGX_OpenSocket + * @param debug no stripping, no compression, timing information + */ +fast_request_t *fast_request_create(int fd, bool debug); + +#endif /** REQUEST_H_ @}*/ 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 . + * + * 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; +} diff --git a/src/libfast/fast_session.h b/src/libfast/fast_session.h new file mode 100644 index 000000000..2ff450b93 --- /dev/null +++ b/src/libfast/fast_session.h @@ -0,0 +1,77 @@ +/* + * 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 . + * + * 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. + */ + +/** + * @defgroup fast_session fast_session + * @{ @ingroup libfast + */ + +#ifndef FAST_SESSION_H_ +#define FAST_SESSION_H_ + +#include "fast_request.h" +#include "fast_controller.h" +#include "fast_filter.h" + +typedef struct fast_session_t fast_session_t; + +/** + * Session handling class, instanciated for each user session. + */ +struct fast_session_t { + + /** + * Get the session ID of the session. + * + * @return session ID + */ + char* (*get_sid)(fast_session_t *this); + + /** + * Add a controller instance to the session. + * + * @param controller controller to add + */ + void (*add_controller)(fast_session_t *this, fast_controller_t *controller); + + /** + * Add a filter instance to the session. + * + * @param filter filter to add + */ + void (*add_filter)(fast_session_t *this, fast_filter_t *filter); + + /** + * Process a request in this session. + * + * @param request request to process + */ + void (*process)(fast_session_t *this, fast_request_t *request); + + /** + * Destroy the fast_session_t. + */ + void (*destroy) (fast_session_t *this); +}; + +/** + * Create a session new session. + * + * @param context user defined session context instance + * @return client session, NULL on error + */ +fast_session_t *fast_session_create(fast_context_t *context); + +#endif /** SESSION_H_ @}*/ diff --git a/src/libfast/fast_smtp.c b/src/libfast/fast_smtp.c new file mode 100644 index 000000000..89e74d79b --- /dev/null +++ b/src/libfast/fast_smtp.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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. + */ + +#include "fast_smtp.h" + +#include +#include + +#include + +typedef struct private_fast_smtp_t private_fast_smtp_t; + +/** + * Private data of an fast_smtp_t object. + */ +struct private_fast_smtp_t { + + /** + * Public fast_smtp_t interface. + */ + fast_smtp_t public; + + /** + * file stream to SMTP server + */ + FILE *f; +}; + +/** + * Read the response code from an SMTP server + */ +static int read_response(private_fast_smtp_t *this) +{ + char buf[256], *end; + int res = 0; + + while (TRUE) + { + if (!fgets(buf, sizeof(buf), this->f)) + { + return 0; + } + res = strtol(buf, &end, 10); + switch (*end) + { + case '-': + continue; + case ' ': + case '\0': + case '\n': + break; + default: + return 0; + } + break; + } + return res; +} + +/** + * write a SMTP command to the server, read response code + */ +static int write_cmd(private_fast_smtp_t *this, char *fmt, ...) +{ + char buf[256]; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (fprintf(this->f, "%s\n", buf) < 1) + { + DBG1(DBG_LIB, "sending SMTP command failed"); + return 0; + } + return read_response(this); +} + +METHOD(fast_smtp_t, send_mail, bool, + private_fast_smtp_t *this, char *from, char *to, char *subject, char *fmt, ...) +{ + va_list args; + + if (write_cmd(this, "MAIL FROM:<%s>", from) != 250) + { + DBG1(DBG_LIB, "SMTP MAIL FROM failed"); + return FALSE; + } + if (write_cmd(this, "RCPT TO:<%s>", to) != 250) + { + DBG1(DBG_LIB, "SMTP RCPT TO failed"); + return FALSE; + } + if (write_cmd(this, "DATA") != 354) + { + DBG1(DBG_LIB, "SMTP DATA failed"); + return FALSE; + } + + fprintf(this->f, "From: %s\n", from); + fprintf(this->f, "To: %s\n", to); + fprintf(this->f, "Subject: %s\n", subject); + fprintf(this->f, "\n"); + va_start(args, fmt); + vfprintf(this->f, fmt, args); + va_end(args); + fprintf(this->f, "\n.\n"); + return read_response(this) == 250; +} + + +METHOD(fast_smtp_t, destroy, void, + private_fast_smtp_t *this) +{ + write_cmd(this, "QUIT"); + fclose(this->f); + free(this); +} + +/** + * See header + */ +fast_smtp_t *fast_smtp_create() +{ + private_fast_smtp_t *this; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(25), + .sin_addr = { + .s_addr = htonl(INADDR_LOOPBACK), + }, + }; + int s; + + INIT(this, + .public = { + .send_mail = _send_mail, + .destroy = _destroy, + }, + ); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + { + DBG1(DBG_LIB, "opening SMTP socket failed: %s", strerror(errno)); + free(this); + return NULL; + } + if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_LIB, "connecting to SMTP server failed: %s", strerror(errno)); + close(s); + free(this); + return NULL; + } + this->f = fdopen(s, "a+"); + if (!this->f) + { + DBG1(DBG_LIB, "opening stream to SMTP server failed: %s", + strerror(errno)); + close(s); + free(this); + return NULL; + } + if (read_response(this) != 220 || + write_cmd(this, "EHLO localhost") != 250) + { + DBG1(DBG_LIB, "SMTP EHLO failed"); + fclose(this->f); + free(this); + return NULL; + } + return &this->public; +} diff --git a/src/libfast/fast_smtp.h b/src/libfast/fast_smtp.h new file mode 100644 index 000000000..962ba2cc7 --- /dev/null +++ b/src/libfast/fast_smtp.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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. + */ + +/** + * @defgroup fast_smtp fast_smtp + * @{ @ingroup libfast + */ + +#ifndef FAST_SMTP_H_ +#define FAST_SMTP_H_ + +typedef struct fast_smtp_t fast_smtp_t; + +#include + +/** + * Ultra-minimalistic SMTP client. Works at most with Exim on localhost. + */ +struct fast_smtp_t { + + /** + * Send an e-mail message. + * + * @param from sender address + * @param to recipient address + * @param subject mail subject + * @param fmt mail body format string + * @param ... arguments for body format string + */ + bool (*send_mail)(fast_smtp_t *this, char *from, char *to, + char *subject, char *fmt, ...); + + /** + * Destroy a fast_smtp_t. + */ + void (*destroy)(fast_smtp_t *this); +}; + +/** + * Create a smtp instance. + */ +fast_smtp_t *fast_smtp_create(); + +#endif /** FAST_SMTP_H_ @}*/ diff --git a/src/libfast/filter.h b/src/libfast/filter.h deleted file mode 100644 index 305a8bb6e..000000000 --- a/src/libfast/filter.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2008 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 . - * - * 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. - */ - -/* - * @defgroup filter filter - * @{ @ingroup libfast - */ - -#ifndef FILTER_H_ -#define FILTER_H_ - -#include "request.h" -#include "context.h" -#include "controller.h" - -typedef struct filter_t filter_t; - -/** - * Constructor function for a filter - * - * @param context session specific context - * @param param user supplied param - */ -typedef filter_t *(*filter_constructor_t)(context_t* context, void *param); - -/** - * Filter interface, to be implemented by users filters. - */ -struct filter_t { - - /** - * Called before the controller handles the request. - * - * @param request HTTP request - * @param p1 first parameter - * @param p2 second parameter - * @param p3 third parameter - * @param p4 forth parameter - * @param p5 fifth parameter - * @return TRUE to continue request handling - */ - bool (*run)(filter_t *this, request_t *request, - char *p0, char *p1, char *p2, char *p3, char *p4, char *p5); - - /** - * Destroy the filter instance. - */ - void (*destroy) (filter_t *this); -}; - -#endif /* FILTER_H_ @} */ diff --git a/src/libfast/request.c b/src/libfast/request.c deleted file mode 100644 index 5d03227af..000000000 --- a/src/libfast/request.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * 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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -typedef struct private_request_t private_request_t; - -/** - * private data of the task manager - */ -struct private_request_t { - - /** - * public functions - */ - request_t public; - - /** - * FastCGI request object - */ - FCGX_Request req; - - /** - * length of the req.envp array - */ - int req_env_len; - - /** - * ClearSilver CGI Kit context - */ - CGI *cgi; - - /** - * ClearSilver HDF dataset for this request - */ - HDF *hdf; - - /** - * close the session? - */ - bool closed; - - /** - * reference count - */ - refcount_t ref; -}; - -/** - * ClearSilver cgiwrap is not threadsave, so we use a private - * context for each thread. - */ -static thread_value_t *thread_this; - -/** - * control variable for pthread_once - */ -pthread_once_t once = PTHREAD_ONCE_INIT; - -/** - * fcgiwrap read callback - */ -static int read_cb(void *null, char *buf, int size) -{ - private_request_t *this = (private_request_t*)thread_this->get(thread_this); - - return FCGX_GetStr(buf, size, this->req.in); -} - -/** - * fcgiwrap writef callback - */ -static int writef_cb(void *null, const char *format, va_list args) -{ - private_request_t *this = (private_request_t*)thread_this->get(thread_this); - - FCGX_VFPrintF(this->req.out, format, args); - return 0; -} -/** - * fcgiwrap write callback - */ -static int write_cb(void *null, const char *buf, int size) -{ - private_request_t *this = (private_request_t*)thread_this->get(thread_this); - - return FCGX_PutStr(buf, size, this->req.out); -} - -/** - * fcgiwrap getenv callback - */ -static char *getenv_cb(void *null, const char *key) -{ - char *value; - private_request_t *this = (private_request_t*)thread_this->get(thread_this); - - value = FCGX_GetParam(key, this->req.envp); - return strdupnull(value); -} - -/** - * fcgiwrap getenv callback - */ -static int putenv_cb(void *null, const char *key, const char *value) -{ - /* not supported */ - return 1; -} - -/** - * fcgiwrap iterenv callback - */ -static int iterenv_cb(void *null, int num, char **key, char **value) -{ - *key = NULL; - *value = NULL; - private_request_t *this = (private_request_t*)thread_this->get(thread_this); - if (num < this->req_env_len) - { - char *eq; - - eq = strchr(this->req.envp[num], '='); - if (eq) - { - *key = strndup(this->req.envp[num], eq - this->req.envp[num]); - *value = strdup(eq + 1); - } - if (*key == NULL || *value == NULL) - { - free(*key); - free(*value); - return 1; - } - } - return 0; -} - -METHOD(request_t, get_cookie, char*, - private_request_t *this, char *name) -{ - return hdf_get_valuef(this->hdf, "Cookie.%s", name); -} - -METHOD(request_t, get_path, char*, - private_request_t *this) -{ - char * path = FCGX_GetParam("PATH_INFO", this->req.envp); - return path ? path : ""; -} - -METHOD(request_t, get_host, char*, - private_request_t *this) -{ - char *addr = FCGX_GetParam("REMOTE_ADDR", this->req.envp); - return addr ? addr : ""; -} - -METHOD(request_t, get_user_agent, char*, - private_request_t *this) -{ - char *agent = FCGX_GetParam("HTTP_USER_AGENT", this->req.envp); - return agent ? agent : ""; -} - -METHOD(request_t, get_query_data, char*, - private_request_t *this, char *name) -{ - return hdf_get_valuef(this->hdf, "Query.%s", name); -} - -METHOD(request_t, get_env_var, char*, - private_request_t *this, char *name) -{ - return FCGX_GetParam(name, this->req.envp); -} - -METHOD(request_t, read_data, int, - private_request_t *this, char *buf, int len) -{ - return FCGX_GetStr(buf, len, this->req.in); -} - -METHOD(request_t, get_base, char*, - private_request_t *this) -{ - return FCGX_GetParam("SCRIPT_NAME", this->req.envp); -} - -METHOD(request_t, add_cookie, void, - private_request_t *this, char *name, char *value) -{ - thread_this->set(thread_this, this); - cgi_cookie_set(this->cgi, name, value, NULL, NULL, NULL, 0, 0); -} - -METHOD(request_t, redirect, void, - private_request_t *this, char *fmt, ...) -{ - va_list args; - - FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); - FCGX_FPrintF(this->req.out, "Location: %s%s", get_base(this), - *fmt == '/' ? "" : "/"); - va_start(args, fmt); - FCGX_VFPrintF(this->req.out, fmt, args); - va_end(args); - FCGX_FPrintF(this->req.out, "\n\n"); -} - -METHOD(request_t, get_referer, char*, - private_request_t *this) -{ - return FCGX_GetParam("HTTP_REFERER", this->req.envp); -} - -METHOD(request_t, to_referer, void, - private_request_t *this) -{ - char *referer; - - referer = get_referer(this); - if (referer) - { - FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); - FCGX_FPrintF(this->req.out, "Location: %s\n\n", referer); - } - else - { - redirect(this, "/"); - } -} - -METHOD(request_t, session_closed, bool, - private_request_t *this) -{ - return this->closed; -} - -METHOD(request_t, close_session, void, - private_request_t *this) -{ - this->closed = TRUE; -} - -METHOD(request_t, serve, void, - private_request_t *this, char *headers, chunk_t chunk) -{ - FCGX_FPrintF(this->req.out, "%s\n\n", headers); - - FCGX_PutStr(chunk.ptr, chunk.len, this->req.out); -} - -METHOD(request_t, sendfile, bool, - private_request_t *this, char *path, char *mime) -{ - struct stat sb; - chunk_t data; - void *addr; - int fd, written; - char buf[24]; - - fd = open(path, O_RDONLY); - if (fd == -1) - { - return FALSE; - } - if (fstat(fd, &sb) == -1) - { - close(fd); - return FALSE; - } - addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (addr == MAP_FAILED) - { - close(fd); - return FALSE; - } - - /* FCGX does not like large integers, print to a buffer using libc */ - snprintf(buf, sizeof(buf), "%lld", (int64_t)sb.st_size); - FCGX_FPrintF(this->req.out, "Content-Length: %s\n", buf); - if (mime) - { - FCGX_FPrintF(this->req.out, "Content-Type: %s\n", mime); - } - FCGX_FPrintF(this->req.out, "\n"); - - data = chunk_create(addr, sb.st_size); - - while (data.len) - { - written = FCGX_PutStr(data.ptr, data.len, this->req.out); - if (written == -1) - { - munmap(addr, sb.st_size); - close(fd); - return FALSE; - } - data = chunk_skip(data, written); - } - - munmap(addr, sb.st_size); - close(fd); - return TRUE; -} - -METHOD(request_t, render, void, - private_request_t *this, char *template) -{ - NEOERR* err; - - thread_this->set(thread_this, this); - err = cgi_display(this->cgi, template); - if (err) - { - cgi_neo_error(this->cgi, err); - nerr_log_error(err); - } -} - -METHOD(request_t, streamf, int, - private_request_t *this, char *format, ...) -{ - va_list args; - int written; - - va_start(args, format); - written = FCGX_VFPrintF(this->req.out, format, args); - va_end(args); - if (written >= 0 && - FCGX_FFlush(this->req.out) == -1) - { - return -1; - } - return written; -} - -METHOD(request_t, set, void, - private_request_t *this, char *key, char *value) -{ - hdf_set_value(this->hdf, key, value); -} - -METHOD(request_t, setf, void, - private_request_t *this, char *format, ...) -{ - va_list args; - - va_start(args, format); - hdf_set_valuevf(this->hdf, format, args); - va_end(args); -} - -METHOD(request_t, get_ref, request_t*, - private_request_t *this) -{ - ref_get(&this->ref); - return &this->public; -} - -METHOD(request_t, destroy, void, - private_request_t *this) -{ - if (ref_put(&this->ref)) - { - thread_this->set(thread_this, this); - cgi_destroy(&this->cgi); - FCGX_Finish_r(&this->req); - free(this); - } -} - -/** - * This initialization method is guaranteed to run only once - * for all threads. - */ -static void init(void) -{ - cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb, - getenv_cb, putenv_cb, iterenv_cb); - thread_this = thread_value_create(NULL); -} - -/* - * see header file - */ -request_t *request_create(int fd, bool debug) -{ - NEOERR* err; - private_request_t *this; - bool failed = FALSE; - - INIT(this, - .public = { - .get_path = _get_path, - .get_base = _get_base, - .get_host = _get_host, - .get_user_agent = _get_user_agent, - .add_cookie = _add_cookie, - .get_cookie = _get_cookie, - .get_query_data = _get_query_data, - .get_env_var = _get_env_var, - .read_data = _read_data, - .session_closed = _session_closed, - .close_session = _close_session, - .redirect = _redirect, - .get_referer = _get_referer, - .to_referer = _to_referer, - .render = _render, - .streamf = _streamf, - .serve = _serve, - .sendfile = _sendfile, - .set = _set, - .setf = _setf, - .get_ref = _get_ref, - .destroy = _destroy, - }, - .ref = 1, - ); - - thread_cleanup_push(free, this); - if (FCGX_InitRequest(&this->req, fd, 0) != 0 || - FCGX_Accept_r(&this->req) != 0) - { - failed = TRUE; - } - thread_cleanup_pop(failed); - if (failed) - { - return NULL; - } - - pthread_once(&once, init); - thread_this->set(thread_this, this); - - while (this->req.envp[this->req_env_len] != NULL) - { - this->req_env_len++; - } - - err = hdf_init(&this->hdf); - if (!err) - { - hdf_set_value(this->hdf, "base", get_base(this)); - hdf_set_value(this->hdf, "Config.NoCache", "true"); - if (!debug) - { - hdf_set_value(this->hdf, "Config.TimeFooter", "0"); - hdf_set_value(this->hdf, "Config.CompressionEnabled", "1"); - hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2"); - } - - err = cgi_init(&this->cgi, this->hdf); - if (!err) - { - err = cgi_parse(this->cgi); - if (!err) - { - return &this->public; - } - cgi_destroy(&this->cgi); - } - } - nerr_log_error(err); - FCGX_Finish_r(&this->req); - free(this); - return NULL; -} - diff --git a/src/libfast/request.h b/src/libfast/request.h deleted file mode 100644 index 63a465bb8..000000000 --- a/src/libfast/request.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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 . - * - * 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. - */ - -/** - * @defgroup request request - * @{ @ingroup libfast - */ - -#ifndef REQUEST_H_ -#define REQUEST_H_ - -#include -#include - -typedef struct request_t request_t; - -/** - * A HTTP request, encapsulates FCGX_Request. - * - * The response is also handled through the request object. - */ -struct request_t { - - /** - * Add a cookie to the reply (Set-Cookie header). - * - * @param name name of the cookie to set - * @param value value of the cookie - */ - void (*add_cookie)(request_t *this, char *name, char *value); - - /** - * 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); - - /** - * Get the request path relative to the application. - * - * @return path - */ - char* (*get_path)(request_t *this); - - /** - * Get the base path of the application. - * - * @return base path - */ - char* (*get_base)(request_t *this); - - /** - * Get the remote host address of this request. - * - * @return host address as string - */ - char* (*get_host)(request_t *this); - - /** - * Get the user agent string. - * - * @return user agent string - */ - char* (*get_user_agent)(request_t *this); - - /** - * Get a post/get variable included in the request. - * - * @param name name of the POST/GET variable - * @return value, NULL if not found - */ - char* (*get_query_data)(request_t *this, char *name); - - /** - * Get an arbitrary environment variable. - * - * @param name name of the environment variable - * @return value, NULL if not found - */ - char* (*get_env_var)(request_t *this, char *name); - - /** - * Read raw POST/PUT data from HTTP request. - * - * @param buf buffer to read data into - * @param len size of the supplied buffer - * @return number of bytes read, < 0 on error - */ - int (*read_data)(request_t *this, char *buf, int len); - - /** - * Close the session and it's context after handling. - */ - void (*close_session)(request_t *this); - - /** - * Has the session been closed by close_session()? - * - * @return TRUE if session has been closed - */ - bool (*session_closed)(request_t *this); - - /** - * Redirect the client to another location. - * - * @param fmt location format string - * @param ... variable argument for fmt - */ - void (*redirect)(request_t *this, char *fmt, ...); - - /** - * Get the HTTP referer. - * - * @return HTTP referer - */ - char* (*get_referer)(request_t *this); - - /** - * Redirect back to the referer. - */ - void (*to_referer)(request_t *this); - - /** - * Set a template value. - * - * @param key key to set - * @param value value to set key to - */ - void (*set)(request_t *this, char *key, char *value); - - /** - * 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)(request_t *this, char *format, ...); - - /** - * Render a template. - * - * The render() function additionally sets a HDF variable "base" - * which points to the root of the web application and allows to point to - * other targets without to worry about path location. - * - * @param template clearsilver template file location - */ - void (*render)(request_t *this, char *template); - - /** - * Stream a format string to the client. - * - * Stream is not closed and may be called multiple times to allow - * server-push functionality. - * - * @param format printf like format string - * @param ... argmuent list to format string - * @return number of streamed bytes, < 0 if stream closed - */ - int (*streamf)(request_t *this, char *format, ...); - - /** - * Serve a request with headers and a body. - * - * @param headers HTTP headers, \n separated - * @param chunk body to write to output - */ - void (*serve)(request_t *this, char *headers, chunk_t chunk); - - /** - * Send a file from the file system. - * - * @param path path to file to serve - * @param mime mime type of file to send, or NULL - * @return TRUE if file served successfully - */ - bool (*sendfile)(request_t *this, char *path, char *mime); - - /** - * Increase the reference count to the stream. - * - * @return this with increased refcount - */ - request_t* (*get_ref)(request_t *this); - - /** - * Destroy the request_t. - */ - void (*destroy) (request_t *this); -}; - -/** - * Create a request from the fastcgi struct. - * - * @param fd file descripter opened with FCGX_OpenSocket - * @param debug no stripping, no compression, timing information - */ -request_t *request_create(int fd, bool debug); - -#endif /** REQUEST_H_ @}*/ diff --git a/src/libfast/session.c b/src/libfast/session.c deleted file mode 100644 index 87a157b61..000000000 --- a/src/libfast/session.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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 . - * - * 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 -#include -#include - -#include - -#define COOKIE_LEN 16 - -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[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 - */ - context_t *context; -}; - -METHOD(session_t, add_controller, void, - private_session_t *this, controller_t *controller) -{ - this->controllers->insert_last(this->controllers, controller); -} - -METHOD(session_t, add_filter, void, - private_session_t *this, filter_t *filter) -{ - this->filters->insert_last(this->filters, filter); -} - -/** - * Create a session ID and a cookie - */ -static bool create_sid(private_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_session_t *this, request_t *request, char *p0, - char *p1, char *p2, char *p3, char *p4, char *p5) -{ - enumerator_t *enumerator; - 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(session_t, process, void, - private_session_t *this, request_t *request) -{ - char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; - enumerator_t *enumerator; - bool handled = FALSE; - 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(session_t, get_sid, char*, - private_session_t *this) -{ - return this->sid; -} - -METHOD(session_t, destroy, void, - private_session_t *this) -{ - this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy)); - this->filters->destroy_offset(this->filters, offsetof(filter_t, destroy)); - DESTROY_IF(this->context); - free(this); -} - -/* - * see header file - */ -session_t *session_create(context_t *context) -{ - private_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; -} - diff --git a/src/libfast/session.h b/src/libfast/session.h deleted file mode 100644 index acbab8964..000000000 --- a/src/libfast/session.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 . - * - * 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. - */ - -/** - * @defgroup session session - * @{ @ingroup libfast - */ - -#ifndef SESSION_H_ -#define SESSION_H_ - -#include "request.h" -#include "controller.h" -#include "filter.h" - -typedef struct session_t session_t; - -/** - * Session handling class, instanciated for each user session. - */ -struct session_t { - - /** - * Get the session ID of the session. - * - * @return session ID - */ - char* (*get_sid)(session_t *this); - - /** - * Add a controller instance to the session. - * - * @param controller controller to add - */ - void (*add_controller)(session_t *this, controller_t *controller); - - /** - * Add a filter instance to the session. - * - * @param filter filter to add - */ - void (*add_filter)(session_t *this, filter_t *filter); - - /** - * Process a request in this session. - * - * @param request request to process - */ - void (*process)(session_t *this, request_t *request); - - /** - * Destroy the session_t. - */ - void (*destroy) (session_t *this); -}; - -/** - * Create a session new session. - * - * @param context user defined session context instance - * @return client session, NULL on error - */ -session_t *session_create(context_t *context); - -#endif /** SESSION_H_ @}*/ diff --git a/src/libfast/smtp.c b/src/libfast/smtp.c deleted file mode 100644 index a6ca67ddc..000000000 --- a/src/libfast/smtp.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * 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. - */ - -#include "smtp.h" - -#include -#include - -#include - -typedef struct private_smtp_t private_smtp_t; - -/** - * Private data of an smtp_t object. - */ -struct private_smtp_t { - - /** - * Public smtp_t interface. - */ - smtp_t public; - - /** - * file stream to SMTP server - */ - FILE *f; -}; - -/** - * Read the response code from an SMTP server - */ -static int read_response(private_smtp_t *this) -{ - char buf[256], *end; - int res = 0; - - while (TRUE) - { - if (!fgets(buf, sizeof(buf), this->f)) - { - return 0; - } - res = strtol(buf, &end, 10); - switch (*end) - { - case '-': - continue; - case ' ': - case '\0': - case '\n': - break; - default: - return 0; - } - break; - } - return res; -} - -/** - * write a SMTP command to the server, read response code - */ -static int write_cmd(private_smtp_t *this, char *fmt, ...) -{ - char buf[256]; - va_list args; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - if (fprintf(this->f, "%s\n", buf) < 1) - { - DBG1(DBG_LIB, "sending SMTP command failed"); - return 0; - } - return read_response(this); -} - -METHOD(smtp_t, send_mail, bool, - private_smtp_t *this, char *from, char *to, char *subject, char *fmt, ...) -{ - va_list args; - - if (write_cmd(this, "MAIL FROM:<%s>", from) != 250) - { - DBG1(DBG_LIB, "SMTP MAIL FROM failed"); - return FALSE; - } - if (write_cmd(this, "RCPT TO:<%s>", to) != 250) - { - DBG1(DBG_LIB, "SMTP RCPT TO failed"); - return FALSE; - } - if (write_cmd(this, "DATA") != 354) - { - DBG1(DBG_LIB, "SMTP DATA failed"); - return FALSE; - } - - fprintf(this->f, "From: %s\n", from); - fprintf(this->f, "To: %s\n", to); - fprintf(this->f, "Subject: %s\n", subject); - fprintf(this->f, "\n"); - va_start(args, fmt); - vfprintf(this->f, fmt, args); - va_end(args); - fprintf(this->f, "\n.\n"); - return read_response(this) == 250; -} - - -METHOD(smtp_t, destroy, void, - private_smtp_t *this) -{ - write_cmd(this, "QUIT"); - fclose(this->f); - free(this); -} - -/** - * See header - */ -smtp_t *smtp_create() -{ - private_smtp_t *this; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = htons(25), - .sin_addr = { - .s_addr = htonl(INADDR_LOOPBACK), - }, - }; - int s; - - INIT(this, - .public = { - .send_mail = _send_mail, - .destroy = _destroy, - }, - ); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - { - DBG1(DBG_LIB, "opening SMTP socket failed: %s", strerror(errno)); - free(this); - return NULL; - } - if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) - { - DBG1(DBG_LIB, "connecting to SMTP server failed: %s", strerror(errno)); - close(s); - free(this); - return NULL; - } - this->f = fdopen(s, "a+"); - if (!this->f) - { - DBG1(DBG_LIB, "opening stream to SMTP server failed: %s", - strerror(errno)); - close(s); - free(this); - return NULL; - } - if (read_response(this) != 220 || - write_cmd(this, "EHLO localhost") != 250) - { - DBG1(DBG_LIB, "SMTP EHLO failed"); - fclose(this->f); - free(this); - return NULL; - } - return &this->public; -} - diff --git a/src/libfast/smtp.h b/src/libfast/smtp.h deleted file mode 100644 index 9589ea2a6..000000000 --- a/src/libfast/smtp.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * 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. - */ - -/** - * @defgroup smtp smtp - * @{ @ingroup libfast - */ - -#ifndef SMTP_H_ -#define SMTP_H_ - -typedef struct smtp_t smtp_t; - -#include - -/** - * Ultra-minimalistic SMTP client. Works at most with Exim on localhost. - */ -struct smtp_t { - - /** - * Send an e-mail message. - * - * @param from sender address - * @param to recipient address - * @param subject mail subject - * @param fmt mail body format string - * @param ... arguments for body format string - */ - bool (*send_mail)(smtp_t *this, char *from, char *to, - char *subject, char *fmt, ...); - - /** - * Destroy a smtp_t. - */ - void (*destroy)(smtp_t *this); -}; - -/** - * Create a smtp instance. - */ -smtp_t *smtp_create(); - -#endif /** SMTP_H_ @}*/ -- cgit v1.2.3