libfast: Remove FastCGI application server library
The two users (manager, medsrv) are gone, so there is no reason to keep this around.
This commit is contained in:
+1
-34
@@ -287,7 +287,6 @@ ARG_ENABL_SET([aikgen], [enable AIK generator for TPM 1.2.])
|
||||
ARG_DISBL_SET([charon], [disable the IKEv1/IKEv2 keying daemon charon.])
|
||||
ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.])
|
||||
ARG_ENABL_SET([conftest], [enforce Suite B conformance test framework.])
|
||||
ARG_ENABL_SET([fast], [enable libfast (FastCGI Application Server w/ templates.])
|
||||
ARG_ENABL_SET([fuzzing], [enable fuzzing scripts (found in directory fuzz).])
|
||||
ARG_ENABL_SET([libipsec], [enable user space IPsec implementation.])
|
||||
ARG_ENABL_SET([nm], [enable NetworkManager backend.])
|
||||
@@ -1106,36 +1105,6 @@ if test x$imc_swima = xtrue -o x$imv_swima = xtrue; then
|
||||
AC_SUBST(json_LIBS)
|
||||
fi
|
||||
|
||||
if test x$fast = xtrue; then
|
||||
AC_CHECK_LIB([neo_utl],[hdf_init],[LIBS="$LIBS"],[AC_MSG_ERROR([ClearSilver library neo_utl not found!])],[])
|
||||
AC_MSG_CHECKING([for -lneo_cgi and dependencies])
|
||||
saved_CFLAGS=$CFLAGS
|
||||
saved_LIBS=$LIBS
|
||||
LIBS="-lneo_cgi -lneo_cs -lneo_utl"
|
||||
CFLAGS="-I/usr/include/ClearSilver"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <cgi/cgi.h>]],
|
||||
[[NEOERR *err = cgi_display(NULL, NULL);]])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[LIBS="$LIBS -lz";
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <cgi/cgi.h>]],
|
||||
[[NEOERR *err = cgi_display(NULL, NULL);]])],
|
||||
[AC_MSG_RESULT([yes, zlib required])],
|
||||
[AC_MSG_ERROR([not found])]
|
||||
)]
|
||||
)
|
||||
clearsilver_LIBS="$LIBS"
|
||||
AC_SUBST(clearsilver_LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
CFLAGS=$saved_CFLAGS
|
||||
|
||||
AC_CHECK_LIB([fcgi],[FCGX_Init],[LIBS="$LIBS"],[AC_MSG_ERROR([FastCGI library fcgi not found!])],[])
|
||||
AC_CHECK_HEADER([fcgiapp.h],,[AC_MSG_ERROR([FastCGI header file fcgiapp.h not found!])])
|
||||
fi
|
||||
|
||||
if test x$mysql = xtrue; then
|
||||
if test "x$windows" = xtrue; then
|
||||
AC_CHECK_HEADER([mysql.h],,[AC_MSG_ERROR([MySQL header file mysql.h not found!])])
|
||||
@@ -1846,7 +1815,6 @@ AM_CONDITIONAL(USE_PF_HANDLER, test x$dhcp = xtrue -o x$farp = xtrue)
|
||||
# ---------------
|
||||
AM_CONDITIONAL(USE_LEAK_DETECTIVE, test x$leak_detective = xtrue)
|
||||
AM_CONDITIONAL(USE_LOCK_PROFILER, test x$lock_profiler = xtrue)
|
||||
AM_CONDITIONAL(USE_FAST, test x$fast = xtrue)
|
||||
AM_CONDITIONAL(USE_ME, test x$mediation = xtrue)
|
||||
AM_CONDITIONAL(USE_INTEGRITY_TEST, test x$integrity_test = xtrue)
|
||||
AM_CONDITIONAL(USE_LOAD_WARNING, test x$load_warning = xtrue)
|
||||
@@ -1861,7 +1829,7 @@ AM_CONDITIONAL(USE_PKI, test x$pki = xtrue)
|
||||
AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
|
||||
AM_CONDITIONAL(USE_FUZZING, test x$fuzzing = xtrue)
|
||||
AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
|
||||
AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
|
||||
AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$conftest = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
|
||||
AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
|
||||
AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
|
||||
AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
|
||||
@@ -2162,7 +2130,6 @@ AC_CONFIG_FILES([
|
||||
src/pki/Makefile
|
||||
src/pki/man/Makefile
|
||||
src/pool/Makefile
|
||||
src/libfast/Makefile
|
||||
src/checksum/Makefile
|
||||
src/conftest/Makefile
|
||||
src/pt-tls-client/Makefile
|
||||
|
||||
+1
-3
@@ -280,7 +280,7 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
|
||||
CONFIG="$CONFIG --without-testable-ke"
|
||||
fi
|
||||
DEPS="$DEPS libcurl4-gnutls-dev libsoup-3.0-dev libunbound-dev libldns-dev
|
||||
libmysqlclient-dev libsqlite3-dev clearsilver-dev libfcgi-dev
|
||||
libmysqlclient-dev libsqlite3-dev
|
||||
libldap2-dev libpcsclite-dev libpam0g-dev binutils-dev libnm-dev
|
||||
libgcrypt20-dev libjson-c-dev libtspi-dev libsystemd-dev
|
||||
libselinux1-dev libiptc-dev ruby-rubygems python3-build tox"
|
||||
@@ -303,8 +303,6 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
|
||||
CONFIG="$CONFIG --disable-systemd --disable-cert-enroll-timer"
|
||||
# no TrouSerS either
|
||||
CONFIG="$CONFIG --disable-tss-trousers --disable-aikgen"
|
||||
# and no Clearsilver
|
||||
CONFIG="$CONFIG --disable-fast"
|
||||
fi
|
||||
if test "$1" = "build-deps"; then
|
||||
build_botan
|
||||
|
||||
@@ -87,10 +87,6 @@ if USE_CONFTEST
|
||||
SUBDIRS += conftest
|
||||
endif
|
||||
|
||||
if USE_FAST
|
||||
SUBDIRS += libfast
|
||||
endif
|
||||
|
||||
if USE_ATTR_SQL
|
||||
SUBDIRS += pool
|
||||
else
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/libstrongswan \
|
||||
-I/usr/include/ClearSilver
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(PLUGIN_CFLAGS)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-undefined
|
||||
|
||||
ipseclib_LTLIBRARIES = libfast.la
|
||||
|
||||
libfast_la_SOURCES = \
|
||||
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 = \
|
||||
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) $(ATOMICLIB)
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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_ @}*/
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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_ @}*/
|
||||
@@ -1,465 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "fast_dispatcher.h"
|
||||
|
||||
#include "fast_request.h"
|
||||
#include "fast_session.h"
|
||||
|
||||
#include <fcgiapp.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <threading/thread.h>
|
||||
#include <threading/condvar.h>
|
||||
#include <threading/mutex.h>
|
||||
#include <collections/linked_list.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
/** Interval 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;
|
||||
|
||||
/**
|
||||
* Hashtable 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 instantiate 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
|
||||
*/
|
||||
CALLBACK(dispatch, void*,
|
||||
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);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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(dispatch, this);
|
||||
if (this->threads[threads - 1])
|
||||
{
|
||||
threads--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(fast_dispatcher_t, waitsignal, void,
|
||||
private_fast_dispatcher_t *this)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGINT);
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &set, NULL);
|
||||
while (sigwaitinfo(&set, NULL) == -1 && errno == EINTR)
|
||||
{
|
||||
/* wait for signal */
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 threadsafe. Often a database wrapper is the global context.
|
||||
* The session context is instantiated 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 instantiated. 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 instantiated 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 controller
|
||||
* @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.
|
||||
*
|
||||
* Instantiate 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_ @}*/
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @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_ @} */
|
||||
@@ -1,492 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "fast_request.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/debug.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <ClearSilver/ClearSilver.h>
|
||||
|
||||
#include <threading/thread.h>
|
||||
#include <threading/thread_value.h>
|
||||
|
||||
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 threadsafe, 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)
|
||||
{
|
||||
chunk_t *data;
|
||||
int written;
|
||||
char buf[24];
|
||||
|
||||
data = chunk_map(path, FALSE);
|
||||
if (!data)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
/* FCGX does not like large integers, print to a buffer using libc */
|
||||
snprintf(buf, sizeof(buf), "%"PRId64, (int64_t)data->len);
|
||||
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");
|
||||
|
||||
while (data->len)
|
||||
{
|
||||
written = FCGX_PutStr(data->ptr, data->len, this->req.out);
|
||||
if (written == -1)
|
||||
{
|
||||
chunk_unmap(data);
|
||||
return FALSE;
|
||||
}
|
||||
*data = chunk_skip(*data, written);
|
||||
}
|
||||
|
||||
chunk_unmap(data);
|
||||
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;
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup fast_request fast_request
|
||||
* @{ @ingroup libfast
|
||||
*/
|
||||
|
||||
#ifndef FAST_REQUEST_H_
|
||||
#define FAST_REQUEST_H_
|
||||
|
||||
#include <fcgiapp.h>
|
||||
#include <library.h>
|
||||
|
||||
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 ... argument 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 descriptor 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_ @}*/
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "fast_session.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcgiapp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <collections/linked_list.h>
|
||||
|
||||
#define COOKIE_LEN 16
|
||||
|
||||
typedef struct private_fast_session_t private_fast_session_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
*/
|
||||
struct private_fast_session_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
fast_session_t public;
|
||||
|
||||
/**
|
||||
* session ID
|
||||
*/
|
||||
char sid[COOKIE_LEN * 2 + 1];
|
||||
|
||||
/**
|
||||
* have we sent the session cookie?
|
||||
*/
|
||||
bool cookie_sent;
|
||||
|
||||
/**
|
||||
* list of controller instances controller_t
|
||||
*/
|
||||
linked_list_t *controllers;
|
||||
|
||||
/**
|
||||
* list of filter instances filter_t
|
||||
*/
|
||||
linked_list_t *filters;
|
||||
|
||||
/**
|
||||
* user defined session context
|
||||
*/
|
||||
fast_context_t *context;
|
||||
};
|
||||
|
||||
METHOD(fast_session_t, add_controller, void,
|
||||
private_fast_session_t *this, fast_controller_t *controller)
|
||||
{
|
||||
this->controllers->insert_last(this->controllers, controller);
|
||||
}
|
||||
|
||||
METHOD(fast_session_t, add_filter, void,
|
||||
private_fast_session_t *this, fast_filter_t *filter)
|
||||
{
|
||||
this->filters->insert_last(this->filters, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a session ID and a cookie
|
||||
*/
|
||||
static bool create_sid(private_fast_session_t *this)
|
||||
{
|
||||
char buf[COOKIE_LEN];
|
||||
rng_t *rng;
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!rng->get_bytes(rng, sizeof(buf), buf))
|
||||
{
|
||||
rng->destroy(rng);
|
||||
return FALSE;
|
||||
}
|
||||
rng->destroy(rng);
|
||||
chunk_to_hex(chunk_create(buf, sizeof(buf)), this->sid, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* run all registered filters
|
||||
*/
|
||||
static bool run_filter(private_fast_session_t *this, fast_request_t *request,
|
||||
char *p0, char *p1, char *p2, char *p3, char *p4, char *p5)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
fast_filter_t *filter;
|
||||
|
||||
enumerator = this->filters->create_enumerator(this->filters);
|
||||
while (enumerator->enumerate(enumerator, &filter))
|
||||
{
|
||||
if (!filter->run(filter, request, p0, p1, p2, p3, p4, p5))
|
||||
{
|
||||
enumerator->destroy(enumerator);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(fast_session_t, process, void,
|
||||
private_fast_session_t *this, fast_request_t *request)
|
||||
{
|
||||
char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
enumerator_t *enumerator;
|
||||
bool handled = FALSE;
|
||||
fast_controller_t *current;
|
||||
int i = 0;
|
||||
|
||||
if (!this->cookie_sent)
|
||||
{
|
||||
request->add_cookie(request, "SID", this->sid);
|
||||
this->cookie_sent = TRUE;
|
||||
}
|
||||
|
||||
start = request->get_path(request);
|
||||
if (start)
|
||||
{
|
||||
if (*start == '/')
|
||||
{
|
||||
start++;
|
||||
}
|
||||
while ((pos = strchr(start, '/')) != NULL && i < 5)
|
||||
{
|
||||
param[i++] = strndupa(start, pos - start);
|
||||
start = pos + 1;
|
||||
}
|
||||
param[i] = strdupa(start);
|
||||
|
||||
if (run_filter(this, request, param[0], param[1], param[2], param[3],
|
||||
param[4], param[5]))
|
||||
{
|
||||
enumerator = this->controllers->create_enumerator(this->controllers);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (streq(current->get_name(current), param[0]))
|
||||
{
|
||||
current->handle(current, request, param[1], param[2],
|
||||
param[3], param[4], param[5]);
|
||||
handled = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
else
|
||||
{
|
||||
handled = TRUE;
|
||||
}
|
||||
}
|
||||
if (!handled)
|
||||
{
|
||||
if (this->controllers->get_first(this->controllers,
|
||||
(void**)¤t) == SUCCESS)
|
||||
{
|
||||
request->streamf(request,
|
||||
"Status: 301 Moved permanently\nLocation: %s/%s\n\n",
|
||||
request->get_base(request), current->get_name(current));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(fast_session_t, get_sid, char*,
|
||||
private_fast_session_t *this)
|
||||
{
|
||||
return this->sid;
|
||||
}
|
||||
|
||||
METHOD(fast_session_t, destroy, void,
|
||||
private_fast_session_t *this)
|
||||
{
|
||||
this->controllers->destroy_offset(this->controllers,
|
||||
offsetof(fast_controller_t, destroy));
|
||||
this->filters->destroy_offset(this->filters,
|
||||
offsetof(fast_filter_t, destroy));
|
||||
DESTROY_IF(this->context);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
fast_session_t *fast_session_create(fast_context_t *context)
|
||||
{
|
||||
private_fast_session_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.add_controller = _add_controller,
|
||||
.add_filter = _add_filter,
|
||||
.process = _process,
|
||||
.get_sid = _get_sid,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.controllers = linked_list_create(),
|
||||
.filters = linked_list_create(),
|
||||
.context = context,
|
||||
);
|
||||
if (!create_sid(this))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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, instantiated 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_ @}*/
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "fast_smtp.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup fast_smtp fast_smtp
|
||||
* @{ @ingroup libfast
|
||||
*/
|
||||
|
||||
#ifndef FAST_SMTP_H_
|
||||
#define FAST_SMTP_H_
|
||||
|
||||
typedef struct fast_smtp_t fast_smtp_t;
|
||||
|
||||
#include <library.h>
|
||||
|
||||
/**
|
||||
* 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_ @}*/
|
||||
@@ -555,8 +555,6 @@ static char *whitelist[] = {
|
||||
"mysql_init_character_set",
|
||||
"init_client_errs",
|
||||
"my_thread_init",
|
||||
/* fastcgi library */
|
||||
"FCGX_Init",
|
||||
/* libxml */
|
||||
"xmlInitCharEncodingHandlers",
|
||||
"xmlInitParser",
|
||||
@@ -566,8 +564,6 @@ static char *whitelist[] = {
|
||||
/* libldap */
|
||||
"ldap_int_initialize",
|
||||
"ldap_pvt_tls_set_option",
|
||||
/* ClearSilver */
|
||||
"nerr_init",
|
||||
/* libgcrypt */
|
||||
"gcrypt_plugin_create",
|
||||
"gcry_control",
|
||||
|
||||
Reference in New Issue
Block a user