pax_global_header00006660000000000000000000000064132042657060014517gustar00rootroot0000000000000052 comment=254d5004bc875247eb4f3da6a3ecfac8c6dcc4dd bitz-server-1.0.2/000077500000000000000000000000001320426570600137735ustar00rootroot00000000000000bitz-server-1.0.2/.gitignore000066400000000000000000000005441320426570600157660ustar00rootroot00000000000000# Some generics first # Compiled Object files *.slo *.lo *.o # Compiled Dynamic libraries *.so *.dylib # Compiled Static libraries *.lai *.la *.a # autotools autom4te.cache/* aux-build/* aclocal.m4 config.h.in configure Makefile.in # eclipse .project .cproject .settings/* .pydevproject # swap files *.swp # python *.pyc # project specific build/* bitz-server-1.0.2/.travis.yml000066400000000000000000000020311320426570600161000ustar00rootroot00000000000000language: cpp sudo: false addons: apt: packages: - liblog4cpp5-dev compiler: - gcc - clang before_install: - echo $LANG - echo $LC_ALL - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install libconfig log4cpp; fi install: - curl -L https://github.com/nukedzn/psocksxx/releases/download/v1.0.0/psocksxx-1.0.0.tar.gz | tar -zx -C /tmp - cd /tmp/psocksxx-* && ./configure --prefix=/tmp/root && make && make install - if [ $TRAVIS_OS_NAME == linux ]; then curl -L http://www.hyperrealm.com/packages/libconfig-1.4.10.tar.gz | tar -zx -C /tmp; fi - if [ $TRAVIS_OS_NAME == linux ]; then cd /tmp/libconfig-* && ./configure --prefix=/tmp/root && make && make install; fi - cd ${TRAVIS_BUILD_DIR} before_script: - if [ $TRAVIS_OS_NAME == linux ]; then libtoolize; fi - if [ $TRAVIS_OS_NAME == osx ]; then glibtoolize; fi - aclocal - autoheader - autoconf - automake --add-missing - export PKG_CONFIG_PATH=/tmp/root/lib/pkgconfig && ./configure script: - make distcheck os: - linux - osx bitz-server-1.0.2/Makefile.am000066400000000000000000000003731320426570600160320ustar00rootroot00000000000000## Makefile.am -- Process this file with automake to produce Makefile.in # amflags ACLOCAL_AMFLAGS = -I aux-build/m4 # sub dirs SUBDIRS = \ conf \ doc \ include \ lib \ modules \ src # extra dist files EXTRA_DIST = \ changelog \ README.md bitz-server-1.0.2/README.md000066400000000000000000000061651320426570600152620ustar00rootroot00000000000000bitz-server =========== [![Build Status](https://travis-ci.org/uditha-atukorala/bitz-server.svg)](https://travis-ci.org/uditha-atukorala/bitz-server) An ICAP server implementation in C++ ## Copyright and License Copyright (C) 2012-2015 Uditha Atukorala. 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 3 of the License, or (at your option) any later version. 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](http://gnu.org/licenses/gpl.html) for more details. ## The concept The main goal of this project is to create an ICAP server ([RFC 3507](http://www.ietf.org/rfc/rfc3507.txt)) implementation in C++ to use the power of object oriented programming. Starting from scratch, the server is developed with a modular architecture in mind. The server core (written in C++) will handle the client requests, manage workers (child processes) etc. and will provide basic handlers to serve ICAP requests. To extend this core functionality the idea is to have pluggable modules (like apache server modules). These modules will provide features like content filtering, anti-virus scanning etc. and to make it easier to write (and faster to implement) such modules there is hope to exploit python programming language. ## Acknowledgements * Many thanks to Kenneth Oksanen for his support in finding and fixing bugs ## Downloads You can download the source distributions from https://github.com/uditha-atukorala/bitz-server/releases. ## Dependencies * [psocksxx >= 0.0.6](https://nukedzn.github.io/psocksxx/) * [libconfig++ >= 1.4](http://www.hyperrealm.com/libconfig/) * log4cpp >= 1.0 * python 2.7 (for modpy module) ## Bugs and Feature Requests Please report all bugs and feature requests under [issues](https://github.com/uditha-atukorala/bitz-server/issues). ## Compiling from source If you are using the github source then first you need to initialise autotools. $ libtoolize (glibtoolize in OS X) $ aclocal $ autoheader $ autoconf $ automake --add-missing After that you can use the usual `./configure && make` -------------------------------------------------------------------------------- ### Notes #### modpy This is the (long awaited) python interface module. It provides a template for any other python interface module implementations either as C++ module template or as a C++ interface for python modules. #### Debugging Use the following to create the binaries with debug symbols $ ./configure CXXFLAGS="-g -O0" #### config file The default config file location is `/etc/bitz/bitz-server.conf` but this can changed using the `--with-config` option when you run `configure`. e.g. $ ./configure --with-config=/[path to source code]/conf/bitz-server.conf #### valgrind checks $ valgrind --leak-check=full --read-var-info=yes --trace-children=yes --suppressions=test/valgrind.supp --log-file=valgrind.log ./src/bitz-server --debug bitz-server-1.0.2/acinclude.m4000066400000000000000000000074221320426570600161710ustar00rootroot00000000000000## this one is commonly used with AM_PATH_PYTHONDIR ... dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) dnl Check if a module containing a given symbol is visible to python. AC_DEFUN([AM_CHECK_PYMOD], [AC_REQUIRE([AM_PATH_PYTHON]) py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ ifelse([$2],[], [prog=" import sys try: import $1 except ImportError: sys.exit(1) except: sys.exit(0) sys.exit(0)"], [prog=" import $1 $1.$2"]) if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC then eval "py_cv_mod_$py_mod_var=yes" else eval "py_cv_mod_$py_mod_var=no" fi ]) py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` if test "x$py_val" != xno; then AC_MSG_RESULT(yes) ifelse([$3], [],, [$3 ])dnl else AC_MSG_RESULT(no) ifelse([$4], [],, [$4 ])dnl fi ]) dnl a macro to check for ability to create python extensions dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_INCLUDES AC_DEFUN([AM_CHECK_PYTHON_HEADERS], [AC_REQUIRE([AM_PATH_PYTHON]) AC_MSG_CHECKING(for headers required to compile python extensions) dnl deduce PYTHON_INCLUDES py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` if $PYTHON-config --help 2>/dev/null; then PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` else PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi fi AC_SUBST(PYTHON_INCLUDES) dnl check if the headers exist: save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" AC_TRY_CPP([#include ],dnl [AC_MSG_RESULT(found) $1],dnl [AC_MSG_RESULT(not found) $2]) CPPFLAGS="$save_CPPFLAGS" ]) dnl a macro to check for ability to embed python dnl AM_CHECK_PYTHON_LIBS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_LIBS AC_DEFUN([AM_CHECK_PYTHON_LIBS], [AC_REQUIRE([AM_CHECK_PYTHON_HEADERS]) AC_MSG_CHECKING(for libraries required to embed python) dnl deduce PYTHON_LIBS py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` PYTHON_LIBS="-L${py_prefix}/lib -lpython${PYTHON_VERSION}" PYTHON_LIB_LOC="${py_prefix}/lib" AC_SUBST(PYTHON_LIBS) AC_SUBST(PYTHON_LIB_LOC) dnl check if the headers exist: save_LIBS="$LIBS" LIBS="$LIBS $PYTHON_LIBS" AC_TRY_LINK_FUNC(Py_Initialize, dnl [LIBS="$save_LIBS"; AC_MSG_RESULT(yes); $1], dnl [LIBS="$save_LIBS"; AC_MSG_RESULT(no); $2]) ]) dnl as-ac-expand.m4 0.2.0 dnl autostars m4 macro for expanding directories using configure's prefix dnl thomas@apestaart.org dnl dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) dnl example dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local AC_DEFUN([AS_AC_EXPAND], [ EXP_VAR=[$1] FROM_VAR=[$2] dnl first expand prefix and exec_prefix if necessary prefix_save=$prefix exec_prefix_save=$exec_prefix dnl if no prefix given, then use /usr/local, the default prefix if test "x$prefix" = "xNONE"; then prefix="$ac_default_prefix" fi dnl if no exec_prefix given, then use prefix if test "x$exec_prefix" = "xNONE"; then exec_prefix=$prefix fi full_var="$FROM_VAR" dnl loop until it doesn't change anymore while true; do new_full_var="`eval echo $full_var`" if test "x$new_full_var" = "x$full_var"; then break; fi full_var=$new_full_var done dnl clean up full_var=$new_full_var AC_SUBST([$1], "$full_var") dnl restore prefix and exec_prefix prefix=$prefix_save exec_prefix=$exec_prefix_save ]) bitz-server-1.0.2/changelog000066400000000000000000000034651320426570600156550ustar00rootroot000000000000001.0.2 - 19th November 2017 * Fix broken v1.0.1 release 1.0.1 - 19th November 2017 * Make builds reproducible (https://bugs.debian.org/882112) 1.0.0 - 25th November 2015 * [New] Configurable communication (socket) timeouts * [New] Support for persistent connections * [New] Use psocksxx as the socket library * Code restructure * Updated man pages * Fix issue #2 0.1.6 - 28th September 2013 * Few tweaks and minor changes to distribution files (no functional changes) 0.1.5 - 11th August 2013 * Fix modpy interface module string copy bug 0.1.4 - 01st August 2013 * Code optimisations * Make sure all the data requested is read in icap::util::read_data() (found by Kenneth Oksanen) 0.1.3 - 29th July 2013 * Fix char buffers (found by Kenneth Oksanen) * Fix modpy module to handle null-characters properly (found by Kenneth Oksanen) 0.1.2 - 07th July 2013 * [New] RESPMOD handler * [New] Message Preview features * Code cleanup and optimisations * Stop workers from segfaulting when modifier modules aren't loaded * Minor bug fixes 0.1.1 - 06th March 2013 * Remove hard coded file paths in daemonized code * Fix `make install` to not to install empty log files 0.1.0 - 03rd March 2013 * Daemonized version (hence the minor version bump), Server core is re-organised with bitz::server namespace to be more cleaner and easier to read, * Make it possible to pass in command-line options * Closed a memory leak in modpy module * Make workers (child processes) and max requests per worker configurable * Man pages 0.0.1 - 24th February 2013 * Proof of concept. An ICAP server with only a REQMOD handler. Includes a template 'echo' module to demonstrate the pluggable module architecture and the 'modpy' module to demonstrate the python interface. bitz-server-1.0.2/conf/000077500000000000000000000000001320426570600147205ustar00rootroot00000000000000bitz-server-1.0.2/conf/Makefile.am000066400000000000000000000007571320426570600167650ustar00rootroot00000000000000## conf/ configdir = $(sysconfdir)/bitz config_DATA = bitz-server.conf # extra dist files EXTRA_DIST = \ bitz-server.conf.in edit = sed \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ -e 's|@pkglibdir[@]|$(pkglibdir)|g' bitz-server.conf: bitz-server.conf.in rm -f $@ $@.tmp srcdir=''; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit) $${srcdir}$@.in >$@.tmp chmod +r $@.tmp chmod og-wx $@.tmp mv $@.tmp $@ clean-local: rm -f *.conf bitz-server-1.0.2/conf/bitz-server.conf.in000066400000000000000000000017531320426570600204560ustar00rootroot00000000000000# # @sysconfdir@/bitz/bitz-server.conf # port = 1344; pid_file = "@localstatedir@/run/bitz/bitz-server.pid"; log_file = "@localstatedir@/log/bitz/bitz-server.log"; log_category = "bitz-server"; # maximum number of workers max_workers = 1; # maximum number of requests a worker will serve max_worker_requests = 100; # communication timeout value in seconds. set this value to # be 0 to disable timeouts. comm_timeout = 5; # request handlers req_handlers : ({ handler = "REQMOD"; class = "ReqmodRequestHandler"; modules : ( { name = "modpy"; module = "@pkglibdir@/modules/mod_py.so"; } ); }, { handler = "RESPMOD"; class = "RespmodRequestHandler"; modules : ( { name = "modpy"; module = "@pkglibdir@/modules/mod_py.so"; } ); }); # module configurations modules : { modpy : { # search path for python modules module_path = "@pkglibdir@/modules/modpy"; # python module containing the interface methods module_name = "modpy"; }; }; bitz-server-1.0.2/configure.ac000066400000000000000000000074401320426570600162660ustar00rootroot00000000000000# configure.ac # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) AC_INIT([bitz-server], [1.0.2], [https://github.com/uditha-atukorala/bitz-server/issues]) AC_CONFIG_AUX_DIR([aux-build]) AC_CONFIG_MACRO_DIR([aux-build/m4]) AC_CONFIG_HEADERS([include/config.h]) # Versioning rules ( C:R:A ) # # 1. Start with version 0:0:0. # 2. If any of the sources have changed, increment R. This is a new revision # of the current interface. # 3. If the interface has changed, increment C and set R to 0. This is the # first revision of a new interface. # 4. If the new interface is a superset of the previous interface # (that is, if the previous interface has not been broken by the # changes in this new release), increment A. This release is backwards # compatible with the previous release. # 5. If the new interface has removed elements with respect to the # previous interface, then backward compatibility is broken; set A to 0. # This release has a new, but backwards incompatible interface. # # For more info see section 6.3 of the GNU Libtool Manual. # # In short; # +1 : ? : +1 == new interface that does not break old one # +1 : ? : 0 == new interface that breaks old one # ? : ? : 0 == no new interfaces, but breaks apps # ? :+1 : ? == just some internal changes, nothing breaks but might work # better # CURRENT : REVISION : AGE # lib versions ICAP_LT_VERSION=1:0:0 AC_SUBST(ICAP_LT_VERSION) # Init AM_INIT_AUTOMAKE([foreign]) LT_INIT() # Check for programs AC_PROG_CXX AC_PROG_INSTALL AC_PROG_AWK AC_PROG_MKDIR_P AC_PROG_LIBTOOL # Language AC_LANG(C++) # Options AC_ARG_WITH([config], [AS_HELP_STRING([--with-config], [specify the config file to be used])], [], [with_config=no]) AC_ARG_ENABLE([modpy], [AS_HELP_STRING([--enable-modpy],[Enable modpy module (default is yes)])], [case "${enableval}" in yes) modpy=true ;; no) modpy=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-modpy]) ;; esac], [modpy=true] ) AM_CONDITIONAL([MODPY], [test x$modpy = xtrue]) # Checks for libraries AM_PROG_LIBTOOL PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES([libconfig], [libconfig++ >= 1.4],, AC_MSG_ERROR([libconfig++ 1.4 or newer not found.]) ) PKG_CHECK_MODULES([log4cpp], [log4cpp >= 1.0],, AC_MSG_ERROR([log4cpp 1.0 or newer not found.]) ) PKG_CHECK_MODULES([psocksxx], [psocksxx >= 0.0.6],, AC_MSG_ERROR([psocksxx 0.0.6 or newer not found.]) ) # Checks for header files. #AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL AC_C_INLINE AC_TYPE_SIZE_T AC_CHECK_TYPES([ptrdiff_t]) # Checks for library functions. AC_FUNC_ERROR_AT_LINE AC_FUNC_FORK AC_CHECK_FUNCS([gethostbyname inet_ntoa memmove memset select socket strchr strerror]) # conditional statements AS_IF([test x$modpy = xtrue], [ AM_PATH_PYTHON([2.7]) AM_CHECK_PYTHON_HEADERS AM_CHECK_PYTHON_LIBS ] ) # defines / substitutes AS_IF([test "x$with_config" != xno], AC_DEFINE_UNQUOTED([BITZ_SERVER_CONFIG_FILE], ["$with_config"], [server configuration file] ), [ AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) AC_DEFINE_UNQUOTED( [BITZ_SERVER_CONFIG_FILE], ["${SYSCONFDIR}/bitz/bitz-server.conf"], [server configuration file] ) ] ) # doxygen AC_CHECK_PROGS([DOXYGEN], [doxygen], [false]) AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$DOXYGEN" != xfalse]) AM_COND_IF([HAVE_DOXYGEN],, AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) ) AC_CONFIG_FILES([ \ Makefile \ conf/Makefile \ doc/doxygen.cfg \ doc/Makefile \ include/Makefile \ lib/Makefile \ lib/icap/Makefile \ src/Makefile \ modules/Makefile \ modules/echo/Makefile \ modules/modpy/Makefile \ modules/modpy/modules/Makefile \ ]) AC_OUTPUT bitz-server-1.0.2/doc/000077500000000000000000000000001320426570600145405ustar00rootroot00000000000000bitz-server-1.0.2/doc/Makefile.am000066400000000000000000000006021320426570600165720ustar00rootroot00000000000000# doc/ # man man1_MANS = bitz-server.man man5_MANS = bitz-server.conf.man # extra dist files EXTRA_DIST = \ bitz-server.man \ bitz-server.conf.man # doxygen if HAVE_DOXYGEN .PHONY: doxygen-doc doxygen.stamp: $(DOXYGEN) doxygen.cfg echo timestamp > doxygen.stamp CLEANFILES = doxygen.stamp doxygen-doc: doxygen.stamp clean-local: rm -rf $(top_builddir)/doc/doxygen endif bitz-server-1.0.2/doc/bitz-server.conf.man000066400000000000000000000032141320426570600204350ustar00rootroot00000000000000.TH bitz-server.conf 5 "November 2015" Linux "File Formats Manual" .SH NAME bitz-server.conf \- bitz-server configuration file .SH SYNOPSIS .B /etc/bitz/bitz-server.conf .SH DESCRIPTION .BR bitz-server (1) obtains configuration data from a config file, the location of which is specified at compile-time and can be overridden by command-line options during run-time. .SS Grammer Below is the BNF grammar for configuration files. Comments and include directives are not part of the grammar, so they are not included here. See libconfig manual at http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar for more details. .PP .RS .nf configuration = setting-list | empty setting-list = setting | setting-list setting setting = name (":" | "=") value (";" | "," | empty) value = scalar-value | array | list | group value-list = value | value-list "," value scalar-value = boolean | integer | integer64 | hex | hex64 | float | string scalar-value-list = scalar-value | scalar-value-list "," scalar-value array = "[" (scalar-value-list | empty) "]" list = "(" (value-list | empty) ")" group = "{" (setting-list | empty) "}" empty = .fi .RE .PP Terminals are defined below as regular expressions: .TP .B boolean ([Tt][Rr][Uu][Ee])|([Ff][Aa][Ll][Ss][Ee]) .TP .B string \\"([^\\"\\\\]|\\\\.)*\\" .TP .B name [A-Za-z\\*][\-A-Za-z0-9_\\*]* .TP .B integer [\-+]?[0-9]+ .TP .B integer64 [\-+]?[0-9]+L(L)? .TP .B hex 0[Xx][0-9A-Fa-f]+ .TP .B hex64 0[Xx][0-9A-Fa-f]+L(L)? .TP .B float .nf ([\-+]?([0-9]*)?\\.[0-9]*([eE][-+]?[0-9]+)?)| ([\-+]([0-9]+)(\\.[0-9]*)?[eE][-+]?[0-9]+) .fi .SH AUTHOR Uditha Atukorala .SH "SEE ALSO" .BR bitz-server (1) bitz-server-1.0.2/doc/bitz-server.man000066400000000000000000000030031320426570600175050ustar00rootroot00000000000000.TH bitz-server 1 "November 2015" Linux "User Manuals" .SH NAME bitz-server \- An ICAP server .SH SYNOPSIS .B bitz-server [\-\-version] [\-\-help] [\-\-usage] [\-\-debug] [\-\-config=] .SH DESCRIPTION .B bitz-server is an ICAP server implementation in C++. Starting from scratch, the server is developed with a modular architecture in mind. The server core (written in C++) will handle the client requests, manage workers (child processes) etc. and will provide basic handlers to serve ICAP requests but won't do any actual content adaptation. .P To extend this core functionality and do some actual content adaptation a pluggable modules architecture is used. These modules will provide features like content filtering, anti-virus scanning etc. and to make it easier to write (and faster to implement) such modules a python interface module is included. .SH OPTIONS .TP .B \-\-version, \-v Prints version information .TP .B \-\-help, \-\-usage, \-h Prints the synopsis .TP .B \-\-debug Run the server in debug mode. This will force the server to run in the terminal rather than in the background. .TP .B \-\-config= Set the alternative config file to use instead of the compiled default. .SH FILES .I /etc/bitz/bitz-server.conf .RS Default configuration file. See .BR bitz-server.conf (5) for further details. .RE .SH BUGS Please report all bugs and feature requests at .SH AUTHOR Uditha Atukorala .SH "SEE ALSO" .BR bitz-server.conf (5) bitz-server-1.0.2/doc/doxygen.cfg.in000066400000000000000000000251511320426570600173070ustar00rootroot00000000000000# Doxyfile 1.8.7 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = @PACKAGE_NAME@ PROJECT_NUMBER = @PACKAGE_VERSION@ PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = @top_srcdir@ INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = YES EXCLUDE = @top_srcdir@/doc @top_srcdir@/README.md EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_DYNAMIC_SECTIONS = NO HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_SUBDIR = MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES bitz-server-1.0.2/include/000077500000000000000000000000001320426570600154165ustar00rootroot00000000000000bitz-server-1.0.2/include/Makefile.am000066400000000000000000000000141320426570600174450ustar00rootroot00000000000000## include/ bitz-server-1.0.2/lib/000077500000000000000000000000001320426570600145415ustar00rootroot00000000000000bitz-server-1.0.2/lib/Makefile.am000066400000000000000000000000461320426570600165750ustar00rootroot00000000000000## [bitz-server] lib/ SUBDIRS = icap bitz-server-1.0.2/lib/icap/000077500000000000000000000000001320426570600154555ustar00rootroot00000000000000bitz-server-1.0.2/lib/icap/Makefile.am000066400000000000000000000010461320426570600175120ustar00rootroot00000000000000## [icap-library] lib/icap/ AM_CPPFLAGS = -I$(top_srcdir)/lib ${psocksxx_CFLAGS} libicapincludedir = $(includedir)/icap lib_LTLIBRARIES = libicap.la libicap_la_LIBADD = ${psocksxx_LIBS} libicap_la_LDFLAGS = -version-info @ICAP_LT_VERSION@ -no-undefined libicap_la_SOURCES = \ header.cpp \ request_header.cpp \ response_header.cpp \ request.cpp \ response.cpp \ util.cpp libicapinclude_HEADERS = \ common.h \ header.h \ request_header.h \ response_header.h \ request.h \ response.h \ util.h bitz-server-1.0.2/lib/icap/common.h000066400000000000000000000024421320426570600171200ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_COMMON_H #define ICAP_COMMON_H #include namespace icap { /** * Payload structure common to both requests and responses. */ struct payload_t { std::string req_header; /**< request header */ std::string req_body; /**< request body */ std::string res_header; /**< response header */ std::string res_body; /**< response body */ bool ieof; /**< boolen flag to store the presence of "ieof" */ }; } /* end of namespace icap */ #endif /* !ICAP_COMMON_H */ bitz-server-1.0.2/lib/icap/header.cpp000066400000000000000000000121761320426570600174200ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "header.h" #include "util.h" #include #include namespace icap { Header::Header() { // initialise defaults _encapsulated["req-hdr"] = -1; _encapsulated["req-body"] = -1; _encapsulated["res-hdr"] = -1; _encapsulated["res-body"] = -1; _encapsulated["opt-body"] = -1; _encapsulated["null-body"] = -1; } Header::~Header() {} const Header::headers_t &Header::headers() const throw() { return _headers; } const std::string Header::value( const std::string &key ) throw() { std::string value = ""; Header::headers_index_t idx = _headers.find( key ); if ( idx != _headers.end() ) { value = idx->second; } return value; } const int Header::encapsulated_header( const std::string &entity ) throw() { Header::encapsulated_header_index_t idx; idx = _encapsulated.find( entity ); if ( idx == _encapsulated.end() ) { return -1; } return idx->second; } void Header::attach( std::string key, std::string value ) throw() { // trim key = util::trim( key ); value = util::trim( value ); // check for 'Encapsulated' headers if ( key == "Encapsulated" ) { attach_encapsulated( value ); } else { _headers[key] = value; } } bool Header::attach_encapsulated( std::string header_value ) throw() { std::vector list_data; std::vector entity_data; encapsulated_header_index_t idx; bool r_status = true; // grab the entity list [ req-hdr=0, null-body=170 ] list_data = util::split( util::trim( header_value ), "," ); for ( size_t i = 0; i < list_data.size(); i++ ) { // get entity data [ req-hdr=0 ] entity_data = util::split( util::trim( list_data.at( i ) ), "=" ); if ( entity_data.size() == 2 ) { idx = _encapsulated.find( util::trim( entity_data.at( 0 ) ) ); if ( idx != _encapsulated.end() ) { idx->second = atoi( util::trim( entity_data.at( 1 ) ).c_str() ); } } else { r_status = false; } } return r_status; } bool Header::remove( std::string key ) throw() { return ( (bool) _headers.erase( util::trim( key ) ) ); } const std::string Header::encapsulated_header_str() throw() { /* * Encapsulated request header grammer: * REQMOD request encapsulated_list: [reqhdr] reqbody * REQMOD response encapsulated_list: {[reqhdr] reqbody} | * {[reshdr] resbody} * RESPMOD request encapsulated_list: [reqhdr] [reshdr] resbody * RESPMOD response encapsulated_list: [reshdr] resbody * OPTIONS response encapsulated_list: optbody */ Header::encapsulated_header_index_t idx; std::string encaps_header = ""; // FIXME: chances are that we will always get the correct order // but should consider sorting for ( idx = _encapsulated.begin(); idx != _encapsulated.end(); idx++ ) { if ( idx->second > 0 ) { if ( encaps_header != "" ) { encaps_header.append( ", " ); } encaps_header.append( idx->first ).append( "=" ).append( util::itoa( idx->second ) ); } } // sanity check if ( encaps_header == "" ) { encaps_header = "null-body=0"; } return encaps_header; } void Header::update_encapsulated( const payload_t &payload ) throw() { unsigned int data_length = 0; unsigned int data_offset = 0; // request header if ( payload.req_header.size() > 0 ) { _encapsulated["req-hdr"] = data_length; data_offset = data_length; data_length += payload.req_header.size(); } // request body (POST data) if ( payload.req_body.size() > 0 ) { _encapsulated["req-body"] = data_length; data_offset = data_length; data_length += payload.req_body.size(); } // response header if ( payload.res_header.size() > 0 ) { _encapsulated["res-hdr"] = data_length; data_offset = data_length; data_length += payload.res_header.size(); } // response body if ( payload.res_body.size() > 0 ) { _encapsulated["res-body"] = data_length; data_offset = data_length; data_length += payload.res_body.size(); } // null-body if ( data_offset == 0 ) { _encapsulated["null-body"] = data_length; } } std::vector Header::sort_encapsulated_header() { std::vector data( _encapsulated.begin(), _encapsulated.end() ); std::sort(data.begin(), data.end(), encapsulated_header_compare()); return data; } } bitz-server-1.0.2/lib/icap/header.h000066400000000000000000000111531320426570600170570ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_HEADER_H #define ICAP_HEADER_H #include "common.h" #include #include #include #include namespace icap { class Header { public: /* headers data type */ typedef std::map headers_t; /* headers iterator type */ typedef headers_t::iterator headers_index_t; /* encapsulated header type */ typedef std::map encapsulated_header_t; /* encapsulated header iterator type */ typedef encapsulated_header_t::iterator encapsulated_header_index_t; /* encapsulated header data type */ typedef std::pair encapsulated_header_data_t; /** * Binary compare structure to compare two encapsulated header * entity (data) values. Used for sorting. */ struct encapsulated_header_compare : std::binary_function { inline bool operator()( const icap::Header::encapsulated_header_data_t &lhs, const icap::Header::encapsulated_header_data_t &rhs ) { return lhs.second < rhs.second; } }; Header(); virtual ~Header(); /** * Return headers * @return headers */ const headers_t &headers() const throw(); /** * Returns the header value for the given header key or an empty string * if the header is not found. * * @param key header key * @return header value */ const std::string value( const std::string &key ) throw(); /** * Return Encapsulated header value for the given entity * or -1 if the given entity is invalid. * * @param entity encapsulated header entity * @return -1 | encapsulated header value */ const int encapsulated_header( const std::string &entity ) throw(); /** * Attach header data into the header * *
		*   e.g.
		*   Host: icap-server.net
		*   Encapsulated: req-hdr=0, null-body=170
		*   [key]: [value]
		*   
