summaryrefslogtreecommitdiffstats
path: root/httpserver
diff options
context:
space:
mode:
authorConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
committerConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
commit8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch)
treebd328a4dd4f92d32202241b5e3a7f36177792c5f /httpserver
downloadrasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip
Initial commitv8.0
Diffstat (limited to 'httpserver')
-rw-r--r--httpserver/Makefile.am33
-rw-r--r--httpserver/childs.cc246
-rw-r--r--httpserver/config.cc465
-rw-r--r--httpserver/defs.h249
-rw-r--r--httpserver/http-date.cc97
-rw-r--r--httpserver/http-defs.h214
-rw-r--r--httpserver/http-doit.cc536
-rw-r--r--httpserver/http-error.cc446
-rw-r--r--httpserver/http-fields.cc218
-rw-r--r--httpserver/http-methods.cc163
-rw-r--r--httpserver/http-readmsg.cc1014
-rw-r--r--httpserver/http-support.cc503
-rw-r--r--httpserver/http-writemsg.cc314
-rw-r--r--httpserver/http.cc181
-rw-r--r--httpserver/http.h133
-rw-r--r--httpserver/httpserver.conf14
-rw-r--r--httpserver/httpserver.h38
-rw-r--r--httpserver/init.cc319
-rw-r--r--httpserver/logging.cc297
-rw-r--r--httpserver/main.cc191
-rw-r--r--httpserver/protos.h178
-rw-r--r--httpserver/server.h190
-rw-r--r--httpserver/signals.cc287
-rw-r--r--httpserver/support.cc640
-rw-r--r--httpserver/test/Makefile63
-rw-r--r--httpserver/test/httpserver.conf14
-rw-r--r--httpserver/test/post_test.html116
-rw-r--r--httpserver/types.h38
28 files changed, 7197 insertions, 0 deletions
diff --git a/httpserver/Makefile.am b/httpserver/Makefile.am
new file mode 100644
index 0000000..94d883b
--- /dev/null
+++ b/httpserver/Makefile.am
@@ -0,0 +1,33 @@
+# This file is part of rasdaman community.
+#
+# Rasdaman community 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.
+#
+# Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# Rasdaman http server
+#
+##################################################################
+
+noinst_LIBRARIES=libhttpserver.a
+AM_CFLAGS=$(CXXFLAGS)
+libhttpserver_a_SOURCES= types.h http.h server.h defs.h http-defs.h protos.h \
+ logging.cc signals.cc config.cc support.cc childs.cc init.cc \
+ http-support.cc http-methods.cc http-fields.cc http-date.cc \
+ http-error.cc http-readmsg.cc http-writemsg.cc \
+ http-doit.cc http.cc httpserver.h main.cc
diff --git a/httpserver/childs.cc b/httpserver/childs.cc
new file mode 100644
index 0000000..66729f1
--- /dev/null
+++ b/httpserver/childs.cc
@@ -0,0 +1,246 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* childs.c - child process handling. */
+/* */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - intended purpose: */
+/* Keep all functions related to child processes in one place. */
+/* - Status: */
+/* - Functions to Create and Initialize a child is thrown in. */
+/* - Should think over the actual design - looks somewhat */
+/* messy now. It should be something more clean and of */
+/* generic use, so it can be reused in future projects. */
+/* - Nevertheless -- it works, and there should be no creeping */
+/* surprises in the code... [FLW Alert... ;-)] */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: childs.c,v $ $Revision: 1.6 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+
+/****** childs/InitChild *****************************************************
+*
+* NAME
+* InitChild -- data initializition after forking the child process.
+*
+* SYNOPSIS
+* int InitChild( struct ClientBase *Client );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t InitChild( struct ClientBase *Client )
+{
+ char *UnknownIP = "0.0.0.0";
+
+ /* Init ClientBase */
+ strcpy( Client->Host.IPAddrString, inet_ntoa( Client->Socket.sin_addr ) );
+ if( Client->Host.IPAddrString == NULL )
+ strcpy( Client->Host.IPAddrString, UnknownIP );
+ Client->Host.IPAddress = inet_addr( Client->Host.IPAddrString );
+
+ Client->Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Client->Response );
+ InitReqInfo( &Client->Request );
+
+ return( OK );
+}
+
+
+
+/****** childs/NewChild ******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* ### Temporary fork() wrapper.
+* Will be later expanded into something more usefull...
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+pid_t NewChild( struct ChildBase *List, struct FDsets *PDSets, struct ClientBase *Client )
+{
+ struct ChildBase *Child;
+
+ Child = (struct ChildBase*)mymalloc( sizeof( struct ChildBase ) );
+ if( Child == NULL ) // Failure? => QUIT.
+ ErrorMsg( E_SYS, FAIL, "FAIL: NewChild(): malloc() failed!" );
+
+ // Open pipe
+ if( pipe( Child->PD ) < 0 )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: NewChild(): pipe() failed." );
+ Child->PipeStatus = PIPE_CLOSED;
+ }
+ else
+ {
+ Child->PipeStatus = PIPE_OPEN;
+ }
+
+ Child->PId = fork();
+
+ if( Child->PId < 0 ) // fork() Error? => QUIT.
+ ErrorMsg( E_SYS, FAIL, "FAIL: NewChild(): fork() failed!" );
+
+ if( Child->PId > 0 ) // parent process?
+ {
+ // Add Pipe-Descriptors to PipeSets
+ if( Child->PipeStatus == PIPE_OPEN )
+ {
+ FD_SET( Child->PD[0], &PDSets->Read );
+ if( Child->PD[0] > PDSets->MaxFD )
+ PDSets->MaxFD = Child->PD[0];
+ close( Child->PD[1] );
+ }
+ // Add Child to List
+ AddChild( List, Child );
+ }
+ else // child process
+ {
+ InitChild( Client );
+ // Remember PD to parent
+ Client->Pipe = Child->PD[1];
+ close( Child->PD[0] );
+ free( Child );
+ }
+
+ return( Child->PId );
+}
+
+
+void CleanupChild( struct ChildBase *List, struct FDsets *PDSets, pid_t PId )
+{
+ struct ChildBase *Ptr;
+ struct ChildBase *Tmp;
+
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Begin CleanupChild ..." );
+
+ if(PDSets == NULL)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### PDSets is NULL!" );
+ if(PId == (pid_t)0)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### ChildPid is NULL!" );
+ if(List == NULL)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### ChildBase is NULL!" );
+
+ if( List->PId > 0 )
+ {
+ for( Ptr = List; Ptr->next != List; Ptr = Ptr->next )
+ {
+ if( Ptr->next->PId == PId )
+ {
+ Tmp = Ptr->next;
+ break;
+ }
+ }
+ // Close pipe
+ close( Tmp->PD[0] );
+ // Remove Pipe-Descriptors from PipeSets
+ FD_CLR( Tmp->PD[0], &PDSets->Read );
+ RemChild( List, Tmp );
+ }
+}
+
+
+void AddChild( struct ChildBase *List, struct ChildBase *Child )
+{
+ Child->next = List->next;
+ Child->prev = List;
+ List->next->prev = Child;
+ List->next = Child;
+ List->PId++;
+}
+
+
+void RemChild( struct ChildBase *List, struct ChildBase *Child )
+{
+ Child->prev->next = Child->next;
+ Child->next->prev = Child->prev;
+ List->PId--;
+ free( Child );
+}
+
+
+struct ChildBase *GetChild( struct ChildBase *List, pid_t PId )
+{
+ struct ChildBase *Ptr;
+
+ if( List->PId > 0 )
+ {
+ for( Ptr = List; Ptr->next != List; Ptr = Ptr->next )
+ {
+ if( Ptr->next->PId == PId )
+ return( Ptr->next );
+ }
+ return( NULL );
+ }
+ else
+ return( NULL );
+}
diff --git a/httpserver/config.cc b/httpserver/config.cc
new file mode 100644
index 0000000..d4c235b
--- /dev/null
+++ b/httpserver/config.cc
@@ -0,0 +1,465 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* config.c - configuration and setup stuff. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - intended purpose: */
+/* Contains all code related to setup the configuration. */
+/* - Status: */
+/* - There were more features planned than are now available. */
+/* - Especially some arguments are disabled or non-functional, */
+/* so: onle use "-c <config-filepath>", and don't care about */
+/* the rest! */
+/* - The Flag Handling of Verbose/Debug-Mode is somewhat broken */
+/* - ReadConfig() uses static buffers. But they are protected */
+/* against overwriting. */
+/* - ReadConfig() contains some printf()'s. */
+/* - Handling of Sub-Server configuration still disabled. */
+/* - The rest should be okay. */
+/*------------------------------------------------------------------------*/
+
+#include <iostream>
+using namespace std;
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include <unistd.h> // for gethostname()
+
+#ifdef SOLARIS
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#endif
+
+extern int globalHTTPPort;
+
+/****** config/ReadArgs ******************************************************
+*
+* NAME
+* ReadArgs --
+*
+* SYNOPSIS
+* int ReadArgs( int argc, char *argv[] );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ReadArgs( struct ServerBase *Server, int argc, char *argv[] )
+{
+ int i;
+ int LogMode = LM_VERBOSE;
+ char *Filename = NULL;
+
+ for( i = 1; i < argc; ++i)
+ {
+ if( argv[i][0] != '-' )
+ {
+ break;
+ }
+ switch( argv[i][1] )
+ {
+ case 'D': /* Debug-Flag setzen */
+ LogMode |= LF_STDERR;
+ break;
+ case 'V': /* Verbose-Flag setzen */
+ LogMode |= LF_VERB;
+ break;
+ case 'c': /* Config-File im naechsten Argument */
+ if( ++i >= argc ) /* Keine weiteren Argumente? */
+ {
+ printf( "Oops: Missing config filename after '-c' switch.\n" );
+ printf( "Please try again.\n" );
+ Exit( FAIL );
+ }
+ else
+ {
+ Filename = argv[i];
+ }
+ break;
+ case 'h':
+ printf( "Usage: %s [-c <ConfigFile>] [-V] [-D]\n", argv[0] );
+ Exit( WARN );
+ break;
+ case '?':
+ printf( "Usage: %s [-c <ConfigFile>] [-V] [-D]\n", argv[0] );
+ Exit( WARN );
+ break;
+ default: /* Kein bekanntes Argument */
+ printf( "Unknown option '%s'.\n", argv[i] );
+ Exit( FAIL );
+ break;
+ }
+ }
+
+ return( CheckAndSet( Server, Filename, LogMode ) );
+}
+
+
+/****** config/CheckAndSet ***************************************************
+*
+* NAME
+* CheckAndSet --
+*
+* SYNOPSIS
+* int CheckAndSet( char *Directory, char *Filename, int LogMode );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t CheckAndSet( struct ServerBase *Server, char *Filename, int LogMode )
+{
+ rc_t RC = 0;
+
+ /* we skipped the config file
+ char *Def_ConfFile = "httpserver.conf";
+
+ if( Filename == NULL )
+ {
+ LogMsg( LG_SERVER, WARN, "WARN: No config file given - using default %s.",
+ Def_ConfFile );
+ Filename = Def_ConfFile;
+ }
+
+ SetFilename( Server, FT_CONFFILE, Filename );
+ */
+ Server->Log.Mode = LogMode;
+
+ return( RC );
+}
+
+
+/****** config/SetServDir ****************************************************
+*
+* NAME
+* SetServDir --
+*
+* SYNOPSIS
+* int SetServDir( char *Dirname );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t SetServDir( struct ServerBase *Server, char *Dirname )
+{
+ char *Buffer;
+ size_t BuffSize;
+ size_t MaxPath;
+
+ if ( ( Buffer = PathAlloc( &BuffSize ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for pathname of server directory." );
+ Buffer[0] = '\0';
+
+ /* Platz lassen, um auch noch Filenamen + '\0' im Buffer */
+ /* unterbringen zu können. */
+
+ MaxPath = BuffSize - strlen( "httpserver.conf" );
+ if( strlen( Dirname ) >= MaxPath )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Pathname of server directory too long." );
+ Buffer = strncpy( Buffer, Dirname, MaxPath );
+
+ if( Buffer[ strlen( Buffer ) - 1 ] != '/' )
+ Buffer = strcat( Buffer, "/" );
+
+ if(Server->Directory) free(Server->Directory);
+ Server->Directory = Buffer;
+ return( OK );
+}
+
+
+/****** config/SetFilename ***************************************************
+*
+* NAME
+* SetConfFile --
+*
+* SYNOPSIS
+* int SetConfFile( char *Filename );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+
+rc_t SetFilename( struct ServerBase *Server, int Type, char *Filename )
+{
+ char *Buffer = NULL;
+ size_t BuffSize = 0;
+ size_t PathLength, FileLength;
+
+ if( Filename != NULL )
+ {
+ if ( ( Buffer = PathAlloc( &BuffSize ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for filename \"%s\".", Filename );
+ Buffer[0] = '\0';
+
+ if( Server->Directory != NULL )
+ PathLength = strlen( Server->Directory );
+ FileLength = strlen( Filename );
+
+ if( FileLength >= BuffSize )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Pathname of file \"%s\" too long.", Filename );
+
+ if( Filename[0] != '/' )
+ {
+ if( ( PathLength + FileLength ) >= BuffSize )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Path/filename of file \"%s\" too long.", Filename );
+
+ Buffer = strncpy( Buffer, Server->Directory, BuffSize );
+ }
+ Buffer = strncat( Buffer, Filename, FileLength );
+ }
+
+ switch( Type )
+ {
+ case FT_CONFFILE:
+ Server->ConfigFile = Buffer;
+ break;
+ case FT_ACCESSLOG:
+ Server->Log.Access.Filename = Buffer;
+ break;
+ case FT_SERVERLOG:
+ Server->Log.Server.Filename = Buffer;
+ break;
+ case FT_COMMLOG:
+ Server->Log.Comm.Filename = Buffer;
+ break;
+ case FT_PIDFILE:
+ Server->PidFile = Buffer;
+ break;
+ default:
+ ErrorMsg( E_SYS, ERROR, "ERROR: Unknown filetype: %d.", Type );
+ return( ERROR );
+ break;
+ }
+ return( OK );
+}
+
+
+rc_t SetString( struct ServerBase *Server, int Type, char *String )
+{
+ char *Buffer = NULL;
+ size_t BuffSize = 0;
+
+ if( String != NULL )
+ {
+ BuffSize = strlen( String );
+ if ( ( Buffer = (char*)mymalloc( BuffSize+1 ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for string \"%s\".", String );
+ strcpy( Buffer, String );
+
+ switch( Type )
+ {
+ case ST_HOSTNAME:
+ Server->Host.Name = Buffer;
+ break;
+ case ST_MAILADDRESS:
+ Server->AdminMailAddress = Buffer;
+ break;
+ default:
+ ErrorMsg( E_SYS, ERROR, "ERROR: Unknown stringtype: %d.", Type );
+ return( ERROR );
+ break;
+ }
+ return( OK );
+ }
+ else
+ return( ERROR );
+}
+
+
+/****** config/ConfigureServer ***********************************************
+*
+* NAME
+* ConfigureServer --
+*
+* SYNOPSIS
+* int ConfigureServer( char *Keyword, char *Value1, char *Value2,
+* char *Value3 );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ConfigureServer( struct ServerBase *Server )
+{
+ char* myName;
+ char* rmanhome = CONFDIR;
+ int MaxURLLength = 120;
+ int BuffSize;
+ char* Buffer;
+
+ BuffSize = strlen( rmanhome );
+
+ if ( ( Buffer = (char*)mymalloc( BuffSize+200 ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for Server Configuration" );
+ if( gethostname( Buffer, 200 ) )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Could not determine my Hostname" );
+
+ myName=strdup(Buffer);
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_COMMLOG, strcat(Buffer,"/httpcomm.log") );
+
+ Server->Port = globalHTTPPort;
+
+ SetString( Server, ST_MAILADDRESS, "admin@localhost" );
+
+ SetString( Server, ST_HOSTNAME, myName );
+
+ SetServDir( Server, rmanhome );
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_ACCESSLOG, strcat(Buffer,"/httpaccess.log") );
+
+ Server->MaxURLLength = MaxURLLength;
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_PIDFILE, strcat(Buffer,"/httpserver.pid") );
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_SERVERLOG, strcat(Buffer,"/httpserver.log") );
+
+ free(Buffer);
+ free(myName);
+
+ return( OK );
+}
+
+
+/****** config/GetConfigKey **************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* With Help from K&R, Chapter 6, binsearch().
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int GetConfigKey( char *Keyword )
+{
+ struct KeywordKey KeyTable[] =
+ {
+ { "AccessLog", KEY_ACCESSLOG },
+ { "CommLog", KEY_COMMLOG },
+ { "IndexFile", KEY_INDEXFILE },
+ { "MaxURLLength", KEY_MAXURLLENGTH },
+ { "PidFile", KEY_PIDFILE },
+ { "Port", KEY_PORT },
+ { "ServerAdmin", KEY_SERVERADMIN },
+ { "ServerLog", KEY_SERVERLOG },
+ { "ServerName", KEY_SERVERNAME },
+ { "ServerRoot", KEY_SERVERROOT },
+ };
+
+ int cond;
+ int low;
+ int high;
+
+ low = 0;
+ high = NUM_KEYS - 1;
+
+ while( low < high )
+ {
+ if( ( cond = strcmp( Keyword, KeyTable[ low ].Keyword ) ) == 0 )
+ return( KeyTable[ low ].Key );
+ low++;
+ }
+
+ return -1;
+}
+
diff --git a/httpserver/defs.h b/httpserver/defs.h
new file mode 100644
index 0000000..26d3b36
--- /dev/null
+++ b/httpserver/defs.h
@@ -0,0 +1,249 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* defs.h - Global defines and typedefs. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _DEFS_H
+#define _DEFS_H
+
+
+/* Name of this daemon
+ */
+
+#define PROGRAM_NAME "httpserver"
+#define PROGRAM_VERSION "1.0"
+#define DAEMONNAME PROGRAM_NAME "/" PROGRAM_VERSION
+#define SERVERFIELD "Server: " DAEMONNAME "\r\n"
+
+
+/* These constants *may* be changed
+ */
+
+#define BUFFSIZE 8192
+#define MAXLINELEN 4096
+#define PIPE_BUFFSIZE 4096
+#define DATE_BUFFSIZE 40
+#define IO_BUFFSIZE 65536
+#define DEFAULT_MAXURLLENGTH 1000000
+// #define IO_BUFFSIZE 1024
+
+/* TimeOut values are given in seconds
+ */
+
+ /* Timeout when talking with subservers and client */
+#define DIALOG_TIMEOUT 30
+ /* Timeout when trying to get an unspecified mesage body, for example */
+ /* dynamically generated output (typically CGI output). */
+ /* You may have to *really* wait for it, so don't make it too small! */
+#define MSGBODY_TIMEOUT 30
+
+
+/* Misc. defines
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef SOCKLENNOTDEFINED
+typedef int socklen_t;
+#endif
+
+#define max(a,b) (a > b ? a : b)
+#define min(a,b) (a < b ? a : b)
+
+#define FOREGROUND 0
+#define BACKGROUND 1
+
+/* Std.-Zugriffsberechtigung für neue Dateien */
+#define FILE_MODE ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )
+
+/* Filetypes: */
+#define FT_NOFILE 0
+#define FT_CONFFILE 1
+#define FT_ACCESSLOG 2
+#define FT_SERVERLOG 3
+#define FT_COMMLOG 4
+#define FT_PIDFILE 5
+#define FT_CACHEFILE 6
+
+/* Stringtypes: */
+#define ST_NOSTRING 0
+#define ST_HOSTNAME 1
+#define ST_MAILADDRESS 2
+
+
+/* Pipe Status:
+ */
+
+#define PIPE_OPEN 1
+#define PIPE_CLOSED 0
+
+/* LogFile Status:
+ */
+
+#define FILE_OPEN 1
+#define FILE_CLOSED 0
+
+/* Logging Modes:
+ * FILE (0) ServerLog und AccessLog einrichten und oeffnen
+ * STDIO (1) ServerLog -> stderr; AccessLog -> stdout
+ * DEBUG (2) Detaillierte Meldungen
+ */
+
+#define LF_VERB 0x0001
+#define LF_STDERR 0x0002
+
+#define LM_NORMAL 0 /* Not Verbose, write into log files */
+#define LM_VERBOSE 1 /* Verbose, write into log files */
+#define LM_STDERR 2 /* Not Verbose, use STDOUT/STDERR */
+#define LM_VERBOSE_STDERR 3 /* Verbose, use STDOUT/STDERR */
+
+
+/* LogLevels / ReturnCodes:
+ * DEBUG (1) Detaillierte Aktionsmeldungen
+ * INFO (2) Statusmeldungen
+ * NOTE (3) Hinweise auf besondere Situationen
+ * WARN (5) Behebbare Fehlersituationen
+ * ERROR (10) Fehler die zu Aktionsabbruch fuehren
+ * FAIL (20) Fehler die zum Programmabbruch fuehren
+ */
+
+#define OK 0
+#define DEBUG 1
+#define INFO 2
+#define NOTE 3
+#define WARN 5
+#define ERROR 10
+#define FAIL 20
+#define DUMP 50
+
+#define SYS_ERROR -1
+
+/* Logging sub-systems:
+ * LG_SERVER generic server logfile
+ * LG_ACCESS HTTP request logfile
+ */
+
+#define LG_SERVER 1
+#define LG_ACCESS 2
+#define LG_COMM 3
+
+/* Error-Type flags:
+ * SYS TRUE System Error: strerror(errno)
+ * PRIV FALSE Application Error
+ */
+
+#define E_SYS TRUE
+#define E_PRIV FALSE
+
+/* Configuration Keyword Keys:
+ */
+
+#define KEY_ACCESSLOG 1
+#define KEY_COMMLOG 2
+#define KEY_INDEXFILE 3
+#define KEY_MAXURLLENGTH 4
+#define KEY_PIDFILE 5
+#define KEY_PORT 6
+#define KEY_SERVERADMIN 7
+#define KEY_SERVERLOG 8
+#define KEY_SERVERNAME 9
+#define KEY_SERVERROOT 10
+#define NUM_KEYS 11
+
+/* SubServer Communication Status Codes:
+ */
+
+#define COMM_UNSUPPORTED -3 /* don't know how to handle comm state */
+#define COMM_UNEXPECTED -2 /* unexpected data received */
+#define COMM_FAILED -1 /* trouble while communicating, protocol failure */
+#define COMM_IDLE 0 /* not connected and ready */
+#define COMM_CONNECTING 1 /* trying to connect or "Keep-Alive" connection */
+#define COMM_GET_RESPHEAD 2 /* reading and processing response header */
+#define COMM_GET_RESPBODY 3 /* reading response body */
+#define COMM_MAY_GET_BODY 4 /* have to check for response body */
+#define COMM_HERE_IS_MORE 5 /* select() indicated that there IS more data */
+#define COMM_DONE 9 /* communication done, protocol OK */
+/* Currently not in use: */
+#define COMM_RECONNECTING 10 /* trying to reconnect for authorization */
+#define COMM_VERIFYING 11 /* analysing response: add. processing required */
+#define COMM_SENDINGAUTH 12 /* (re-)sending request with authorization */
+
+/* Connection Mode Codes:
+ */
+
+#define CONN_FAILURE -3 /* Failure when setting up connection */
+#define CONN_BROKEN -2 /* Connection broken while communicating */
+#define CONN_UNDEFINED -1 /* Connection not initiated */
+#define CONN_CLOSE 0 /* Connection will be closed ASAP */
+#define CONN_OPEN 1 /* Connection is ready for communication */
+#define CONN_ERROR 2 /* Error condition in communication */
+
+/* ToDo Action Codes:
+ */
+
+#define DO_NOTHING 0
+#define DO_SINGLE_SERVER 1
+#define DO_REWRITE 2
+#define DO_SEND_RESPONSE 3
+#define DO_SEND_ERROR 4
+#define DO_SHUTDOWN 5
+
+/* Client Types */
+#define BROWSER 1
+#define RASCLIENT 2
+
+/* ToDo Argument Codes:
+ */
+
+/* - DO_REWRITE: */
+#define MODE_HTTP_1_0 1
+#define MODE_HTTP_1_1 2
+
+/* - INTERPRETE_POST_REQUEST: - */
+#define REQU_OK 1
+#define REQU_UNKNOWN_PARAMETER 2
+#define REQU_UNKNOWN_CLIENT 3
+
+/* - Result Types: Error, MDD, Skalar - */
+#define RESULT_ERROR 1
+#define RESULT_MDD 2
+#define RESULT_SKALAR 3
+
+/* - DO_SEND_ERROR: */
+/* -> use HTTP Status Codes (see http-defs.h) */
+
+/* - DO_SHUTDOWN: */
+#define CLOSE_ALL 1
+#define CLOSE_CLIENT_ONLY 2 /* Currently not used */
+
+/* - DO_NOTHING: */
+#define REALLY_NOTHING 0
+
+#endif /* _DEFS_H not defined */
diff --git a/httpserver/http-date.cc b/httpserver/http-date.cc
new file mode 100644
index 0000000..82324dd
--- /dev/null
+++ b/httpserver/http-date.cc
@@ -0,0 +1,97 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-support.c - get and set HTTP date strings. */
+/* */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-date.c,v $ $Revision: 1.1 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "types.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+/****** http-date/HTTP_Date **************************************************
+*
+* NAME
+* HTTP_Date -- create a HTTP date string.
+*
+* SYNOPSIS
+* rc_t HTTP_Date( char *Buffer, size_t BuffSize );
+*
+* FUNCTION
+* Creates a date (and time) string as defined in the HTTP
+* specifications. It uses the `gmtime()' system function to get the
+* current time in Greenwich Mean Time and creates a date string with
+* the help of `strftime()'.
+*
+* INPUTS
+* Buffer - a pointer to a buffer for the new string.
+* BuffSize - size of the Buffer for the date string.
+*
+* RESULT
+* Returns the "OK" status code if it succesfully created the date
+* string, "ERROR" otherwise. The only reason for this function should
+* fail, is when the Buffer is not large enough.
+* As a side effect, if the function succeeds, Buffer will contain the
+* current time and date in a format conforming to the HTTP
+* specifications.
+*
+* BUGS
+* Does not check if Buffer is NULL-pointer.
+*
+* SEE ALSO
+* RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1
+*
+******************************************************************************
+*
+*/
+
+rc_t HTTP_Date( char *Buffer, size_t BuffSize )
+{
+ time_t systime;
+ time_t *time_ptr;
+ struct tm *tm_ptr;
+ size_t strsize;
+
+ time_ptr = &systime;
+ time( time_ptr );
+
+ /* HTTP Date: "wdy, dd mmm yyyy hh:mm:ss GMT" */
+
+ tm_ptr = gmtime( time_ptr );
+ strsize = strftime( Buffer, BuffSize, "%a, %d %b %Y %H:%M:%S GMT", tm_ptr );
+ if( strsize == BuffSize )
+ return( ERROR );
+ else
+ return( OK );
+}
+
diff --git a/httpserver/http-defs.h b/httpserver/http-defs.h
new file mode 100644
index 0000000..12df7bc
--- /dev/null
+++ b/httpserver/http-defs.h
@@ -0,0 +1,214 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-defs.h - defines for HTTP. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _HTTP_DEFS_H
+#define _HTTP_DEFS_H
+
+#define AUTH_MAX_RETRIES 1
+
+/*
+ */
+
+#define HTTP_REQUEST 1
+#define HTTP_RESPONSE 2
+
+
+/* ReqInfo/RespInfo structure states when reading/parsing requests/responses
+ */
+
+#define RI_EMPTY 0
+#define RI_READ_OK 1
+#define RI_READ_ERROR 2
+#define RI_PARSE_OK 3
+#define RI_PARSE_WARN 4 /* trouble when parsing MsgHeaders */
+#define RI_PARSE_ERROR 5 /* Request Line/Status Line not found */
+
+/* Known Protocols:
+ */
+
+#define HTTP_0_9 0
+#define HTTP_0_9_STRING ""
+#define HTTP_1_0 1
+#define HTTP_1_0_STRING "HTTP/1.0"
+#define HTTP_1_1 2
+#define HTTP_1_1_STRING "HTTP/1.1"
+
+
+/* HTTP Method Keys:
+ */
+
+#define MKEY_NONE 0
+#define MKEY_GET 1
+#define MKEY_HEAD 2
+#define MKEY_PUT 3
+#define MKEY_POST 4
+#define MKEY_DELETE 5
+#define MKEY_OPTIONS 6
+#define MKEY_TRACE 7
+#define MKEY_UNKNOWN 999
+
+#define NUM_MKEYS 7
+
+
+/* HTTP Status Codes:
+ */
+
+#define STATUS_UNKNOWN 0
+#define STATUS_UNDEFINED 0
+#define STATUS_Continue 100
+#define STATUS_Switching_Protocols 101
+#define STATUS_OK 200
+#define STATUS_Created 201
+#define STATUS_Accepted 202
+#define STATUS_Non_Authoritative_Information 203
+#define STATUS_No_Content 204
+#define STATUS_Reset_Content 205
+#define STATUS_Partial_Content 206
+#define STATUS_Multiple_Choices 300
+#define STATUS_Moved_Permanently 301
+#define STATUS_Moved_Temporarily 302
+#define STATUS_See_Other 303
+#define STATUS_Not_Modified 304
+#define STATUS_Use_Proxy 305
+#define STATUS_Switch_Proxy 306
+#define STATUS_Bad_Request 400
+#define STATUS_Unauthorized 401
+#define STATUS_Payment_Required 402
+#define STATUS_Forbidden 403
+#define STATUS_Not_Found 404
+#define STATUS_Method_Not_Allowed 405
+#define STATUS_Not_Acceptable 406
+#define STATUS_Proxy_Authentication_Required 407
+#define STATUS_Request_Timeout 408
+#define STATUS_Conflict 409
+#define STATUS_Gone 410
+#define STATUS_Length_Required 411
+#define STATUS_Precondition_Failed 412
+#define STATUS_Request_Entity_Too_Large 413
+#define STATUS_Request_URI_Too_Long 414
+#define STATUS_Unsupported_Media_Type 415
+#define STATUS_Requested_Range_Not_Valid 416
+#define STATUS_Expectation_Failed 419
+#define STATUS_Internal_Server_Error 500
+#define STATUS_Not_Implemented 501
+#define STATUS_Bad_Gateway 502
+#define STATUS_Service_Unavailable 503
+#define STATUS_Gateway_Timeout 504
+#define STATUS_HTTP_Version_Not_Supported 505
+#define STATUS_Redirection_Failed 506
+
+
+/* HTTP Header Keys:
+ */
+
+#define HKEY_CONTINUE 0
+#define HKEY_Accept 1
+#define HKEY_Accept_Charset 2
+#define HKEY_Accept_Encoding 3
+#define HKEY_Accept_Language 4
+#define HKEY_Accept_Ranges 5
+#define HKEY_Age 6
+#define HKEY_Allow 7
+#define HKEY_Authorization 8
+#define HKEY_Cache_Control 9
+#define HKEY_Compliance 10
+#define HKEY_Connection 11
+#define HKEY_Content_Base 12
+#define HKEY_Content_Encoding 13
+#define HKEY_Content_Language 14
+#define HKEY_Content_Length 15
+#define HKEY_Content_Location 16
+#define HKEY_Content_MD5 17
+#define HKEY_Content_Range 18
+#define HKEY_Content_Type 19
+#define HKEY_Date 20
+#define HKEY_ETag 21
+#define HKEY_Expect 22
+#define HKEY_Expires 23
+#define HKEY_From 24
+#define HKEY_Host 25
+#define HKEY_If_Modified_Since 26
+#define HKEY_If_Match 27
+#define HKEY_If_None_Match 28
+#define HKEY_If_Range 29
+#define HKEY_If_Unmodified_Since 30
+#define HKEY_Keep_Alive 31
+#define HKEY_Last_Modified 32
+#define HKEY_Location 33
+#define HKEY_Max_Forwards 34
+#define HKEY_Non_Compliance 35
+#define HKEY_Pragma 36
+#define HKEY_Proxy_Authenticate 37
+#define HKEY_Proxy_Authorization 38
+#define HKEY_Public 39
+#define HKEY_Range 40
+#define HKEY_Referer 41
+#define HKEY_Retry_After 42
+#define HKEY_Server 43
+#define HKEY_Set_Proxy 44
+#define HKEY_Transfer_Encoding 45
+#define HKEY_Upgrade 46
+#define HKEY_User_Agent 47
+#define HKEY_Vary 48
+#define HKEY_Warning 49
+#define HKEY_WWW_Authenticate 50
+#define HKEY_UNKNOWN 999
+
+#define NUM_HKEYS 50
+
+
+/* Language Keys:
+ */
+
+ /* These numbers are intentionally choosen: */
+ /* Space left for upgrades. */
+ /* See also: ISP 639 / Version 1 */
+
+#define LANG_UNKNOWN 0
+#define LANG_DE 22
+#define LANG_EN 25
+#define LANG_EO 26
+#define LANG_ES 27
+#define LANG_FR 34
+#define LANG_IT 53
+
+
+/* Security Realm Keys:
+ */
+
+#define REALM_ERROR -1
+#define REALM_UNKNOWN 0
+#define REALM_UNDEFINED 0
+#define REALM_IPCLASS_A 1
+#define REALM_IPCLASS_B 2
+#define REALM_IPCLASS_C 3
+#define REALM_IPADDRESS 4
+#define REALM_HOSTNAME 10
+#define REALM_DOMAIN 11
+
+
+#endif /* _HTTP_DEFS_H not defined */
diff --git a/httpserver/http-doit.cc b/httpserver/http-doit.cc
new file mode 100644
index 0000000..1136fb6
--- /dev/null
+++ b/httpserver/http-doit.cc
@@ -0,0 +1,536 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-doit.c - functions for handling the communication in its */
+/* various states. */
+/*------------------------------------------------------------------------*/
+
+#include "servercomm/httpserver.hh"
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+/****** http/Accept **********************************************************
+*
+* NAME
+* Accept -- wrapper function to `accept()' system call.
+*
+* SYNOPSIS
+* rc_t Accept( int SockFD, struct ClientBase *Client );
+*
+* FUNCTION
+* This function is used as a wrapper for the `accept()' system call so
+* the appropriate variables and structures as defined for this program
+* will be used. In addition, if `accept()' fails it will lead the
+* program into immediate abortion.
+*
+* INPUTS
+* SockFD - the file descriptor of the socket, which will be used to
+* accept connections.
+* Client - a pointer to a ClientBase structure, where all necessary
+* informations of the client who made the connection is stored.
+*
+* RESULT
+* Returns the "OK" status code on success, never returns if it fails.
+* As a side effect, when `accept()' returns, the socket structure that
+* is part of the ClientBase structure is setup by `accpet()'.
+*
+* NOTES
+* "Client" must be a pointer to a valid ClientBase structure.
+* Calls `ErrorMsg()' in case of an failure with option fail, which will
+* cause an immediate abortion of the program.
+*
+* BUGS
+* 1) Does not check if "Client" is a NULL pointer.
+* 2) On some systems the accept call has to be made twice to succeed,
+* because the first attempt fails with an "interrupted system call"
+* error message.
+*
+******************************************************************************
+*
+*/
+
+rc_t Accept( int SockFD, struct ClientBase *Client )
+{
+ short cc = 0;
+ int test = -1;
+
+ if( Client == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: accept(): Client is NULL." );
+ Client->SockSize = sizeof( Client->Socket );
+
+ while (( cc < 10 ) && ( test < 0 ))
+ {
+#ifdef DECALPHA
+ test = accept( SockFD, (struct sockaddr *)&Client->Socket,
+ (int*)&Client->SockSize );
+#else
+ test = accept( SockFD, (struct sockaddr *)&Client->Socket,
+ (socklen_t*)&Client->SockSize );
+#endif
+ cc++;
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: accept call # %d",cc );
+ }
+ Client->SockFD = test;
+ if( Client->SockFD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: accept()." );
+ return( OK );
+}
+
+
+
+
+void GetRequest( struct ClientBase *Client )
+{
+ int flags;
+
+ /*-- Try to make SockFD non-blocking; */
+ /* if it fails, try to continue nevertheless --*/
+ flags = fcntl( Client->SockFD, F_GETFL, 0 );
+ if( flags < 0 )
+ ErrorMsg( E_SYS, WARN,
+ "WARN: GetRequest(): Client Socket: fcntl() (get flags) failed." );
+ else if( fcntl( Client->SockFD, F_SETFL, flags | O_NONBLOCK ) < 0 )
+ ErrorMsg( E_SYS, WARN,
+ "WARN: GetRequest(): Client Socket: fcntl() (set to non-blocking) failed." );
+
+ /*-- Read Header of Request */
+ Client->Request.State = ReadHeader( Client->SockFD,
+ &Client->Request.HeadBuff,
+ &Client->Request.HeadSize );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Header is:\n %s",Client->Request.HeadBuff );
+}
+
+
+
+
+void InterpreteRequest( struct ClientBase *Client, struct ToDoArgs *ToDo )
+{
+ struct CacheData *Data = NULL;
+
+ switch( Client->Request.State )
+ {
+ case RI_PARSE_ERROR:
+ // The request couldn't be parsed (comm. error or something similar)
+ // --> Shutdown the connection.
+ Client->Comm.Protocol = HTTP_1_0;
+ Client->Comm.ConnStatus = CONN_ERROR;
+ ToDo->What = DO_SHUTDOWN;
+ ToDo->Which.Code = CLOSE_CLIENT_ONLY;
+ break;
+ case RI_PARSE_OK:
+ // Check for Protocol Version of Client
+ // May be a HTTP/0.9 request?
+ if( Client->Request.Line.Version.Major <= 0 )
+ {
+ // Yes -- we don't support it, would be too much trouble ahead...
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_HTTP_Version_Not_Supported;
+ return;
+ }
+ else if( Client->Request.Line.Version.Major == 1 )
+ {
+ Client->Comm.Protocol = HTTP_1_0;
+ }
+ else
+ {
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_HTTP_Version_Not_Supported;
+ return;
+ }
+
+ // Check for Content-Length and if available, then ReadBody()
+ Client->Request.BodySize = GetContentLength( Client->Request.First );
+ if( Client->Request.BodySize > 0 )
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpreteRequest() -> ReadBody()." );
+ Client->Request.BodyBuff = ReadBody( Client->SockFD, Client->Request.BodySize );
+ }
+ // Get Connection Status //### currently not really...
+ if( TRUE )
+ Client->Comm.ConnStatus = CONN_CLOSE;
+
+ // Check for supported Methods
+ if( Client->Request.Line.Method != MKEY_POST )
+ {
+ // No supported Method found...
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: No post request!" );
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_Method_Not_Allowed;
+ }
+ // Send response
+ else
+ {
+ ToDo->What = DO_SEND_RESPONSE;
+ ToDo->Which.Code = REQU_OK;
+ }
+ break;
+ default:
+ // Strange State...
+ ErrorMsg( E_PRIV, ERROR,
+ "ERROR: InterpreteRequest(): Request can't be handled!" );
+ Client->Comm.ConnStatus = CONN_ERROR;
+ ToDo->What = DO_SHUTDOWN;
+ ToDo->Which.Code = CLOSE_CLIENT_ONLY;
+ break;
+ }
+}
+
+
+
+char *ComposeErrorResponse( int Errno, int ClientType )
+{
+ char *Msg;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+
+ if( ( Msg = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: ComposeErrorMsg() - malloc() error for Msg Buffer buffer." );
+ }
+ BuffSize -= 1;
+ Buff = Msg;
+
+ switch( ClientType )
+ {
+ case BROWSER:
+ /* Fehlermeldungen fuer HTML-Browser */
+ SNPrintf( Buff, &BuffSize, "<BR><H1>Error %d: ", Errno );
+ Buff = Msg + strlen( Msg );
+ switch( Errno )
+ {
+ case REQU_UNKNOWN_PARAMETER:
+ SNPrintf( Buff, &BuffSize, "Unknown protocol parameter." );
+ break;
+ default:
+ SNPrintf( Buff, &BuffSize, "Undefined protocol error." );
+ break;
+ }
+ break;
+
+ case RASCLIENT:
+ default:
+ /* Fehlermeldungen fuer RasClients */
+ SNPrintf( Buff, &BuffSize, "%d+%d+%d", RESULT_ERROR, Errno, 0 );
+ break;
+ }
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ComposeErrorMsg() returns %s", Msg );
+ return Msg;
+}
+
+
+
+void SendResponse( struct ClientBase *Client )
+{
+
+ /*
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() : %s",
+ Client->Response.Body );
+ */
+
+ SendHTTPMsg( Client->SockFD, &Client->Response );
+}
+
+
+/*********************************************************************
+ *
+ * This function interpretes the body of an incoming request
+ * and fills the RequestInfo struct accordingly.
+ *
+ *********************************************************************/
+rc_t GetHTTPRequest( char *Source, int SourceLen, struct HTTPRequest *RequestInfo)
+{
+ char *Buffer = NULL;
+ char *Input;
+
+ Input = (char*)mymalloc( SourceLen + 1 );
+ memcpy( Input, Source, SourceLen );
+ Input[SourceLen] = '\0';
+ // Read the message body and check for the post parameters
+ Buffer = strtok( Input, "=" );
+ while( Buffer != NULL )
+ {
+ if( strcmp(Buffer,"Database") == 0 )
+ {
+ RequestInfo->Database = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Database is %s", RequestInfo->Database );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"QueryString") == 0 )
+ {
+ RequestInfo->QueryString = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter QueryString is %s", RequestInfo->QueryString );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Capability") == 0 )
+ {
+ RequestInfo->Capability = strdup(strtok( NULL, "&\0" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Capability is %s", RequestInfo->Capability );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"ClientID") == 0 )
+ {
+ RequestInfo->ClientID = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter ClientID is %s", RequestInfo->ClientID );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Command") == 0 )
+ {
+ RequestInfo->Command = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Command is %i", RequestInfo->Command );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Endianess") == 0 )
+ {
+ RequestInfo->Endianess = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Endianess is %i", RequestInfo->Endianess );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"NumberOfQueryParameters") == 0 )
+ {
+ RequestInfo->NumberOfQueryParams = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter NumberOfQueryParams is %i", RequestInfo->NumberOfQueryParams );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinDataSize") == 0 )
+ {
+ RequestInfo->BinDataSize = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter BinDataSize is %i", RequestInfo->BinDataSize );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinData") == 0 )
+ {
+ // This parameter has to be the last one!
+ RequestInfo->BinData = (char*)mymalloc( RequestInfo->BinDataSize );
+ memcpy(RequestInfo->BinData, Source + (SourceLen-RequestInfo->BinDataSize), RequestInfo->BinDataSize );
+ //set Buffer to NULL => exit this while block
+ Buffer = NULL;
+ }
+ else if( strcmp(Buffer,"ClientType") == 0 )
+ {
+ Buffer = strtok( NULL, "&" );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Type is %s", Buffer );
+ /* BROWSER? */
+ if( strcmp(Buffer,"BROWSER") == 0 )
+ RequestInfo->ClientType = 1;
+ /* Rasclient? */
+ else if( strcmp(Buffer,"RASCLIENT") == 0 )
+ RequestInfo->ClientType = 2;
+ /* Sonstiges */
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Unknown Parameter %s", Buffer );
+ return REQU_UNKNOWN_CLIENT;
+ }
+ Buffer = strtok( NULL, "=" );
+ }
+ else
+ return REQU_UNKNOWN_PARAMETER;
+ }
+
+ free(Input);
+ return REQU_OK;
+}
+
+
+/********************************************************
+ *
+ * Analyses the client request (using the "GetHTTPRequest" function)
+ * and executes the query (function "processQuery").
+ * The result is written into the client response structure.
+ *
+ **********************************************************/
+void InterpretePOSTRequest ( struct ClientBase *Client )
+{
+ int result = 0;
+ struct HTTPRequest RequestInfo;
+ char *tmp;
+
+ /* Initialize RequestInfo */
+ RequestInfo.Database = NULL;
+ RequestInfo.QueryString = NULL;
+ RequestInfo.ClientType = 0;
+ RequestInfo.ClientID = NULL;
+ RequestInfo.Command = 0;
+ RequestInfo.Endianess = 0;
+ RequestInfo.NumberOfQueryParams = 0;
+ RequestInfo.BinDataSize = 0;
+ RequestInfo.BinData = NULL;
+ RequestInfo.Capability = NULL;
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpretePostRequest() ..." );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Request.BodySize is %d",Client->Request.BodySize );
+
+ /* get the necessary parameters */
+ result = GetHTTPRequest( Client->Request.BodyBuff, Client->Request.BodySize, &RequestInfo );
+
+ if( result == REQU_OK )
+ {
+ // here the query is actually executed
+ char* queryResult;
+ long resultLen;
+ ServerComm* scObject = ServerComm::actual_servercomm;
+
+ // the cast should be save, function only called on HTTP requests
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Vor processRequest ..." );
+ resultLen = ((HttpServer*)scObject)->processRequest(1, RequestInfo.Database, RequestInfo.Command,
+ RequestInfo.QueryString, RequestInfo.BinDataSize,
+ RequestInfo.BinData, RequestInfo.Endianess,
+ queryResult,RequestInfo.Capability);
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ... nach processRequest." );
+
+ // Note that this has to be freed!!!!!
+ Client->Response.Body = queryResult;
+ Client->Response.BodySize = resultLen;
+
+
+ Client->ClientType = RequestInfo.ClientType;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ResponseBody is %s", Client->Response.Body );
+ }
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpretePostRequest(): send error response. " );
+ Client->Response.Body = ComposeErrorResponse( result, RequestInfo.ClientType );
+ Client->Response.BodySize = strlen( Client->Response.Body );
+ Client->ClientType = RequestInfo.ClientType;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ResponseBody is %s", Client->Response.Body );
+ }
+
+ // free RequestInfo
+ free(RequestInfo.Database);
+ free(RequestInfo.QueryString);
+ free(RequestInfo.Capability);
+ free(RequestInfo.BinData);
+ free(RequestInfo.ClientID);
+
+}
+
+
+
+void CreateRasResponse( struct HTTPMode *Mode, struct ClientBase *Client )
+{
+ char *Head;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+ char MDate[30];
+
+
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Response Header begin, malloc BUFFSIZE is %d", BUFFSIZE );
+
+ HTTP_Date( MDate, 30 );
+
+ if( ( Head = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: CreateRasResponse() - malloc() error for head buffer." );
+ }
+
+ BuffSize -= 1;
+ Buff = Head;
+ bzero( Head, BuffSize );
+ CreateStatusLine( Buff, &BuffSize, STATUS_OK, Mode->Protocol );
+
+ /* General Message Header */
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Date: %s\r\n", MDate );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Connection: close\r\n" );
+
+ /* Response Message Header */
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, SERVERFIELD );
+
+ /* Entity Message Header */
+ Buff = Head + strlen( Head );
+ switch( Client->ClientType )
+ {
+ case BROWSER:
+ SNPrintf( Buff, &BuffSize, "Content-Type: text/html\r\n" );
+ break;
+ case RASCLIENT:
+ SNPrintf( Buff, &BuffSize, "Content-Type: application/octet-stream\r\n" );
+ break;
+ default:
+ SNPrintf( Buff, &BuffSize, "Content-Type: application/octet-stream\r\n" );
+ break;
+ }
+ Buff = Head + strlen( Head );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ClientResponse BodySize is %d", Client->Response.BodySize );
+
+ SNPrintf( Buff, &BuffSize, "Content-Length: %d\r\n", Client->Response.BodySize );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Last-Modified: %s\r\n", MDate );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "\r\n" );
+
+ Client->Response.Head = Head;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Response Header is %s", Client->Response.Head );
+
+}
+
+
+
+void WriteAccessLog( struct ClientBase *Client )
+{
+ char TimeString[ DATE_BUFFSIZE ];
+ struct hostent *Host;
+ char *Hostname = NULL;
+
+ bzero( TimeString, DATE_BUFFSIZE );
+
+ if( (int)Client->Host.IPAddress != -1 )
+ {
+ Host = gethostbyaddr( (const char *)&Client->Host.IPAddress,
+ sizeof( Client->Host.IPAddress ), AF_INET );
+ if( Host != NULL )
+ Hostname = Host->h_name;
+ else
+ Hostname = Client->Host.IPAddrString;
+ }
+ else
+ Hostname = Client->Host.IPAddrString;
+
+ LogDate( TimeString, DATE_BUFFSIZE );
+ LogMsg( LG_ACCESS, INFO, "%s - - %s \"%s\" %d %d\n",
+ Hostname,
+ TimeString,
+ Client->Request.Line.Vanilla,
+ Client->RespStatus,
+ Client->Response.BodySize );
+}
+
+
+
+
diff --git a/httpserver/http-error.cc b/httpserver/http-error.cc
new file mode 100644
index 0000000..92fd451
--- /dev/null
+++ b/httpserver/http-error.cc
@@ -0,0 +1,446 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-error.c - HTTP Error message handling. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - The internal response strings should be completed and */
+/* the overly long lines should be broken up. */
+/* - A somewhat more dynamic approach to the handling of the */
+/* error string table should be used. */
+/*------------------------------------------------------------------------*/
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+struct HTTPError HTTPErrorTable[] =
+{
+ {
+ STATUS_Continue,
+ "Continue",
+ "",
+ ""
+ },
+ {
+ STATUS_Switching_Protocols,
+ "Switching Protocols",
+ "",
+ ""
+ },
+ {
+ STATUS_OK,
+ "OK",
+ "",
+ ""
+ },
+ {
+ STATUS_Created,
+ "Created",
+ "",
+ ""
+ },
+ {
+ STATUS_Accepted,
+ "Accepted",
+ "",
+ ""
+ },
+ {
+ STATUS_Non_Authoritative_Information,
+ "Non-Authoritative Information",
+ "",
+ ""
+ },
+ {
+ STATUS_No_Content,
+ "No Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Reset_Content,
+ "Reset Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Partial_Content,
+ "Partial Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Multiple_Choices,
+ "Multiple Choices",
+ "",
+ ""
+ },
+ {
+ STATUS_Moved_Permanently,
+ "Moved Permanently",
+ "",
+ ""
+ },
+ {
+ STATUS_Moved_Temporarily,
+ "Moved Temporarily",
+ "",
+ ""
+ },
+ {
+ STATUS_See_Other,
+ "See Other",
+ "",
+ ""
+ },
+ {
+ STATUS_Not_Modified,
+ "Not Modified",
+ "",
+ ""
+ },
+ {
+ STATUS_Use_Proxy,
+ "Use Proxy",
+ "",
+ ""
+ },
+ {
+ STATUS_Bad_Request,
+ "Bad Request",
+ "<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Bad Request</H1>\n"\
+ "Your browser sent a request that this server could not understand.\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Problem mit Request</H1>\n"\
+ "Ihr Browser hat einen Request geschickt, der von diesem Server "\
+ "nicht verstanden wurde.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Unauthorized,
+ "Unauthorized",
+ "<HTML><HEAD>\n<TITLE>401 Unauthorized</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Unauthorized</H1>\n"\
+ "You have not the necessary rights to get the requested document.\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>401 Unauthorized</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Nicht Authorisiert</H1>\n"\
+ "Sie haben nicht die notwendigen Rechte um auf das angeforderte "\
+ "Dokument zuzugreifen.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Payment_Required,
+ "Payment Required",
+ "<HTML><HEAD>\n<TITLE>402 Payment Required</TITLE>\n</HEAD><BODY>\n<H1>Payment Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>402 Payment Required</TITLE>\n</HEAD><BODY>\n<H1>Payment Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Forbidden,
+ "Forbidden",
+ "<HTML><HEAD>\n<TITLE>403 Forbidden</TITLE>\n</HEAD><BODY>\n<H1>Forbidden</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>403 Forbidden</TITLE>\n</HEAD><BODY>\n<H1>Forbidden</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Found,
+ "Not Found",
+ "<HTML><HEAD>\n<TITLE>404 Not Found</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Not Found</H1>\n"\
+ "<EM>Tried hard, really...</EM>\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>404 Not Found</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Nicht Gefunden</H1>\n"\
+ "Das angeforderte Dokument wurde nicht gefunden.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Method_Not_Allowed,
+ "Method Not Allowed",
+ "<HTML><HEAD>\n<TITLE>405 Method Not Allowed</TITLE>\n</HEAD><BODY>\n<H1>Method Not Allowed</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>405 Method Not Allowed</TITLE>\n</HEAD><BODY>\n<H1>Method Not Allowed</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Acceptable,
+ "Not Acceptable",
+ "<HTML><HEAD>\n<TITLE>406 Not Acceptable</TITLE>\n</HEAD><BODY>\n<H1>Not Acceptable</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>406 Not Acceptable</TITLE>\n</HEAD><BODY>\n<H1>Not Acceptable</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Proxy_Authentication_Required,
+ "Proxy Authentication Required",
+ "<HTML><HEAD>\n<TITLE>407 Proxy Authentication Required</TITLE>\n</HEAD><BODY>\n<H1>Proxy Authentication Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>407 Proxy Authentication Required</TITLE>\n</HEAD><BODY>\n<H1>Proxy Authentication Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_Timeout,
+ "Request Timeout",
+ "<HTML><HEAD>\n<TITLE>408 Request Timeout</TITLE>\n</HEAD><BODY>\n<H1>Request Timeout</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>408 Request Timeout</TITLE>\n</HEAD><BODY>\n<H1>Request Timeout</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Conflict,
+ "Conflict",
+ "<HTML><HEAD>\n<TITLE>409 Conflict</TITLE>\n</HEAD><BODY>\n<H1>Conflict</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>409 Conflict</TITLE>\n</HEAD><BODY>\n<H1>Conflict</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Gone,
+ "Gone",
+ "<HTML><HEAD>\n<TITLE>410 Gone</TITLE>\n</HEAD><BODY>\n<H1>Gone</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>410 Gone</TITLE>\n</HEAD><BODY>\n<H1>Gone</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Length_Required,
+ "Length Required",
+ "<HTML><HEAD>\n<TITLE>411 Length Required</TITLE>\n</HEAD><BODY>\n<H1>Length Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>411 Length Required</TITLE>\n</HEAD><BODY>\n<H1>Length Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Precondition_Failed,
+ "Precondition Failed",
+ "<HTML><HEAD>\n<TITLE>412 Precondition Failed</TITLE>\n</HEAD><BODY>\n<H1>Precondition Failed</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>412 Precondition Failed</TITLE>\n</HEAD><BODY>\n<H1>Precondition Failed</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_Entity_Too_Large,
+ "Request Entity Too Large",
+ "<HTML><HEAD>\n<TITLE>413 Request Entity Too Large</TITLE>\n</HEAD><BODY><H1>Request Entity Too Large\n</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>413 Request Entity Too Large</TITLE>\n</HEAD><BODY><H1>Request Entity Too Large\n</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_URI_Too_Long,
+ "Request-URI Too Long",
+ "<HTML><HEAD>\n<TITLE>414 Request-URI Too Long</TITLE>\n</HEAD><BODY><H1>Request-URI Too Long\n</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>414 Request-URI Too Long</TITLE>\n</HEAD><BODY><H1>Request-URI Too Long\n</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Unsupported_Media_Type,
+ "Unsupported Media Type",
+ "<HTML><HEAD>\n<TITLE>415 Unsupported Media Type</TITLE>\n</HEAD><BODY>\n<H1>Unsupported Media Type</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>415 Unsupported Media Type</TITLE>\n</HEAD><BODY>\n<H1>Unsupported Media Type</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Requested_Range_Not_Valid,
+ "Requested Range Not Valid",
+ "<HTML><HEAD>\n<TITLE>416 Requested Range Not Valid</TITLE>\n</HEAD><BODY>\n<H1>Requested Range Not Valid</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>416 Requested Range Not Valid</TITLE>\n</HEAD><BODY>\n<H1>Requested Range Not Valid</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Internal_Server_Error,
+ "Internal Server Error",
+ "<HTML><HEAD>\n<TITLE>500 Internal Server Error</TITLE>\n</HEAD><BODY>\n<H1>Internal Server Error</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>500 Internal Server Error</TITLE>\n</HEAD><BODY>\n<H1>Internal Server Error</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Implemented,
+ "Not Implemented",
+ "<HTML><HEAD>\n<TITLE>501 Not Implemented</TITLE>\n</HEAD><BODY>\n<H1>Not Implemented</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>501 Not Implemented</TITLE>\n</HEAD><BODY>\n<H1>Not Implemented</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Bad_Gateway,
+ "Bad Gateway",
+ "<HTML><HEAD>\n<TITLE>502 Bad Gateway</TITLE>\n</HEAD><BODY>\n<H1>Bad Gateway</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>502 Bad Gateway</TITLE>\n</HEAD><BODY>\n<H1>Bad Gateway</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Service_Unavailable,
+ "Service Unavailable",
+ "<HTML><HEAD>\n<TITLE>503 Service Unavailable</TITLE>\n</HEAD><BODY>\n<H1>Service Unavailable</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>503 Service Unavailable</TITLE>\n</HEAD><BODY>\n<H1>Service Unavailable</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Gateway_Timeout,
+ "Gateway Timeout",
+ "<HTML><HEAD>\n<TITLE>504 Gateway Timeout</TITLE>\n</HEAD><BODY>\n<H1>Gateway Timeout</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>504 Gateway Timeout</TITLE>\n</HEAD><BODY>\n<H1>Gateway Timeout</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_HTTP_Version_Not_Supported,
+ "HTTP Version Not Supported",
+ "<HTML><HEAD>\n<TITLE>505 HTTP Version Not Supported</TITLE>\n</HEAD><BODY>\n<H1>HTTP Version Not Supported</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>505 HTTP Version Not Supported</TITLE>\n</HEAD><BODY>\n<H1>HTTP Version Not Supported</H1>\n</BODY></HTML>\n"
+ },
+};
+
+#define NUM_STATUSCODES 37
+
+
+/****** http-error/GetHTTPErrorTableEntry ************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int GetHTTPErrorTableEntry( int Code )
+{
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_STATUSCODES ];
+ int i;
+
+ low = 0;
+ high = NUM_STATUSCODES - 1;
+ for( i = 0; i < NUM_STATUSCODES; i++ )
+ check[ i ] = 0;
+
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( Code < HTTPErrorTable[mid].Code )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( 0 );
+ }
+ else if( Code > HTTPErrorTable[mid].Code )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( 0 );
+ }
+ else
+ {
+ return( mid );
+ }
+ }
+}
+
+
+/****** http-error/CreateHTTPError *******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CreateHTTPError( int Code, struct HTTPMode *Mode, struct HTTPMsg *Msg )
+{
+ char *Head;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+ char *Body;
+ size_t BodySize;
+ size_t Used;
+
+ int Entry;
+ char Date[DATE_BUFFSIZE];
+
+ bzero( Date, DATE_BUFFSIZE );
+ if( ( Head = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: CreateHTTPError() - malloc() error for head buffer." );
+ return( ERROR );
+ }
+ Buff = Head;
+ BuffSize -= 1;
+
+ HTTP_Date( Date, DATE_BUFFSIZE );
+ Entry = GetHTTPErrorTableEntry( Code );
+ Body = HTTPErrorTable[Entry].Message_en;
+ BodySize = strlen( HTTPErrorTable[Entry].Message_en );
+
+ CreateStatusLine( Buff, &BuffSize, Code, Mode->Protocol );
+ Used = strlen( Head );
+ Buff = Head + Used;
+ BuffSize -= Used;
+ SNPrintf( Buff, &BuffSize,
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+ "%s"
+ "Content-Type: text/html\r\n"
+ "Content-Language: %s\r\n"
+ "Content-Length: %d\r\n\r\n",
+ Date, SERVERFIELD, "en", BodySize );
+
+ Msg->Head = Head;
+ Msg->Body = strdup(Body);
+ Msg->BodySize = BodySize;
+
+ return( OK );
+}
diff --git a/httpserver/http-fields.cc b/httpserver/http-fields.cc
new file mode 100644
index 0000000..76f00f7
--- /dev/null
+++ b/httpserver/http-fields.cc
@@ -0,0 +1,218 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-fields.c - get and set HTTP Header fieldnames. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+struct KeywordKey FieldnameKeyTable[] =
+{
+ { "Accept" , HKEY_Accept },
+ { "Accept-Charset" , HKEY_Accept_Charset },
+ { "Accept-Encoding" , HKEY_Accept_Encoding },
+ { "Accept-Language" , HKEY_Accept_Language },
+ { "Accept-Ranges" , HKEY_Accept_Ranges },
+ { "Accept-charset" , HKEY_Accept_Charset },
+ { "Accept-encoding" , HKEY_Accept_Encoding },
+ { "Accept-language" , HKEY_Accept_Language },
+ { "Accept-ranges" , HKEY_Accept_Ranges },
+ { "Age" , HKEY_Age },
+ { "Allow" , HKEY_Allow },
+ { "Authorization" , HKEY_Authorization },
+ { "Cache-Control" , HKEY_Cache_Control },
+ { "Cache-control" , HKEY_Cache_Control },
+ { "Compliance" , HKEY_Compliance },
+ { "Connection" , HKEY_Connection },
+ { "Content-Base" , HKEY_Content_Base },
+ { "Content-Encoding" , HKEY_Content_Encoding },
+ { "Content-Language" , HKEY_Content_Language },
+ { "Content-Length" , HKEY_Content_Length },
+ { "Content-Location" , HKEY_Content_Location },
+ { "Content-MD5" , HKEY_Content_MD5 },
+ { "Content-Range" , HKEY_Content_Range },
+ { "Content-Type" , HKEY_Content_Type },
+ { "Content-base" , HKEY_Content_Base },
+ { "Content-encoding" , HKEY_Content_Encoding },
+ { "Content-language" , HKEY_Content_Language },
+ { "Content-length" , HKEY_Content_Length },
+ { "Content-location" , HKEY_Content_Location },
+ { "Content-range" , HKEY_Content_Range },
+ { "Content-type" , HKEY_Content_Type },
+ { "Date" , HKEY_Date },
+ { "ETag" , HKEY_ETag },
+ { "Expect" , HKEY_Expect },
+ { "Expires" , HKEY_Expires },
+ { "From" , HKEY_From },
+ { "Host" , HKEY_Host },
+ { "If-Modified-Since" , HKEY_If_Modified_Since },
+ { "If-Match" , HKEY_If_Match },
+ { "If-None-Match" , HKEY_If_None_Match },
+ { "If-Range" , HKEY_If_Range },
+ { "If-Unmodified-Since" , HKEY_If_Unmodified_Since },
+ { "Keep-Alive" , HKEY_Keep_Alive },
+ { "Last-Modified" , HKEY_Last_Modified },
+ { "Location" , HKEY_Location },
+ { "Max-Forwards" , HKEY_Max_Forwards },
+ { "Non-Compliance" , HKEY_Non_Compliance },
+ { "Pragma" , HKEY_Pragma },
+ { "Proxy-Authenticate" , HKEY_Proxy_Authenticate },
+ { "Proxy-Authorization" , HKEY_Proxy_Authorization },
+ { "Public" , HKEY_Public },
+ { "Range" , HKEY_Range },
+ { "Referer" , HKEY_Referer },
+ { "Retry-After" , HKEY_Retry_After },
+ { "Server" , HKEY_Server },
+ { "Set-Proxy" , HKEY_Set_Proxy },
+ { "Transfer-Encoding" , HKEY_Transfer_Encoding },
+ { "Upgrade" , HKEY_Upgrade },
+ { "User-Agent" , HKEY_User_Agent },
+ { "Vary" , HKEY_Vary },
+ { "WWW-Authenticate" , HKEY_WWW_Authenticate },
+ { "Warning" , HKEY_Warning },
+};
+
+#define NUM_FIELDS 62
+
+
+/****** http-fields/HTTP_GetHKey *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int HTTP_GetHKey( char *Keyword )
+{
+ int cond;
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_FIELDS ];
+ int i;
+
+ low = 0;
+ high = NUM_FIELDS - 1;
+ for( i = 0; i < NUM_FIELDS; i++ )
+ check[ i ] = 0;
+
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( ( cond = strcmp( Keyword, FieldnameKeyTable[mid].Keyword ) ) < 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( HKEY_UNKNOWN );
+ }
+ else if( cond > 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( HKEY_UNKNOWN );
+ }
+ else
+ return( FieldnameKeyTable[mid].Key );
+ }
+ return( HKEY_UNKNOWN );
+}
+
+
+/****** http-fields/HTTP_GetFieldName ****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+char *HTTP_GetFieldName( int Key )
+{
+ int i;
+
+ for( i = 0; i < NUM_FIELDS; i++ )
+ {
+ if( FieldnameKeyTable[i].Key == Key )
+ return( FieldnameKeyTable[i].Keyword );
+ }
+ return( NULL );
+}
diff --git a/httpserver/http-methods.cc b/httpserver/http-methods.cc
new file mode 100644
index 0000000..4a99f71
--- /dev/null
+++ b/httpserver/http-methods.cc
@@ -0,0 +1,163 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-methods.c - get and set HTTP Method names. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+#include <ctype.h>
+
+struct KeywordKey MethodKeyTable[] =
+{
+ { "GET", MKEY_GET },
+ { "HEAD", MKEY_HEAD },
+ { "PUT", MKEY_PUT },
+ { "POST", MKEY_POST },
+ { "DELETE", MKEY_DELETE },
+ { "OPTIONS", MKEY_OPTIONS },
+ { "TRACE", MKEY_TRACE },
+};
+
+
+/****** http-methods/HTTP_GetMKey ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int HTTP_GetMKey( char *Keyword )
+{
+ int cond;
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_MKEYS ];
+ int i;
+
+ low = 0;
+ high = NUM_MKEYS - 1;
+ for( i = 0; i < NUM_MKEYS; i++ )
+ check[ i ] = 0;
+ if( !isalpha( *Keyword ) )
+ return( MKEY_NONE );
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( ( cond = strcmp( Keyword, MethodKeyTable[mid].Keyword ) ) < 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( MKEY_UNKNOWN );
+ }
+ else if( cond > 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( MKEY_UNKNOWN );
+ }
+ else
+ return( MethodKeyTable[mid].Key );
+ }
+ return( MKEY_UNKNOWN );
+}
+
+
+/****** http-methods/HTTP_GetMethodName **************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+char *HTTP_GetMethodName( int Key )
+{
+ int i;
+
+ for( i = 0; i < NUM_MKEYS; i++ )
+ {
+ if( MethodKeyTable[i].Key == Key )
+ return( MethodKeyTable[i].Keyword );
+ }
+ return( NULL );
+}
diff --git a/httpserver/http-readmsg.cc b/httpserver/http-readmsg.cc
new file mode 100644
index 0000000..da88274
--- /dev/null
+++ b/httpserver/http-readmsg.cc
@@ -0,0 +1,1014 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-readmsg.c - generic HTTP-Message functions: */
+/* Reading and parsing of HTTP-Messages. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - Missing symbolic constant BUFFBLOCK_SIZE. */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/* - ParseReqLine()/ParseRespLine() use static buffers, but */
+/* they are protected against overwriting. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+/****** http-readmsg/ReadHeader **********************************************
+*
+* NAME
+* ReadHeader -- Read a HTTP message header from a socket.
+*
+* SYNOPSIS
+* char *ReadHeader( int SockFD, size_t *size );
+*
+* FUNCTION
+* This function reads from the socket descriptor "SockFD" until it
+* detects an empty line (two <CR><LF> sequences in a row). Every read
+* character is stored in a buffer, which is dynamically allocated.
+* If the empty line is detected, it returns a pointer to the buffer
+* and the variable "*size" contains the buffersize.
+*
+* INPUTS
+* SockFD - The socket descriptor to read from.
+* size - A pointer to a variable which may hold the size of the buffer
+* which contains the message header.
+*
+* RESULT
+* A pointer a buffer with the HTTP message header.
+*
+* NOTES
+* The function checks for errors returned by the "read()" system call.
+* Other problems ("out-of-band" data, socket errors) are not checked.
+*
+******************************************************************************
+*
+*/
+
+int ReadHeader( int SockFD, char **Buffer, size_t *BuffSize )
+{
+ size_t BuffBlock = 1024;
+ size_t minbuff = 2;
+ size_t nread = 0;
+ size_t sumread = 0;
+ char *Ptr;
+ int check_eol = 0;
+ int error = FALSE;
+ int elapsed = 0;
+
+ for(;;)
+ {
+ if( *BuffSize - sumread < minbuff )
+ {
+ *BuffSize += BuffBlock;
+ *Buffer = (char*)realloc( *Buffer, *BuffSize );
+ if( *Buffer == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadHeader(): malloc() failed." );
+ error = TRUE;
+ break;
+ }
+ bzero( *Buffer, *BuffSize );
+ }
+
+ Ptr = *Buffer + sumread;
+ nread = read( SockFD, Ptr, 1 );
+ if( nread == 1 )
+ {
+ elapsed = 0; /* Clear timeout counter */
+ sumread++;
+ if( *Ptr == '\n' ) /* Check for two consecutive "\r\n" */
+ {
+ if( check_eol == 1 )
+ break; /* if found => End-Of-Header */
+ else
+ check_eol = 1;
+ }
+ else if( *Ptr != '\r' )
+ check_eol = 0;
+ }
+ else if( nread == 0 )
+ {
+ if( elapsed >= 30 )
+ {
+ ErrorMsg( E_PRIV, ERROR, "ERROR: ReadHeader() timed out." );
+ error = TRUE;
+ break;
+ }
+ sleep(1);
+ elapsed++;
+ }
+ else
+ {
+ if( errno != EAGAIN )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadHeader(): read() failed." );
+ error = TRUE;
+ break;
+ }
+ else
+ {
+ sleep( elapsed );
+ if( elapsed >= 30 )
+ {
+ ErrorMsg( E_PRIV, ERROR, "ERROR: ReadHeader() timed out." );
+ error = TRUE;
+ break;
+ }
+ sleep(1);
+ elapsed++;
+ }
+ }
+ }
+ if( error == TRUE )
+ {
+ if( *Buffer != NULL )
+ free( *Buffer );
+ *Buffer = NULL;
+ *BuffSize = 0;
+ return( RI_READ_ERROR );
+ }
+ else
+ return( RI_READ_OK );
+}
+
+
+/****** http-readmsg/ReadBody ************************************************
+*
+* NAME
+* ReadBody -- Read a HTTP message body from a socket.
+*
+* SYNOPSIS
+* char *ReadBody( int SockFD, size_t BuffSize );
+*
+* FUNCTION
+* This functions reads the HTTP message body with the size "BuffSize"
+* from the socket "SockFD". A buffer for the message body is allocated
+* within this function and a pointer to this buffer is returned.
+*
+* INPUTS
+* SockFD - The socket descriptor to read from.
+* BuffSize - The size of the message body.
+*
+* RESULT
+* A pointer to the buffer which contains the message body.
+*
+* NOTES
+* The function checks for errors returned by the "read()" system call.
+* Other problems ("out-of-band" data, socket errors) are not checked.
+*
+******************************************************************************
+*
+*/
+
+char *ReadBody( int SockFD, size_t BuffSize )
+{
+ int nread = 0;
+ char *Buffer = NULL;
+
+ if( ( Buffer = (char*)mymalloc( BuffSize + 1 ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for HTTP-Body buffer." );
+ return( Buffer );
+ }
+ bzero( Buffer, BuffSize + 1);
+ nread = ReadN( SockFD, Buffer, BuffSize );
+ if( nread < 0 )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadBody(): read() failed." );
+ free( Buffer );
+ Buffer = NULL;
+ return( Buffer );
+ }
+ else if( nread < BuffSize )
+ {
+ ErrorMsg( E_PRIV, WARN, "WARN: MessageBody not of expected size." );
+ }
+ return( Buffer );
+}
+
+
+/****** http-readmsg/ParseReqHeader ******************************************
+*
+* NAME
+* ParseReqHeader - Parse the HTTP request header.
+*
+* SYNOPSIS
+* rc_t ParseReqHeader( struct ReqInfo *Request );
+*
+* FUNCTION
+* This is the main function for parsing the HTTP request headers.
+* It first calls "ParseReqLine()" to actually parse the "Request
+* Line" (the first line of an HTTP request) and then calls
+* subsequently "ParseMsgLine()" for every non-empty line following
+* the request-line.
+*
+* The results of this parsing process are stored in a data structure
+* of the type "ReqInfo", which is later used for searching in and
+* reconstructing of the header informations.
+*
+* INPUTS
+* Request - A pointer to a data structure of the type ReqInfo.
+*
+* RESULT
+* Returns "OK" if everything went well.
+*
+* BUGS
+* It doesn't check if "Request" is a NULL pointer.
+*
+* SEE ALSO
+* ParseRespHeader(), ParseReqLine(), ParseMsgLine().
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseReqHeader( struct ReqInfo *Request )
+{
+ char *Buffer;
+ char *Param;
+ int Key;
+ struct MsgHeader *Header;
+
+ Header = NULL;
+ Buffer = Request->HeadBuff;
+ if( Request->State == RI_READ_OK )
+ {
+ Buffer = ParseReqLine( Buffer, Request );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: *** Parsed Req %s", Buffer );
+ if( Request->State == RI_PARSE_ERROR )
+ return( WARN );
+ }
+ else
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( WARN );
+ }
+
+ while( Buffer != NULL && *Buffer != '\0' )
+ {
+ Key = -1;
+ Param = NULL;
+ Buffer = ParseMsgLine( Buffer, &Key, &Param );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: *** Parsed Msg %s", Buffer );
+ if( Buffer != NULL )
+ {
+ Header = AppendMsgHeader( Request->Last, Key, Param );
+ Request->Last = Header;
+ }
+ if( Request->First == NULL )
+ Request->First = Header;
+ }
+ if( Request->First == NULL )
+ {
+ Request->State = RI_PARSE_WARN;
+ return( WARN );
+ }
+ else
+ {
+ Request->State = RI_PARSE_OK;
+ return( OK );
+ }
+}
+
+
+/****** http-readmsg/ParseRespHeader *****************************************
+*
+* NAME
+* ParseRespHeader - Parse the HTTP response header.
+*
+* SYNOPSIS
+* rc_t ParseRespHeader( struct RespInfo *Response );
+*
+* FUNCTION
+* This is the main function for parsing the HTTP response headers.
+* It first calls "ParseRespLine()" to actually parse the "Response
+* Line" (the first line of an HTTP response) and then calls
+* subsequently "ParseMsgLine()" for every non-empty line following
+* the request-line.
+*
+* The results of this parsing process are stored in a data structure
+* of the type "RespInfo", which is later used for searching in and
+* reconstructing of the header informations.
+*
+* INPUTS
+* Response - A pointer to a data structure of the type RespInfo.
+*
+* RESULT
+* Returns "OK" if everything went well.
+*
+* BUGS
+* Actually, it always returns an "OK" status code.
+* It doesn't check if "Response" is a NULL pointer.
+*
+* SEE ALSO
+* ParseReqHeader(), ParseRespLine(), ParseMsgLine().
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseRespHeader( struct RespInfo *Response )
+{
+ char *Buffer;
+ char *Keyword;
+ char *Param;
+ size_t i;
+ int Key;
+ struct MsgHeader *Header;
+
+ Header = NULL;
+ Buffer = Response->HeadBuff;
+ Buffer = ParseRespLine( Buffer, Response );
+
+ while( Buffer != NULL )
+ {
+ Key = -1;
+ Param = NULL;
+ Buffer = ParseMsgLine( Buffer, &Key, &Param );
+ if( Buffer != NULL )
+ {
+ Header = AppendMsgHeader( Response->Last, Key, Param );
+ Response->Last = Header;
+ }
+ if( Response->First == NULL )
+ Response->First = Header;
+ }
+ return( OK );
+}
+
+
+/****** http-readmsg/ParseReqLine ********************************************
+*
+* NAME
+* ParseReqLine - Parse the HTTP request line.
+*
+* SYNOPSIS
+* char *ParseReqLine( char *Buffer, struct ReqInfo *Request );
+*
+* FUNCTION
+* This function parses the beginning of the buffer "Buffer" for the
+* contents of a HTTP request line. Since the parsing process (as
+* implemented here) is destructive to the original string, the buffer
+* is first scanned for a <CR><LF> sequence (end-of-line mark of a
+* HTTP message) while copying any other character encountered to a
+* secondary buffer. This "Backup" of the request line is later used
+* for logging purposes, so it can be referred to in case of a problem.
+*
+* Then the request line is parsed and broken up in its components, as
+* they are: Request method, URL, protocol-id and version. These are
+* stored in the appropriate places in a "ReqInfo" data structure.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Request - A pointer to a data structure of the type ReqInfo.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* BUGS
+* "Buffer" and "Request" are not checked for NULL pointers.
+* The "Backup" of the request line has a maximum length of
+* "MAXLINELEN".
+*
+* SEE ALSO
+* ParseRespLine().
+*
+******************************************************************************
+*
+*/
+
+char *ParseReqLine( char *Buffer, struct ReqInfo *Request )
+{
+ char Tmp[ MAXLINELEN ];
+ char *NewBuffer;
+ char *Ptr;
+ char *Keyword;
+ char *URL = NULL;
+ char *PVersion = NULL;
+ int Key = 0;
+ int PVmaj = -1;
+ int PVmin = -1;
+ int i;
+ int eol_found = FALSE;
+
+ Keyword = Buffer;
+
+ for( Ptr = Buffer, i = 0; i < MAXLINELEN; Ptr++, i++ )
+ {
+ if( *Ptr == '\r')
+ Tmp[i] = '\0';
+ else if( *Ptr == '\n' )
+ {
+ Tmp[i] = '\0';
+ eol_found = TRUE;
+ break;
+ }
+ else
+ Tmp[i] = *Ptr;
+ }
+ Tmp[i+1] = '\0';
+ if( eol_found != TRUE )
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( NULL );
+ }
+
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == ' ' )
+ {
+ if( URL == NULL )
+ {
+ *Ptr = '\0';
+ URL = ++Ptr;
+ }
+ else
+ {
+ *Ptr = '\0';
+ ++Ptr;
+ if( strcmp( "HTTP/", Ptr ) )
+ {
+ Ptr += 5;
+ PVersion = Ptr;
+ }
+ }
+ }
+ else if( *Ptr == '\r' )
+ {
+ *Ptr = '\0';
+ }
+ }
+ *Ptr = '\0';
+ NewBuffer = ++Ptr;
+
+ if( PVersion != NULL )
+ {
+ for( Ptr = PVersion; *Ptr != '\0'; Ptr++ )
+ {
+ if( *Ptr == '.' )
+ {
+ *Ptr = '\0';
+ ++Ptr;
+ break;
+ }
+ }
+ PVmaj = strtol( PVersion, NULL, 10 );
+ PVmin = strtol( Ptr, NULL, 10 );
+ }
+
+ if( URL != NULL )
+ {
+ Request->Line.Vanilla = (char*)mymalloc( strlen( Tmp ) + 1 );
+ Request->Line.Method = HTTP_GetMKey( Keyword );
+ // SplitURL( URL, &Request->Line.URL );
+ Request->Line.URL.Path = URL;
+ Request->Line.Version.Major = PVmaj;
+ Request->Line.Version.Minor = PVmin;
+ strcpy( Request->Line.Vanilla, Tmp );
+ Request->State = RI_PARSE_OK;
+ return( NewBuffer );
+ }
+ else
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( NULL );
+ }
+}
+
+
+/****** http-readmsg/ParseRespLine *******************************************
+*
+* NAME
+* ParseRespLine - Parse the HTTP response line.
+*
+* SYNOPSIS
+* char *ParseRespLine( char *Buffer, struct RespInfo *Response );
+*
+* FUNCTION
+* This function parses the beginning of the buffer "Buffer" for the
+* contents of a HTTP response line. Since the parsing process (as
+* implemented here) is destructive to the original string, the buffer
+* is first scanned for a <CR><LF> sequence (end-of-line mark of a
+* HTTP message) while copying any other character encountered to a
+* secondary buffer. This "Backup" of the response line is later used
+* for logging purposes, so it can be referred to in case of a problem.
+*
+* Then the response line is parsed and broken up in its components, as
+* they are: Protocol-id and version, (numeric) status code and
+* "reason phrase". These are stored in the appropriate places in a
+* "RespInfo" data structure.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Response - A pointer to a data structure of the type RespInfo.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* BUGS
+* "Buffer" and "Response" are not checked for NULL pointers.
+* The "Backup" of the response line has a maximum length of
+* "MAXLINELEN".
+*
+* SEE ALSO
+* ParseReqLine().
+*
+******************************************************************************
+*
+*/
+
+char *ParseRespLine( char *Buffer, struct RespInfo *Response )
+{
+ char Tmp[ MAXLINELEN ];
+ char *Ptr;
+ char *Reason = NULL;
+ char *PVersion = NULL;
+ char *Status = NULL;
+ char *PVmaj = NULL;
+ char *PVmin = NULL;
+ int i;
+
+ for( Ptr = Buffer, i = 0; i <= MAXLINELEN - 1; Ptr++, i++ )
+ {
+ if( *Ptr == '\r')
+ Tmp[i] = '\0';
+ else if( *Ptr == '\n' )
+ {
+ Tmp[i] = '\0';
+ break;
+ }
+ else
+ Tmp[i] = *Ptr;
+ }
+ Tmp[i+1] = '\0';
+
+ Response->Line.Vanilla = (char*)mymalloc( strlen( Tmp ) + 1 );
+ strcpy( Response->Line.Vanilla, Tmp );
+
+ if( strcmp( "HTTP/", Buffer ) )
+ {
+ PVmaj = Buffer + 5;
+ for( Ptr = PVmaj; *Ptr != ' '; Ptr++ )
+ {
+ if( *Ptr == '.' )
+ {
+ *Ptr = '\0';
+ PVmin = ++Ptr;
+ }
+ }
+ *Ptr = '\0';
+ Response->Line.Version.Major = strtol( PVmaj, NULL, 10 );
+ Response->Line.Version.Minor = strtol( PVmin, NULL, 10 );
+ }
+ else
+ return( NULL );
+
+ Status = ++Ptr;
+ while( *Ptr != ' ' )
+ Ptr++;
+ *Ptr = '\0';
+ Response->Line.Status = strtol( Status, NULL, 10 );
+
+ Ptr++;
+ Response->Line.Reason = Ptr;
+
+ while( *Ptr != '\n' )
+ {
+ if( *Ptr == '\r' )
+ *Ptr = '\0';
+ Ptr++;
+ }
+ *Ptr = '\0';
+
+ return( ++Ptr );
+}
+
+
+/****** http-readmsg/ParseMsgLine ********************************************
+*
+* NAME
+* ParseMsgLine - Parse a HTTP message header line.
+*
+* SYNOPSIS
+* char *ParseMsgLine( char *Buffer, int *Key, char **Param );
+*
+* FUNCTION
+* This function parses a HTTP message header field into the
+* components field name and field content ("value" of this field).
+* The appropriate token for the field name is stored in the variable
+* where "Key" points to and "Param" points to the field content
+* string.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Key - A pointer to a variable which will store the field name token.
+* Param - A pointer to a character pointer, which will refer to
+* the field content string.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* NOTES
+* In case of unknown field names, the field content string will
+* contain not only the value of the field, instead it will contain the
+* complete header line.
+*
+* BUGS
+* "Buffer", "Key" and "Param" are not checked against NULL pointers.
+*
+******************************************************************************
+*
+*/
+
+char *ParseMsgLine( char *Buffer, int *Key, char **Param )
+{
+ char *Keyword;
+ char *Ptr;
+ int HaveKey = FALSE;
+
+ if( ( *Buffer == ' ' ) || ( *Buffer == '\t' ) )
+ {
+ *Key = HKEY_CONTINUE;
+ *Param = Buffer;
+
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == '\r' )
+ *Ptr = '\0';
+ else if( *Ptr == '\0' )
+ break;
+ }
+ *Ptr = '\0';
+ return( ++Ptr );
+ }
+
+ Keyword = Buffer;
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == ':' )
+ {
+ if( HaveKey == FALSE )
+ {
+ HaveKey = TRUE;
+ *Ptr = '\0';
+ *Key = HTTP_GetHKey( Keyword );
+ if( *Key != HKEY_UNKNOWN )
+ {
+ Ptr++;
+ while( ( *Ptr == ' ' ) || ( *Ptr == '\t' ) )
+ ++Ptr;
+ *Param = Ptr;
+ }
+ else
+ {
+ *Ptr = ':';
+ *Param = Buffer;
+ }
+ }
+ }
+ else if( *Ptr == '\r' )
+ *Ptr = '\0';
+ else if( *Ptr == '\0' )
+ break;
+ }
+ *Ptr = '\0';
+
+ if( *Key == -1 || HaveKey == FALSE )
+ return( NULL );
+ else
+ return( ++Ptr );
+}
+
+
+/****** http-readmsg/splitURL ************************************************
+*
+* NAME
+* splitURL - break up an URL string into its components.
+*
+* SYNOPSIS
+* void splitURL( char *Buffer, struct URLComps *URL );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with a "Content_Length" token, and returns the integer
+* value of it.
+*
+* INPUTS
+* Buffer - the URL string.
+* URL - a pointer to structure, which holds the pointers to the
+* the strings of the components.
+*
+* RESULT
+* If the creation of a buffer for the components fails, all components
+* of URL will have NULL pointers. If no protocol is found in Buffer,
+* URL->Path will contain the complete contents of Buffer (it is
+* assumed that Buffer conatins a relative URL). In this case
+* URL->Extra whill always be NULL.
+* URL->Servername may be NULL, if there was no Servername separator
+* ("//") found - this may be the case for URLs pointing to "this"
+* Server ("localhost").
+*
+******************************************************************************
+*
+*/
+
+void SplitURL( char *Buffer, struct URLComps *URL )
+{
+ char *NewBuffer;
+ size_t BuffSize;
+ char *Ptr1;
+ char *Ptr2;
+ char *Tmp;
+ int HaveProto = FALSE;
+ int CheckSep = FALSE;
+ int HaveServer = FALSE;
+ int HavePath = FALSE;
+ int HaveExtra = FALSE;
+
+ BuffSize = strlen( Buffer ) + 4;
+ NewBuffer = (char*)mymalloc( BuffSize );
+ if( NewBuffer != NULL )
+ {
+ bzero( NewBuffer, BuffSize );
+ Tmp = NewBuffer;
+ for( Ptr1 = Buffer, Ptr2 = NewBuffer; Ptr1 <= Buffer + BuffSize; Ptr1++, Ptr2++ )
+ {
+ if( HaveProto == FALSE )
+ {
+ if( *Ptr1 == ':' )
+ {
+ HaveProto = TRUE;
+ URL->Protocol = Tmp;
+ Tmp = Ptr2 + 1;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else if( CheckSep == FALSE )
+ {
+ CheckSep = TRUE;
+ if( *Ptr1 == '/' && *(Ptr1+1) == '/' )
+ {
+ Ptr1++;
+ }
+ else
+ {
+ HaveServer = TRUE;
+ URL->Servername = NULL;
+ Ptr1--;
+ }
+ }
+ else if( HaveServer == FALSE )
+ {
+ if( *Ptr1 == '/' )
+ {
+ HaveServer = TRUE;
+ URL->Servername = Tmp;
+ Tmp = Ptr2 + 1;
+ Ptr1--;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else if( HavePath == FALSE )
+ {
+ if( *Ptr1 == '#' || *Ptr1 == '?' )
+ {
+ HavePath = TRUE;
+ URL->Path = Tmp;
+ Tmp = Ptr2 + 1;
+ Ptr1--;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else
+ {
+ if( HaveExtra == FALSE )
+ {
+ HaveExtra = TRUE;
+ URL->Extra = Tmp;
+ }
+ *Ptr2 = *Ptr1;
+ }
+ }
+ if( HaveProto == FALSE )
+ {
+ URL->Path = Tmp;
+ }
+ }
+ else
+ {
+ URL->Protocol = NULL;
+ URL->Servername = NULL;
+ URL->Path = NULL;
+ URL->Extra = NULL;
+ }
+
+ return;
+}
+
+
+/****** http-readmsg/GetContentLength ****************************************
+*
+* NAME
+* GetContentLength - search for the "Content-Length" header in a HTTP
+* message and return the value if found.
+*
+* SYNOPSIS
+* size_t GetContentLength( struct MsgHeader *Ptr );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with a "Content_Length" token, and returns the integer
+* value of it.
+*
+* INPUTS
+* Ptr - A pointer to a "MsgHeader" node.
+*
+* RESULT
+* 0 if no "Content-Length" header is found, otherwise the value of
+* this message header converted into an integer (more precisely: the
+* return value of "strtol()").
+*
+* BUGS
+* The return value of "strtol()" should maybe checked for proper
+* results.
+*
+* SEE ALSO
+* GetFieldContent().
+*
+******************************************************************************
+*
+*/
+
+size_t GetContentLength( struct MsgHeader *Ptr )
+{
+ while( Ptr != NULL )
+ {
+ if( Ptr->Field == HKEY_Content_Length )
+ return( strtol( Ptr->Content, NULL, 10 ) );
+ Ptr = Ptr->Next;
+ }
+ return( 0 );
+}
+
+
+/****** http-readmsg/GetFieldContent *****************************************
+*
+* NAME
+* GetFieldContent - Return the content of a specific message header.
+*
+* SYNOPSIS
+* char *GetFieldContent( struct MsgHeader *Ptr, int Field,
+* struct MsgHeader **Next );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with the token in the argument "Field", and returns the
+* value of it.
+*
+* INPUTS
+* Ptr - A pointer to a "MsgHeader" node.
+* Field - The token of the field to search for.
+* Next - A pointer to the next "MsgHeader" in the list.
+*
+* RESULT
+* NULL if the header is not found, otherwise a pointer to the content
+* string.
+*
+* SEE ALSO
+* GetContentLength().
+*
+******************************************************************************
+*
+*/
+
+char *GetFieldContent( struct MsgHeader *Ptr, int Field, struct MsgHeader **Next )
+{
+ while( Ptr != NULL )
+ {
+ if( Ptr->Field == Field )
+ {
+ if( Next != NULL )
+ *Next = Ptr->Next;
+ return( Ptr->Content );
+ }
+ Ptr = Ptr->Next;
+ }
+ return( NULL );
+}
+
+
+/****** http-readmsg/GetRealm ************************************************
+*
+* NAME
+* GetRealm - Search for specific Authentication realms.
+*
+* SYNOPSIS
+* int GetRealm( char *String );
+*
+* FUNCTION
+* This function searches in the "WWW-Authenticate" header for specific
+* authentication realm strings. If one of them is found, the
+* appropriate code for this realm is returned.
+*
+* INPUTS
+* String - A pointer to the contents of the "WWW-Authenticate" header
+* field.
+*
+* RESULT
+* A realm type code.
+*
+* BUGS
+* "String" is not checked against a NULL pointer.
+*
+******************************************************************************
+*
+*/
+
+int GetRealm( char *String )
+{
+ struct KeywordKey RealmKeyTable[] =
+ {
+ { "httpserver-IPClass-A", REALM_IPCLASS_A },
+ { "httpserver-IPClass-B", REALM_IPCLASS_B },
+ { "httpserver-IPClass-C", REALM_IPCLASS_C },
+ { "httpserver-IPAddress", REALM_IPADDRESS },
+ { "httpserver-Hostname", REALM_HOSTNAME },
+ { "httpserver-Domain", REALM_DOMAIN },
+ };
+#define NUM_REALMS 6
+
+ char *Buff;
+ char *Ptr;
+ char *Tmp;
+ int i;
+
+ Ptr = String;
+ if( ( strncasecmp( "realm=", Ptr, 6 ) == 0 ) )
+ {
+ Ptr = Ptr + 6;
+ if( ( Buff = (char*)mymalloc( strlen( Ptr ) + 1 ) ) == NULL )
+ return( REALM_ERROR );
+ strcpy( Buff, Ptr );
+
+ /* Kill Quotes... */
+ if( *Ptr == '"' )
+ {
+ Ptr++;
+ Tmp = strrchr( Ptr, '"' );
+ if( Tmp != NULL )
+ *Tmp = '\0';
+ }
+ for( i = 0; i < NUM_REALMS; i++ )
+ {
+ if( strcmp( RealmKeyTable[i].Keyword, Ptr ) == 0 )
+ {
+ free( Buff );
+ return( RealmKeyTable[i].Key );
+ }
+ }
+ return( REALM_UNKNOWN );
+ }
+ else
+ return( REALM_ERROR );
+}
diff --git a/httpserver/http-support.cc b/httpserver/http-support.cc
new file mode 100644
index 0000000..c4a03b4
--- /dev/null
+++ b/httpserver/http-support.cc
@@ -0,0 +1,503 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-support.c - Support functions for HTTP-Message data. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-support.c,v $ $Revision: 1.5 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+
+/****** http-support/InitClientBase ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitClientBase( struct ClientBase *Client )
+{
+ return( ERROR );
+}
+
+
+/****** http-support/InitReqInfo *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitReqInfo( struct ReqInfo *Request )
+{
+ Request->HeadBuff = NULL;
+ Request->HeadSize = 0;
+ Request->BodyBuff = NULL;
+ Request->BodySize = 0;
+ Request->Line.Method = 0;
+ Request->Line.URL.Protocol = NULL;
+ Request->Line.URL.Servername = NULL;
+ Request->Line.URL.Path = NULL;
+ Request->Line.URL.Extra = NULL;
+ Request->Line.Version.Major = 0;
+ Request->Line.Version.Minor = 0;
+ Request->First = NULL;
+ Request->Last = NULL;
+ Request->Body = NULL;
+ return( OK );
+}
+
+
+/****** http-support/InitRespInfo ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitRespInfo( struct RespInfo *Response )
+{
+ Response->HeadBuff = NULL;
+ Response->HeadSize = 0;
+ Response->BodyBuff = NULL;
+ Response->BodySize = 0;
+ Response->Line.Version.Major = 0;
+ Response->Line.Version.Minor = 0;
+ Response->Line.Status = 0;
+ Response->Line.Reason = NULL;
+ Response->First = NULL;
+ Response->Last = NULL;
+ Response->Body = NULL;
+ return( OK );
+}
+
+
+/****** http-support/InitHTTPMsg *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void InitHTTPMsg( struct HTTPMsg *Msg )
+{
+ Msg->Head = NULL;
+ Msg->Body = NULL;
+ Msg->BodySize = 0;
+}
+
+
+/****** http-support/NewMsgHeader ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct MsgHeader *NewMsgHeader( int Key, char *String )
+{
+ struct MsgHeader *NewHeader;
+
+ NewHeader = (struct MsgHeader*)mymalloc( sizeof( struct MsgHeader ) );
+ if( NewHeader == NULL )
+ return( NULL );
+ NewHeader->Next = NULL;
+ NewHeader->Field = Key;
+ NewHeader->Content = String;
+ return( NewHeader );
+}
+
+
+/****** http-support/AppendMsgHeader *****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct MsgHeader *AppendMsgHeader( struct MsgHeader *Last, int Key, char *String )
+{
+ struct MsgHeader *NewHeader;
+
+ NewHeader = NewMsgHeader( Key, String );
+ if( NewHeader == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for MsgHeader structure." );
+ return( NULL );
+ }
+ if( Last != NULL )
+ {
+ Last->Next = NewHeader;
+ }
+ return( NewHeader );
+}
+
+
+/****** http-support/DeleteMsgHeader *****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void DeleteMsgHeader( struct MsgHeader *First )
+{
+ struct MsgHeader *Tmp;
+
+ if( First != NULL )
+ {
+ Tmp = First->Next;
+ free( First );
+ First = Tmp;
+ }
+ return;
+}
+
+
+/****** http-support/PrintReqInfo ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void PrintReqInfo( struct ReqInfo *Request )
+{
+ struct MsgHeader *Ptr;
+
+ printf( ">> %s %s HTTP/%d.%d\n",
+ HTTP_GetMethodName( Request->Line.Method ),
+ Request->Line.URL.Protocol ? Request->Line.URL.Protocol : "",
+ Request->Line.URL.Servername ? Request->Line.URL.Servername : "",
+ Request->Line.URL.Path ? Request->Line.URL.Path : "",
+ Request->Line.URL.Extra ? Request->Line.URL.Extra : "",
+ Request->Line.Version.Major, Request->Line.Version.Minor );
+
+ Ptr = Request->First;
+ while( Ptr != NULL )
+ {
+ printf( ">> %s: %s\n", HTTP_GetFieldName( Ptr->Field ), Ptr->Content );
+ Ptr = Ptr->Next;
+ }
+ return;
+}
+
+
+/****** http-support/PrintRespInfo *******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void PrintRespInfo( struct RespInfo *Response )
+{
+ struct MsgHeader *Ptr;
+
+ printf( ">> HTTP/%d.%d %d %s\n",
+ Response->Line.Version.Major, Response->Line.Version.Minor ,
+ Response->Line.Status,
+ Response->Line.Reason );
+
+ Ptr = Response->First;
+ while( Ptr != NULL )
+ {
+ printf( ">> %s: %s\n", HTTP_GetFieldName( Ptr->Field ), Ptr->Content );
+ Ptr = Ptr->Next;
+ }
+ return;
+}
+
+
+/****** http-support/CheckSockError ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CheckSockError( int SockFD, int Level, int OptName )
+{
+ int error;
+ size_t len = sizeof( error );
+
+#ifdef DECALPHA
+ if( getsockopt( SockFD, Level, OptName, (char *)&error, (int*)&len ) < 0 )
+#else
+ if( getsockopt( SockFD, Level, OptName, (char *)&error, (socklen_t*)&len ) < 0 )
+#endif
+ return( FAIL );
+ if( error )
+ {
+ errno = error;
+ return( ERROR );
+ }
+ return( OK );
+}
+
+
diff --git a/httpserver/http-writemsg.cc b/httpserver/http-writemsg.cc
new file mode 100644
index 0000000..20d430f
--- /dev/null
+++ b/httpserver/http-writemsg.cc
@@ -0,0 +1,314 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-writemsg.c - generic HTTP-Message functions: */
+/* Creating and sending of HTTP-Messages. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-writemsg.c,v $ $Revision: 1.3 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct HTTPError HTTPErrorTable[];
+
+
+/****** http-writemsg/AddField ***********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t AddField( struct MsgHeader *Ptr, int Field, char *Content )
+{
+ struct MsgHeader *NewHeader;
+
+ if( Ptr != NULL )
+ while( Ptr->Next != NULL )
+ Ptr = Ptr->Next;
+
+ NewHeader = AppendMsgHeader( Ptr, Field, Content );
+ if( NewHeader != NULL )
+ return( OK );
+ else
+ return( WARN );
+}
+
+
+/****** http-writemsg/CreateStatusLine ***************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CreateStatusLine( char *Buffer, size_t *BuffSize, int Code, int Protocol )
+{
+ int Entry;
+
+ Entry = GetHTTPErrorTableEntry( Code );
+ switch( Protocol )
+ {
+ case HTTP_1_0:
+ {
+ if( Entry != 0 )
+ SNPrintf( Buffer, BuffSize, "HTTP/1.0 %d %s\r\n", Code, HTTPErrorTable[Entry].Reason );
+ else
+ SNPrintf( Buffer, BuffSize, "HTTP/1.0 %d Statuscode %d\r\n", Code, Code );
+ return( OK );
+ }
+ break;
+ case HTTP_1_1:
+ {
+ if( Entry != 0 )
+ SNPrintf( Buffer, BuffSize, "HTTP/1.1 %d %s\r\n", Code, HTTPErrorTable[Entry].Reason );
+ else
+ SNPrintf( Buffer, BuffSize, "HTTP/1.1 %d Statuscode %d\r\n", Code, Code );
+ return( OK );
+ }
+ break;
+ default:
+ {
+ return( ERROR );
+ }
+ }
+}
+
+
+/****** http-writemsg/CreateHTTPMsg ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct HTTPMsg *CreateHTTPMsg( char *Header, char *Body, size_t BodySize )
+{
+ struct HTTPMsg *Msg;
+
+ /* printf( "### CreateHTTPMsg(+)\n" ); */
+ Msg = (struct HTTPMsg*)mymalloc( sizeof( struct HTTPMsg ) );
+ if( Msg != NULL )
+ {
+ /* printf( "### Header[%d]:\n%s", strlen( Header ), Header ); */
+ /* printf( "### Body[%d]:\n", BodySize ); */
+
+ Msg->Body = Body;
+ Msg->BodySize = BodySize;
+
+ if( ( Msg->Head = (char*)mymalloc( strlen( Header ) + 1 ) ) != NULL )
+ strcpy( Msg->Head, Header );
+ else
+ {
+ free( Msg );
+ return( NULL );
+ }
+ /* printf( "### Done!\n" ); */
+ }
+ /* printf( "### CreateHTTPMsg(-)\n" ); */
+ return( Msg );
+}
+
+
+/****** http-writemsg/SendHTTPMsg ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t SendHTTPMsg( int SockFD, struct HTTPMsg *Msg )
+{
+ size_t Check;
+
+ if( ( Msg != NULL ) && ( Msg->Head != NULL ) )
+ {
+ Check = WriteN( SockFD, Msg->Head, strlen(Msg->Head) );
+ if( Check < 0 )
+ ErrorMsg( E_SYS, ERROR, "ERROR: WriteN(): write() failed." );
+ else if( Check != strlen(Msg->Head) )
+ LogMsg( LG_SERVER, WARN,
+ "WARN: SendHTTPMsg(): %d of %d Bytes of Header written!",
+ Check, strlen(Msg->Head) );
+
+ if( ( Msg->Body != NULL ) && ( Msg->BodySize > 0 ) )
+ {
+ Check = WriteN( SockFD, Msg->Body, Msg->BodySize );
+ if( Check < 0 )
+ ErrorMsg( E_SYS, ERROR, "ERROR: WriteN(): write() failed." );
+ else if( Check != Msg->BodySize )
+ LogMsg( LG_SERVER, WARN,
+ "WARN: SendHTTPMsg(): %d of %d Bytes of Body written!",
+ Check, Msg->BodySize );
+ }
+ return( OK );
+ }
+ else
+ {
+ return( ERROR );
+ }
+}
+
+
+/****** http-writemsg/FreeHTTPMsg ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t FreeHTTPMsg( struct HTTPMsg *Ptr )
+{
+ free( Ptr->Head );
+ free( Ptr );
+ return( OK );
+}
diff --git a/httpserver/http.cc b/httpserver/http.cc
new file mode 100644
index 0000000..898be85
--- /dev/null
+++ b/httpserver/http.cc
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http.c - reworked HTTP communication main loop. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+/*
+ * Release ClientBase
+ */
+void releaseClientBase(struct ClientBase *cb)
+{
+ // free Host
+ free(cb->Host.Name);
+
+ // free Socket
+ // struct sockaddr_in Socket;
+
+ // free TimeOut
+ // struct timeval TimeOut;
+
+ // free Request
+ free(cb->Request.HeadBuff);
+ free(cb->Request.BodyBuff);
+ struct MsgHeader *dummy = NULL;
+ while(cb->Request.First != NULL)
+ {
+ dummy = cb->Request.First->Next;
+ //free(cb->Request.First->Content);
+ free(cb->Request.First);
+ cb->Request.First = dummy;
+ }
+ free(cb->Request.Body);
+ free(cb->Request.Line.Vanilla);
+
+ // free Response
+ free(cb->Response.Head);
+ free(cb->Response.Body);
+
+}
+
+
+/****** http/HandleRequest ***************************************************
+*
+* NAME
+* HandleRequest -- main function for communication processing.
+*
+* SYNOPSIS
+* void HandleRequest( struct ClientBase *Client,
+* SubServerPtr SubServerList );
+*
+* FUNCTION
+* This is the main function which handles the HTTP communication.
+* It calls successivley the functions for handling the request from
+* the client, opening the sockets to the sub-servers and sending
+* the rewritten requests to them, handling the responses and finally
+* sending a response to the client.
+*
+* INPUTS
+* Client - Data structure which holds various informations about
+* the client.
+* SubServerList - The head to a list of all sub-server data structures.
+*
+* NOTES
+* "Client" and "SubServerList" must be valid - they will not be
+* checked. Since "Client" have to be valid in the previous call to
+* "Accept()" this shouldn't be much of a problem...
+*
+* This is "rewritten from scratch" version of "HandleRequest()"
+* since the old version seemed not suitable enough for expansion
+* to handle more error conditions in the communication, and for
+* integration of more features.
+*
+* BUGS
+* Various left. Especially the authorization mechanism doesn't work
+* (yet). Also, some aspects of the HTTP aren't handled gracefully
+* (HTTP/0.9 messages, handling of other methods than GET, HEAD and
+* POST, etc.).
+*
+******************************************************************************
+*
+*/
+void HandleRequest( struct ClientBase *Client )
+{
+ struct ToDoArgs ToDo;
+ int RespState;
+
+ ToDo.What = DO_NOTHING;
+ ToDo.Which.Code = REALLY_NOTHING;
+ Client->Comm.ConnStatus = CONN_OPEN;
+
+ while( Client->Comm.ConnStatus == CONN_OPEN )
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Reading Request.");
+ GetRequest( Client );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Parsing Request.");
+ ParseReqHeader( &Client->Request );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Interpreting Request.");
+ InterpreteRequest( Client, &ToDo );
+ switch( ToDo.What )
+ {
+ case DO_SEND_RESPONSE:
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing InterpreteRequest.");
+ InterpretePOSTRequest( Client );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing CreateRasResponse.");
+ CreateRasResponse( &Client->Comm, Client );
+ /*
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() for Request: \"%s\".",
+ Client->Request.Line.Vanilla );
+ */
+
+ SendHTTPMsg( Client->SockFD, &Client->Response );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SEND_RESPONSE done.");
+ break;
+
+ case DO_SEND_ERROR:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing SEND_ERROR." );
+ Client->RespStatus = ToDo.Which.Code;
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: CreateHTTPError( %d, -, %p )...",
+ Client->RespStatus, &Client->Response );
+ CreateHTTPError( Client->RespStatus, &Client->Comm, &Client->Response );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: CreateHTTPError() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse()..." );
+ SendResponse( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Write*Log()..." );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: WriteLog() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SEND_ERROR done.");
+ break;
+
+ case DO_SHUTDOWN:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing SHUTDOWN.");
+ close( Client->SockFD );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SHUTDOWN done.");
+ break;
+
+ default:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing UNDEFINED ACTION.");
+ ErrorMsg( E_PRIV, ERROR, "ERROR: HandleRequest(): Undefined action!" );
+ Client->RespStatus = STATUS_Internal_Server_Error;
+ CreateHTTPError( Client->RespStatus, &Client->Comm, &Client->Response );
+ SendResponse( Client );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): UNDEFINED ACTION done.");
+ break;
+ }
+ releaseClientBase(Client);
+
+ }
+}
+
diff --git a/httpserver/http.h b/httpserver/http.h
new file mode 100644
index 0000000..f22ee49
--- /dev/null
+++ b/httpserver/http.h
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http.h - typedefs and structures for HTTP. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http.h,v $ $Revision: 1.3 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+
+struct KeywordKey
+{
+ char *Keyword;
+ int Key;
+};
+
+struct HTTPError
+{
+ int Code;
+ char *Reason;
+ char *Message_en;
+ char *Message_de;
+};
+
+/* HTTP Message structure
+ */
+
+struct HTTPMsg
+{
+ char *Head;
+ char *Body;
+ int BodySize;
+};
+
+
+struct URLComps
+{
+ char *Protocol;
+ char *Servername;
+ char *Path;
+ char *Extra;
+};
+
+
+struct Version
+{
+ int Major;
+ int Minor;
+};
+
+
+struct RequestLine
+{
+ char *Vanilla;
+ int Method;
+ struct URLComps URL;
+ struct Version Version;
+};
+
+struct StatusLine
+{
+ char *Vanilla;
+ struct Version Version;
+ int Status;
+ char *Reason;
+};
+
+struct MsgHeader
+{
+ struct MsgHeader *Next;
+ int Field;
+ char *Content;
+};
+
+
+/* Data Structure for HTTP Request
+ */
+
+struct ReqInfo
+{
+ int State;
+ char *HeadBuff;
+ size_t HeadSize;
+ char *BodyBuff;
+ size_t BodySize;
+ struct RequestLine Line;
+ struct MsgHeader *First;
+ struct MsgHeader *Last;
+ char *Body;
+};
+
+/* Data Structure for HTTP Response
+ */
+
+struct RespInfo
+{
+ int State;
+ char *HeadBuff;
+ size_t HeadSize;
+ char *BodyBuff;
+ size_t BodySize;
+ struct StatusLine Line;
+ struct MsgHeader *First;
+ struct MsgHeader *Last;
+ char *Body;
+};
+
+#endif /* _HTTP_H not defined */
diff --git a/httpserver/httpserver.conf b/httpserver/httpserver.conf
new file mode 100644
index 0000000..a56c060
--- /dev/null
+++ b/httpserver/httpserver.conf
@@ -0,0 +1,14 @@
+#
+# httpserver Configuration file
+#
+ServerName: sunwibas15.forwiss.tu-muenchen.de
+Port: 8080
+
+ServerAdmin: widmann@forwiss.tu-muenchen.de
+
+ServerRoot: /home/gast/beinhofe/rman/
+AccessLog: /home/gast/beinhofe/rman/httpserver/httpaccess.log
+ServerLog: /home/gast/beinhofe/rman/httpserver/httpserver.log
+PidFile: /home/gast/beinhofe/rman/httpserver/httpserver.pid
+MaxURLLength: 120
+
diff --git a/httpserver/httpserver.h b/httpserver/httpserver.h
new file mode 100644
index 0000000..9c95c5b
--- /dev/null
+++ b/httpserver/httpserver.h
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/***
+ * INCLUDE: httpserver.h
+ *
+ * MODULE: httpserver
+ * CLASS: none, C header
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _HTTPSERVERC_
+#define _HTTPSERVERC_
+
+extern int init_httpserver( int argc, char *argv[] );
+
+#endif
diff --git a/httpserver/init.cc b/httpserver/init.cc
new file mode 100644
index 0000000..b58ce35
--- /dev/null
+++ b/httpserver/init.cc
@@ -0,0 +1,319 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* init.c - Functions to setup the server. */
+/*------------------------------------------------------------------------*/
+
+#include <iostream>
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+
+/****** init/Initialize ******************************************************
+*
+* NAME
+* Initialize -- central function for initializing the servers data
+* structures and environment.
+*
+* SYNOPSIS
+* int Initialize( int argc, char *argv[], struct ServerBase *Server );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t Initialize( int argc, char *argv[], struct ServerBase *Server )
+{
+
+ /* Make sure that the Server structure is empty. -------------------- */
+ bzero( (char *)Server, sizeof( *Server ) );
+
+ /* Create Head of ChildList */
+ Server->ChildList = (struct ChildBase*)mymalloc( sizeof( struct ChildBase ) );
+ if( Server->ChildList == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Initialize(): malloc() failed!" );
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Creating Head of ChildList" );
+ Server->ChildList->next = Server->ChildList;
+ Server->ChildList->prev = Server->ChildList;
+ Server->ChildList->PId = 0;
+ }
+
+ /* Read the environment variables */
+ char* dummy = CONFDIR;
+ if( dummy == NULL)
+ ErrorMsg( E_SYS, FAIL, "FAIL: Environment variable RMANHOME is not set!" );
+ Server->Directory = (char*)mymalloc(strlen(dummy) + 2);
+ strcpy(Server->Directory, dummy);
+ if( Server->Directory[strlen(Server->Directory)] != '/' )
+ strcat( Server->Directory, "/" );
+
+ /* Read Arguments and Server configuration file - and setup --------- */
+ /* the corresponding data structures. --------------------------- */
+
+ ReadArgs( Server, argc, argv );
+ //ReadConfig( Server );
+
+ ConfigureServer( Server );
+ // CheckConfig( Server ); // Check for reasonable configuration
+
+ /* Set timeout for communication with subservers and client --------- */
+ Server->Client.TimeOut.tv_sec = DIALOG_TIMEOUT;
+ Server->Client.TimeOut.tv_usec = 0;
+
+ /* Get the process into "daemon"-mode. ------------------------------ */
+ InitDaemon( Server->Log.Mode );
+ Server->PId = getpid();
+
+ //SavePId( Server->PidFile );
+ /* Initialize the Server Socket. ------------------------------------ */
+ InitSocket( &Server->SockFD, &Server->Socket, Server->Port );
+
+ /* Setup and Open the logfiles. ------------------------------------- */
+ OpenLog( &Server->Log, Server->Log.Access.Filename,
+ Server->Log.Server.Filename,
+ Server->Log.Comm.Filename );
+
+
+ LogMsg( LG_SERVER, INFO, "INFO: ========= %s started. ===============", DAEMONNAME );
+
+ // We don't do that so that the one process running can be exited with simple ^C
+ /* Initialize the signal handlers. ---------------------------------- */
+ // InitSigHandler();
+
+ /* Everything is just great... -------------------------------------- */
+ return( OK );
+}
+
+
+/****** init/InitDaemon ******************************************************
+*
+* NAME
+* InitDaemon -- going into "daemon"-mode: process forks to run in the
+* background and closes all open file-descriptors.
+*
+* SYNOPSIS
+* int InitDaemon( int Mode );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t InitDaemon( int Mode )
+{
+ int i;
+ pid_t pid;
+ int openmax;
+
+ // RasDaMan does not go into background!
+ chdir( Server.Directory ); /* Arbeitsverzeichnis wechseln */
+ umask( 0 ); /* Dateischutzbitmaske loeschen */
+ return( OK );
+}
+
+
+/****** init/InitSocket ******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* ### Minimum Socket Setup. Stay tuned.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitSocket( int *SockFD, struct sockaddr_in *Socket, int Port )
+{
+ int val = 0;
+ size_t len;
+
+ Socket->sin_family = AF_INET;
+ Socket->sin_addr.s_addr = htonl( INADDR_ANY );
+ Socket->sin_port = htons( Port );
+ if( ( *SockFD = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open socket for server." );
+
+#ifdef SO_REUSEADDR
+ val = 1;
+ len = sizeof( val );
+ if( setsockopt( *SockFD, SOL_SOCKET, SO_REUSEADDR, (char*)&val, len ) < 0 )
+ ErrorMsg( E_SYS, WARN, "WARN: InitSocket(): can't set sockopt REUSEADDR." );
+#else
+ LogMsg( LG_SERVER, INFO, "INFO: InitSocket(): sockopt REUSEADDR not available." );
+#endif
+
+ if( bind( *SockFD, (struct sockaddr *)Socket, sizeof( *Socket ) ) < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Bind socket for server." );
+ return( OK );
+}
+
+
+/****** init/InitClientSocket ************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitClientSocket( int *SockFD,
+ struct sockaddr_in *Socket,
+ char *Hostname,
+ int Port )
+{
+ struct hostent *Host;
+
+ bzero( (char *)Socket, sizeof( *Socket ) );
+
+ Socket->sin_family = AF_INET;
+ Host = gethostbyname( Hostname );
+ if( Host == NULL )
+ {
+ return( ERROR );
+ }
+ memcpy( (char *)&Socket->sin_addr, (char *)Host->h_addr, Host->h_length );
+
+ Socket->sin_port = htons( Port );
+ if( ( *SockFD = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+ return( ERROR );
+ return( OK );
+}
+
+
+/****** init/SavePId *********************************************************
+*
+* NAME
+* SavePId -- store process id in file.
+*
+* SYNOPSIS
+* void SavePId( char *PIdFilename );
+*
+* FUNCTION
+* THis function saves the parent process id in a file, so this file
+* can be used by for example shell scripts to identify the correct
+* process to signal it.
+*
+* INPUTS
+* PIdFilename -- Full pathname of the file which stortes the pid.
+*
+* RESULT
+* Does not return anything.
+*
+* NOTES
+* This function is called by Initialize(), right after the logs are
+* opened. So the content of the pidfile is also only valid afterwards.
+* To ensure, that there is no stale pidfile, it is deleted on normal
+* termination.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+
+void SavePId( char *PIdFilename )
+{
+ FILE *PIdFile;
+
+ if( ( PIdFile = fopen( PIdFilename, "w" ) ) != NULL )
+ {
+ fprintf( PIdFile, "%d", getpid() );
+ fclose( PIdFile );
+ }
+}
diff --git a/httpserver/logging.cc b/httpserver/logging.cc
new file mode 100644
index 0000000..e486c66
--- /dev/null
+++ b/httpserver/logging.cc
@@ -0,0 +1,297 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* logging.c - logging and error message handling. */
+/*------------------------------------------------------------------------*/
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+
+
+extern struct Logging *LogBase;
+
+
+rc_t OpenLog( struct Logging *Log, char *AccessLog, char *ServerLog, char *CommLog )
+{
+ /* removed this, we don't need this logs
+ if( (Log->Mode & LF_STDERR) == LF_STDERR ) // Log to STDOUT/STDERR ?
+ {
+ Log->Access.Filename = NULL;
+ Log->Access.FD = STDOUT_FILENO;
+ Log->Access.State = FILE_OPEN;
+ Log->Server.Filename = NULL;
+ Log->Server.FD = STDERR_FILENO;
+ Log->Server.State = FILE_OPEN;
+ Log->Comm.Filename = NULL;
+ Log->Comm.FD = STDOUT_FILENO;
+ Log->Comm.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Access.Filename = AccessLog;
+ if( AccessLog != NULL )
+ {
+ Log->Access.FD = open( Log->Access.Filename,
+ O_WRONLY | O_CREAT | O_APPEND, FILE_MODE );
+ if( Log->Server.FD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open AccessLog failed." );
+ Log->Access.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Access.State = FILE_CLOSED;
+ }
+
+ Log->Server.Filename = ServerLog;
+ if( ServerLog != NULL )
+ {
+ Log->Server.FD = open( Log->Server.Filename,
+ O_WRONLY | O_CREAT | O_APPEND, FILE_MODE );
+ if( Log->Server.FD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open ServerLog failed." );
+ Log->Server.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Server.State = FILE_CLOSED;
+ }
+ }
+ */
+
+ Log->Server.State = FILE_CLOSED;
+ Log->Access.State = FILE_CLOSED;
+ Log->Comm.State = FILE_CLOSED;
+ return( OK );
+}
+
+
+void CloseLog( struct Logging *Log )
+{
+ //close( Log->Server.FD );
+ Log->Server.State = FILE_CLOSED;
+ //close( Log->Access.FD );
+ Log->Access.State = FILE_CLOSED;
+}
+
+
+
+void ErrorMsg( int errnoFlag, int ErrLevel, const char *ErrMsg, ... )
+{
+ int errno_save;
+ char ErrMsgBuffer[ MAXLINELEN ];
+ size_t StringSize, BuffSize;
+ va_list ArgPtr;
+
+ errno_save = errno;
+
+ va_start( ArgPtr, ErrMsg );
+ if( VSNPrintf( ErrMsgBuffer, MAXLINELEN, ErrMsg, ArgPtr ) < 0)
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ va_end( ArgPtr );
+
+ StringSize = strlen( ErrMsgBuffer );
+ BuffSize = MAXLINELEN - StringSize;
+
+ if( errnoFlag )
+ {
+ if( SNPrintf( ErrMsgBuffer + StringSize, &BuffSize,
+ " Reason: %s", StrError( errno_save ) ) < 0)
+ {
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ }
+ }
+ LogMsg( LG_SERVER, ErrLevel, ErrMsgBuffer );
+
+ switch( ErrLevel )
+ {
+ case DUMP:
+ {
+ abort(); /* core dump erzeugen und beenden */
+ exit( DUMP ); /* sollte nicht soweit kommen... */
+ }
+ break;
+ case FAIL:
+ {
+ exit( FAIL ); /* Ausstieg mit Status "FAIL". */
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+
+void LogMsg( int SubSys, int Level, const char *Msg, ... )
+{
+ return;
+ /*
+ char MsgBuffer[ MAXLINELEN ];
+ char *BufferPtr;
+ size_t BuffSize = MAXLINELEN;
+ size_t TimeBuffSize = DATE_BUFFSIZE;
+ va_list ArgPtr;
+
+ if( (Level == DEBUG) && ((LogBase->Mode & LF_VERB) == 0) ) // DEBUG Msgs wanted?
+ return;
+
+ bzero( MsgBuffer, MAXLINELEN );
+ BufferPtr = &MsgBuffer[0];
+
+ // ### HACK! access.log datestamp is already in msg string!
+ if( SubSys != LG_ACCESS )
+ {
+ LogDate( BufferPtr, TimeBuffSize );
+ strcat( BufferPtr, " " );
+ }
+ if( SubSys == LG_SERVER )
+ {
+ BufferPtr = &MsgBuffer[0] + strlen( MsgBuffer );
+ sprintf( BufferPtr, "<%d> ", getpid() );
+ }
+
+ BufferPtr = &MsgBuffer[0] + strlen( MsgBuffer );
+ BuffSize = MAXLINELEN - strlen( MsgBuffer ) - 2;
+
+ va_start( ArgPtr, Msg );
+ if( VSNPrintf( BufferPtr, BuffSize , Msg, ArgPtr ) < 0)
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ va_end( ArgPtr );
+
+ // Log-Meldungen sollten immer ein <EOL> am Ende haben.
+ // Also kontrollieren und nötigenfalls ergänzen.
+ // Da MsgBuffer mit maximal MAXLINELEN - 2 Zeichen gefüllt sein
+ // sollte, kann gefahrlos <EOL> angehängt werden.
+
+ if( MsgBuffer[ strlen( MsgBuffer ) - 1 ] != '\n' )
+ strcat( MsgBuffer, "\n" );
+
+ // Moeglichkeiten:
+ // stdio offen, Server.Log nicht initialisiert
+ // stdio offen, Server.Log initialisiert (Log auf stdio)
+ // stdio geschlossen, Server.Log initialisiert (Log in File)
+
+ switch( SubSys )
+ {
+ case LG_SERVER:
+ if( LogBase->Server.State == FILE_OPEN )
+ write( LogBase->Server.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDERR_FILENO, MsgBuffer, strlen( MsgBuffer ) );
+ break;
+ case LG_ACCESS:
+ if( LogBase->Access.State == FILE_OPEN )
+ write( LogBase->Access.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDOUT_FILENO, Msg, strlen( MsgBuffer ) );
+ break;
+ case LG_COMM:
+ if( LogBase->Comm.State == FILE_OPEN )
+ write( LogBase->Comm.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDOUT_FILENO, Msg, strlen( MsgBuffer ) );
+ break;
+ default:
+ ErrorMsg( E_PRIV, WARN, "WARN: Unknown Logging sub-system!" );
+ }
+ */
+ return;
+}
+
+rc_t LogDate( char *Buffer, int BuffSize )
+{
+ struct tm *ltime;
+ int TZoffset;
+ char sign;
+
+ size_t strsize;
+ size_t RestSize;
+
+ ltime = Get_GMToffset( &TZoffset );
+
+ /* LOG Date Format: "[dd/mmm/yyyy:HH:MM:SS {-|+}XXXX]" */
+ /* XXXX = Timezone offset format: HHMM */
+ sign = ( TZoffset < 0 ? '-' : '+' );
+ if( TZoffset < 0 )
+ TZoffset = -TZoffset;
+
+ strsize = strftime( Buffer, BuffSize, "[%d/%b/%Y:%H:%M:%S ", ltime );
+ if( strsize >= BuffSize-6 || strsize == 0 )
+ return( ERROR );
+ else
+ {
+ RestSize = BuffSize-strsize;
+ SNPrintf( Buffer+strsize, &RestSize, "%c%.2d%.2d]",
+ sign, TZoffset/60, TZoffset%60 );
+ return( OK );
+ }
+}
+
+
+/****** logging/Get_GMToffset ************************************************
+*
+* NAME
+* Get_GMToffset -- Get numerical offset of localtime to gmtime.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* Source code taken from Apache 1.3.1 distribution.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct tm *Get_GMToffset( int *tz )
+{
+ time_t tt = time(NULL);
+ struct tm gmt;
+ struct tm *t;
+ int days, hours, minutes;
+
+ /* Assume we are never more than 24 hours away. */
+ gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */
+ t = localtime(&tt); /* buffer... so be careful */
+ days = t->tm_yday - gmt.tm_yday;
+ hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
+ + t->tm_hour - gmt.tm_hour);
+ minutes = hours * 60 + t->tm_min - gmt.tm_min;
+ *tz = minutes;
+ return( t );
+}
diff --git a/httpserver/main.cc b/httpserver/main.cc
new file mode 100644
index 0000000..5082fe9
--- /dev/null
+++ b/httpserver/main.cc
@@ -0,0 +1,191 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+#include "httpserver.h"
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+/*--- Global Data Section: ------------------------------------------------*/
+/* All we need to remember or may want to know is in this structure */
+
+struct ServerBase Server;
+
+struct Logging *LogBase = &Server.Log;
+
+/****** main/main ************************************************************
+*
+* NAME
+* main -- the main function of this program.
+*
+* SYNOPSIS
+* void main( int argc, char *argv[] );
+*
+* FUNCTION
+* "main" calls "Initialize()" for setting up the program, activates
+* the main socket with the "listen()" system call, and then waits
+* forever for a client to connect. If a client connection request is
+* received, a child process will be spawned and the child will handle
+* the request while the parent process will wait again for new
+* connection requests.
+*
+* INPUTS
+* argc - The number of arguments given on the command line.
+* argv[] - An array of strings, containing the arguments given on the
+* command line.
+*
+* NOTES
+* The program can only be stopped by sending it the corresponding
+* signals ("SIGQUIT", "SIGTERM").
+*
+* BUGS
+* None known. Not here.
+*
+* SEE ALSO
+* Initialize(), Accept(), AddChild(), InitChild(), HandleRequest().
+*
+******************************************************************************
+*
+*/
+
+extern int init_httpserver( int argc, char *argv[] )
+{
+ pid_t ChildPId; /* -> Server.ChildInfo */
+
+ RMInit::logOut << "Initialising parameters for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ Initialize( argc, argv, &Server );
+
+ RMInit::logOut << "Initialising server socket for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ listen( Server.SockFD, 5 );
+ RMInit::logOut << "Waiting for client calls... " << endl;
+ RMInit::logOut.flush();
+
+#ifdef PURIFY
+ purify_printf( "Server Startup Finnished." );
+ purify_new_leaks();
+#endif
+
+/* // this is a quick hack for testing */
+/* return 0; */
+ for(;;)
+ {
+ Accept( Server.SockFD, &Server.Client );
+
+ strcpy( Server.Client.Host.IPAddrString, inet_ntoa( Server.Client.Socket.sin_addr ) );
+
+ if( Server.Client.Host.IPAddrString == NULL )
+ strcpy( Server.Client.Host.IPAddrString, "0.0.0.0" );
+
+ Server.Client.Host.IPAddress = inet_addr( Server.Client.Host.IPAddrString );
+ Server.Client.Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Server.Client.Response );
+ InitReqInfo( &Server.Client.Request );
+
+ LogMsg( LG_SERVER, INFO, "INFO: ====== Connection from %s accepted...",
+ Server.Client.Host.IPAddrString );
+ HandleRequest( &Server.Client );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== EOT. Disconnecting." );
+
+ close( Server.Client.SockFD );
+
+ }
+ // otherwise Exit(OK) should have been called
+ return -1;
+}
+
+
+
+/****** main/Exit ************************************************************
+*
+* NAME
+* Exit -- Cleanup when exiting.
+*
+* SYNOPSIS
+* void Exit( int RC );
+*
+* FUNCTION
+* This function closes all open socket descriptors and the logging
+* subsystem. If the calling process is the parent process, it also
+* deletes the file where the process Id is stored.
+* After that, it calls the "exit()" function with the return code
+* "RC".
+*
+* INPUTS
+* RC - return or exit code, indicating the error condition of the
+* program.
+*
+* NOTES
+* This function is called by the signal handlers for "SIGQUIT",
+* "SIGTERM", "SIGINT" and "SIGHUP" and the main() function.
+* In future versions, "SIGHUP" should be changed to reread the
+* configuration file instead of calling Exit().
+*
+* BUGS
+* The global variable "SubServer[]" should not be used.
+*
+* SEE ALSO
+* Exit().
+*
+******************************************************************************
+*
+*/
+
+int Exit( int RC )
+{
+ int i;
+
+ // for( i = 0; i < NUM_SUBSERVER; i++ )
+ // close( SubServer[i].SockFD );
+ close( Server.SockFD );
+
+ if( getpid() == Server.PId ) /* Is this the parent process? */
+ {
+ unlink( Server.PidFile );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Main process exiting (RC=%d)...", RC );
+ LogMsg( LG_SERVER, INFO,
+ "INFO: ========= %s terminated. ============", DAEMONNAME );
+ }
+ else
+ {
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Exiting (RC=%d)...", RC );
+ }
+
+ CloseLog( &Server.Log );
+
+ free(Server.Directory);
+
+ if(RC != OK) throw r_Error( r_Error::r_Error_General );
+ return RC;
+}
+
diff --git a/httpserver/protos.h b/httpserver/protos.h
new file mode 100644
index 0000000..60a0ac9
--- /dev/null
+++ b/httpserver/protos.h
@@ -0,0 +1,178 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* protos.h - Prototypes of all functions */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: protos.h,v $ $Revision: 1.10 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _PROTOS_H
+#define _PROTOS_H
+
+#include "server.h"
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from main.c */
+/*------------------------------------------------------------------------*/
+
+int Exit( int );
+
+/* init.c */
+rc_t Initialize( int, char **, struct ServerBase * );
+rc_t InitDaemon( int );
+rc_t InitSocket( int *, struct sockaddr_in *, int );
+rc_t InitClientSocket( int *, struct sockaddr_in *, char *, int );
+void SavePId( char * );
+
+/* childs.c */
+rc_t InitChild( struct ClientBase * );
+pid_t NewChild( struct ChildBase *List, struct FDsets *PDSets, struct ClientBase *Client );
+void CleanupChild( struct ChildBase *List, struct FDsets *PDSets, pid_t PId );
+void AddChild( struct ChildBase *List, struct ChildBase *Child );
+void RemChild( struct ChildBase *List, struct ChildBase *Child );
+struct ChildBase *GetChild( struct ChildBase *List, pid_t PId );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from config.c */
+/*------------------------------------------------------------------------*/
+
+rc_t ReadArgs( struct ServerBase *, int, char ** );
+rc_t ReadConfig( struct ServerBase * );
+rc_t CheckAndSet( struct ServerBase *, char *, int );
+rc_t SetServDir( struct ServerBase *, char * );
+rc_t SetFilename( struct ServerBase *, int, char * );
+rc_t SetString( struct ServerBase *, int, char * );
+rc_t ConfigureServer( struct ServerBase * );
+int GetConfigKey( char * );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from signals.c */
+/*------------------------------------------------------------------------*/
+
+typedef void(*sighandler)(int);
+
+sighandler Signal( int, sighandler );
+void SigHandler( int );
+rc_t InitSigHandler( void );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from logging.c */
+/*------------------------------------------------------------------------*/
+
+rc_t OpenLog( struct Logging *, char *, char *, char * );
+void CloseLog( struct Logging *Log );
+void LogMsg( int, int, const char *, ... );
+void ErrorMsg( int, int, const char *, ... );
+rc_t LogDate( char *, int );
+struct tm *Get_GMToffset( int * );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes for communication handling. */
+/*------------------------------------------------------------------------*/
+
+/* http.c */
+void HandleRequest( struct ClientBase *Client );
+
+/* http-doit.c */
+rc_t Accept( int, struct ClientBase * );
+void GetRequest( struct ClientBase *Client );
+void InterpreteRequest( struct ClientBase *Client, struct ToDoArgs *ToDo );
+int SendRequest( int SockFD, struct HTTPMsg *Request, struct FDsets *RW_Sets );
+int ReadResponseHead( int SockFD, struct RespInfo *Response, struct FDsets *RW_Sets );
+int ReadResponseBody( int SockFD, struct RespInfo *Response, struct FDsets *RW_Sets );
+void SendResponse( struct ClientBase *Client );
+void CreateRasResponse( struct HTTPMode *Mode, struct ClientBase *Client );
+void DoMessageBody( struct ClientBase *Client );
+void InterpretePOSTRequest ( struct ClientBase *Client );
+void WriteAccessLog( struct ClientBase *Client );
+
+
+/* http-readmsg.c */
+int ReadHeader( int SockFD, char **Buffer, size_t *BuffSize );
+char *ReadBody( int SockFD, size_t BuffSize );
+rc_t ParseReqHeader( struct ReqInfo *Request );
+rc_t ParseRespHeader( struct RespInfo *Response );
+char *ParseReqLine( char *Buffer, struct ReqInfo *Request );
+char *ParseRespLine( char *Buffer, struct RespInfo *Response );
+char *ParseMsgLine( char *Buffer, int *Key, char **Param );
+void SplitURL( char *Buffer, struct URLComps *URL );
+size_t GetContentLength( struct MsgHeader *Ptr );
+char *GetFieldContent( struct MsgHeader *Ptr, int Field, struct MsgHeader **Next );
+int GetRealm( char *String );
+
+/* http-writemsg.g */
+rc_t AddField( struct MsgHeader *Ptr, int Field, char *Content );
+rc_t CreateStatusLine( char *Buffer, size_t *BuffSize, int Code, int Protocol );
+struct HTTPMsg *CreateHTTPMsg( char *, char *, size_t ); // ???
+rc_t SendHTTPMsg( int SockFD, struct HTTPMsg *Msg );
+rc_t FreeHTTPMsg( struct HTTPMsg *Ptr );
+
+/* http-error.c */
+int GetHTTPErrorTableEntry( int Code );
+rc_t CreateHTTPError( int Code, struct HTTPMode *Mode, struct HTTPMsg *Msg );
+
+/* http-methods.c */
+int HTTP_GetMKey( char * );
+char *HTTP_GetMethodName( int );
+
+/* http-fields.c */
+int HTTP_GetHKey( char * );
+char *HTTP_GetFieldName( int );
+
+/* http-date.c */
+rc_t HTTP_Date( char *, size_t );
+
+/* http-support.c */
+rc_t InitClientBase( struct ClientBase * );
+rc_t InitReqInfo( struct ReqInfo * );
+rc_t InitRespInfo( struct RespInfo * );
+void InitHTTPMsg( struct HTTPMsg *Msg );
+struct MsgHeader *NewMsgHeader( int, char * );
+struct MsgHeader *AppendMsgHeader( struct MsgHeader *, int, char * );
+void DeleteMsgHeader( struct MsgHeader * );
+void PrintReqInfo( struct ReqInfo * );
+void PrintRespInfo( struct RespInfo * );
+rc_t CheckSockError( int, int, int );
+char *CharToBits( char c );
+
+
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from support.c */
+/*------------------------------------------------------------------------*/
+
+int Get_OpenMax( void );
+char *PathAlloc( size_t * );
+int ReadN( register int, register char *, register int );
+int WriteN( register int, register char *, register int );
+int ReadLine( register int, register char *, register int );
+rc_t ParseString( char *, char *, ... );
+int SNPrintf( char *, size_t *, const char *, ... );
+int VSNPrintf( char *, size_t, const char *, va_list );
+char *StrError( int );
+char *StrToLower( char * );
+
+#endif /* _PROTOS_H not defined */
diff --git a/httpserver/server.h b/httpserver/server.h
new file mode 100644
index 0000000..e3b3f54
--- /dev/null
+++ b/httpserver/server.h
@@ -0,0 +1,190 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* server.h - server structures. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _SERVER_H
+#define _SERVER_H
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifndef AIX
+ #include <sys/fcntl.h>
+#endif
+
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "types.h"
+#include "http.h"
+
+struct HTTPRequest
+{
+ char *Database;
+ int Command;
+ char *QueryString;
+ int ClientType;
+ char *ClientID;
+ int Endianess;
+ int NumberOfQueryParams;
+ char *BinData;
+ int BinDataSize;
+ char *Capability;
+};
+
+union WhichArg
+{
+ int Code;
+};
+
+struct ToDoArgs
+{
+ int What;
+ union WhichArg Which;
+};
+
+struct FDsets
+{
+ int MaxFD;
+ fd_set Read;
+ fd_set Write;
+};
+
+struct LogFile
+{
+ char *Filename;
+ int FD;
+ int State;
+};
+
+
+struct Logging
+{
+ int Mode;
+ struct LogFile Server;
+ struct LogFile Access;
+ struct LogFile Comm;
+};
+
+struct ChildBase
+{
+ struct ChildBase *next;
+ struct ChildBase *prev;
+ pid_t PId;
+ int PD[2];
+ int PipeStatus;
+};
+
+
+struct Host
+{
+ char *Name;
+ char IPAddrString[ 16 ];
+#ifdef NO_in_addr_t
+ unsigned long IPAddress;
+#else
+ in_addr_t IPAddress;
+#endif
+};
+
+
+struct HTTPMode
+{
+ int Protocol;
+ int ConnStatus;
+};
+
+
+struct ClientBase
+{
+ /* Client Host Infos */
+ struct Host Host;
+ int ClientType;
+ /* Socket */
+ int SockFD;
+ struct sockaddr_in Socket;
+ int SockSize;
+ /* select() timeout */
+ struct timeval TimeOut;
+
+ struct HTTPMode Comm;
+ /* Request */
+ struct ReqInfo Request;
+ /* Response */
+ struct HTTPMsg Response;
+ int RespStatus;
+ /* Pipe to Parent process */
+ int Pipe;
+ char PipeBuffer[PIPE_BUFFSIZE];
+};
+
+
+struct ServerBase
+{
+ pid_t PId;
+ /* -- Config.Information */
+ struct Host Host;
+ int Port;
+ char *AdminMailAddress;
+ char *Directory;
+ char *ConfigFile;
+ char *PidFile;
+ //char *CacheFile;
+ size_t MaxURLLength;
+ /* -- Status Information */
+ int Status;
+ struct ChildBase *ChildList;
+ struct FDsets PipeSets;
+ /* -- Global Data */
+ struct Logging Log;
+ struct CacheNode *Cache;
+ /* -- Server Socket */
+ int SockFD;
+ struct sockaddr_in Socket;
+ /* -- Client Information */
+ struct ClientBase Client;
+};
+
+
+#endif /* _SERVER_H not defined */
diff --git a/httpserver/signals.cc b/httpserver/signals.cc
new file mode 100644
index 0000000..4bda368
--- /dev/null
+++ b/httpserver/signals.cc
@@ -0,0 +1,287 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* signals.c - signal handling stuff. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: signals.c,v $ $Revision: 1.8 $ $State: Exp $
+ * $Locker: $
+*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+
+extern struct ServerBase Server;
+
+
+/****** signals/Signal *******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* Own Signal() function, based on sigaction().
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+sighandler Signal( int signo, sighandler x)
+{
+ struct sigaction SigAction;
+ struct sigaction OldAction;
+
+ SigAction.sa_handler = (void(*)(int))SigHandler;
+ sigemptyset( & SigAction.sa_mask );
+ SigAction.sa_flags = 0;
+
+ if( signo == SIGALRM )
+ {
+#ifdef SA_INTERRUPT
+ SigAction.sa_flags |= SA_INTERRUPT; /* SunOS */
+#endif
+ }
+ else
+ {
+#ifdef SA_RESTART
+ SigAction.sa_flags |= SA_RESTART; /* SVR4, 4.3+ BSD */
+#endif
+ }
+
+ if( sigaction( signo, &SigAction, &OldAction ) < 0 )
+ return( SIG_ERR );
+ return( OldAction.sa_handler );
+}
+
+
+/****** signals/SigHandler ***************************************************
+*
+* NAME
+* SigHandler -- Little Signal Handler.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void SigHandler( int Signal )
+{
+ //not used(see line 169) char Buffer[PIPE_BUFFSIZE];
+ int errno_bak;
+ int ChildStatus;
+ pid_t ChildPId;
+ struct ChildBase *Child = NULL;
+
+ errno_bak = errno;
+ switch( Signal )
+ {
+ case SIGHUP:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGHUP'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGINT:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGINT'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGQUIT:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGQUIT'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGUSR1:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGUSR1'." );
+ // SaveCache( Server.Cache, Server.CacheFile );
+ break;
+
+ case SIGUSR2:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGUSR2'." );
+ break;
+
+ case SIGPIPE:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGPIPE'." );
+ break;
+
+ case SIGTERM:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGTERM'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGCHLD:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGCHLD'." );
+ ChildPId = waitpid( -1, &ChildStatus, WNOHANG );
+ while( ChildPId > 0 )
+ {
+ if( WIFEXITED( ChildStatus ) )
+ {
+ /*-- Has Child send a Message? --*/
+ if( WEXITSTATUS( ChildStatus ) == NOTE )
+ {
+ Child = GetChild( Server.ChildList, ChildPId );
+ if( Child != NULL )
+ {
+ /*
+ bzero( Buffer, PIPE_BUFFSIZE );
+ read( Child->PD[0], Buffer, PIPE_BUFFSIZE );
+ HandlePipeMsg( Buffer, Server.SubServerList, Server.Cache );
+ */
+ }
+ }
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> exited normally with status %d.",
+ ChildPId, WEXITSTATUS( ChildStatus ) );
+ }
+ else if( WIFSIGNALED( ChildStatus ) )
+ {
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> exited abnormally, signal number = %d.",
+ ChildPId, WTERMSIG( ChildStatus ) );
+ }
+ else if( WIFSTOPPED( ChildStatus ) )
+ {
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> is stopped, signal number = %d.",
+ ChildPId, WSTOPSIG( ChildStatus ) );
+ }
+ else
+ {
+ LogMsg( LG_SERVER, WARN,
+ "WARN: Something strange with Child <%d> (Status: %d).",
+ ChildPId, ChildStatus );
+ }
+
+ CleanupChild( Server.ChildList, &Server.PipeSets, ChildPId );
+ ChildPId = waitpid( -1, &ChildStatus, WNOHANG );
+
+ }
+ if( ChildPId == -1 && errno != ECHILD )
+ ErrorMsg( E_SYS, WARN, "WARN: waitpid() returned an Error.", errno );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Exiting Signal Handler ..." );
+ break;
+ default:
+ ErrorMsg( E_PRIV, ERROR, "ERROR: Signal %d couldn't be handled!", Signal );
+ break;
+ }
+ errno = errno_bak;
+ return;
+}
+
+
+/****** signals/InitSigHandler ***********************************************
+*
+* NAME
+* InitSigHandler -- Minimum Signal Handler setup.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitSigHandler( void )
+{
+ if( Signal( SIGHUP, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (HUP)." );
+ if( Signal( SIGINT, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (INT)." );
+ if( Signal( SIGQUIT, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (QUIT)." );
+ if( Signal( SIGTERM, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (TERM)." );
+ if( Signal( SIGCHLD, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (CHLD)." );
+ if( Signal( SIGUSR1, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (USR1)." );
+ if( Signal( SIGUSR2, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (USR2)." );
+
+ if( Signal( SIGPIPE, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (PIPE)." );
+ return( OK );
+}
+
diff --git a/httpserver/support.cc b/httpserver/support.cc
new file mode 100644
index 0000000..6a011fd
--- /dev/null
+++ b/httpserver/support.cc
@@ -0,0 +1,640 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* support.c - support functions for the gateway httpd. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: support.c,v $ $Revision: 1.6 $ $State: Exp $
+ * $Locker: $
+ */
+
+#include <ctype.h>
+
+#include "defs.h"
+#include "types.h"
+#include "protos.h"
+#include "server.h"
+
+
+/****** support/Get_OpenMax **************************************************
+*
+* NAME
+* Get_OpenMax -- get the maximum of file descriptors per process.
+*
+* SYNOPSIS
+* int Get_OpenMax( void );
+*
+* FUNCTION
+* Get the systems maximum number of file descriptors per process. Uses
+* OPEN_MAX -- if defined -- else asks the system per sysconf() call.
+* If this still doesn't succeed, returns some kind of "reasonable
+* default".
+*
+* INPUTS
+* openmax - A global variable that holds the value of OPEN_MAX,
+* if defined, else '0'.
+*
+* RESULT
+* Returns the number of file descriptors, may be zero or a positive
+* int value.
+* openmax will be set to an appropriate value if it was set to '0'
+* when Get_OpenMax() was called.
+*
+* NOTES
+* Uses ErrMsg() to report problems with sysconf(). Hmmm...
+*
+* BUGS
+* Does also return the guessed value if sysconf() reported an error.
+* This seems to be okay for my needs...
+*
+* SEE ALSO
+* Richard W. Stevens: "Advanced Programming in the UNIX Environment",
+* 1992 Addison-Wesley Publishing Company, Inc.
+*
+******************************************************************************
+*
+*/
+
+#ifdef OPEN_MAX
+static size_t openmax = OPEN_MAX; /* Wenn vorhanden, dann ist das alles */
+#else /* was gebraucht wird. */
+static size_t openmax = 0;
+#endif
+
+#ifdef NOFILE
+#define OPEN_MAX_GUESS NOFILE
+#else
+#define OPEN_MAX_GUESS 256 /* Falls OPEN_MAX undefiniert (dynamisch) */
+#endif /* ist, ist dies u.U. nicht adaequat! */
+
+int Get_OpenMax( void )
+{
+ if( openmax == 0 )
+ {
+ errno = 0;
+ if( ( openmax = sysconf( _SC_OPEN_MAX ) ) < 0 )
+ {
+ if( errno == 0 )
+ {
+ openmax = OPEN_MAX_GUESS;
+ }
+ else
+ {
+ /* sysconf() returned an error... strange, but... */
+ /* Does it justify to break the program? */
+ /* Naah, I don't think so... So we just print a note */
+ /* and give back our "reasonable default"... */
+ ErrorMsg( E_SYS, WARN, "WARN: sysconf error for _SC_OPEN_MAX." );
+ openmax = OPEN_MAX_GUESS;
+ }
+ }
+ }
+
+ return( openmax );
+}
+
+
+/****** support/PathAlloc ****************************************************
+*
+* NAME
+* PathAlloc -- allocate memory as buffer for pathnames.
+*
+* SYNOPSIS
+* char *PathAlloc( size_t *size );
+*
+* FUNCTION
+* Get the systems maximum of characters in absolute pathnames. Uses
+* PATH_MAX -- if defined -- else asks the system per pathconf() call.
+* If this still doesn't succeed, uses some kind of "reasonable
+* default".
+* Then it calls malloc() to allocate the buffer.
+*
+* INPUTS
+* size - A pointer to a variable, which will set to the size of
+* the buffer. If it is NULL, you won't get any size
+* information.
+* pathmax - A global variable that holds the value of PATH_MAX,
+* if defined, else '0'
+*
+* RESULT
+* Returns a "char" pointer to the allocated buffer.
+* NULL, if the allocation failed. Then it will also print a log
+* message.
+* pathmax will be set to an appropriate value if it was set to '0'
+* when PathAlloc() was called.
+*
+* NOTES
+* Uses ErrMsg() to report problems with pathconf() and malloc().
+*
+* BUGS
+* Does also use the guessed value if pathconf() reported an error.
+* This seems to be okay for my needs...
+*
+* SEE ALSO
+* Richard W. Stevens: "Advanced Programming in the UNIX Environment",
+* 1992 Addison-Wesley Publishing Company, Inc.
+*
+******************************************************************************
+*
+*/
+
+#ifdef PATH_MAX
+static size_t pathmax = PATH_MAX; /* Wenn vorhanden, dann ist das alles */
+#else /* was gebraucht wird. */
+static size_t pathmax = 0;
+#endif
+
+#ifdef MAXPATHLEN
+#define PATH_MAX_GUESS MAXPATHLEN
+#else
+#define PATH_MAX_GUESS 1024 /* Falls PATH_MAX undefiniert (dynamisch) */
+#endif /* ist, ist dies u.U. nicht adäquat! */
+
+char *PathAlloc( size_t *size )
+{
+ char *Ptr;
+
+ if( pathmax == 0 )
+ {
+ errno = 0;
+ if( ( pathmax = pathconf( "/", _PC_PATH_MAX ) ) < 0 )
+ {
+ if( errno == 0 )
+ {
+ pathmax = PATH_MAX_GUESS;
+ }
+ else
+ {
+ /* pathconf() returned an error... strange, but... */
+ /* See also Get_OpenMax(). */
+ /* We give back our "reasonable default"... */
+ ErrorMsg( E_SYS, WARN, "WARN: pathconf error for _PC_PATH_MAX." );
+ pathmax = PATH_MAX_GUESS;
+ }
+ }
+ }
+ else
+ {
+ // it appears that every call makes the path 1 byte longer. Anyway, the config file
+ // is not read too often and I am not willing to debug it now
+ pathmax++; /* Don't forget the "/" character... */
+ }
+
+ if( ( Ptr = (char*)mymalloc( pathmax + 1 ) ) == NULL )
+ {
+ if( size != NULL )
+ *size = 0;
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for pathname buffer." );
+ }
+ else
+ {
+ if( size != NULL )
+ *size = pathmax + 1;
+ }
+ return( Ptr );
+}
+
+
+/****** support/ReadN ********************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Read "n" bytes from a descriptor.
+ * Use in place of read() when fd is a stream socket.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int ReadN( register int fd, register char *ptr, register int nbytes )
+{
+ int nleft;
+ int nread;
+
+ nleft = nbytes;
+ while( nleft > 0 )
+ {
+ nread = read( fd, ptr, nleft );
+ if( nread < 0 )
+ if( errno != EAGAIN )
+ return( nread ); /* error, return < 0 */
+ else
+ continue;
+ else if( nread == 0 )
+ break; /* EOF */
+ nleft -= nread;
+ ptr += nread;
+ }
+ return( nbytes - nleft ); /* return >= 0 */
+}
+
+
+/****** support/WriteN *******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Write "n" bytes to a descriptor.
+ * Use in place of write() when fd is a stream socket.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int WriteN( register int fd, register char *ptr, register int nbytes )
+{
+ long nleft;
+ long nwritten = 0;
+
+ nleft = nbytes;
+ while( nleft > 0 )
+ {
+ nwritten = write( fd, ptr, nleft );
+ if( nwritten < 0 )
+ {
+ if( errno != EAGAIN )
+ return( nwritten ); /* error */
+ else
+ continue;
+ }
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return( nbytes - nleft );
+}
+
+
+/****** support/ReadLine *****************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Read a line from a descriptor.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int ReadLine( register int fd, register char *ptr, register int maxlen )
+{
+ int n;
+ int rc;
+ char c;
+
+ for( n = 1; n < maxlen; n++ )
+ {
+ if( ( rc = read( fd, &c, 1 ) ) == 1 )
+ {
+ *ptr++ = c;
+ if( c == '\n' )
+ break;
+ }
+ else if( rc == 0 )
+ if( n == 1 )
+ return( 0 ); /* EOF, no data read */
+ else
+ break; /* EOF, some data was read */
+ else
+ if( errno != EAGAIN )
+ return( -1 ); /* error */
+ }
+ *ptr = 0;
+ return( n );
+}
+
+
+/****** support/ParseString **************************************************
+*
+* NAME
+* ParseString -- Break string into words.
+*
+* SYNOPSIS
+* int ParseString( char *String, char *Token, ... );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseString( char *String, char *Token, ... )
+{
+ /* ###TODO: Das letzte Argument sollte den kompletten Reststring erhalten */
+ /* Buffer loeschen vor Austritt */
+ va_list ArgPtr;
+ char *Keyword;
+ char *Value;
+ char *NextToken;
+ char *NNextToken;
+ char *Delim = " \t\n\r"; /* Begrenzungszeichen */
+
+ if( ( String[0] == '#' ) || /* Kommentar, */
+ ( String[0] == '\n' ) || /* oder Leerzeile? */
+ ( String[0] == '\r' ) )
+ return( ERROR ); /* => Zurück. */
+
+ Keyword = strtok( String, Delim ); /* 1. Token suchen */
+ if( Keyword != NULL ) /* Etwas gefunden? */
+ {
+ if( Keyword[0] == '#' ) /* Auch Kommentarzeile: */
+ return( ERROR ); /* => Zurück. */
+ strcpy( Token, Keyword ); /* Keyword in Buffer kopieren */
+
+ /* Var.Arg. Liste abarbeiten bis Arg == NULL. */
+ /* Letztes Arg. muss NULL sein, da va_arg() nicht selbst in der Lage */
+ /* ist das letzte Argument zu erkennen. */
+
+ va_start( ArgPtr, Token ); /* VarArg initialisieren */
+ NextToken = va_arg( ArgPtr, char * ); /* 1. zus. Argument holen. */
+ if( NextToken != NULL)
+ {
+ NNextToken = va_arg( ArgPtr, char * ); /* 2. zus. Arg. holen */
+ while( NNextToken != NULL ) /* Argument vorhanden? */
+ {
+ Value = strtok( NULL, Delim ); /* Weiteres Token suchen */
+ if( Value != NULL ) /* Wort gefunden? */
+ strcpy( NextToken, Value ); /* Token in Buffer kopieren */
+ else /* Ansonsten: */
+ strcpy( NextToken, "\0" ); /* Leerstring uebergeben */
+ NextToken = NNextToken;
+ NNextToken = va_arg( ArgPtr, char * ); /* Zeiger auf nächstes Arg. */
+ }
+ Value = strtok( NULL, "\n\r" ); /* Zeiger auf Reststring holen */
+ if( Value != NULL ) /* Wenn vorhanden, */
+ strcpy( NextToken, Value ); /* in letztes Arg. übergeben */
+ else /* wenn nicht, */
+ strcpy( NextToken, "\0" ); /* Leerstring übergeben */
+ }
+ va_end( ArgPtr ); /* VarArg aufräumen */
+ return( OK ); /* OK: Es wurde etwas gefunden */
+ }
+ return( ERROR ); /* ERROR: String war leer. */
+}
+
+
+/****** support/SNPrintf *****************************************************
+*
+* NAME
+* SNPrintf -- print into buffer with size-check.
+*
+* SYNOPSIS
+* int SNPrintf( char *String, size_t *Size, const char *Format, ... );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+int SNPrintf( char *String, size_t *Size, const char *Format, ... )
+{
+ va_list ArgPtr;
+ int n = 0;
+
+ if( *Size > 0 )
+ {
+ va_start( ArgPtr, Format );
+ n = VSNPrintf( String, *Size, Format, ArgPtr );
+ va_end( ArgPtr );
+
+ if( n >= 0 )
+ *Size = *Size - n;
+ else
+ *Size = 0;
+ }
+ return( n );
+}
+
+
+/****** support/VSNPrintf ****************************************************
+*
+* NAME
+* VSNPrintf -- print variable argument list into buffer with size-check.
+*
+* SYNOPSIS
+* int VSNPrintf( char *String, size_t Size,
+* const char *Format, va_list ArgPtr );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+int VSNPrintf( char *String, size_t Size, const char *Format, va_list ArgPtr )
+{
+ int n = 0;
+ char *Buffer = NULL;
+
+#ifdef NO_vsnprintf
+ if( Size == 0 )
+ n = 0;
+ else if( Size > 0 )
+ {
+ if( ( Buffer = (char*)mymalloc( BUFFSIZE ) ) != NULL )
+ {
+ n = vsprintf( Buffer, Format, ArgPtr );
+ if( n < Size )
+ strncpy( String, Buffer, Size );
+ else
+ {
+ strncpy( String, Buffer, Size-1 );
+ *( String + Size ) = '\0';
+ n = -1;
+ }
+ free( Buffer );
+ }
+ else
+ n = -1;
+ }
+ else
+ n = -1;
+#else
+ n = vsnprintf( String, Size, Format, ArgPtr );
+#endif
+ return( n );
+}
+
+
+/****** support/StrError *****************************************************
+*
+* NAME
+* StrError - return error string for given error code.
+*
+* SYNOPSIS
+* char *StrError( int ErrNum );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+char *StrError( int ErrNum )
+{
+#ifdef NO_strerror
+ char Buffer[20];
+
+ bzero( Buffer, 20 );
+ sprintf( Buffer, "Error %d", ErrNum );
+ return( Buffer );
+#else
+ return( strerror( ErrNum ) );
+#endif
+}
+
+/****** support/StrToLower ***************************************************
+*
+* NAME
+* StrToLower - make all characters of a string lower case.
+*
+* SYNOPSIS
+* char *StrToLower( char *String );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+char *StrToLower( char *String )
+{
+ while( *String != '\0' )
+ {
+ *String = tolower( *String );
+ String++;
+ }
+ return( String );
+}
diff --git a/httpserver/test/Makefile b/httpserver/test/Makefile
new file mode 100644
index 0000000..2fef649
--- /dev/null
+++ b/httpserver/test/Makefile
@@ -0,0 +1,63 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community 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.
+#
+# Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# a RasDaMan module
+#
+# COMMENTS:
+# This Makefile was created during the relational port when
+# splitting up catalogif into O2 dependent und not O2 dependent.
+#
+# IMPORTANT:
+# As opposed to all other Makefiles catalogmgr does not have
+# its own library. catalogif is used instead, otherwise the
+# linking of all executables would have had to be changed.
+#
+##################################################################
+
+#
+# IMPORTANT:
+# This is an example Makefile, it has to be adapted for
+# every module. This is usually done by editing the
+# following:
+# * variables OBJS, TESTOBJS and TESTPRG
+# * the dependencies at the end
+# * every occurence of EXLIB
+# * the toplevel Makefile and Makefile.inc
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+MISCCLEAN := core
+
+########################### Targets ##############################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/httpserver/test/httpserver.conf b/httpserver/test/httpserver.conf
new file mode 100644
index 0000000..63ae3fd
--- /dev/null
+++ b/httpserver/test/httpserver.conf
@@ -0,0 +1,14 @@
+#
+# httpserver Configuration file
+#
+ServerName: sunwibas13.forwiss.tu-muenchen.de
+Port: 8080
+
+ServerAdmin: zoller@forwiss.tu-muenchen.de
+
+ServerRoot: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test
+AccessLog: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/access.log
+ServerLog: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/server.log
+PidFile: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/httpserver.pid
+MaxURLLength: 120
+
diff --git a/httpserver/test/post_test.html b/httpserver/test/post_test.html
new file mode 100644
index 0000000..46aab47
--- /dev/null
+++ b/httpserver/test/post_test.html
@@ -0,0 +1,116 @@
+<HEAD>
+<TITLE>Error</TITLE>
+</HEAD>
+
+<BODY>
+<H1>IMPORTANT NOTE</H1>
+
+<P>Unfortunately requests to the RasDaMan HTTP server are cached by
+ default. Be sure to disable the proxy in your webserver and also
+ disable the internal cache by telling the browser to verify the
+ document every time.</P>
+
+
+<CENTER>
+<P>
+<BR>
+<H1>Test for Post-Request: Client is Browser</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="BROWSER">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Everything correct!">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="xyz">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Wrong Client Type">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="BROWSER">
+<INPUT TYPE=HIDDEN NAME="TestParam" VALUE="wfwef">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Unknown Post Parameters">
+</FORM>
+<P>
+
+<P>
+<A HREF="http://sunwibas0.forwiss.tu-muenchen.de:8080/">Get-request</A>
+
+
+<H1>Testing different return types</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT count_cells(img > 9l) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns scalar">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT sdom(img) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns spatial domain">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT grmblfx(img) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns error">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM rockies AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Retrieve whole rockies">
+</FORM>
+<P>
+
+<P>
+
+
+<H1>Test for Post-Request: Client is RasClient</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Everything correct!">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+<INPUT TYPE=HIDDEN NAME="TestParam" VALUE="wfwef">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Unknown Post Parameters">
+</FORM>
+<P>
+
+
+
+</CENTER>
+
+</BODY>
+
diff --git a/httpserver/types.h b/httpserver/types.h
new file mode 100644
index 0000000..dab5bb0
--- /dev/null
+++ b/httpserver/types.h
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* types.h - data types. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: types.h,v $ $Revision: 1.1 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+typedef struct SubServerBase *SubServerPtr;
+typedef int rc_t;
+
+#endif /* _TYPES_H not defined */