summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore23
-rw-r--r--AUTHORS3
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--Doxyfile.in247
-rw-r--r--Makefile.am27
-rw-r--r--NEWS.xml6
-rw-r--r--NEWS.xsl24
-rw-r--r--README0
-rw-r--r--acinclude.m480
-rwxr-xr-xautogen.sh9
-rw-r--r--configure.ac62
-rw-r--r--include/.gitignore2
-rw-r--r--include/Makefile.am6
-rw-r--r--include/kingate/cgi_gateway.h164
-rw-r--r--include/kingate/cgi_interface.h70
-rw-r--r--include/kingate/exception.h44
-rw-r--r--include/kingate/fastcgi.h98
-rw-r--r--include/kingate/util.h26
-rw-r--r--kingate-fcgi.pc.in11
-rw-r--r--kingate.pc.in11
-rw-r--r--src/.gitignore7
-rw-r--r--src/Makefile.am15
-rw-r--r--src/cgi_gateway.cc88
-rw-r--r--src/cgi_interface.cc16
-rw-r--r--src/fastcgi.cc67
-rw-r--r--src/util.cc53
27 files changed, 1178 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..02145e3
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+configure
+Makefile.in
+kingate.pc
+Doxyfile
+config.log
+depcomp
+kingate-fcgi.pc
+config.guess
+config.h
+ltmain.sh
+config.sub
+INSTALL
+Makefile
+config.status
+stamp-h1
+config.h.in
+libtool
+autom4te.cache
+missing
+aclocal.m4
+install-sh
+NEWS
+doxydox
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Klever dissected:
+ Michael 'hacker' Krelin <hacker@klever.net>
+ Leonid Ivanov <kamel@klever.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..96befc6
--- a/dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2005 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/ChangeLog
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644
index 0000000..2d072ce
--- a/dev/null
+++ b/Doxyfile.in
@@ -0,0 +1,247 @@
+# Doxyfile 1.3.9.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = @PACKAGE@
+PROJECT_NUMBER = @VERSION@
+OUTPUT_DIRECTORY = @builddir@/doxydox
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = include
+STRIP_FROM_INC_PATH = include
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = YES
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+INPUT = \
+ @srcdir@/include/kingate/
+FILE_PATTERNS = *.h
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 2
+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_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# 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 = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# 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_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+GENERATE_XML = YES
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# 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::additions related to external references
+#---------------------------------------------------------------------------
+
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = @HAVE_DOT@
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = @DOT@
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+SEARCHENGINE = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..9833732
--- a/dev/null
+++ b/Makefile.am
@@ -0,0 +1,27 @@
+SUBDIRS=include src
+EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
+
+DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig
+if HAVE_PKGCONFIG
+pkgconfigdir=@PKGCONFIG_DIR@
+pkgconfig_DATA=kingate.pc kingate-fcgi.pc
+endif
+
+LOCAL_TARGETS=
+if HAVE_DOXYGEN
+LOCAL_TARGETS+=doxygen
+endif
+
+all-local: NEWS $(addprefix all-lota-,${LOCAL_TARGETS})
+clean-local: $(addprefix clean-lota-,${LOCAL_TARGETS})
+
+NEWS: NEWS.xsl NEWS.xml
+ ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
+
+all-lota-doxygen: doxydox/built
+doxydox/built: $(wildcard ${top_srcdir}/include/kingate/*.h)
+ ${DOXYGEN}
+ touch $@
+
+clean-lota-doxygen:
+ rm -rf doxydox
diff --git a/NEWS.xml b/NEWS.xml
new file mode 100644
index 0000000..d1d89f6
--- a/dev/null
+++ b/NEWS.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<news>
+ <version version="0.0" date="January 29th, 2005">
+ <ni>Initial release</ni>
+ </version>
+</news>
diff --git a/NEWS.xsl b/NEWS.xsl
new file mode 100644
index 0000000..7c71307
--- a/dev/null
+++ b/NEWS.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ >
+ <xsl:output
+ method="text"
+ encoding="us-ascii"
+ media-type="text/plain" />
+
+ <xsl:template match="news">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="version">
+ <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ni">
+ <xsl:text> - </xsl:text>
+ <xsl:apply-templates mode="text"/>
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:template>
+ <xsl:template match="*|text()"/>
+
+</xsl:stylesheet>
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/README
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..ec2c50f
--- a/dev/null
+++ b/acinclude.m4
@@ -0,0 +1,80 @@
+dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR
+dnl AM_CONDTIONAL: HAVE_PKGCONFIG
+AC_DEFUN([AC_WITH_PKGCONFIG],[
+ PKGCONFIG_PKGCONFIG=""
+ PKGCONFIG_DIR=""
+ HAVE_PKGCONFIG="no"
+ EXPLICIT_PKGCONFIGDIR="no"
+ test -z "${WANT_PKGCONFIG}" && WANT_PKGCONFIG=""
+ AC_PATH_PROG([PKGCONFIG_PKGCONFIG],[pkg-config],[false])
+ if test "${PKGCONFIG_PKGCONFIG}" != "false" ; then
+ AC_ARG_WITH([pkgconfigdir],
+ AC_HELP_STRING([--with-pkgconfigdir=dir],[Specify pkgconfig directory]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PKGCONFIG="no"
+ else
+ PKGCONFIG_DIR="${withval}"
+ EXPLICIT_PKGCONFIGDIR="yes"
+ fi
+ ],[
+ AC_MSG_CHECKING([for pkgconfig directory])
+ PKGCONFIG_DIR="`${PKGCONFIG_PKGCONFIG} --debug 2>&1 | grep '^Scanning'| head -n 1 | cut -d\' -f2-|cut -d\' -f1`"
+ AC_MSG_RESULT([${PKGCONFIG_DIR}])
+ ]
+ )
+ if test -d "${PKGCONFIG_DIR}" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ AC_MSG_NOTICE([unexistent pkgconfig directory: ${PKGCONFIG_DIR}])
+ if test "${EXPLICIT_PKGCONFIGDIR}" = "yes" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ ifelse([$2], , :, [$2])
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PKGCONFIG],[test "${HAVE_PKGCONFIG}" = "yes"])
+])
+
+dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN
+dnl AM_CONDTIONAL: HAVE_DOXYGEN
+AC_DEFUN([AC_WITH_DOXYGEN],[
+ HAVE_DOXYGEN="no"
+ AC_PATH_PROG([DOXYGEN],[doxygen],[false])
+ if test "${DOXYGEN}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOXYGEN="yes"
+ AC_SUBST([DOXYGEN])
+ $1
+ fi
+ AC_SUBST([HAVE_DOXYGEN])
+ AM_CONDITIONAL([HAVE_DOXYGEN],[test "${HAVE_DOXYGEN}" = "yes"])
+])
+
+dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOT HAVE_DOT
+dnl AM_CONDITIONAL: HAVE_DOT
+AC_DEFUN([AC_WITH_DOT],[
+ HAVE_DOT="no"
+ AC_PATH_PROG([DOT],[dot],[false])
+ if test "${DOT}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOT="yes"
+ AC_SUBST([DOT])
+ $1
+ fi
+AC_SUBST([HAVE_DOT])
+ AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"])
+])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ba27501
--- a/dev/null
+++ b/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+WANT_AUTOMAKE=1.8
+export WANT_AUTOMAKE
+libtoolize -f \
+&& aclocal \
+&& autoheader \
+&& automake -a \
+&& autoconf \
+&& ./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..109eddf
--- a/dev/null
+++ b/configure.ac
@@ -0,0 +1,62 @@
+AC_INIT([kingate], [0.0], [kingate-bugs@klever.net])
+AC_CONFIG_SRCDIR([include/kingate/cgi_gateway.h])
+AC_CONFIG_HEADER([config.h])
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AC_PROG_INSTALL
+AC_PROG_AWK
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS([sys/types.h sys/stat.h])
+
+AC_LANG_PUSH(C++)
+AC_CHECK_HEADERS([fcgio.h],,[
+ exit 1
+])
+AC_CHECK_LIB(fcgi,FCGX_Init,,[
+ exit 1
+])
+AC_CHECK_LIB([fcgi++],[main],,[
+ exit 1
+])
+AC_LANG_POP(C++)
+
+AC_C_CONST
+
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+
+AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
+
+AC_WITH_PKGCONFIG
+
+PKG_CHECK_MODULES([KONFORKA],[konforka],,[
+ AC_MSG_ERROR([no konforka library found. get one from http://kin.klever.net/konforka/])
+])
+
+WANT_DOXYGEN="yes"
+AC_ARG_ENABLE([doxygen],
+ AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
+ [
+ test "${enableval}" = "no" && WANT_DOXYGEN="no"
+ ]
+)
+if test "${WANT_DOXYGEN}" = "yes" ; then
+ AC_WITH_DOXYGEN
+ AC_WITH_DOT
+else
+ AM_CONDITIONAL([HAVE_DOXYGEN],[false])
+ AM_CONDITIONAL([HAVE_DOT],[false])
+fi
+
+AC_CONFIG_FILES([
+ Makefile
+ kingate.pc kingate-fcgi.pc
+ Doxyfile
+ include/Makefile
+ src/Makefile
+])
+AC_OUTPUT
diff --git a/include/.gitignore b/include/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/include/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..c1ec36e
--- a/dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,6 @@
+nobase_include_HEADERS = \
+ kingate/cgi_gateway.h \
+ kingate/cgi_interface.h \
+ kingate/fastcgi.h \
+ kingate/exception.h \
+ kingate/util.h
diff --git a/include/kingate/cgi_gateway.h b/include/kingate/cgi_gateway.h
new file mode 100644
index 0000000..f683580
--- a/dev/null
+++ b/include/kingate/cgi_gateway.h
@@ -0,0 +1,164 @@
+#ifndef __KINGATE_CGI_GATEWAY_H
+#define __KINGATE_CGI_GATEWAY_H
+
+#include <map>
+#include "kingate/cgi_interface.h"
+
+/**
+ * @file
+ * @brief the cgi_gateway -- main interface to CGI.
+ */
+
+namespace kingate {
+ using namespace std;
+
+ /**
+ * The main class interfacing with the CGI environment.
+ */
+ class cgi_gateway {
+ public:
+ /**
+ * The interface to CGI environment (e.g. fastcgi).
+ */
+ cgi_interface& iface;
+ /**
+ * The type describing map holding parameters parsed from query string or input.
+ */
+ typedef multimap<string,string> params_t;
+ /**
+ * The GET-passed parameters.
+ */
+ params_t get;
+ /**
+ * The POST-passed parameters.
+ */
+ params_t post;
+ /**
+ * Was the stdin content parsed?
+ */
+ bool b_parsed_content;
+
+ /**
+ * @param ci the interface to use.
+ */
+ cgi_gateway(cgi_interface& ci);
+
+ /**
+ * Check whether there is an 'environment' meta-variable with specific name
+ * passed to CGI.
+ * @param n variable name.
+ * @return true if yes.
+ * @see cgi_interface::has_meta()
+ * @see get_meta()
+ */
+ bool has_meta(const string& n) const { return iface.has_meta(n); }
+ /**
+ * Retrieve the 'environment' meta-variable value.
+ * @param n variable name.
+ * @return variable contents.
+ * @see exception_notfound
+ * @see cgi_interface::get_meta()
+ */
+ string get_meta(const string& n) const { return iface.get_meta(n); }
+
+ /**
+ * fetch reference to the 'stdin' stream.
+ * @return the reference to the corresponding istream object.
+ * @see cgi_interface::in()
+ */
+ istream& in() { return iface.in(); }
+ /**
+ * fetch reference to the 'stdout' stream.
+ * @return the reference to the corresponding ostream object.
+ * @see cgi_interface::out()
+ */
+ ostream& out() { return iface.out(); }
+ /**
+ * fetch reference to the 'stderr' stream.
+ * @return the reference to the corresponding ostream object.
+ * @see cgi_interface::err()
+ */
+ ostream& err() { return iface.err(); }
+ /**
+ * cast to the ostream -- fetches the reference to the 'stdout'
+ * stream.
+ * @see out()
+ */
+ operator ostream& (void) { return out(); }
+
+ /**
+ * Check to see whether the parameter was passed via GET.
+ * @param n the parameter name.
+ * @return true if yes.
+ */
+ bool has_GET(const string& n) const;
+ /**
+ * Retrieve the parameter passed via GET.
+ * @param n the parameter name.
+ * @return the parameter contents.
+ * @see exception_notfound
+ */
+ string get_GET(const string& n) const;
+ /**
+ * Check to see whether the parameter was passed via POST.
+ * @param n the parameter name.
+ * @return true if yes.
+ */
+ bool has_POST(const string& n) const;
+ /**
+ * Retrieve the POST-parameter.
+ * @param n the parameter name.
+ * @return the parameter contents.
+ * @see exception_notfound
+ */
+ string get_POST(const string& n) const;
+ /**
+ * Check to see whether the parameter was passed either via POST or
+ * GET.
+ * @param n the parameter name.
+ * @return true if yes.
+ */
+ bool has_param(const string& n) const;
+ /**
+ * Retrieve the parameter passed either via POST or GET
+ * (GET-parameter takes precedence).
+ * @param n the parameter name.
+ * @return true if yes.
+ * @see exception_notfound.
+ */
+ string get_param(const string& n) const;
+
+ /**
+ * Retrieve the POST content-type (as passed via CONTENT_TYPE
+ * environment variable).
+ * @return the content type.
+ */
+ const string& get_content_type() const;
+ /**
+ * Retrieve the POST content length (as passed via the
+ * CONTENT_LENGTH environment variable).
+ * @return the content length.
+ */
+ unsigned long get_content_length() const;
+
+ /**
+ * Check to see whether the content from stdin stream was parsed.
+ * @return true if yes.
+ */
+ bool is_content_parsed() const { return b_parsed_content; }
+ private:
+ /**
+ * Parse the query string, putting the parameters into the map
+ * specified.
+ * @param q the query string.
+ * @param p destination parameters map.
+ */
+ static void parse_query(string& q,params_t& p);
+ };
+
+}
+
+#endif /* __KINGATE_CGI_GATEWAY_H */
+/*
+ * vim:set ft=cpp:
+ */
diff --git a/include/kingate/cgi_interface.h b/include/kingate/cgi_interface.h
new file mode 100644
index 0000000..84ea6dd
--- a/dev/null
+++ b/include/kingate/cgi_interface.h
@@ -0,0 +1,70 @@
+#ifndef __KINGATE_CGI_INTERFACE_H
+#define __KINGATE_CGI_INTERFACE_H
+
+#include <iostream>
+#include <string>
+#include <map>
+
+/**
+ * @file
+ * @brief the abstract base for various interfaces to CGI.
+ */
+
+namespace kingate {
+ using namespace std;
+
+ /**
+ * The abstract base class for interface to CGI subsystem.
+ */
+ class cgi_interface {
+ public:
+ /**
+ * The type for map holding 'environment' meta-variables.
+ */
+ typedef map<string,string> metavars_t;
+ /**
+ * The environment variables.
+ */
+ metavars_t metavars;
+
+ cgi_interface() { }
+ virtual ~cgi_interface() { }
+
+ /**
+ * Check to see whether there is a particular 'environment'
+ * meta-variable passed.
+ * @param n the variable name.
+ * @return true if yes.
+ */
+ bool has_meta(const string& n) const;
+ /**
+ * Retrieve the 'environment' variable.
+ * @param n the variable name.
+ * @return the variable contents.
+ * @see exception_notfound
+ */
+ const string& get_meta(const string& n) const;
+
+ /**
+ * Fetch reference to CGI 'stdout' stream.
+ * @return reference to the corresponding ostream object.
+ */
+ virtual ostream& out() = 0;
+ /**
+ * Fetch reference to CGI 'stdin' stream.
+ * @return reference to the corresponding istream object.
+ */
+ virtual istream& in() = 0;
+ /**
+ * Fetch reference to CGI 'stderr' stream.
+ * @return reference to the corresponding ostream object.
+ */
+ virtual ostream& err() = 0;
+ };
+
+}
+
+#endif /* __KINGATE_CGI_INTERFACE_H */
+/*
+ * vim:set ft=cpp:
+ */
diff --git a/include/kingate/exception.h b/include/kingate/exception.h
new file mode 100644
index 0000000..6ebb361
--- a/dev/null
+++ b/include/kingate/exception.h
@@ -0,0 +1,44 @@
+#ifndef __KINGATE_EXCEPTION_H
+#define __KINGATE_EXCEPTION_H
+
+#include <stdexcept>
+#include <konforka/exception.h>
+
+/**
+ * @file
+ * @brief The kingate-specific exceptions.
+ */
+
+/**
+ * @brief the main kingate namespace.
+ */
+namespace kingate {
+ using namespace std;
+
+ /**
+ * The base for kingate-specific exception.
+ */
+ class exception : public konforka::exception {
+ public:
+ explicit exception(const string& w)
+ : konforka::exception(NOCODEPOINT,w) { }
+ exception(const string& fi,const string& fu,int l,const string &w)
+ : konforka::exception(fi,fu,l,w) { }
+ };
+
+ /**
+ * Thrown if the specified variable or parameter wasn't found.
+ */
+ class exception_notfound : public exception {
+ public:
+ explicit exception_notfound(const string& w)
+ : exception(w) { }
+ exception_notfound(const string& fi,const string& fu,int l,const string& w)
+ : exception(fi,fu,l,w) { }
+ };
+}
+
+#endif /* __KINGATE_EXCEPTION_H */
+/*
+ * vim:set ft=cpp:
+ */
diff --git a/include/kingate/fastcgi.h b/include/kingate/fastcgi.h
new file mode 100644
index 0000000..fd293b9
--- a/dev/null
+++ b/include/kingate/fastcgi.h
@@ -0,0 +1,98 @@
+#ifndef __KINGATE_FASTCGI_H
+#define __KINGATE_FASTCGI_H
+
+#include "kingate/cgi_interface.h"
+#include <fcgio.h>
+
+/**
+ * @file
+ * @brief the fastcgi-specific implementation.
+ */
+
+namespace kingate {
+
+ /**
+ * The fcgi listening socket.
+ */
+ class fcgi_socket {
+ static bool _initialized;
+ public:
+ /**
+ * socket file descriptor.
+ */
+ int sock;
+
+ /**
+ * @param s the socket name. (if the socket starts with a colon,
+ * then it is interpreted as a tcp port number.
+ * @param bl backlog listen queue depth.
+ */
+ fcgi_socket(const char* s,int bl);
+ /**
+ * @param s the file descriptor of preopened socket.
+ */
+ fcgi_socket(int s);
+ ~fcgi_socket();
+ };
+
+ /**
+ * The implementation of the interface to the FastCGI.
+ */
+ class fcgi_interface : public cgi_interface {
+ public:
+ /**
+ * stdin fcgi streambuf.
+ */
+ fcgi_streambuf sbin;
+ /**
+ * stdout fcgi streambuf.
+ */
+ fcgi_streambuf sbout;
+ /**
+ * stderr fcgi streambuf.
+ */
+ fcgi_streambuf sberr;
+ /**
+ * stdin istream.
+ */
+ istream sin;
+ /**
+ * stdout ostream.
+ */
+ ostream sout;
+ /**
+ * stderr ostream.
+ */
+ ostream serr;
+ /**
+ * The FCGI request.
+ */
+ FCGX_Request request;
+
+ /**
+ * @param s the socked used for interfacing with the server.
+ * @param f the request flags (e.g. FCGI_FAIL_ON_INTR).
+ */
+ fcgi_interface(fcgi_socket& s,int f=0);
+ virtual ~fcgi_interface();
+
+ /**
+ * @overload cgi_interface::in()
+ */
+ istream& in() { return sin; }
+ /**
+ * @overload cgi_interface::out()
+ */
+ ostream& out() { return sout; }
+ /**
+ * @overload cgi_interface::out()
+ */
+ ostream& err() { return serr; }
+ };
+
+}
+
+#endif /* __KINGATE_FASTCGI_H */
+/*
+ * vim:set ft=cpp:
+ */
diff --git a/include/kingate/util.h b/include/kingate/util.h
new file mode 100644
index 0000000..4b0dca8
--- a/dev/null
+++ b/include/kingate/util.h
@@ -0,0 +1,26 @@
+#ifndef __KINGATE_UTIL_H
+#define __KINGATE_UTIL_H
+
+#include <string>
+
+namespace kingate {
+ using namespace std;
+
+ /**
+ * Escape string for passing via URL.
+ * @param str string unescaped.
+ * @return the escaped string.
+ */
+ string url_escape(const string& str);
+ /**
+ * Remove URL-encoding from the string.
+ * @param str the URL-encoded string.
+ * @return the unescaped string.
+ */
+ string url_unescape(const string& str);
+}
+
+#endif /* __KINGATE_UTIL_H */
+/*
+ * vim:set ft=cpp:
+ */
diff --git a/kingate-fcgi.pc.in b/kingate-fcgi.pc.in
new file mode 100644
index 0000000..03e0155
--- a/dev/null
+++ b/kingate-fcgi.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: kingate-fcgi
+Description: FastCGI implementation of kingate interface
+Version: @VERSION@
+Requires: kingate = @VERSION@
+Libs: -L${libdir} -lkingate-fcgi
+Cflags: -I${includedir}
diff --git a/kingate.pc.in b/kingate.pc.in
new file mode 100644
index 0000000..671faac
--- a/dev/null
+++ b/kingate.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: kingate
+Description: C++ CGI support library
+Version: @VERSION@
+Requires: konforka
+Libs: -L${libdir} -lkingate
+Cflags: -I${includedir}
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..af4f4dd
--- a/dev/null
+++ b/src/.gitignore
@@ -0,0 +1,7 @@
+Makefile.in
+.deps
+Makefile
+.libs
+*.o
+*.lo
+*.la
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..8a5447b
--- a/dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,15 @@
+lib_LTLIBRARIES = libkingate.la libkingate-fcgi.la
+
+INCLUDES = -I${top_srcdir}/include
+AM_CXXFLAGS = ${KONFORKA_CFLAGS}
+LDADD = ${KONFORKA_LIBS}
+
+libkingate_la_SOURCES = \
+ cgi_gateway.cc \
+ cgi_interface.cc \
+ util.cc
+libkingate_la_LDFLAGS = -version-info 1:0:0
+
+libkingate_fcgi_la_SOURCES = \
+ fastcgi.cc
+libkingate_fcgi_la_LDFLAGS = -version-info 1:0:0
diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc
new file mode 100644
index 0000000..eae7a03
--- a/dev/null
+++ b/src/cgi_gateway.cc
@@ -0,0 +1,88 @@
+#include "kingate/cgi_gateway.h"
+#include "kingate/util.h"
+#include "kingate/exception.h"
+
+namespace kingate {
+
+ cgi_gateway::cgi_gateway(cgi_interface& ci)
+ : iface(ci), b_parsed_content(false) {
+ // Fetch GET content
+ if(iface.has_meta("QUERY_STRING")) {
+ string qs = iface.get_meta("QUERY_STRING");
+ parse_query(qs,get);
+ }
+ // Fetch POST content
+ if(!strcasecmp(get_content_type().c_str(),"application/x-www-form-urlencoded")) {
+ unsigned long cl = get_content_length();
+ if(cl) {
+ char * tmp = new char[cl];
+ iface.in().read(tmp,cl);
+ string qs(tmp,cl);
+ delete tmp;
+ parse_query(qs,post);
+ }
+ b_parsed_content = true;
+ }
+ }
+
+ bool cgi_gateway::has_GET(const string& n) const {
+ return get.find(n) != get.end();
+ }
+ string cgi_gateway::get_GET(const string& n) const {
+ params_t::const_iterator i = get.find(n);
+ if(i==get.end())
+ throw exception_notfound(CODEPOINT,"no such parameter");
+ return i->second;
+ }
+ bool cgi_gateway::has_POST(const string& n) const {
+ return post.find(n) != post.end();
+ }
+ string cgi_gateway::get_POST(const string& n) const {
+ params_t::const_iterator i = post.find(n);
+ if(i==post.end())
+ throw exception_notfound(CODEPOINT,"no such parameter");
+ return i->second;
+ }
+ bool cgi_gateway::has_param(const string& n) const {
+ return has_GET(n) || has_POST(n);
+ }
+ string cgi_gateway::get_param(const string& n) const {
+ params_t::const_iterator i = get.find(n);
+ if(i!=get.end())
+ return i->second;
+ i = post.find(n);
+ if(i!=post.end())
+ return i->second;
+ throw exception_notfound(CODEPOINT,"no such parameter");
+ }
+
+ const string& cgi_gateway::get_content_type() const {
+ if(!has_meta("CONTENT_TYPE"))
+ return ""; // XXX:
+ return get_meta("CONTENT_TYPE");
+ }
+ unsigned long cgi_gateway::get_content_length() const {
+ if(!has_meta("CONTENT_LENGTH"))
+ return 0;
+ string cl = get_meta("CONTENT_LENGTH");
+ return strtol(cl.c_str(),NULL,10);
+ }
+
+ void cgi_gateway::parse_query(string& q,params_t& p) {
+ while(!q.empty()) {
+ string::size_type amp = q.find('&');
+ string pp = (amp==string::npos)?q:q.substr(0,amp);
+ if(amp==string::npos)
+ q.clear();
+ else
+ q.erase(0,amp+1);
+ string::size_type eq = pp.find('=');
+ if(eq == string::npos) {
+ p.insert(params_t::value_type("",url_unescape(pp)));
+ }else{
+ p.insert(params_t::value_type(url_unescape(pp.substr(0,eq)),url_unescape(pp.substr(eq+1))));
+ }
+ }
+ }
+
+}
diff --git a/src/cgi_interface.cc b/src/cgi_interface.cc
new file mode 100644
index 0000000..ffbd2bf
--- a/dev/null
+++ b/src/cgi_interface.cc
@@ -0,0 +1,16 @@
+#include "kingate/cgi_interface.h"
+#include "kingate/exception.h"
+
+namespace kingate {
+
+ bool cgi_interface::has_meta(const string& n) const {
+ return metavars.find(n) != metavars.end();
+ }
+ const string& cgi_interface::get_meta(const string& n) const {
+ metavars_t::const_iterator rv = metavars.find(n);
+ if(rv == metavars.end())
+ throw exception_notfound(CODEPOINT,"no such meta-variable");
+ return rv->second;
+ }
+
+}
diff --git a/src/fastcgi.cc b/src/fastcgi.cc
new file mode 100644
index 0000000..7484449
--- a/dev/null
+++ b/src/fastcgi.cc
@@ -0,0 +1,67 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "kingate/fastcgi.h"
+#include "kingate/exception.h"
+
+namespace kingate {
+
+ bool fcgi_socket::_initialized = false;
+
+ fcgi_socket::fcgi_socket(const char *s,int bl)
+ : sock(-1) {
+ if(!_initialized) {
+ if( FCGX_Init() )
+ throw exception(CODEPOINT,"failed to FCGX_Init()");
+ _initialized = true;
+ }
+ sock = FCGX_OpenSocket(s,bl);
+ if(sock<0)
+ throw exception(CODEPOINT,"failed to FCGX_OpenSocket(");
+ // TODO: check if there is a ':', not if it starts with ':'
+ if(*s != ':')
+ if(chmod(s,0777)) // XXX: configurable.
+ throw exception(CODEPOINT,"failed to chmod()");
+ }
+ fcgi_socket::fcgi_socket(int s)
+ : sock(0) {
+ if(!_initialized) {
+ if( FCGX_Init() )
+ throw exception(CODEPOINT,"failed to FCGX_Init()");
+ _initialized = true;
+ }
+ }
+ fcgi_socket::~fcgi_socket() {
+ if(sock>=0)
+ close(sock);
+ }
+
+ fcgi_interface::fcgi_interface(fcgi_socket& s,int f)
+ : sin(&sbin), sout(&sbout), serr(&sberr) {
+ if( FCGX_InitRequest(&request,s.sock,f) )
+ throw exception(CODEPOINT,"failed to FCGX_InitRequest()");
+ if( FCGX_Accept_r(&request) )
+ throw exception(CODEPOINT,"failed to FCGX_Accept_r()");
+ sbin.attach(request.in);
+ sbout.attach(request.out);
+ sberr.attach(request.err);
+ metavars.clear(); // XXX: redundant.
+ for(char **p = request.envp; *p; p++) {
+ const char *e = strchr(*p,'=');
+ if(!e){
+ // XXX: check if we have it already?
+ metavars[*p] = string(0);
+ }else{
+ int l = e-*p; e++;
+ // XXX: check if we have it already?
+ metavars[string(*p,l)]=e;
+ }
+ }
+ }
+ fcgi_interface::~fcgi_interface() {
+ sout.flush();
+ serr.flush();
+ FCGX_Finish_r(&request);
+ }
+
+}
diff --git a/src/util.cc b/src/util.cc
new file mode 100644
index 0000000..2e2d305
--- a/dev/null
+++ b/src/util.cc
@@ -0,0 +1,53 @@
+#include "kingate/util.h"
+#include "kingate/exception.h"
+
+namespace kingate {
+
+ static const char *safeChars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "_-" ;
+
+ string url_escape(const string& str) {
+ string rv = str;
+ string::size_type screwed = 0;
+ for(;;) {
+ screwed = rv.find_first_not_of(safeChars,screwed);
+ if(screwed == string::npos)
+ break;
+ while(screwed<rv.length() && !strchr(safeChars,rv.at(screwed))) {
+ char danger = rv.at(screwed);
+ if(danger==' ') {
+ rv.replace(screwed++,1,1,'+');
+ }else{
+ static char tmp[4] = {'%',0,0,0};
+ snprintf(&tmp[1],3,"%02X",0xFF&(int)danger);
+ rv.replace(screwed,1,tmp,3);
+ screwed+=3;
+ }
+ }
+ }
+ return rv;
+ }
+ string url_unescape(const string& str) {
+ string rv = str;
+ string::size_type unscrewed = 0;
+ for(;;) {
+ unscrewed = rv.find_first_of("%+",unscrewed);
+ if(unscrewed == string::npos)
+ break;
+ if(rv.at(unscrewed)=='+') {
+ rv.replace(unscrewed++,1,1,' ');
+ }else{
+ if((rv.length()-unscrewed)<3)
+ throw exception(CODEPOINT,"incorrectly escaped string");
+ // XXX: ensure it's hex?
+ int danger = strtol(rv.substr(unscrewed+1,2).c_str(),NULL,16);
+ rv.replace(unscrewed,3,1,danger);
+ unscrewed++;
+ }
+ }
+ return rv;
+ }
+}