* * @param key header key * @param value header value */ virtual void attach( std::string key, std::string value ) throw(); /** * Attach Encapsulated header data. This method should only be used * when reading a raw request / response. Consider using update_encapsulated() * method for other scenarios. * *
		*   e.g.
		*   Encapsulated: req-hdr=0, req-body=412
		*   Encapsulated: req-hdr=0, res-hdr=822, res-body=1655
		*   Encapsulated: [header_value]
		*   
* * @param header_value Encapsulated header value * @return boolean to denote success or failure */ virtual bool attach_encapsulated( std::string header_value ) throw(); /** * Update Encapsulated header data using the passed in (icap::payload_t) payload. * When the request / response has been populated with the payload, calling this * method will update the encapsulated header entities with appropriate values. * * This methos will always succeed. * * @param payload request or response payload */ virtual void update_encapsulated( const payload_t &payload ) throw(); /** * Remove header data from the header instance with the given key * * @param key header key * @return boolean to denote success or failure */ virtual bool remove( std::string key ) throw(); /** * Return Encapsulated header as a std::string value. * @return encapsulated header value (e.g. res-hdr=0, res-body=213) */ virtual const std::string encapsulated_header_str() throw(); /** * Sort the encapsulated header data and return a std::vector of * encapsulated_header_data_t. The actual header data won't be changed. * * @return sorted encapsulated header */ virtual std::vector sort_encapsulated_header(); protected: headers_t _headers; encapsulated_header_t _encapsulated; private: }; } /* end of namespace icap */ #endif /* !ICAP_HEADER_H */ bitz-server-1.0.2/lib/icap/request.cpp000066400000000000000000000033421320426570600176530ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "request.h" #include namespace icap { Request::Request( RequestHeader * req_header ) { _header = req_header; // initialise defaults _payload.req_header = ""; _payload.req_body = ""; _payload.res_header = ""; _payload.res_body = ""; _payload.ieof = false; } Request::~Request() { } RequestHeader * const Request::header() const throw() { return _header; } void Request::payload( payload_t payload ) throw() { _payload = payload; // update encapsulated data _header->update_encapsulated( _payload ); } const payload_t &Request::payload() const throw() { return _payload; } const int Request::preview_size() throw() { int size = -1; // grab the size from request header std::string s_size = _header->value( "Preview" ); // sanity check if (! s_size.empty() ) { // convert string to integer size = atoi( s_size.c_str() ); } return size; } } /* end of namespace icap */ bitz-server-1.0.2/lib/icap/request.h000066400000000000000000000034441320426570600173230ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_REQUEST_H #define ICAP_REQUEST_H #include "common.h" #include "request_header.h" namespace icap { class Request { public: Request( RequestHeader * req_header ); virtual ~Request(); /** * Return the request header * @return request header */ RequestHeader * const header() const throw(); /** * Set the payload data for this response instance from a * icap::payload_t data structure * * @param payload payload data structure */ void payload( payload_t payload ) throw(); /** * Return the payload data for this response instance * @return payload data */ const payload_t &payload() const throw(); /** * Returns the number of preview bytes in the request. If the preview * header is not present in the request then a minus (-1) value will be * returned. * * @return preview bytes */ const int preview_size() throw(); private: RequestHeader * _header; payload_t _payload; }; } /* end of namespace icap */ #endif /* !ICAP_REQUEST_H */ bitz-server-1.0.2/lib/icap/request_header.cpp000066400000000000000000000051451320426570600211660ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "request_header.h" #include "util.h" namespace icap { /* * sample icap request header: * REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0 * Host: icap-server.net * Encapsulated: req-hdr=0, null-body=170 * * [payload] */ RequestHeader::RequestHeader( const std::string &raw_data ) : Header() { // initialise defaults _request.method = ""; _request.uri = ""; _request.protocol = "ICAP/1.0"; // read header read_header( raw_data ); } RequestHeader::~RequestHeader() { } const std::string &RequestHeader::method() const throw() { return _request.method; } const std::string &RequestHeader::uri() const throw() { return _request.uri; } const std::string &RequestHeader::protocol() const throw() { return _request.protocol; } const RequestHeader::request_t &RequestHeader::request() const throw() { return _request; } const std::string &RequestHeader::raw_data() const throw() { return _raw_data; } void RequestHeader::read_header( const std::string &raw_data ) throw() { std::vector data; _raw_data = raw_data; data = util::split( raw_data, "\r\n" ); if ( data.size() > 0 ) { std::vector header_data; std::vector request; std::string request_data = data.at( 0 ); request = util::split( util::trim( request_data ) ); if ( request.size() == 3 ) { _request.method = request.at(0); _request.uri = request.at(1); _request.protocol = request.at(2); } else { // TODO: error, invalid request format } for ( int i = 1; i < data.size(); i++ ) { header_data = util::split( data.at( i ), ":" ); if ( header_data.size() == 2 ) { this->attach( header_data.at( 0 ), header_data.at( 1 ) ); } else { // TODO: error parsing header data } } } } } /* end of namespace icap */ bitz-server-1.0.2/lib/icap/request_header.h000066400000000000000000000035141320426570600206310ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_REQUEST_HEADER_H #define ICAP_REQUEST_HEADER_H #include "header.h" #include #include namespace icap { class RequestHeader : public Header { public: struct request_t { std::string method; std::string uri; std::string protocol; }; RequestHeader( const std::string &raw_data ); virtual ~RequestHeader(); /** * Return request method * @return method */ const std::string &method() const throw(); /** * Return request URI * @return URI */ const std::string &uri() const throw(); /** * Return request protocol * @return protocol */ const std::string &protocol() const throw(); /** * Return request * @return request */ const request_t &request() const throw(); /** * Return raw header data * @return raw request header */ const std::string &raw_data() const throw(); private: request_t _request; std::string _raw_data; void read_header( const std::string &raw_data ) throw(); }; } /* end of namespace icap */ #endif /* !ICAP_REQUEST_HEADER_H */ bitz-server-1.0.2/lib/icap/response.cpp000066400000000000000000000034211320426570600200170ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "response.h" namespace icap { Response::Response( ResponseHeader * header ) { if ( header != NULL ) { _header = header; _cleanup_header = false; } else { _header = new ResponseHeader( ResponseHeader::SERVER_ERROR ); _cleanup_header = true; } // initialise defaults _payload.req_header = ""; _payload.req_body = ""; _payload.res_header = ""; _payload.res_body = ""; _payload.ieof = false; } Response::Response( ResponseHeader::status_t status ) { _header = new ResponseHeader( status ); _cleanup_header = true; } Response::~Response() { // cleanup if ( _cleanup_header ) { delete _header; } } ResponseHeader * const Response::header() const throw() { return _header; } void Response::payload( payload_t payload ) throw() { _payload = payload; // update encapsulated data _header->update_encapsulated( _payload ); } const payload_t &Response::payload() const throw() { return _payload; } } /* end of namespace icap */ bitz-server-1.0.2/lib/icap/response.h000066400000000000000000000032111320426570600174610ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_RESPONSE_H #define ICAP_RESPONSE_H #include "common.h" #include "response_header.h" namespace icap { class Response { public: Response( ResponseHeader * response_header = NULL ); Response( ResponseHeader::status_t status ); virtual ~Response(); /** * Return the response header * @return response header */ ResponseHeader * const header() const throw(); /** * Set the payload data for this response instance from a * icap::payload_t data structure * * @param payload payload data structure */ void payload( payload_t payload ) throw(); /** * Return the payload data for this response instance * @return payload data */ const payload_t &payload() const throw(); private: ResponseHeader * _header; payload_t _payload; bool _cleanup_header; }; } /* end of namespace icap */ #endif /* !ICAP_RESPONSE_H */ bitz-server-1.0.2/lib/icap/response_header.cpp000066400000000000000000000043271320426570600213350ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "response_header.h" #include "util.h" #include #include #include namespace icap { ResponseHeader::ResponseHeader( status_t status ) : Header() { // FIXME: protocol shouldn't be hard-coded _response.protocol = "ICAP/1.0"; _response.status = status; // initialise default headers init_defaults(); } ResponseHeader::~ResponseHeader() { } const std::string &ResponseHeader::protocol() const throw() { return _response.protocol; } const ResponseHeader::status_t &ResponseHeader::status() const throw() { return _response.status; } void ResponseHeader::init_defaults() throw() { update_timestamp(); generate_istag(); attach( "Server", PACKAGE_STRING ); // close connection header if ( _response.status != ResponseHeader::CONTINUE ) { attach( "Connection" , "close" ); } } void ResponseHeader::update_timestamp() throw() { time_t raw_time; struct tm * time_info; char buffer [80]; time( &raw_time ); time_info = localtime( &raw_time ); strftime ( buffer, 80, "%c %Z", time_info ); attach( "Date", buffer ); } void ResponseHeader::generate_istag() throw() { time_t raw_time; clock_t clock_time; std::string istag; time( &raw_time ); clock_time = clock(); istag = "BITZ-"; istag.append( util::itoa( raw_time ) ).append( "-" ); istag.append( util::itoa( clock_time) ); attach( "ISTag", istag.substr( 0, 32 ) ); } } /* end of namespace icap */ bitz-server-1.0.2/lib/icap/response_header.h000066400000000000000000000035461320426570600210040ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_RESPONSE_HEADER_H #define ICAP_RESPONSE_HEADER_H #include "header.h" namespace icap { class ResponseHeader : public Header { public: enum status_t { CONTINUE = 100, OK = 200, NO_CONTENT = 204, BAD_REQUEST = 400, NOT_FOUND = 404, NOT_ALLOWED = 405, REQ_TIMEOUT = 408, SERVER_ERROR = 500, NOT_IMPLEMENTED = 501, BAD_GATEWAY = 502, SERVICE_OVERLOADED = 503, NOT_SUPPORTED = 505 }; struct response_t { std::string protocol; status_t status; }; ResponseHeader( status_t status ); virtual ~ResponseHeader(); /** * Return the response protocol * @return protocol */ const std::string &protocol() const throw(); /** * Return the response status * @return status */ const status_t &status() const throw(); private: response_t _response; void update_timestamp() throw(); void generate_istag() throw(); void init_defaults() throw(); }; } /* end of namespace icap */ #endif /* !ICAP_RESPONSE_HEADER_H */ bitz-server-1.0.2/lib/icap/util.cpp000066400000000000000000000356531320426570600171520ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "util.h" #include #include #include #include namespace icap { namespace util { unsigned int hextodec( const std::string &hex ) throw() { unsigned int dec; std::stringstream ss; ss << std::hex << hex; ss >> dec; return dec; } const std::string dectohex( const unsigned int &dec ) throw() { std::string hex; std::stringstream ss; ss << std::hex << dec; ss >> hex; return hex; } int read_line( psocksxx::iosockstream * socket, char * buf, int buf_length, bool incl_endl ) throw() { int i = 0; char c = '\0'; char c_last = '\0'; while ( i < ( buf_length - 1 ) ) { // read a char if ( ( c = socket->get() ) > 0 ) { // check last read char for \r if ( c_last == '\r' ) { // check for \n if ( c == '\n' ) { // include \r\n in the read buffer? if ( incl_endl ) { buf[i] = c; i++; } else { // remove \r i--; } break; } } buf[i] = c; i++; c_last = c; } else { break; // nothing read from socket } } buf[i] = '\0'; return i; } std::string read_line( psocksxx::iosockstream * socket, bool incl_endl ) throw() { int n; std::string line; char c = '\0'; char c_last = '\0'; while ( ( c = socket->get() ) > 0 ) { if ( c_last == '\r' ) { if ( c == '\n' ) { if ( incl_endl ) { line += c; } else { line.erase( line.size() - 1 ); } break; } } line += c; c_last = c; } return line; } std::string read_data( psocksxx::iosockstream * socket, int size ) throw() { char buffer[ICAP_BUFFER_SIZE]; std::string data = ""; int n; // loop until we have read all the bytes while ( size > 0 ) { try { // read from socket socket->read( buffer, std::min( size, ICAP_BUFFER_SIZE ) ); // sanity check if (! socket->good() ) { break; } // append to data data.append( buffer, socket->gcount() ); // update size with remaining bytes size -= socket->gcount(); } catch ( psocksxx::sockexception &e ) { // TODO: log errors ?? } } return data; } unsigned int read_chunk_size( psocksxx::iosockstream * socket ) throw() { std::string line; std::vector chunk_header; line = read_line( socket ); chunk_header = split( line, ";" ); return hextodec( chunk_header.at( 0 ) ); } void read_chunk_header( psocksxx::iosockstream * socket, chunk_t &chunk ) throw() { std::string line; std::vector chunk_header; line = read_line( socket ); chunk_header = split( line, ";" ); // sanity check if ( chunk_header.size() > 0 ) { // sanity check if ( chunk_header.at( 0 ).size() > 0 ) { chunk.size = hextodec( chunk_header.at( 0 ) ); } // check for chunk-extension if ( chunk_header.size() == 2 ) { chunk.extention = trim( chunk_header.at( 1 ) ); } } return; } chunk_t read_chunk( psocksxx::iosockstream * socket ) throw() { chunk_t chunk; std::string line; std::vector chunk_header; // initialise chunk chunk.size = 0; chunk.extention = ""; chunk.data = ""; // read chunk header read_chunk_header( socket, chunk ); // read chunk data if ( chunk.size > 0 ) { chunk.data = read_data( socket, chunk.size ); } // read \r\n ending for the chunk read_data( socket, 2 ); return chunk; } std::string read_chunked( psocksxx::iosockstream * socket ) throw() { unsigned int chunk_size = 0; unsigned int offset = 0; std::string chunked_data = ""; while ( ( chunk_size = read_chunk_size( socket ) ) > 0 ) { offset = chunked_data.size(); // read chunk-data chunked_data.append( read_data( socket, chunk_size ) ); // sanity check if ( ( chunked_data.size() - offset ) != chunk_size ) { // something went wrong break; } // extra \r\n read_data( socket, 2 ); } // read until the end of chunked data while ( read_line( socket, true ).size() > 2 ) ; return chunked_data; } bool read_chunked_payload( psocksxx::iosockstream * socket, std::string &payload ) throw() { chunk_t chunk; bool ieof = false; do { // read chunk chunk = read_chunk( socket ); // append to payload payload.append( chunk.data ); // sanity check if ( chunk.data.size() != chunk.size ) { // something went wrong break; } } while( chunk.size > 0 ); // check for ieof if ( chunk.extention == "ieof" ) { ieof = true; } return ieof; } bool send_line( const std::string &line, psocksxx::iosockstream * socket ) throw() { try { socket->write( line.c_str(), line.length() ); socket->write( "\r\n", 2 ); } catch ( psocksxx::sockexception &e ) { // TODO: log errors return false; } return true; } bool send_data( const std::string &data, psocksxx::iosockstream * socket ) throw() { try { socket->write( data.c_str(), data.size() ); } catch ( psocksxx::sockexception &e ) { // TODO: log errors return false; } return true; } bool send_chunked( const std::string &data, psocksxx::iosockstream * socket ) throw() { std::string chunked_data = ""; unsigned int offset = 0; int chunks = 0; // calculate the number of chunks we need if ( data.size() > ICAP_BUFFER_SIZE ) { chunks = ( data.size() / ICAP_BUFFER_SIZE ); } try { do { // prepare data for this chunk chunked_data = data.substr( offset, ICAP_BUFFER_SIZE ); // sanity check if ( chunked_data.size() <= 0 ) { // we shouldn't get here break; } // update offset offset += chunked_data.size(); // send chunk size if (! send_line( dectohex( chunked_data.size() ), socket ) ) { return false; } // send chunk if (! send_data( chunked_data, socket ) ) { return false; } chunks--; } while ( chunks > 0 ); // end of chunk if (! send_data( "\r\n0\r\n\r\n", socket ) ) { return false; } } catch ( psocksxx::sockexception &e ) { // TODO: log errors ?? return false; } return true; } std::vector split( const std::string &str, const std::string &delimiter ) throw() { std::vector result; size_t current; size_t next = -1; do { current = next + 1; next = str.find_first_of( delimiter, current ); result.push_back( str.substr( current, ( next - current ) ) ); } while ( next != std::string::npos ); return result; } std::string <rim( std::string &str ) throw() { str.erase( str.begin(), std::find_if( str.begin(), str.end(), std::not1( std::ptr_fun( std::isspace ) ) ) ); return str; } std::string &rtrim( std::string &str ) throw() { str.erase( std::find_if( str.rbegin(), str.rend(), std::not1( std::ptr_fun( std::isspace ) ) ).base(), str.end() ); return str; } std::string &trim( std::string &str ) throw() { return ltrim( rtrim( str ) ); } icap::RequestHeader * read_req_header( psocksxx::iosockstream * socket ) throw() { char buffer[ICAP_BUFFER_SIZE]; int n = 0; std::string data = ""; while ( ( n = read_line( socket, buffer, ICAP_BUFFER_SIZE, true ) ) > 2 ) { data.append( buffer ); } icap::RequestHeader * req_header = new icap::RequestHeader( data ); return req_header; } bool read_req_data( icap::Request * request, psocksxx::iosockstream * socket ) throw() { int data_offset = 0; int data_length = 0; int data_read = 0; std::vector sorted_encaps_header; std::vector::iterator sorted_idx; // payload icap::payload_t payload; payload.req_header = ""; payload.req_body = ""; payload.res_header = ""; payload.res_body = ""; payload.ieof = false; // header icap::Header * header = request->header(); sorted_encaps_header = header->sort_encapsulated_header(); // loop through the sorted header for ( sorted_idx = sorted_encaps_header.begin(); sorted_idx != sorted_encaps_header.end(); sorted_idx++ ) { // don't want to read negative headers if ( sorted_idx->second < 0 ) { continue; } // if this is the last header entity then check for chunked content if ( sorted_idx == ( sorted_encaps_header.end() - 1 ) ) { if ( sorted_idx->first == "req-body" ) { payload.ieof = read_chunked_payload( socket, payload.req_body ); } else if ( sorted_idx->first == "res-body" ) { payload.ieof = read_chunked_payload( socket, payload.res_body ); } else { /* * null-body is the only other legal possibility here * we take that into account in the previous iterations */ break; } } else { data_offset = sorted_idx->second; data_length = ( ( sorted_idx + 1 )->second - data_offset ); /* read request data */ // is there anything to read? if ( data_length > 0 ) { // update payload if ( sorted_idx->first == "req-hdr" ) { payload.req_header = read_data( socket, data_length ); } else if ( sorted_idx->first == "req-body" ) { payload.req_body = read_data( socket, data_length ); } else if ( sorted_idx->first == "res-hdr" ) { payload.res_header = read_data( socket, data_length ); } else if ( sorted_idx->first == "res-body" ) { payload.res_body = read_data( socket, data_length ); } else { // TODO: error? } } } } // update request request->payload( payload ); return true; } bool read_req_continue_data( icap::Request * request, psocksxx::iosockstream * socket ) throw() { std::vector sorted_encaps_header; icap::Header::encapsulated_header_data_t header_idx; // copy the payload from request so we can append to it icap::payload_t payload; payload.req_header = request->payload().req_header; payload.req_body = request->payload().req_body; payload.res_header = request->payload().res_header; payload.res_body = request->payload().res_body; payload.ieof = request->payload().ieof; // header icap::Header * header = request->header(); sorted_encaps_header = header->sort_encapsulated_header(); // sanity check if ( sorted_encaps_header.size() > 0 ) { // we are only interested in the last header entity header_idx = sorted_encaps_header.back(); // read payload data if ( header_idx.first == "req-body" ) { payload.ieof = read_chunked_payload( socket, payload.req_body ); } else if ( header_idx.first == "res-body" ) { payload.ieof = read_chunked_payload( socket, payload.res_body ); } } else { // something isn't quite right return false; } // update request request->payload( payload ); return true; } bool send_headers( icap::Header * header, psocksxx::iosockstream * socket ) throw() { std::string line; icap::Header::headers_index_t i; icap::ResponseHeader::headers_t headers; // headers headers = header->headers(); for ( i = headers.begin(); i != headers.end(); i++ ) { line = i->first; line.append( ": " ); line.append( i->second ); if (! send_line( line, socket ) ) { return false; } } // send encapsulated header line = "Encapsulated: "; line.append( header->encapsulated_header_str() ); if (! send_line( line, socket ) ) { return false; } // end of header if (! send_data( "\r\n", socket ) ) { return false; } return true; } bool send_response( icap::Response * response, psocksxx::iosockstream * socket ) throw() { bool r_success = true; icap::ResponseHeader * header; // grab the response header header = response->header(); // response status std::string line = header->protocol(); line.append( " " ); line.append( itoa( header->status() ) ); line.append( " " ); line.append( response_status( header->status() ) ); r_success = send_line( line, socket ); // response headers if ( r_success ) { r_success = send_headers( header, socket ); } // response content (if there are any) if ( r_success ) { // req-hdr if ( response->payload().req_header.size() > 0 ) { send_data( response->payload().req_header, socket ); } // red-body if ( response->payload().req_body.size() > 0 ) { send_chunked( response->payload().req_body, socket ); } // res-hdr if ( response->payload().res_header.size() > 0 ) { send_data( response->payload().res_header, socket ); } // res-body if ( response->payload().res_body.size() > 0 ) { send_chunked( response->payload().res_body, socket ); } } // flush-out socket stream buffer socket->flush(); return r_success; } const std::string response_status( const ResponseHeader::status_t &status ) throw() { // FIXME: probably there's a better way of mapping this std::map status_text; status_text[ResponseHeader::CONTINUE] = "Continue"; status_text[ResponseHeader::OK] = "OK"; status_text[ResponseHeader::NO_CONTENT] = "No modifications needed"; status_text[ResponseHeader::BAD_REQUEST] = "Bad request"; status_text[ResponseHeader::NOT_FOUND] = "ICAP Service not found"; status_text[ResponseHeader::NOT_ALLOWED] = "Method not allowed for service"; status_text[ResponseHeader::REQ_TIMEOUT] = "Request timeout"; status_text[ResponseHeader::SERVER_ERROR] = "Server error"; status_text[ResponseHeader::NOT_IMPLEMENTED] = "Method not implemented"; status_text[ResponseHeader::BAD_GATEWAY] = "Bad gateway"; status_text[ResponseHeader::SERVICE_OVERLOADED] = "Service overloaded"; status_text[ResponseHeader::NOT_SUPPORTED] = "ICAP version not supported by server"; return status_text[status]; } } /* end of namespace util */ } /* end of namespace icap */ bitz-server-1.0.2/lib/icap/util.h000066400000000000000000000176141320426570600166140ustar00rootroot00000000000000/* * C++ ICAP library * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ICAP_UTIL_H #define ICAP_UTIL_H #include #include #include "request.h" #include "response.h" #ifndef ICAP_BUFFER_SIZE #define ICAP_BUFFER_SIZE 1024 #endif namespace icap { namespace util { struct chunk_t { unsigned int size; std::string extention; std::string data; }; /** * Convert a number into a string * * @param number number to be converted * @return converted string */ template std::string itoa( T number ) { std::ostringstream ss; ss << number; return ss.str(); } /** * Convert a hexadecimal number to a decimal number. * * @param hex hex to convert to * @return converted decimal value */ unsigned int hextodec( const std::string &hex ) throw(); /** * Convert a decimal number to its hexadecimal value * * @param dec decimal number * @return converted hex value */ const std::string dectohex( const unsigned int &dec ) throw(); /** * Read a line (ending with \r\n) from the socket * * @param socket socket to read from * @param buf buffer to read the data into * @param buf_length length / size of the buffer data is read into * @param incl_endl (optional) switch to control whether to include \r\n in the read line, * default is false. * @return number of bytes read */ int read_line( psocksxx::iosockstream * socket, char * buf, int buf_length, bool incl_endl = false ) throw(); /** * Read a line (ending with \r\n) from the socket * * @param socket socket instance to read data from * @param incl_endl (optional) switch to control whether to include \r\n in the read line, * default is false. * @return read data */ std::string read_line( psocksxx::iosockstream * socket, bool incl_endl = false ) throw(); /** * Read data from the socket * * @param socket socket instance to read data from * @param size size / length of data to be read * @return read data */ std::string read_data( psocksxx::iosockstream * socket, int size ) throw(); /** * Read chunk size. This is a helper method used by read_chunked(). * * @param socket socket instance to read from * @return chunk size */ unsigned int read_chunk_size( psocksxx::iosockstream * socket ) throw(); /** * Read chunk header from the given socket. * * @param socket socket instance to read data from * @param chunk chunk data structure to store header data */ void read_chunk_header( psocksxx::iosockstream * socket, chunk_t &chunk ) throw(); /** * Read a data chunk from a HTTP chunked transfer encoded data stream. * * @param socket socket instance to read data from * @return chunk data structure */ chunk_t read_chunk( psocksxx::iosockstream * socket ) throw(); /** * Read chunked data from the given socket * * @param socket socket instance to read data from * @return read data (without the control characters) */ std::string read_chunked( psocksxx::iosockstream * socket ) throw(); /** * Read chunked payload data from the given socket * * @param socket socket instance to read data from * @param payload payload to read data into * @return boolean flag to denote the presence of "ieof" */ bool read_chunked_payload( psocksxx::iosockstream * socket, std::string &payload ) throw(); /** * Send / write a line (ending with \r\n) to the socket * * @param line line to send through the socket without the line-ending chars * @param socket socket object to write the data to * @return boolean to denote success or failure */ bool send_line( const std::string &line, psocksxx::iosockstream * socket ) throw(); /** * Send / write data to the socket. * If chunked is set to true then data will be transferred using * "chunked" transfer-encoding. * * @param data data to be sent * @param socket socket instance to write to * @return boolean to denote success or failure */ bool send_data( const std::string &data, psocksxx::iosockstream * socket ) throw(); /** * Send / write data to the socket using chunked transfer encoding * * @param data data to be sent * @param socket socket instance to write to * @return boolean to denote success or failure */ bool send_chunked( const std::string &data, psocksxx::iosockstream * socket ) throw(); /** * split a string into a vector by the given delimiter * * @param str input string * @param delimiter (optional) delimiter, defaults to " " */ std::vector split( const std::string &str, const std::string &delimiter = " " ) throw(); /** * Left trim (trim from start) a passed in string * * @param str string to trim * @return trimmed string */ std::string <rim( std::string &str ) throw(); /** * Right trim (trim from end) a passed in string * * @param str string to trim * @return trimmed string */ std::string &rtrim( std::string &str ) throw(); /** * Trim (trim from both ends) a passed in string * * @param str string to trim * @return trimmed string */ std::string &trim( std::string &str ) throw(); /** * Read icap request header from the socket passes in * * @param socket socket object to read data from * @return icap request header object */ icap::RequestHeader * read_req_header( psocksxx::iosockstream * socket ) throw(); /** * Read icap request into the icap::Request instance * using the socket passed in * * @param request request object to read data into * @param socket socket object to read data from * @return boolean to denote success or failure */ bool read_req_data( icap::Request * request, psocksxx::iosockstream * socket ) throw(); /** * Read icap request data after a '100 Continue' response. This will not look for any * additional headers and will treat any data coming through the socket as payload data. * * @param request request object to read data into * @param socket socket object to read data from * @return boolean to denote success or failure */ bool read_req_continue_data( icap::Request * request, psocksxx::iosockstream * socket ) throw(); /** * Send / write header data to a socket * * @param headers headers to be sent * @param socket socket object to write the data to * @return boolean to denote success or failure */ bool send_headers( icap::Header::headers_t headers, psocksxx::iosockstream * socket ) throw(); /** * Output a response using the passed in icap::Response class to the * passed in socket * * @param response response object to get the response data from * @param socket socket object to send the data to * @return boolean to denote success or failure */ bool send_response( icap::Response * response, psocksxx::iosockstream * socket ) throw(); /** * Returns the response status text for the given status * * @param status status to get the text for */ const std::string response_status( const ResponseHeader::status_t &status ) throw(); } /* end of namespace util */ } /* end of namespace icap */ #endif /* !ICAP_UTIL_H */ bitz-server-1.0.2/modules/000077500000000000000000000000001320426570600154435ustar00rootroot00000000000000bitz-server-1.0.2/modules/Makefile.am000066400000000000000000000000421320426570600174730ustar00rootroot00000000000000## modules/ SUBDIRS = echo modpy bitz-server-1.0.2/modules/echo/000077500000000000000000000000001320426570600163615ustar00rootroot00000000000000bitz-server-1.0.2/modules/echo/Makefile.am000066400000000000000000000004061320426570600204150ustar00rootroot00000000000000# modules/echo AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src modlibdir = $(pkglibdir)/modules modlib_LTLIBRARIES = mod_echo.la mod_echo_la_LDFLAGS = -module -avoid-version mod_echo_la_SOURCES = \ echo.h echo.cpp bitz-server-1.0.2/modules/echo/echo.cpp000066400000000000000000000030661320426570600200100ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "echo.h" namespace bitz { Echo::Echo() : Modifier() { } Echo::~Echo() { } icap::Response * Echo::modify( icap::Request * request ) throw() { icap::Response * response; icap::payload_t payload; // copy payload from request payload.req_header = request->payload().req_header; payload.req_body = request->payload().req_body; payload.res_header = request->payload().res_header; payload.res_body = request->payload().res_body; response = new icap::Response( icap::ResponseHeader::OK ); response->payload( payload ); return response; } icap::Response * Echo::preview( icap::Request * request ) throw() { // 100 - continue always return new icap::Response( icap::ResponseHeader::CONTINUE ); } } /* end of namespace bitz */ bitz-server-1.0.2/modules/echo/echo.h000066400000000000000000000024571320426570600174600ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_ECHO_H #define BITZ_ECHO_H #include namespace bitz { class Echo : public Modifier { public: Echo(); virtual ~Echo(); icap::Response * modify( icap::Request * request ) throw(); icap::Response * preview( icap::Request * request ) throw(); private: }; } /* end of namespace bitz */ /* class factories */ extern "C" bitz::Modifier * create() { return new bitz::Echo; } extern "C" void destroy( bitz::Modifier * m ) { delete m; } #endif /* !BITZ_ECHO_H */ bitz-server-1.0.2/modules/modpy/000077500000000000000000000000001320426570600165735ustar00rootroot00000000000000bitz-server-1.0.2/modules/modpy/Makefile.am000066400000000000000000000006471320426570600206360ustar00rootroot00000000000000# modules/modpy SUBDIRS = modules if MODPY modlibdir = $(pkglibdir)/modules modlib_LTLIBRARIES = mod_py.la mod_py_la_LDFLAGS = -module -avoid-version mod_py_la_SOURCES = \ py.h py.cpp \ interface.h interface.cpp AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src \ ${PYTHON_INCLUDES} ${libconfig_CFLAGS} ${log4cpp_CFLAGS} mod_py_la_LIBADD = ${PYTHON_LIBS} endif bitz-server-1.0.2/modules/modpy/interface.cpp000066400000000000000000000122151320426570600212400ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "interface.h" #include #include #include #include PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest ) { PyObject * pyreturn; PyObject * pypayload; icap::Request * request; // logger bitz::Logger &logger = bitz::Logger::instance(); logger.debug( "[modpy.interface] get_request()" ); // initialise return dictionary pyreturn = PyDict_New(); // grab the request object pointer from args void * p = PyCapsule_GetPointer( pyrequest, "request" ); // sanity check if ( p != NULL ) { // construct the request request = static_cast(p); PyDict_SetItemString( pyreturn, "request", PyString_FromString( request->header()->method().c_str() ) ); PyDict_SetItemString( pyreturn, "uri", PyString_FromString( request->header()->uri().c_str() ) ); PyDict_SetItemString( pyreturn, "protocol", PyString_FromString( request->header()->protocol().c_str() ) ); // payload dictionary pypayload = PyDict_New(); PyDict_SetItemString( pypayload, "req_header", PyString_FromStringAndSize( request->payload().req_header.c_str(), request->payload().req_header.size() ) ); PyDict_SetItemString( pypayload, "req_body", PyString_FromStringAndSize( request->payload().req_body.c_str(), request->payload().req_body.size() ) ); PyDict_SetItemString( pypayload, "res_header", PyString_FromStringAndSize( request->payload().res_header.c_str(), request->payload().res_header.size() ) ); PyDict_SetItemString( pypayload, "res_body", PyString_FromStringAndSize( request->payload().res_body.c_str(), request->payload().res_body.size() ) ); PyDict_SetItemString( pypayload, "ieof", PyBool_FromLong( request->payload().ieof ) ); PyDict_SetItemString( pyreturn, "payload", pypayload ); // cleanup Py_DECREF( pypayload ); } else { logger.warn( "[modpy.interface] failed to get request object pointer" ); } return pyreturn; } PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args ) { PyObject * pyresponse; icap::Response * response; unsigned int resp_status; // logger bitz::Logger &logger = bitz::Logger::instance(); logger.debug( "[modpy.interface] get_response_from_status()" ); // parse args if ( PyArg_ParseTuple( args, "I", &resp_status ) ) { response = new icap::Response( (icap::ResponseHeader::status_t) resp_status ); } else { logger.warn( "[modpy.interface] failed to parse arguments" ); response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } // convert the response into a capsule pyresponse = PyCapsule_New( (void *) response, "response", NULL ); return pyresponse; } PyObject * bitz_get_response( PyObject * self, PyObject * args ) { PyObject * pyresponse; PyObject * pypayload; icap::Response * response = NULL; unsigned int resp_status; icap::payload_t payload; // vars to ferry across strings from python dictionary to c++ char * pybuffer; Py_ssize_t pybuflen; // logger bitz::Logger &logger = bitz::Logger::instance(); logger.debug( "[modpy.interface] get_response()" ); // parse args if ( PyArg_ParseTuple( args, "IO!", &resp_status, &PyDict_Type, &pypayload ) ) { // copy strings from python dictionary PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_header" ), &pybuffer, &pybuflen ); payload.req_header.assign( pybuffer, pybuflen ); PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_body" ), &pybuffer, &pybuflen ); payload.req_body.assign( pybuffer, pybuflen ); PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_header" ), &pybuffer, &pybuflen ); payload.res_header.assign( pybuffer, pybuflen ); PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_body" ), &pybuffer, &pybuflen ); payload.res_body.assign( pybuffer, pybuflen ); // copy other data types from python dictionary payload.ieof = PyBool_Check( PyDict_GetItemString( pypayload, "ieof" ) ); // construct the response object response = new icap::Response( (icap::ResponseHeader::status_t) resp_status ); response->payload( payload ); } else { logger.warn( "[modpy.interface] failed to parse arguments" ); } // sanity check if ( response == NULL ) { response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } // convert the response into a capsule pyresponse = PyCapsule_New( (void *) response, "response", NULL ); return pyresponse; } bitz-server-1.0.2/modules/modpy/interface.h000066400000000000000000000031001320426570600206760ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_MODPY_INTERFACE_H #define BITZ_MODPY_INTERFACE_H #include #include PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest ); PyObject * bitz_get_response( PyObject * self, PyObject * args ); PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args); static PyMethodDef bitz_methods[] = { { "get_request", bitz_get_request, METH_O, "Convert a capsule request into a python dictionary" }, { "get_response", bitz_get_response, METH_VARARGS, "Get a response capsule (takes in status and payload dictionary as args)" }, { "get_response_from_status", bitz_get_response_from_status, METH_VARARGS, "Get a response capsule from a response status" }, { NULL, NULL, 0, NULL } }; #endif /* !BITZ_MODPY_INTERFACE_H */ bitz-server-1.0.2/modules/modpy/modules/000077500000000000000000000000001320426570600202435ustar00rootroot00000000000000bitz-server-1.0.2/modules/modpy/modules/Makefile.am000066400000000000000000000002361320426570600223000ustar00rootroot00000000000000# modules/modpy/modules # extra dist files EXTRA_DIST = \ modpy.py if MODPY modpydir = $(pkglibdir)/modules/modpy modpy_DATA = modpy.py endif bitz-server-1.0.2/modules/modpy/modules/modpy.py000066400000000000000000000017311320426570600217470ustar00rootroot00000000000000# # modpy.py # Copyright (c) 2013 Uditha Atukorala # import bitz def init(): print( "init() called" ); def cleanup(): print( "cleanup() called" ); def preview( request ): request = bitz.get_request( request ); req_payload = request['payload']; print( "preview payload: \r\n", req_payload ); # response if req_payload['ieof']: response = bitz.get_response_from_status( 204 ); else: response = bitz.get_response_from_status( 100 ); return response; def modify( request ): request = bitz.get_request( request ); req_payload = request['payload']; print( "modify payload: \r\n", req_payload ); # response resp_payload = {}; resp_payload['req_header'] = req_payload['req_header']; resp_payload['req_body'] = req_payload['req_body']; resp_payload['res_header'] = req_payload['res_header']; resp_payload['res_body'] = req_payload['res_body']; resp_payload['ieof'] = True; response = bitz.get_response( 200, resp_payload ); return response; bitz-server-1.0.2/modules/modpy/py.cpp000066400000000000000000000141351320426570600177330ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "py.h" #include "interface.h" #include #include namespace bitz { Py::Py() : Modifier() { // defaults _pymodule = NULL; // initialise Py::config_t values _config.module_name = "modpy"; _config.module_path = ""; // load configs load_configs(); // initialise python init_python(); } Py::~Py() { // cleanup python cleanup_python(); } icap::Response * Py::modify( icap::Request * request ) throw() { // get the modify response return python_response( request, "modify" ); } icap::Response * Py::preview( icap::Request * request ) throw() { // get the preview response return python_response( request, "preview" ); } void Py::load_configs() throw() { std::string s; Config &server_config = Config::instance(); // interface module name s = server_config.module_config( "modpy", "module_name" ); if ( s != "" ) { _config.module_name = s; } // module lookup path _config.module_path = server_config.module_config( "modpy", "module_path" ); } void Py::init_python() throw() { PyObject * sys_path; PyObject * pymodule_path, * pymodule_name; PyObject * pymethod; PyObject * pyreturn; // logger Logger &logger = Logger::instance(); // python core Py_Initialize(); // bitz python module if ( Py_InitModule( "bitz", bitz_methods ) == NULL ) { logger.warn( "[modpy] failed to init C interface module: bitz" ); } // setup python environment if ( _config.module_path != "" ) { logger.debug( std::string( "[modpy] appending to sys.path, module_path: " ).append( _config.module_path ) ); sys_path = PySys_GetObject( (char *) "path" ); pymodule_path = PyString_FromString( _config.module_path.c_str() ); PyList_Append( sys_path, pymodule_path ); } // load the interface module logger.debug( std::string( "[modpy] interface module: " ).append( _config.module_name ) ); pymodule_name = PyString_FromString( _config.module_name.c_str() ); _pymodule = PyImport_Import( pymodule_name ); if ( _pymodule != NULL ) { logger.debug( "[modpy] interface module loaded successfully" ); // call init() in the interface module pymethod = PyObject_GetAttrString( _pymodule, "init" ); if ( pymethod && PyCallable_Check( pymethod ) ) { pyreturn = PyObject_CallObject( pymethod, NULL ); Py_DECREF( pyreturn ); } else { logger.warn ( "[modpy] failed to call init() in interface module" ); } Py_DECREF( pymethod ); } else { logger.warn( "[modpy] failed to load interface module" ); } // cleanup Py_DECREF( pymodule_name ); Py_DECREF( pymodule_path ); Py_DECREF( sys_path ); } void Py::cleanup_python() throw() { PyObject * pymethod; PyObject * pyreturn; // logger Logger &logger = Logger::instance(); // cleanup if ( _pymodule != NULL ) { // call cleanup() in the interface module pymethod = PyObject_GetAttrString( _pymodule, "cleanup" ); if ( pymethod && PyCallable_Check( pymethod ) ) { pyreturn = PyObject_CallObject( pymethod, NULL ); Py_DECREF( pyreturn ); } else { logger.warn ( "[modpy] failed to call cleanup() in interface module" ); } Py_DECREF( pymethod ); Py_DECREF( _pymodule ); } // finalise python core Py_Finalize(); } icap::Response * Py::python_response( icap::Request * request, const std::string &method ) throw() { /* * notes: * + pass icap::Request to python module as a PyCapsule object * so it can be used to grab the data needed using the C/C++ interface. * + process data (within the python module) and use the C/C++ interface * to create a icap::Response and pass it back to this method * using a PyCapsule object */ icap::Response * response; PyObject * pymethod; PyObject * pyargs; PyObject * pyrequest, * pyresponse; // logger Logger &logger = Logger::instance(); // initialise the response object response = NULL; // check for the interface module if ( _pymodule != NULL ) { /* call the [method]() in the interface module */ pymethod = PyObject_GetAttrString( _pymodule, method.c_str() ); pyargs = PyTuple_New( 1 ); pyrequest = PyCapsule_New( (void *) request, "request", NULL ); PyTuple_SetItem( pyargs, 0, pyrequest ); if ( pymethod && PyCallable_Check( pymethod ) ) { // get the response capsule pyresponse = PyObject_CallObject( pymethod, pyargs ); // sanity check if ( pyresponse != NULL ) { void * p = PyCapsule_GetPointer( pyresponse, "response" ); // sanity check if ( p != NULL ) { // construct the response response = static_cast(p); } else { logger.warn( std::string( "[modpy] invalid capsule response, method: " ).append( method ) ); } Py_DECREF( pyresponse ); } else { logger.warn( std::string( "[modpy] response is NULL, method: " ).append( method ) ); } } else { logger.warn ( std::string( "[modpy] failed to call the method in interface module, method: " ).append( method ) ); } // cleanup // pyrequest is created from the reference passed in Py_DECREF( pyargs ); Py_DECREF( pymethod ); } // sanity check if ( response == NULL ) { response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } return response; } } /* end of namespace bitz */ bitz-server-1.0.2/modules/modpy/py.h000066400000000000000000000031671320426570600174030ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_PY_H #define BITZ_PY_H #include #include namespace bitz { class Py : public Modifier { public: struct config_t { std::string module_path; std::string module_name; }; Py(); virtual ~Py(); icap::Response * modify( icap::Request * request ) throw(); icap::Response * preview( icap::Request * request ) throw(); private: config_t _config; PyObject * _pymodule; void load_configs() throw(); void init_python() throw(); void cleanup_python() throw(); icap::Response * python_response( icap::Request * request, const std::string &method ) throw(); }; } /* end of namespace bitz */ /* class factories */ extern "C" bitz::Modifier * create() { return new bitz::Py; } extern "C" void destroy( bitz::Modifier * m ) { delete m; } #endif /* !BITZ_PY_H */ bitz-server-1.0.2/src/000077500000000000000000000000001320426570600145625ustar00rootroot00000000000000bitz-server-1.0.2/src/Makefile.am000066400000000000000000000021071320426570600166160ustar00rootroot00000000000000## src/ AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = -I$(top_srcdir)/lib ${libconfig_CFLAGS} ${log4cpp_CFLAGS} ${psocksxx_CFLAGS} bitzincludedir = $(pkgincludedir) sbin_PROGRAMS = bitz-server bitz_server_LDFLAGS = -ldl -export-dynamic bitz_server_LDADD = $(top_builddir)/lib/icap/libicap.la \ ${libconfig_LIBS} ${log4cpp_LIBS} \ ${psocksxx_LIBS} bitz_server_SOURCES = main.cpp \ bitz-server.h bitz-server.cpp \ bitz/exception.h bitz/exception.cpp \ bitz/manager_exception.h bitz/manager_exception.cpp \ bitz/config.h bitz/config.cpp \ bitz/logger.h bitz/logger.cpp \ bitz/common.h \ bitz/util.h bitz/util.cpp \ bitz/manager.h bitz/manager.cpp \ bitz/worker.h bitz/worker.cpp \ bitz/request_handler.h bitz/request_handler.cpp \ bitz/options_request_handler.h bitz/options_request_handler.cpp \ bitz/reqmod_request_handler.h bitz/reqmod_request_handler.cpp \ bitz/respmod_request_handler.h bitz/respmod_request_handler.cpp \ bitz/modifier.cpp bitzinclude_HEADERS = \ bitz/config.h \ bitz/logger.h \ bitz/modifier.h bitz-server-1.0.2/src/bitz-server.cpp000066400000000000000000000241351320426570600175470ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include "bitz-server.h" namespace bitz { namespace server { static server_t globals; void init() { // initialise defaults globals.pid_handle = -1; globals.manager = NULL; globals.terminating = 0; globals.daemon = false; // logger (syslog) setlogmask( LOG_UPTO( LOG_INFO ) ); openlog( PACKAGE_NAME, LOG_CONS, LOG_USER ); // signal handlers init_signal_handlers(); } void init_signal_handlers() { sigset_t ignore_mask; // set signal mask - signals we want to block sigemptyset(&ignore_mask); sigaddset(&ignore_mask, SIGTSTP); // ignore Tty stop signals sigaddset(&ignore_mask, SIGTTOU); // ignore Tty background writes sigaddset(&ignore_mask, SIGTTIN); // ignore Tty background reads sigprocmask(SIG_BLOCK, &ignore_mask, NULL); // block the above specified signals init_sigchld_handler(); init_sigterm_handler(); init_sigquit_handler(); init_sigint_handler(); } void init_sigchld_handler() { struct sigaction sa; // block all other signals sigfillset( &sa.sa_mask ); // signal handler proc sa.sa_sigaction = &sigchld_handler; // flags sa.sa_flags = SA_SIGINFO; if ( sigaction( SIGCHLD, &sa, NULL ) < 0 ) { exit( EXIT_FAILURE ); } } void sigchld_handler( int sig, siginfo_t *siginfo, void *context ) { pid_t worker_pid; int status; std::cout << "[" << getpid() << "] inside zombie deleter: "; while ( ( worker_pid = waitpid( WAIT_ANY, &status, WNOHANG ) ) > 0 ) { std::cout << "child " << worker_pid << " terminated with status " << status << std::endl; if ( globals.manager != NULL ) { globals.manager->reap_worker( worker_pid ); } } } void init_sigterm_handler() { struct sigaction sa; // block all other signals sigfillset( &sa.sa_mask ); // signal handler proc sa.sa_sigaction = &sigterm_handler; // flags sa.sa_flags = SA_SIGINFO; if ( sigaction( SIGTERM, &sa, NULL ) < 0 ) { exit( EXIT_FAILURE ); } } void sigterm_handler( int sig, siginfo_t *siginfo, void *context ) { std::cout << "[" << getpid() << "] inside SIGTERM handler" << std::endl; termination_handler( sig, siginfo, context ); } void init_sigquit_handler() { struct sigaction sa; // block all other signals sigfillset( &sa.sa_mask ); // signal handler proc sa.sa_sigaction = &sigquit_handler; // flags sa.sa_flags = SA_SIGINFO; if ( sigaction( SIGQUIT, &sa, NULL ) < 0 ) { exit( EXIT_FAILURE ); } } void sigquit_handler( int sig, siginfo_t *siginfo, void *context ) { std::cout << "[" << getpid() << "] inside SIGQUIT handler" << std::endl; termination_handler( sig, siginfo, context ); } void init_sigint_handler() { struct sigaction sa; // block all other signals sigfillset( &sa.sa_mask ); // signal handler proc sa.sa_sigaction = &sigint_handler; // flags sa.sa_flags = SA_SIGINFO; if ( sigaction( SIGINT, &sa, NULL ) < 0 ) { exit( EXIT_FAILURE ); } } void sigint_handler( int sig, siginfo_t *siginfo, void *context ) { std::cout << "[" << getpid() << "] inside SIGQINT handler" << std::endl; termination_handler( sig, siginfo, context ); } void daemonize( const char *rundir, const char *pidfile ) { pid_t pid, sid; long i; char str[10]; // notify syslog( LOG_NOTICE, "starting daemon (version %s)", PACKAGE_VERSION ); // check parent process id value if ( getppid() == 1 ) { // we are already a daemon return; } /* fork daemon */ pid = fork(); if ( pid < 0 ) { exit( EXIT_FAILURE ); } // exit the parent if ( pid > 0 ) { exit( EXIT_SUCCESS ); } /* child (a.k.a daemon) continues */ // set file permissions (750) umask( 027 ); // get a new process group sid = setsid(); if ( sid < 0 ) { exit(EXIT_FAILURE); } // route I/O connections close( STDIN_FILENO ); close( STDOUT_FILENO ); close( STDERR_FILENO ); // change running directory chdir( rundir ); /* lock pid file to ensure we have only one copy */ globals.pid_handle = open( pidfile, O_RDWR | O_CREAT, 0600 ); if ( globals.pid_handle == -1 ) { syslog( LOG_ERR, "could not open pid lock file: %s", pidfile ); exit( EXIT_FAILURE ); } if ( lockf( globals.pid_handle, F_TLOCK, 0 ) == -1 ) { syslog( LOG_ERR, "could not lock pid lock file: %s", pidfile); exit( EXIT_FAILURE ); } // get and format pid sprintf( str, "%d\n", getpid() ); // write pid to lockfile write( globals.pid_handle, str, strlen( str ) ); // update status globals.daemon = true; } void shutdown() { // notify if ( globals.daemon && ( getppid() == 1 ) ) { syslog( LOG_NOTICE, "shutting down daemon (version %s)", PACKAGE_VERSION ); } // close pid file if ( globals.pid_handle != -1 ) { close( globals.pid_handle ); } // close logger (syslog) closelog(); } void termination_handler( int sig, siginfo_t * sig_info, void * context ) { std::cout << "[" << getpid() << "] inside termination handler" << std::endl; // exit by re-raising the signal if termination // already in progress if ( globals.terminating ) { std::cout << "[" << getpid() << "] already terminating" << std::endl; raise( sig ); } // update termination status globals.terminating = 1; if ( globals.manager != NULL ) { // shutdown the manager globals.manager->shutdown(); // clean-up delete globals.manager; } // cleanup shutdown(); // re-raise the signal after reactivating the signal's default action signal( sig, SIG_DFL ); raise( sig ); } options_t read_options( int argc, char **argv ) { int optidx, optchar; options_t options; options.config_file = ""; struct option lopts[] = { { "config", required_argument, 0, 'c' }, { "debug", no_argument, &options.debug_flag, 1 }, { "help", no_argument, 0, 'h' }, { "usage", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; while ( true ) { optidx = 0; optchar = getopt_long( argc, argv, "c:hv", lopts, &optidx ); // sanity check if ( optchar == -1 ) { break; } switch ( optchar ) { case 0: // TODO: break; case 'c': options.config_file = optarg; break; case 'h': print_usage(); exit( EXIT_SUCCESS ); break; case 'v': print_version(); exit( EXIT_SUCCESS ); case '?': print_usage(); exit( EXIT_FAILURE ); break; default: // TODO: break; } } return options; } void print_version() { std::cout << PACKAGE_STRING << std::endl; std::cout << "" << std::endl; std::cout << "Copyright (C) 2012-2013 Uditha Atukorala" << std::endl; std::cout << "" << std::endl; std::cout << "This program is free software; you can redistribute it and/or modify" << std::endl; std::cout << "it under the terms of the GNU General Public License as published by" << std::endl; std::cout << "the Free Software Foundation; either version 3 of the License, or" << std::endl; std::cout << "(at your option) any later version." << std::endl; std::cout << "" << std::endl; std::cout << "This program is distributed in the hope that it will be useful," << std::endl; std::cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << std::endl; std::cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << std::endl; std::cout << "GNU General Public License (http://gnu.org/licenses/gpl.html)" << std::endl; std::cout << "for more details." << std::endl; std::cout << "" << std::endl; } void print_usage() { std::cout << "usage: " << PACKAGE_NAME << " " << "[--version] [--help] [--usage] [--debug] [--config=]" << std::endl; std::cout << "" << std::endl; std::cout << "See the man pages for more information" << std::endl; } void start( int port, unsigned int children, int max_requests, int comm_timeout ) { try { globals.manager = new bitz::Manager( port ); globals.manager->spawn( children, max_requests, comm_timeout ); } catch ( bitz::ManagerException &mex ) { syslog( LOG_ERR, "failed to start, exception: %s", mex.what() ); exit( EXIT_FAILURE ); } } void run() { sigset_t mask, oldmask; // sanity check if ( globals.manager == NULL ) { return; } // block termination signals until we are ready sigemptyset( &mask ); sigaddset( &mask, SIGTERM ); sigaddset( &mask, SIGQUIT ); sigaddset( &mask, SIGINT ); sigprocmask ( SIG_BLOCK, &mask, &oldmask ); // loop until a termination signal is received while (! globals.terminating ) { // capture any signals sigsuspend( &oldmask ); // unblock termination signals sigprocmask( SIG_UNBLOCK, &mask, NULL ); // manage workers globals.manager->manager_workers(); // block termination signals sigprocmask( SIG_BLOCK, &mask, &oldmask ); } } } /* end of namespace server */ } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz-server.h000066400000000000000000000064201320426570600172110ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_SERVER_H #define BITZ_SERVER_H #include "bitz/manager.h" #include namespace bitz { namespace server { /** * Structure to hold server globals initialised * by the init() method. */ struct server_t { int pid_handle; volatile sig_atomic_t terminating; bool daemon; bitz::Manager * manager; }; /** * Structure to hold command line options. */ struct options_t { int debug_flag; std::string config_file; }; void init(); void init_signal_handlers(); void init_sigchld_handler(); void init_sigterm_handler(); void init_sigquit_handler(); void init_sigint_handler(); void sigchld_handler( int sig, siginfo_t * sig_info, void * context ); void sigterm_handler( int sig, siginfo_t * sig_info, void * context ); void sigquit_handler( int sig, siginfo_t * sig_info, void * context ); void sigint_handler( int sig, siginfo_t * sig_info, void * context ); void daemonize( const char * run_dir, const char * pid_file ); void shutdown(); void termination_handler( int sig, siginfo_t * sig_info, void * context ); /** * Read command line options and return a options_t structure. * This method will terminate the program with an exit status * of EXIT_FAILURE if any errors are found while reading options. * If --version or --help options are found this will print the * appropriate message to the standard output and terminate with * EXIT_SUCCESS. * * @param argc same as main() argc * @param argv same as main() argv * @return read options */ options_t read_options( int argc, char **argv ); /** * Print version information to the standard output */ void print_version(); /** * Print usage message to the standard output */ void print_usage(); /** * Start the server by creating a bitz::Manager instance and spawn * workers. * * @param port port number to listen to * @param children number of children to spawn * @param max_request maximum number of requests that a child will serve * @param comm_timeout communication timeout value in seconds */ void start( int port, unsigned int children, int max_requests, int comm_timeout ); /** * Run the server managing workers until a termination signal is received. * This process will never return, instead the termination signal will * end the process. */ void run(); } /* end of namespace server */ } /* end of namespace bitz */ #endif /* !BITZ_SERVER_H */ bitz-server-1.0.2/src/bitz/000077500000000000000000000000001320426570600155325ustar00rootroot00000000000000bitz-server-1.0.2/src/bitz/common.h000066400000000000000000000022311320426570600171710ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_COMMON_H #define BITZ_COMMON_H #include #include #include "request_handler.h" namespace bitz { /* request handlers type */ typedef std::map req_handlers_t; /* iterator type */ typedef req_handlers_t::iterator req_handlers_index_t; } /* end of namespace bitz */ #endif /* !BITZ_COMMIN_H */ bitz-server-1.0.2/src/bitz/config.cpp000066400000000000000000000127231320426570600175100ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "logger.h" #include #include namespace bitz { Config::Config() { // initialise config_t values _config.port = 1344; _config.pid_file = "/dev/null"; _config.log_file = "/dev/null"; _config.log_category = "bitz"; _config.req_handlers_count = 0; _config.req_handlers = NULL; _config.max_workers = 0; _config.max_worker_requests = 0; _config.comm_timeout = 0; // defaults _lconfig = NULL; } Config::~Config() { // cleanup delete _lconfig; for (int i = 0; i < _config.req_handlers_count ; i++ ) { if ( _config.req_handlers[i].modules_count > 0 ) { delete [] _config.req_handlers[i].modules; } } if ( _config.req_handlers != NULL ) { delete [] _config.req_handlers; } } const config_t &Config::initialise( const std::string &config_file ) { libconfig::Config * config; config = new libconfig::Config; try { config->readFile( config_file.c_str() ); } catch ( const libconfig::FileIOException &ex ) { std::cerr << "[config] failed to read config file: " << config_file << ", exception: " << ex.what() << std::endl; exit( EXIT_FAILURE ); } catch ( const libconfig::ParseException &pex ) { std::cerr << "[config] parse error at " << pex.getFile() << ":" << pex.getLine() << " - " << pex.getError() << std::endl; exit( EXIT_FAILURE ); } try { // read core configs config->lookupValue( "port", _config.port ); config->lookupValue( "pid_file", _config.pid_file ); config->lookupValue( "log_file", _config.log_file ); config->lookupValue( "log_category", _config.log_category ); config->lookupValue( "max_workers", _config.max_workers ); config->lookupValue( "max_worker_requests", _config.max_worker_requests ); config->lookupValue( "comm_timeout", _config.comm_timeout ); } catch ( const libconfig::SettingNotFoundException &e ) { std::cerr << "[config] failed to load core configs, " << e.getPath() << " : " << e.what() << std::endl; } // cache configs _lconfig = config; // read other configs read_req_handler_configs(); return _config; } const config_t &Config::configs() { return _config; } const std::string Config::module_config( const std::string &module, const std::string &config ) throw() { std::string config_value = ""; if ( _lconfig->exists( "modules" ) ) { try { libconfig::Setting &setting = _lconfig->lookup( std::string( "modules." ).append( module ) ); setting.lookupValue( config, config_value ); } catch ( const libconfig::SettingNotFoundException &e ) { // TODO: log errors ?? std::cerr << "[config] " << e.getPath() << " : " << e.what() << std::endl; } } else { std::cout << "[config] 'modules' configs not found" << std::endl; } return config_value; } void Config::read_req_handler_configs() throw() { int i, j; std::string s; std::cout << "[config] looking for req_handlers... "; if ( _lconfig->exists( "req_handlers" ) ) { std::cout << "found "; libconfig::Setting &req_handlers = _lconfig->lookup( "req_handlers" ); _config.req_handlers_count = req_handlers.getLength(); _config.req_handlers = new req_handlers_config_t[_config.req_handlers_count]; std::cout << "(" << _config.req_handlers_count << ")" << std::endl; try { // read request handler configs for ( i = 0; i < _config.req_handlers_count ; i++ ) { _config.req_handlers[i].name = (const char *) req_handlers[i]["handler"]; _config.req_handlers[i].class_name = (const char *) req_handlers[i]["class"]; // read request handler modules config std::cout << "[config] looking for " << _config.req_handlers[i].name << " modules... "; if ( req_handlers[i].exists( "modules" ) ) { std::cout << "found "; _config.req_handlers[i].modules_count = req_handlers[i]["modules"].getLength(); _config.req_handlers[i].modules = new modules_config_t[_config.req_handlers[i].modules_count]; std::cout << "(" << _config.req_handlers[i].modules_count << ")" << std::endl; for ( j = 0; j < _config.req_handlers[i].modules_count; j++ ) { _config.req_handlers[i].modules[j].name = (const char *) req_handlers[i]["modules"][j]["name"]; _config.req_handlers[i].modules[j].module = (const char *) req_handlers[i]["modules"][j]["module"]; } } else { std::cout << "not found" << std::endl; } } } catch ( const libconfig::SettingNotFoundException &ex ) { std::cerr << "[config] Error: " << ex.getPath() << ex.what() << std::endl; } } else { std::cout << "not found" << std::endl; } } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/config.h000066400000000000000000000045221320426570600171530ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_CONFIG_H #define BITZ_CONFIG_H #include #include #ifndef BITZ_SERVER_CONFIG_FILE #define BITZ_SERVER_CONFIG_FILE "/etc/bitz/bitz-server.conf" #endif namespace bitz { struct modules_config_t { std::string name; std::string module; }; struct req_handlers_config_t { std::string name; std::string class_name; unsigned int modules_count; modules_config_t * modules; }; struct config_t { int port; int max_workers; int max_worker_requests; int comm_timeout; std::string pid_file; std::string log_file; std::string log_category; unsigned int req_handlers_count; req_handlers_config_t * req_handlers; }; class Config { public: static Config &instance() { static Config config; return config; } const config_t &initialise( const std::string &config_file = BITZ_SERVER_CONFIG_FILE ); const config_t &configs(); /** * Returns module specific config value (or NULL string if not found) * Note: This method should be only used my the pluggable modules and not * by the core code. * * @param module module name * @param config config name * @return module config value */ const std::string module_config( const std::string &module, const std::string &config ) throw(); private: config_t _config; libconfig::Config * _lconfig; Config(); ~Config(); Config( Config const © ); Config &operator=( const Config © ); void read_req_handler_configs() throw(); }; } /* end of namespace bitz */ #endif /* !BITZ_CONFIG_H */ bitz-server-1.0.2/src/bitz/exception.cpp000066400000000000000000000024301320426570600202330ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exception.h" #include // For errno #include // For strerror namespace bitz { Exception::Exception( const std::string &message, bool inclSystemMessage ) throw() : _message( message ) { if ( inclSystemMessage ) { _message.append( " : " ); _message.append( strerror( errno ) ); } } Exception::~Exception() throw() { } const char * Exception::what() const throw() { return _message.c_str(); } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/exception.h000066400000000000000000000024251320426570600177040ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_EXCEPTION_H #define BITZ_EXCEPTION_H #include // for exception class #include // for std::string namespace bitz { class Exception : public std::exception { public: Exception( const std::string &message, bool inclSystemMessage = false ) throw(); virtual ~Exception() throw(); virtual const char * what() const throw(); private: std::string _message; }; } /* end of namespace bitz */ #endif /* !BITZ_EXCEPTION_H */ bitz-server-1.0.2/src/bitz/logger.cpp000066400000000000000000000054621320426570600175240ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "logger.h" #include #include namespace bitz { Logger::Logger( std::string log_file, std::string category ) { this->LOGGER = NULL; this->initialise( log_file, category ); } Logger::~Logger() { this->LOGGER->debug( "closing down logger" ); } void Logger::initialise( std::string log_file, std::string category ) { this->LOGGER = &log4cpp::Category::getInstance( category ); // setting up appender, layout and category log4cpp::Appender * log_appender = new log4cpp::FileAppender( "FileAppender", log_file ); log4cpp::PatternLayout * log_layout = new log4cpp::PatternLayout(); log_layout->setConversionPattern( "%d %p %c %x: %m%n" ); log_appender->setLayout( log_layout ); this->LOGGER->setAppender( log_appender ); this->LOGGER->setPriority( this->getPriorityValue( "DEBUG" ) ); this->LOGGER->debug( "logger initialised, log_file: " + log_file ); } int Logger::getPriorityValue( const std::string &priority ) { return ( log4cpp::Priority::getPriorityValue( priority ) ); } void Logger::log( log4cpp::Priority::Value priority, const std::string &message ) { this->LOGGER->log( priority, message ); } void Logger::fatal( const std::string& message ) { this->LOGGER->fatal( message ); } void Logger::emerg( const std::string& message ) { this->LOGGER->emerg( message ); } void Logger::alert( const std::string& message ) { this->LOGGER->alert( message ); } void Logger::crit( const std::string& message ) { this->LOGGER->crit( message ); } void Logger::error( const std::string& message ) { this->LOGGER->error( message ); } void Logger::warn( const std::string& message ) { this->LOGGER->warn( message ); } void Logger::notice( const std::string& message ) { this->LOGGER->notice( message ); } void Logger::info( const std::string& message ) { this->LOGGER->info( message ); } void Logger::debug( const std::string& message ) { this->LOGGER->debug( message ); } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/logger.h000066400000000000000000000036421320426570600171670ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_LOGGER_H #define BITZ_LOGGER_H #include #include namespace bitz { class Logger { public: static Logger &instance( std::string log_file = "/dev/null" , std::string category = "logger" ) { static Logger logger( log_file, category ); return logger; } void initialise( std::string log_file, std::string category ); static int getPriorityValue( const std::string& priority ); void log( int priority, const std::string &message ); void fatal( const std::string& message ); void emerg( const std::string& message ); void alert( const std::string& message ); void crit( const std::string& message ); void error( const std::string& message ); void warn( const std::string& message ); void notice( const std::string& message ); void info( const std::string& message ); void debug( const std::string& message ); private: log4cpp::Category * LOGGER; Logger( std::string log_file, std::string category ); ~Logger(); Logger( Logger const © ); Logger &operator=( const Logger © ); }; } /* end of namespace bitz */ #endif /* !BITZ_LOGGER_H */ bitz-server-1.0.2/src/bitz/manager.cpp000066400000000000000000000144041320426570600176530ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "manager.h" #include "logger.h" #include "util.h" #include #include #include namespace bitz { Manager::Manager( unsigned short port, const std::string &address, int backlog ) throw( ManagerException ) { // initialise manager _manager.worker = false; _manager.max_workers = 0; _manager.max_worker_requests = 0; _manager.comm_timeout = 0; _manager.workers_count = 0; _manager.worker_id = 0; _manager.socket = NULL; _manager.worker_pool = NULL; // initialise listening socket try { // network socket address psocksxx::nsockaddr naddr( address.c_str(), port ); _manager.socket = new psocksxx::tcpnsockstream(); _manager.socket->bind( &naddr, true ); _manager.socket->listen( backlog ); } catch ( psocksxx::sockexception &e ) { throw ManagerException( std::string( "failed to initialise socket, " ).append( e.what() ) ); } Logger &logger = Logger::instance(); logger.debug( "manager initialised" ); } Manager::~Manager() { Logger &logger = Logger::instance(); if ( _manager.worker ) { logger.debug( "[worker] cleaning up manager" ); } else { logger.debug( "[manager] shutting down manager" ); } delete [] _manager.worker_pool; delete _manager.socket; } void Manager::spawn( unsigned int max_workers, unsigned int max_worker_requests, unsigned int comm_timeout ) throw( ManagerException ) { _manager.max_workers = max_workers; _manager.max_worker_requests = max_worker_requests; _manager.comm_timeout = comm_timeout; _manager.worker_pool = new worker_pool_t[max_workers]; // pre-fork workers if (! _manager.worker ) { for ( unsigned int i = 0; i < max_workers; i++ ) { try { spawn_worker( i ); } catch ( ManagerException &mex ) { throw mex; } } } } void Manager::spawn_worker( unsigned int worker_id ) throw( ManagerException ) { Logger &logger = Logger::instance(); pid_t worker_pid; // create a worker child worker_pid = fork(); if ( worker_pid == -1 ) { throw ManagerException( "failed to create worker", true ); } if ( worker_pid == 0 ) { /* worker */ _manager.worker = true; _manager.worker_id = worker_id; _manager.worker_pool[worker_id].worker = new Worker(); _manager.worker_pool[worker_id].worker_id = worker_id; _manager.worker_pool[worker_id].worker_pid = worker_pid; _manager.worker_pool[worker_id].worker->run( _manager.socket, _manager.max_worker_requests, _manager.comm_timeout ); logger.info( std::string( "end of cycle, worker[" ).append( util::itoa( worker_id ) ).append( "]" ) ); delete _manager.worker_pool[worker_id].worker; _exit( EXIT_SUCCESS ); } else { /* manager */ logger.info( std::string( "[manager] worker spawned with pid: " ).append( util::itoa( worker_pid) ) ); _manager.workers_count++; _manager.worker = false; _manager.worker_pool[worker_id].worker = NULL; _manager.worker_pool[worker_id].worker_id = worker_id; _manager.worker_pool[worker_id].worker_pid = worker_pid; } } void Manager::shutdown( bool graceful ) throw() { // logger Logger &logger = Logger::instance(); if ( _manager.worker ) { logger.info( "[worker] manager shutdown request received" ); /* worker: cleanup */ delete _manager.worker_pool[_manager.worker_id].worker; } else { /* manager: stop all child processes */ logger.info( "[manager] shutdown request received" ); for (unsigned int i = 0; i < _manager.max_workers; i++ ) { if ( _manager.worker_pool[i].worker_pid != 0 ) { if ( graceful ) { kill( _manager.worker_pool[i].worker_pid, SIGTERM ); logger.debug( std::string( "[manager] sending SIGTERM to worker[" ).append( util::itoa( i ) ) .append( "], pid: " ).append( util::itoa( _manager.worker_pool[i].worker_pid ) ) ); } else { kill( _manager.worker_pool[i].worker_pid, SIGKILL ); logger.debug( std::string( "[manager] sending SIGKILL to worker[" ).append( util::itoa( i ) ) .append( "], pid: " ).append( util::itoa( _manager.worker_pool[i].worker_pid ) ) ); } } else { logger.debug( std::string( "[manager] worker[" ).append( util::itoa( i ) ).append( "] already closed" ) ); } } } } void Manager::reap_worker( pid_t worker_pid ) throw() { // logger Logger &logger = Logger::instance(); logger.debug( std::string( "reaping worker, pid: " ).append( util::itoa( worker_pid ) ) ); if (! _manager.worker ) { for (unsigned int i = 0; i < _manager.max_workers; i++ ) { if ( _manager.worker_pool[i].worker_pid == worker_pid ) { // reap the dead worker _manager.worker_pool[i].worker_pid = 0; _manager.workers_count--; // break out the loop break; } } } } void Manager::manager_workers() throw() { // logger Logger &logger = Logger::instance(); if (! _manager.worker ) { // check the worker count while ( _manager.workers_count != _manager.max_workers ) { // we are missing workers, find out who for (unsigned int i = 0; i < _manager.max_workers; i++ ) { if ( _manager.worker_pool[i].worker_pid == 0 ) { try { // spawn a worker for the missing spawn_worker( i ); } catch ( ManagerException &mex ) { logger.warn( std::string( "[manager] failed to spawn worker[" ).append( util::itoa( i ) ).append( "], exception: ").append( mex.what() ) ); } } } } } } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/manager.h000066400000000000000000000044001320426570600173130ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_MANAGER_H #define BITZ_MANAGER_H #include #include #include "manager_exception.h" #include "worker.h" #ifndef BITZ_MAX_WORKERS #define BITZ_MAX_WORKERS 2 #endif #ifndef BITZ_MAX_WORKER_REQUESTS #define BITZ_MAX_WORKER_REQUESTS 100 #endif namespace bitz { class Manager { public: struct worker_pool_t { pid_t worker_pid; unsigned int worker_id; Worker * worker; }; struct manager_t { bool worker; unsigned int max_workers; unsigned int max_worker_requests; unsigned int comm_timeout; unsigned int workers_count; unsigned int worker_id; psocksxx::tcpnsockstream * socket; worker_pool_t * worker_pool; }; /** * Note: backlog = SOMAXCONN (from sys/socket.h) */ Manager( unsigned short port, const std::string &address = "0.0.0.0", int backlog = 128 ) throw( ManagerException ); /** * deconstructor */ virtual ~Manager(); virtual void spawn( unsigned int max_workers = BITZ_MAX_WORKERS, unsigned int max_worker_requests = BITZ_MAX_WORKER_REQUESTS, unsigned int comm_timeout = 0 ) throw( ManagerException ); virtual void shutdown( bool graceful = true ) throw(); virtual void reap_worker( pid_t worker_pid ) throw(); virtual void manager_workers() throw(); private: manager_t _manager; virtual void spawn_worker( unsigned int worker_id ) throw( ManagerException ); }; } /* end of namespace bitz */ #endif /* !BITZ_MANAGER_H */ bitz-server-1.0.2/src/bitz/manager_exception.cpp000066400000000000000000000021331320426570600217250ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "manager_exception.h" namespace bitz { ManagerException::ManagerException( const std::string &message, bool inclSystemMessage ) throw() : Exception( message, inclSystemMessage ) { // constructor } ManagerException::~ManagerException() throw() { } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/manager_exception.h000066400000000000000000000022361320426570600213760ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_MANAGER_EXCEPTION_H #define BITZ_MANAGER_EXCEPTION_H #include "exception.h" namespace bitz { class ManagerException: public Exception { public: ManagerException( const std::string &message, bool inclSystemMessage = false ) throw(); virtual ~ManagerException() throw(); }; } /* end of namespace bitz */ #endif /* BITZ_MANAGER_EXCEPTION_H */ bitz-server-1.0.2/src/bitz/modifier.cpp000066400000000000000000000016571320426570600200450ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "modifier.h" namespace bitz { Modifier::Modifier() { } Modifier::~Modifier() { } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/modifier.h000066400000000000000000000035211320426570600175020ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_MODIFIER_H #define BITZ_MODIFIER_H #include #include namespace bitz { class Modifier { public: /* types of the class factories */ typedef bitz::Modifier * create_t(); typedef void destroy_t( bitz::Modifier * ); struct symbols_t { void * modifier; create_t * create; destroy_t * destroy; }; Modifier(); virtual ~Modifier(); /** * Modify the request as needed and return a response object. * * @param request request object * @return response object */ virtual icap::Response * modify( icap::Request * request ) throw() =0; /** * Preview the request passed in and return a response object. The * response status of 100 (continue) should be handled by the caller * and pass the complete request to modify() method. * * @param request request object * @return response object */ virtual icap::Response * preview( icap::Request * request ) throw() =0; private: }; } /* end of namespace bitz */ #endif /* !BITZ_MODIFIER_H */ bitz-server-1.0.2/src/bitz/options_request_handler.cpp000066400000000000000000000033231320426570600231770ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "options_request_handler.h" namespace bitz { OptionsRequestHandler::OptionsRequestHandler() : RequestHandler( "OPTIONS" ) { } OptionsRequestHandler::~OptionsRequestHandler() { } icap::Response * OptionsRequestHandler::process( icap::RequestHeader * req_header, psocksxx::iosockstream * socket ) throw() { icap::ResponseHeader * header; icap::Response * response; // header header = new icap::ResponseHeader( icap::ResponseHeader::OK ); // FIXME: Methods are tied to the URIs header->attach( "Methods", _methods.at( 0 ) ); header->attach( "Options-TTL", "3600" ); header->attach( "Allow", "204" ); response = new icap::Response( header ); return response; } void OptionsRequestHandler::register_handler( RequestHandler * req_handler ) throw() { // FIXME: Methods are tied to the URIs _methods.push_back( req_handler->method() ); return; } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/options_request_handler.h000066400000000000000000000027431320426570600226510ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_OPTIONS_REQUEST_HANDLER_H #define BITZ_OPTIONS_REQUEST_HANDLER_H #include "request_handler.h" namespace bitz { class OptionsRequestHandler : public RequestHandler { public: OptionsRequestHandler(); virtual ~OptionsRequestHandler(); icap::Response * process( icap::RequestHeader * req_header, psocksxx::iosockstream * socket ) throw(); /** * Register a request handler so it is known to the OPTIONS * handler * * @param req_handler request handler */ void register_handler( RequestHandler * req_handler ) throw(); private: std::vector _methods; }; } /* end of namespace bitz */ #endif /* !BITZ_OPTIONS_REQUEST_HANDLER_H */ bitz-server-1.0.2/src/bitz/reqmod_request_handler.cpp000066400000000000000000000020131320426570600227660ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "reqmod_request_handler.h" namespace bitz { ReqmodRequestHandler::ReqmodRequestHandler() : RequestHandler( "REQMOD" ) { } ReqmodRequestHandler::~ReqmodRequestHandler() { } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/reqmod_request_handler.h000066400000000000000000000022101320426570600224320ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_REQMOD_REQUEST_HANDLER_H #define BITZ_REQMOD_REQUEST_HANDLER_H #include "request_handler.h" namespace bitz { class ReqmodRequestHandler : public RequestHandler { public: ReqmodRequestHandler(); virtual ~ReqmodRequestHandler(); private: }; } /* end of namespace bitz */ #endif /* !BITZ_REQMOD_REQUEST_HANDLER_H */ bitz-server-1.0.2/src/bitz/request_handler.cpp000066400000000000000000000235661320426570600214370ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "request_handler.h" #include "config.h" #include "logger.h" #include "util.h" #include #include namespace bitz { RequestHandler::RequestHandler( const std::string &method ) { // initialise defaults _handlers_count = 0; _handlers = NULL; // update variables _req_handler.method = method; // load modifier modules load_modules(); } RequestHandler::~RequestHandler() { // cleanup modifier modules cleanup_modules(); if ( _handlers != NULL ) { delete [] _handlers; } Logger &logger = Logger::instance(); logger.debug( std::string( "[req] exiting request handler [" ).append( _req_handler.method ).append( "]" ) ); } const std::string &RequestHandler::method() const throw() { return _req_handler.method; } icap::Response * RequestHandler::process( icap::RequestHeader * req_header, psocksxx::iosockstream * socket ) throw() { icap::Request * request; icap::Response * response = NULL; // logger Logger &logger = Logger::instance(); // request request = new icap::Request( req_header ); // read request data if (! icap::util::read_req_data( request, socket ) ) { logger.warn( "[req] failed to read request data" ); response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } else { logger.debug( std::string( "[req] payload.req-hdr:\r\n").append( request->payload().req_header ) ); logger.debug( std::string( "[req] payload.req-body:\r\n").append( request->payload().req_body ) ); logger.debug( std::string( "[req] payload.res-hdr:\r\n").append( request->payload().res_header ) ); logger.debug( std::string( "[req] payload.res-body:\r\n").append( request->payload().res_body ) ); // check for message preview if ( request->preview_size() >= 0 ) { // process preview logger.debug( std::string( "[req] message preview request, preview: " ).append( util::itoa( request->preview_size() ) ) ); response = process_preview( request, socket ); } /* * When we get here, if the response is NULL then either this is a * pure REQMOD request without message preview or the preview was * inconclusive (i.e. 100 Continue) and we have requested for the full * request. */ if ( response == NULL ) { // process modify logger.debug( "[req] modify request" ); response = process_modify( request ); } } // cleanup delete request; // sanity check if ( response == NULL ) { logger.warn( "[req] no valid response from modifiers, creating a server error (500) response" ); response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } return response; } bool RequestHandler::load_modifier( const std::string &file, Modifier::symbols_t &symbols ) throw() { // logger Logger &logger = Logger::instance(); // vars const char* dlsym_error; // load the modifier module logger.debug( "[req] loading modifier: " + file ); symbols.modifier = dlopen( file.c_str(), RTLD_LAZY | RTLD_LOCAL ); if (! symbols.modifier ) { logger.warn( std::string( "[req] failed to load modifier: " ).append( file ).append( dlerror() ) ); return false; } // reset errors dlerror(); // load the symbols symbols.create = ( Modifier::create_t * ) dlsym( symbols.modifier, "create" ); dlsym_error = dlerror(); if ( dlsym_error ) { logger.warn( std::string( "[req] failed to load create symbol: " ).append( dlsym_error ) ); return false; } symbols.destroy = ( Modifier::destroy_t * ) dlsym( symbols.modifier, "destroy" ); dlsym_error = dlerror(); if ( dlsym_error ) { logger.warn( std::string( "[req] failed to load destroy symbol: " ).append( dlsym_error ) ); return false; } return true; } void RequestHandler::unload_modifier( void * modifier ) throw() { // unload the modifier module dlclose( modifier ); } void RequestHandler::load_modules() throw() { int i = 0; int j = 0; const bitz::config_t &config = Config::instance().configs(); // search for request handlers for ( i = 0; i < config.req_handlers_count; i++ ) { // we are only interested in handlers for the current method (e.g. REQMOD, RESPMOD) if ( config.req_handlers[i].name == method() ) { if ( config.req_handlers[i].modules_count > 0 ) { _handlers_count = config.req_handlers[i].modules_count; _handlers = new handler_t[_handlers_count]; // search for request handler modules for (j = 0; j < _handlers_count; j++ ) { // load module if ( load_modifier( config.req_handlers[i].modules[j].module, _handlers[j].symbols ) ) { _handlers[j].name = config.req_handlers[i].modules[j].name; } else { _handlers[j].name = ""; // FIXME: error handling } } } // not interested in duplicate config entries break; } } } void RequestHandler::cleanup_modules() throw() { int i = 0; // logger Logger &logger = Logger::instance(); for ( i = 0; i < _handlers_count; i++ ) { logger.debug( std::string( "[req] unloading module: " ).append( _handlers[i].name ) ); // unload unload_modifier( _handlers[i].symbols.modifier ); } } icap::Response * RequestHandler::process_preview( icap::Request * request, psocksxx::iosockstream * socket ) throw() { icap::Response * response = NULL; Modifier * modifier; int i = 0; bool continue_status = false; // logger Logger &logger = Logger::instance(); /* * Loop through loaded modifier modules and grab responses * * We will only get a chance to get a response from the first * module. But if the first module returns a '100 Continue' response * then we read the rest of the request here before returning a NULL * response. */ for ( i = 0 ; i < _handlers_count; i++ ) { // sanity check if ( _handlers[i].name == "" ) { logger.info( "[req] modifier not loaded, not trying to get a response" ); continue; } // grab the response from modifier logger.debug( std::string( "[req] getting preview response from modifier: " ).append( _handlers[i].name ) ); modifier = _handlers[i].symbols.create(); response = modifier->preview( request ); // cleanup logger.debug( std::string( "[req] cleaning up modifier: " ).append( _handlers[i].name ) ); _handlers[i].symbols.destroy( modifier ); // check response status if ( ( response->header()->status() == icap::ResponseHeader::NO_CONTENT ) || ( response->header()->status() == icap::ResponseHeader::OK ) ) { // no further action needed, break out of the loop break; } if ( response->header()->status() == icap::ResponseHeader::CONTINUE ) { // read the full response continue_status = preview_continue( response, request, socket ); // cleanup delete response; // sanity check if ( continue_status ) { // success - set the response to NULL response = NULL; } else { // something went wrong, server error response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); } // exit the loop break; } // we shouldn't have got this far logger.info( std::string( "[req] unrecognised preview response from modifier: " ).append( _handlers[i].name ) ); } return response; } icap::Response * RequestHandler::process_modify( icap::Request * request ) throw() { icap::Response * response = NULL; Modifier * modifier; int i = 0; // logger Logger &logger = Logger::instance(); /* * Loop through loaded modifier modules and grab responses * * We will only return the response from the last module * unless a icap::ResponseHeader::OK is received */ for ( i = 0 ; i < _handlers_count; i++ ) { // sanity check if ( _handlers[i].name == "" ) { logger.info( "[req] modifier not loaded, not trying to get a response" ); continue; } // grab the response from modifier logger.debug( std::string( "[req] getting modify response from modifier: " ).append( _handlers[i].name ) ); modifier = _handlers[i].symbols.create(); response = modifier->modify( request ); // cleanup logger.debug( std::string( "[req] cleaning up modifier: " ).append( _handlers[i].name ) ); _handlers[i].symbols.destroy( modifier ); // status 200 OK means content modified if ( response->header()->status() == icap::ResponseHeader::OK ) { logger.debug( "[req] OK response received, not getting responses from other modifiers" ); break; } } return response; } bool RequestHandler::preview_continue( icap::Response * response, icap::Request * request, psocksxx::iosockstream * socket ) throw() { bool status = false; // logger Logger &logger = Logger::instance(); // sanity check if ( request->payload().ieof ) { // we can process a '100 Continue' only if an 'ieof' is not received logger.warn( "[req] illegal '100 Continue' response" ); } else { /* read the full request */ // send back the response first if ( icap::util::send_response( response, socket ) ) { // read the rest of the request status = icap::util::read_req_continue_data( request, socket ); } } return status; } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/request_handler.h000066400000000000000000000072701320426570600210760ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_REQUEST_HANDLER_H #define BITZ_REQUEST_HANDLER_H #include "modifier.h" #include #include #include namespace bitz { class RequestHandler { public: struct req_handler_t { std::string method; }; struct handler_t { std::string name; Modifier::symbols_t symbols; }; RequestHandler( const std::string &method ); virtual ~RequestHandler(); /** * Returns the request method handled by this handler * @return method */ const std::string &method() const throw(); /** * Process the request and return a new response object. This will also * read from the passed in socket if more data needs to be read. * * @param req_header request header object * @param socket socket object to read the data from * @return response object */ virtual icap::Response * process( icap::RequestHeader * req_header, psocksxx::iosockstream * socket ) throw(); protected: unsigned int _handlers_count; handler_t * _handlers; /** * Load a modifier module * * @param file file name / path of the module * @param symbols structure to return the symbols * @return boolean to denote success or failure */ bool load_modifier( const std::string &file, Modifier::symbols_t &symbols ) throw(); /** * Unload a modifier module * * @param modifier pointer to the modifier to unload */ void unload_modifier( void * modifier ) throw(); /** * Load all the configured modifier modules for this request handler */ void load_modules() throw(); /** * Cleanup all the loaded modifier modules */ void cleanup_modules() throw(); /** * Given a request instance and a socket instance to communicate, this method will use the * loaded handler modules to grab a preview response. This will return a icap::Response * object or NULL after processing a '100 Continue' response. * * @param request request object * @param socket socket object to read data from * @return preview response (response object) */ icap::Response * process_preview( icap::Request * request, psocksxx::iosockstream * socket ) throw(); /** * This method will use the loaded handler modules to get a response to the request. * * @param request request object * @return response object */ icap::Response * process_modify( icap::Request * request ) throw(); /** * Helper method to set a '100 Continue' response back to the client and read the full request. * * @param response response object with status 100 * @param request request object * @param socket socket object to read / write data * @return */ bool preview_continue( icap::Response * response, icap::Request * request, psocksxx::iosockstream * socket ) throw(); private: req_handler_t _req_handler; }; } /* end of namespace bitz */ #endif /* !BITZ_REQUEST_HANDLER_H */ bitz-server-1.0.2/src/bitz/respmod_request_handler.cpp000066400000000000000000000020211320426570600231470ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "respmod_request_handler.h" namespace bitz { RespmodRequestHandler::RespmodRequestHandler() : RequestHandler( "RESPMOD" ) { } RespmodRequestHandler::~RespmodRequestHandler() { } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/respmod_request_handler.h000066400000000000000000000022161320426570600226220ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_RESPMOD_REQUEST_HANDLER_H #define BITZ_RESPMOD_REQUEST_HANDLER_H #include "request_handler.h" namespace bitz { class RespmodRequestHandler : public RequestHandler { public: RespmodRequestHandler(); virtual ~RespmodRequestHandler(); private: }; } /* end of namespace bitz */ #endif /* !BITZ_RESPMOD_REQUEST_HANDLER_H */ bitz-server-1.0.2/src/bitz/util.cpp000066400000000000000000000047511320426570600172220ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "util.h" #include #include namespace bitz { namespace util { RequestHandler * find_req_handler( req_handlers_t req_handlers, const std::string &req_method ) throw() { RequestHandler * req_handler; req_handlers_index_t rh_i; rh_i = req_handlers.find( req_method ); if ( rh_i != req_handlers.end() ) { req_handler = rh_i->second; } else { req_handler = NULL; } return req_handler; } void delete_req_handlers( req_handlers_t req_handlers ) throw() { req_handlers_index_t rh_i; for ( rh_i = req_handlers.begin(); rh_i != req_handlers.end(); rh_i++ ) { if ( rh_i->first != "OPTIONS" ) { delete rh_i->second; } } return; } std::string dirpath( const std::string &path ) throw() { return path.substr( 0, path.find_last_of( '/' ) ); } std::string filename( const std::string &path ) throw() { return path.substr( path.find_last_of( '/' ) ); } bool mkdirp( const std::string &path ) throw() { bool r_success = false; if ( ::mkdir( path.c_str(), 0755 ) == -1 ) { switch( errno ) { case ENOENT: // parent didn't exist, try to create it if ( mkdirp( path.substr( 0, path.find_last_of( '/' ) ) ) ) { // try creating the dir again r_success = ( 0 == ::mkdir( path.c_str(), 0755 ) ); } else { // failed to create parent r_success = false; } break; case EEXIST: // already exists r_success = true; break; default: r_success = false; break; } } else { r_success = true; } return r_success; } } /* end of namespace util */ } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/util.h000066400000000000000000000045721320426570600166700ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_UTIL_H #define BITZ_UTIL_H #include "common.h" #include #include namespace bitz { namespace util { /** * Convert a number into a string * * @param number number to be converted * @return converted string */ template std::string itoa( T number ) { std::ostringstream ss; ss << number; return ss.str(); } /** * Find a matching request handler for the given method * * @param req_handlers request handlers * @param req_method request method * @return request handler (or null pointer if not found) */ RequestHandler * find_req_handler( req_handlers_t req_handlers, const std::string &req_method ) throw(); /** * Helper method to delete any loaded request handlers apart * from the OPTIONS handler * * @param req_handlers request handlers */ void delete_req_handlers( req_handlers_t req_handlers ) throw(); /** * Extract directory path from a path * * @param path path to extract the directory from * @return directory path */ std::string dirpath( const std::string &path ) throw(); /** * Extract the file name from a path * * @param path path to extract the file name from * @return file name */ std::string filename( const std::string &path ) throw(); /** * Create a directory tree recursively * * @param path full directory path * @return boolean to denote success or failure */ bool mkdirp( const std::string &path ) throw(); } /* end of namespace util */ } /* end of namespace bitz */ #endif /* !BITZ_UTIL_H */ bitz-server-1.0.2/src/bitz/worker.cpp000066400000000000000000000115701320426570600175530ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "worker.h" #include "logger.h" #include "util.h" #include "options_request_handler.h" #include "reqmod_request_handler.h" #include "respmod_request_handler.h" #include #include namespace bitz { Worker::Worker() { // load request handlers load_req_handlers(); } Worker::~Worker() { // logger Logger &logger = Logger::instance(); logger.debug( "[worker] exiting" ); // cleanup request handlers util::delete_req_handlers( _req_handlers ); delete _req_handlers["OPTIONS"]; } void Worker::run( psocksxx::tcpnsockstream * server_sock, unsigned int max_requests, unsigned int comm_timeout ) throw() { // logger Logger &logger = Logger::instance(); // client socket stream psocksxx::nsockstream * client_sock; while ( max_requests > 0 ) { logger.debug( std::string( "[worker] waiting for a connection" ) ); try { // accept a client connection client_sock = server_sock->accept(); // FIXME: log accepted client details (e.g. address, port etc.) logger.debug( std::string( "[worker] new connection accepted on [...]" ) ); // set timeout value if ( comm_timeout > 0 ) { client_sock->timeout( comm_timeout, 0 ); // TODO: add debug logging } } catch ( psocksxx::sockexception &e ) { // failed to accept client connection logger.error( std::string( "[worker] failed to accept connection: " ).append( e.what() ) ); // update request count max_requests--; continue; } // handle client request(s) max_requests = serve_client( client_sock, max_requests ); // destroy / close connection delete client_sock; }; } void Worker::load_req_handlers() throw() { OptionsRequestHandler * options_handler; // OPTIONS handler options_handler = new OptionsRequestHandler(); _req_handlers["OPTIONS"] = options_handler; /* request handlers */ // REQMOD _req_handlers["REQMOD"] = new ReqmodRequestHandler(); options_handler->register_handler( _req_handlers["REQMOD"] ); // RESPMOD _req_handlers["RESPMOD"] = new RespmodRequestHandler(); options_handler->register_handler( _req_handlers["RESPMOD"] ); } unsigned int Worker::serve_client( psocksxx::nsockstream * client_sock, unsigned int max_requests ) throw() { // logger Logger &logger = Logger::instance(); icap::RequestHeader * req_header = NULL; icap::Response * response; RequestHandler * req_handler; do { // cleanup request header if ( req_header != NULL ) { delete req_header; } // request header req_header = icap::util::read_req_header( client_sock ); logger.debug( std::string( "[worker] request header:\r\n" ).append( req_header->raw_data() ) ); // check timeout if ( client_sock->timedout() ) { logger.warn( "[worker] communication timed out..." ); return --max_requests; } // try to find a handler for the request req_handler = util::find_req_handler( _req_handlers, req_header->method() ); // sanity check if ( req_handler != NULL ) { logger.debug( std::string( "[worker] handling request: " ).append( req_header->method() ) ); // process the request and grab the response response = req_handler->process( req_header, client_sock ); } else { // unsupported request logger.info( std::string( "[worker] unsupported request: " ).append( req_header->method() ) ); response = new icap::Response( new icap::ResponseHeader( icap::ResponseHeader::NOT_ALLOWED ) ); } // FIXME: this should be configurable and should default to close // connection if the client doesn't send a connection header if ( req_header->value( "Connection" ) == "keep-alive" ) { response->header()->attach( "Connection" , "keep-alive" ); } // send the response back to the client icap::util::send_response( response, client_sock ); // cleanup delete response; } while ( ( --max_requests > 0 ) && ( req_header->value( "Connection" ) == "keep-alive" ) ); // cleanup request header if ( req_header != NULL ) { delete req_header; } return max_requests; } } /* end of namespace bitz */ bitz-server-1.0.2/src/bitz/worker.h000066400000000000000000000025661320426570600172250ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BITZ_WORKER_H #define BITZ_WORKER_H #include #include "common.h" namespace bitz { class Worker { public: Worker(); virtual ~Worker(); virtual void run( psocksxx::tcpnsockstream * server_sock, unsigned int max_requests, unsigned int comm_timeout = 0 ) throw(); private: req_handlers_t _req_handlers; virtual void load_req_handlers() throw(); virtual unsigned int serve_client( psocksxx::nsockstream * client_sock, unsigned int max_requests ) throw(); }; } /* end of namespace bitz */ #endif /* !BITZ_WORKER_H */ bitz-server-1.0.2/src/main.cpp000066400000000000000000000045541320426570600162220ustar00rootroot00000000000000/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "bitz-server.h" #include "bitz/config.h" #include "bitz/logger.h" #include "bitz/util.h" int main( int argc, char **argv ) { // initialise the server bitz::server::init(); // read command line options bitz::server::options_t opt = bitz::server::read_options( argc, argv ); // initialise configurations bitz::Config &server_config = bitz::Config::instance(); if ( opt.config_file != "" ) { server_config.initialise( opt.config_file ); } else { server_config.initialise(); } // get a copy of the configs const bitz::config_t &config = server_config.configs(); // create directories if ( ( opt.debug_flag != 1 ) && (! bitz::util::mkdirp( bitz::util::dirpath( config.pid_file ) ) ) ) { std::cerr << "[core] failed to create run dir" << std::endl; exit( EXIT_FAILURE ); } if (! bitz::util::mkdirp( bitz::util::dirpath( config.log_file ) ) ) { std::cerr << "[core] failed to create log dir" << std::endl; exit( EXIT_FAILURE ); } // daemonize if ( opt.debug_flag != 1 ) { bitz::server::daemonize( bitz::util::dirpath( config.pid_file ).c_str(), config.pid_file.c_str() ); } // initialise the logger bitz::Logger &logger = bitz::Logger::instance( config.log_file, config.log_category ); logger.info( std::string( PACKAGE_STRING ) + " initialised" ); // start the server bitz::server::start( config.port, config.max_workers, config.max_worker_requests, config.comm_timeout ); // run the server bitz::server::run(); // we should never get here bitz::server::shutdown(); return( EXIT_SUCCESS ); } bitz-server-1.0.2/test/000077500000000000000000000000001320426570600147525ustar00rootroot00000000000000bitz-server-1.0.2/test/icap-client.py000066400000000000000000000117011320426570600175140ustar00rootroot00000000000000#!/usr/bin/env python # # icap-client.py # Copyright (c) 2013 Uditha Atukorala # # simple icap client to test a server implementation import socket import sys HOST = 'localhost' SERVICE = 'icap://icap.server.net/sample-service' PORT = 1344 # OPTIONS print("----- OPTIONS -----") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: sock.connect((HOST, PORT)) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) sock.send( "OPTIONS %s ICAP/1.0\r\n" % ( SERVICE ) ) sock.send( "Host: %s\r\n" % ( HOST ) ) sock.send( "User-Agent: Python ICAP tester\r\n" ) sock.send( "\r\n" ) data = sock.recv(1024) string = "" while len(data): string = string + data data = sock.recv(1024) sock.close() print(string) # REQMOD, GET print("----- REQMOD - GET -----") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: sock.connect((HOST, PORT)) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) ) sock.send( "Host: %s\r\n" % ( HOST ) ) sock.send( "Encapsulated: req-hdr=0, null-body=170\r\n" ) sock.send( "\r\n" ) sock.send( "GET / HTTP/1.1\r\n" ) sock.send( "Host: www.origin-server.com\r\n" ) sock.send( "Accept: text/html, text/plain\r\n" ) sock.send( "Accept-Encoding: compress\r\n" ) sock.send( "Cookie: ff39fk3jur@4ii0e02i\r\n" ) sock.send( "If-None-Match: \"xyzzy\", \"r2d2xxxe\"\r\n" ) sock.send( "\r\n" ) data = sock.recv(1024) string = "" while len(data): string = string + data data = sock.recv(1024) sock.close() print(string) # REQMOD, POST print("----- REQMOD - POST -----") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: sock.connect((HOST, PORT)) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) ) sock.send( "Host: %s\r\n" % ( HOST ) ) sock.send( "Encapsulated: req-hdr=0, req-body=147\r\n" ) sock.send( "\r\n" ) sock.send( "POST /origin-resource/form.pl HTTP/1.1\r\n" ) sock.send( "Host: www.origin-server.com\r\n" ) sock.send( "Accept: text/html, text/plain\r\n" ) sock.send( "Accept-Encoding: compress\r\n" ) sock.send( "Pragma: no-cache\r\n" ) sock.send( "\r\n" ) sock.send( "1e\r\n" ) sock.send( "I am posting this information.\r\n" ) sock.send( "0\r\n" ) sock.send( "\r\n" ) data = sock.recv(1024) string = "" while len(data): string = string + data data = sock.recv(1024) sock.close() print(string) # REQMOD - Message preview print("----- REQMOD - Message preview -----") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: sock.connect((HOST, PORT)) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) ) sock.send( "Host: %s\r\n" % ( HOST ) ) sock.send( "Preview: 1024\r\n" ) sock.send( "Encapsulated: req-hdr=0, req-body=147\r\n" ) sock.send( "\r\n" ) sock.send( "POST /origin-resource/form.pl HTTP/1.1\r\n" ) sock.send( "Host: www.origin-server.com\r\n" ) sock.send( "Accept: text/html, text/plain\r\n" ) sock.send( "Accept-Encoding: compress\r\n" ) sock.send( "Pragma: no-cache\r\n" ) sock.send( "\r\n" ) sock.send( "1e\r\n" ) sock.send( "I am posting this information.\r\n" ) sock.send( "0; ieof\r\n\r\n" ) data = sock.recv(1024) string = "" while len(data): string = string + data data = sock.recv(1024) sock.close() print(string) # RESPMOD print("----- RESPMOD -----") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: sock.connect((HOST, PORT)) except socket.error as msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) sock.send( "RESPMOD %s ICAP/1.0\r\n" % ( SERVICE ) ) sock.send( "Host: %s\r\n" % ( HOST ) ) sock.send( "Encapsulated: req-hdr=0, res-hdr=137, res-body=296\r\n" ) sock.send( "\r\n" ) sock.send( "GET /origin-resource HTTP/1.1\r\n" ) sock.send( "Host: www.origin-server.com\r\n" ) sock.send( "Accept: text/html, text/plain, image/gif\r\n" ) sock.send( "Accept-Encoding: gzip, compress\r\n" ) sock.send( "\r\n" ) sock.send( "HTTP/1.1 200 OK\r\n" ) sock.send( "Date: Mon, 10 Jan 2000 09:52:22 GMT\r\n" ) sock.send( "Server: Apache/1.3.6 (Unix)\r\n" ) sock.send( 'ETag: "63840-1ab7-378d415b"\r\n' ) sock.send( "Content-Type: text/html\r\n" ) sock.send( "Content-Length: 51\r\n" ) sock.send( "\r\n" ) sock.send( "33\r\n" ) sock.send( "This is data that was returned by an origin server.\r\n" ) sock.send( "0\r\n" ) sock.send( "\r\n" ) data = sock.recv(1024) string = "" while len(data): string = string + data data = sock.recv(1024) sock.close() print(string) sys.exit(0) bitz-server-1.0.2/test/sample.txt000066400000000000000000000123101320426570600167710ustar00rootroot00000000000000REQMOD ====== ICAP Request Modification Example 1 - ICAP Request ---------------------------------------------------------------- REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0 Host: icap-server.net Encapsulated: req-hdr=0, null-body=170 GET / HTTP/1.1 Host: www.origin-server.com Accept: text/html, text/plain Accept-Encoding: compress Cookie: ff39fk3jur@4ii0e02i If-None-Match: "xyzzy", "r2d2xxxx" ---------------------------------------------------------------- ICAP Request Modification Example 1 - ICAP Response ---------------------------------------------------------------- ICAP/1.0 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Server: ICAP-Server-Software/1.0 Connection: close ISTag: "W3E4R7U9-L2E4-2" Encapsulated: req-hdr=0, null-body=231 GET /modified-path HTTP/1.1 Host: www.origin-server.com Via: 1.0 icap-server.net (ICAP Example ReqMod Service 1.1) Accept: text/html, text/plain, image/gif Accept-Encoding: gzip, compress If-None-Match: "xyzzy", "r2d2xxxx" ---------------------------------------------------------------- ICAP Request Modification Example 2 - ICAP Request ---------------------------------------------------------------- REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0 Host: icap-server.net Encapsulated: req-hdr=0, req-body=147 POST /origin-resource/form.pl HTTP/1.1 Host: www.origin-server.com Accept: text/html, text/plain Accept-Encoding: compress Pragma: no-cache 1e I am posting this information. 0 ---------------------------------------------------------------- ICAP Request Modification Example 2 - ICAP Response ---------------------------------------------------------------- ICAP/1.0 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Server: ICAP-Server-Software/1.0 Connection: close ISTag: "W3E4R7U9-L2E4-2" Encapsulated: req-hdr=0, req-body=244 POST /origin-resource/form.pl HTTP/1.1 Host: www.origin-server.com Via: 1.0 icap-server.net (ICAP Example ReqMod Service 1.1) Accept: text/html, text/plain, image/gif Accept-Encoding: gzip, compress Pragma: no-cache Content-Length: 45 2d I am posting this information. ICAP powered! 0 ---------------------------------------------------------------- ICAP Request Modification Example 3 - ICAP Request ---------------------------------------------------------------- REQMOD icap://icap-server.net/content-filter ICAP/1.0 Host: icap-server.net Encapsulated: req-hdr=0, null-body=119 GET /naughty-content HTTP/1.1 Host: www.naughty-site.com Accept: text/html, text/plain Accept-Encoding: compress ---------------------------------------------------------------- ICAP Request Modification Example 3 - ICAP Response ---------------------------------------------------------------- ICAP/1.0 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Server: ICAP-Server-Software/1.0 Connection: close ISTag: "W3E4R7U9-L2E4-2" Encapsulated: res-hdr=0, res-body=213 HTTP/1.1 403 Forbidden Date: Wed, 08 Nov 2000 16:02:10 GMT Server: Apache/1.3.12 (Unix) Last-Modified: Thu, 02 Nov 2000 13:51:37 GMT ETag: "63600-1989-3a017169" Content-Length: 58 Content-Type: text/html 3a Sorry, you are not allowed to access that naughty content. 0 ---------------------------------------------------------------- RESPMOD ======= ICAP Response Modification Example 4 - ICAP Request ---------------------------------------------------------------- RESPMOD icap://icap.example.org/satisf ICAP/1.0 Host: icap.example.org Encapsulated: req-hdr=0, res-hdr=137, res-body=296 GET /origin-resource HTTP/1.1 Host: www.origin-server.com Accept: text/html, text/plain, image/gif Accept-Encoding: gzip, compress HTTP/1.1 200 OK Date: Mon, 10 Jan 2000 09:52:22 GMT Server: Apache/1.3.6 (Unix) ETag: "63840-1ab7-378d415b" Content-Type: text/html Content-Length: 51 33 This is data that was returned by an origin server. 0 ---------------------------------------------------------------- ICAP Response Modification Example 4 - ICAP Response ---------------------------------------------------------------- ICAP/1.0 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Server: ICAP-Server-Software/1.0 Connection: close ISTag: "W3E4R7U9-L2E4-2" Encapsulated: res-hdr=0, res-body=222 HTTP/1.1 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Via: 1.0 icap.example.org (ICAP Example RespMod Service 1.1) Server: Apache/1.3.6 (Unix) ETag: "63840-1ab7-378d415b" Content-Type: text/html Content-Length: 92 5c This is data that was returned by an origin server, but with value added by an ICAP server. 0 ---------------------------------------------------------------- OPTIONS ======= ICAP OPTIONS Example 5 - ICAP OPTIONS Request ---------------------------------------------------------------- OPTIONS icap://icap.server.net/sample-service ICAP/1.0 Host: icap.server.net User-Agent: BazookaDotCom-ICAP-Client-Library/2.3 ---------------------------------------------------------------- ICAP OPTIONS Example 5 - ICAP OPTIONS Response ---------------------------------------------------------------- ICAP/1.0 200 OK Date: Mon, 10 Jan 2000 09:55:21 GMT Methods: RESPMOD Service: FOO Tech Server 1.0 ISTag: "W3E4R7U9-L2E4-2" Encapsulated: null-body=0 Max-Connections: 1000 Options-TTL: 7200 Allow: 204 Preview: 2048 Transfer-Complete: asp, bat, exe, com Transfer-Ignore: html Transfer-Preview: * ----------------------------------------------------------------bitz-server-1.0.2/test/valgrind.supp000066400000000000000000000006031320426570600174700ustar00rootroot00000000000000# # valgrind.supp # # Python { Python 2.7 (libpython2.7.so.1.0) Memcheck:Value4 obj:/usr/lib/libpython2.7.so.1.0 } { Python 2.7 (libpython2.7.so.1.0) Memcheck:Addr4 obj:/usr/lib/libpython2.7.so.1.0 } { Python 2.7 (libpython2.7.so.1.0) Memcheck:Value8 obj:/usr/lib/libpython2.7.so.1.0 } { Python 2.7 (libpython2.7.so.1.0) Memcheck:Cond obj:/usr/lib/libpython2.7.so.1.0 }