/* mod_gsweb.c - GSWeb: Apache Module
   Copyright (C) 1999 Free Software Foundation, Inc.
   
   Written by:	Manuel Guesdon <mguesdon@sbuilders.com>
   Date: 	July 1999
   
   This file is part of the GNUstep Web Library.
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define moduleRevision "$Revision: 1.16 $"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/param.h>

#include "../common/config.h"


#include "GSWUtil.h"
#include "GSWDict.h"
#include "GSWString.h"
#include "GSWConfig.h"
#include "GSWURLUtil.h"
#include "GSWHTTPHeaders.h"

#include "GSWAppRequestStruct.h"
#include "GSWAppConnect.h"
#include "GSWHTTPRequest.h"
#include "GSWHTTPResponse.h"
#include "GSWAppRequest.h"

#include "httpd.h"
#include <http_config.h>
#include <http_request.h>
#include <http_core.h>

#include <http_protocol.h>

// Module Definition:

// Declare the module
module GSWeb_Module;


typedef struct _GSWeb_Config
{
  const char *pszGSWeb;      // default = GSWeb
  const char *pszConfigPath; // path to GSWeb.conf
//  const char *pszRoot;       // normally htdocs/GSWeb
} GSWeb_Config;


#ifdef Apache2
/*
 * Declare ourselves so the configuration routines can find and know us.
 * We'll fill it in at the end of the module.
 */
module AP_MODULE_DECLARE_DATA GSWeb_Module;

#include <ap_compat.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_tables.h>

#define ap_soft_timeout(s, r) ;
#define ap_hard_timeout(s, r) ;
#define ap_kill_timeout(r) ;

typedef apr_pool_t pool;
typedef apr_array_header_t array_header;
typedef apr_table_t table;
typedef apr_table_entry_t table_entry;
#else
//TODO: remove ??
struct table
{
  /* This has to be first to promote backwards compatibility with
   * older modules which cast a table * to an array_header *...
   * they should use the table_elts() function for most of the
   * cases they do this for.
   */
    array_header a;
#ifdef MAKE_TABLE_PROFILE
    void *creator;
#endif
};  
#endif

// 1.x/2.x Compatibility
#ifdef Apache2
#define APR_PSPRINTF apr_psprintf
#else
#define APR_PSPRINTF ap_psprintf
#endif


/*
static CONST char *GSWeb_SetDocRoot(cmd_parms *p_pCmdParams,
				    void      *p_pUnused,
				    char      *p_pszArg);
*/
static CONST char *GSWeb_SetScriptAlias(cmd_parms *p_pCmdParams,
					void      *p_pUnused,
					char      *p_pszArg);
static CONST char *GSWeb_SetConfig(cmd_parms *p_pCmdParams,
				   void      *p_pUnused,
				   char      *p_pszArg);
static int GSWeb_Handler(request_rec *p_pRequestRec);

/*
 * Locate our server configuration record for the current request.
 */
static GSWeb_Config *
GSWeb_GetServerConfig(server_rec *p_pServerRec)
{
  return (GSWeb_Config *)ap_get_module_config(p_pServerRec->module_config,
					      &GSWeb_Module);
}


#ifdef Apache2
static int GSWeb_PostConfig(apr_pool_t *p, apr_pool_t *plog,
                            apr_pool_t *ptemp, server_rec *s)
{
  char buffer[256]="mod_gsweb/" 
    GSWEB_SERVER_ADAPTOR_VERSION_MAJOR_STRING 
    "." GSWEB_SERVER_ADAPTOR_VERSION_MINOR_STRING
    "rev";
  RevisionStringToRevisionValue(buffer+strlen(buffer),moduleRevision);
  ap_add_version_component(p, buffer);
  return OK;
}
#endif
//--------------------------------------------------------------------
// Init
#ifdef Apache2
static void
GSWeb_ChildInit(apr_pool_t *p,
		server_rec *p_pServerRec)
#else
static void
GSWeb_Init(server_rec *p_pServerRec,
	   pool       *p) 
#endif
{
  GSWDict      *pDict=GSWDict_New(0);
  GSWeb_Config *pConfig=NULL;

  pConfig=GSWeb_GetServerConfig(p_pServerRec);
  GSWLog_Init(NULL,GSW_INFO);
  GSWLog(GSW_INFO,p_pServerRec,
	 "GSWeb Init Start Config. Handler: " GSWEB_HANDLER);
  GSWLog(GSW_DEBUG,p_pServerRec,
	 "GSWeb_Init: pConfig->pszGSWeb=%s",
	 pConfig->pszGSWeb);
	
  if (pConfig && pConfig->pszConfigPath)
    GSWDict_AddStringDup(pDict,
			 g_szGSWeb_Conf_ConfigFilePath,
			 pConfig->pszConfigPath);
/*
  if (pConfig && pConfig->pszRoot)
    GSWDict_AddStringDup(pDict,
			 g_szGSWeb_Conf_DocRoot,
			 pConfig->pszRoot);
*/
  GSWLog(GSW_INFO,p_pServerRec,
	 "GSWeb Init LB Init. Handler: " GSWEB_HANDLER);
  GSWConfig_Init(pDict,p_pServerRec);
	
  GSWLog(GSW_INFO,p_pServerRec,
	 "GSWeb Init. Handler: " GSWEB_HANDLER);
  GSWDict_Free(pDict);
};

//--------------------------------------------------------------------
// Create Config
static void *
GSWeb_CreateServerConfig(pool       *p_pPool,
			 server_rec *p_pServerRec)
{
  GSWeb_Config *pConfig = (GSWeb_Config *)ap_palloc(p_pPool,
						    sizeof(GSWeb_Config));

  pConfig->pszGSWeb = g_szGSWeb_Prefix;
  GSWLog(GSW_DEBUG,p_pServerRec,
	 "GSWeb_CreateServerConfig: pConfig->pszGSWeb=%s",
         pConfig->pszGSWeb);
  pConfig->pszConfigPath = NULL;
//  pConfig->pszRoot = NULL;
  return pConfig;
};
/*
//--------------------------------------------------------------------
// Set Param: DocRoot
static CONST char *
GSWeb_SetDocRoot(cmd_parms *p_pCmdParams,
		 void      *p_pUnused,
		 char      *p_pszArg)
{
  server_rec   *pServerRec = p_pCmdParams->server;
  GSWeb_Config *pConfig = NULL;

  GSWLog(GSW_DEBUG,pServerRec,"Start GSWeb_SetDocRoot");
  pConfig=(GSWeb_Config *)ap_get_module_config(pServerRec->module_config,
					       &GSWeb_Module);
  pConfig->pszRoot = p_pszArg;
  GSWLog(GSW_DEBUG,pServerRec,"Start GSWeb_SetDocRoot");
  return NULL;
};
*/
//--------------------------------------------------------------------
// Set Param: ScriptAlias
static CONST char *
GSWeb_SetScriptAlias(cmd_parms *p_pCmdParams,
		     void      *p_pUnused,
		     char      *p_pszArg)
{
  server_rec   *pServerRec = p_pCmdParams->server;
  GSWeb_Config *pConfig = NULL;
  GSWLog(GSW_DEBUG,pServerRec,"Start GSWeb_SetScriptAlias");
  pConfig=GSWeb_GetServerConfig(pServerRec);
  pConfig->pszGSWeb = p_pszArg;
  GSWLog(GSW_DEBUG,pServerRec,"Stop GSWeb_SetScriptAlias");
  return NULL;
};

//--------------------------------------------------------------------
// Set Param: ConfigFile
static CONST char *
GSWeb_SetConfig(cmd_parms *p_pCmdParams,
		void      *p_pUnused,
		char      *p_pszArg)
{
  server_rec   *pServerRec = p_pCmdParams->server;
  GSWeb_Config *pConfig = NULL;

  GSWLog(GSW_DEBUG,pServerRec,"Start GSWeb_SetConfig");
  pConfig=GSWeb_GetServerConfig(pServerRec);
  GSWLog(GSW_DEBUG,pServerRec,"pConfig=%p",pConfig);
  GSWLog(GSW_DEBUG,pServerRec,"p_pszArg=%s",p_pszArg);
  pConfig->pszConfigPath = p_pszArg;
  GSWLog(GSW_DEBUG,pServerRec,"Stop GSWeb_SetConfig");
  return NULL;
};


//--------------------------------------------------------------------
// Translate
int
GSWeb_Translation(request_rec *p_pRequestRec)
{
  int               iRetValue=OK;
  GSWeb_Config     *pConfig=NULL;
  GSWURLComponents  stURL;

  memset(&stURL,0,sizeof(stURL));
  GSWLog(GSW_DEBUG,p_pRequestRec->server,"Start GSWeb_Translation");
  pConfig=GSWeb_GetServerConfig(p_pRequestRec->server);

  // Is this for us ?
  if (strncmp(pConfig->pszGSWeb,
	      p_pRequestRec->uri,
	      strlen(pConfig->pszGSWeb))==0) 
    {
      GSWURLError eError=GSWParseURL(&stURL,p_pRequestRec->uri,
				     p_pRequestRec->server);
      if (eError!=GSWURLError_OK)
	{
	  GSWLog(GSW_ERROR,p_pRequestRec->server,
		 "GSWeb_Translation Declined (Error %d)",(int)eError);
	  iRetValue=DECLINED;
	}
      else
	{
	  GSWLog(GSW_DEBUG,
		 p_pRequestRec->server,
		 "GSWeb_Translation Handler p_pRequestRec->handler=%s pool=%p handler=%s pConfig->pszGSWeb=%s",
		 p_pRequestRec->handler,
		 p_pRequestRec->pool,
		 g_szGSWeb_Handler,
		 pConfig->pszGSWeb);
	  p_pRequestRec->handler=(char *)ap_pstrdup(p_pRequestRec->pool,
						    g_szGSWeb_Handler);
	  iRetValue=OK;
	};
    }
  else
    {
      GSWLog(GSW_DEBUG,p_pRequestRec->server,"GSWeb_Translation Declined");
      iRetValue=DECLINED;
    };
  GSWLog(GSW_DEBUG,p_pRequestRec->server,
	 "Stop GSWeb_Translation return %d",
	 iRetValue);
  return iRetValue;
};

//--------------------------------------------------------------------
// Copy p_pRequestRec in headers into p_pGSWHTTPRequest
// Also add some environment variable headers
static void
copyHeaders(request_rec    *p_pRequestRec,
	    GSWHTTPRequest *p_pGSWHTTPRequest)
{
  server_rec         *pServerRec = p_pRequestRec->server;
  conn_rec           *pConnection = p_pRequestRec->connection;
  const array_header *headers_arr=ap_table_elts(p_pRequestRec->headers_in);
  table_entry        *headers=NULL;
  int i=0;
  char		     *pszPort=NULL;
  CONST char         *pszRemoteLogName=NULL;
  GSWLog(GSW_DEBUG,pServerRec,"Start copyHeaders");

  // copy p_pRequestRec headers
  headers =  (table_entry *) headers_arr->elts;
  for (i=0;i<headers_arr->nelts;i++)
    {
      if (headers[i].key)
        {
          GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
                                   headers[i].key,headers[i].val);
#ifdef	DEBUG
          GSWLog(GSW_DEBUG,pServerRec,"key=%s value=%s",
                 headers[i].key,headers[i].val);
#endif
        };
    };

  // Add server headers
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ServerSoftware,
#ifdef Apache2
			   ap_get_server_version()
#else
			   SERVER_VERSION
#endif
                           );
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_RequestScheme,
			   ap_http_method(p_pRequestRec));

  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_Protocol,
			   p_pRequestRec->protocol);

  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ProtocolNum,
			   APR_PSPRINTF(p_pRequestRec->pool,
                                        "%u",
                                        p_pRequestRec->proto_num));

  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ServerName,
			   pServerRec->server_hostname);

  {
    unsigned int serverPort=(unsigned)ap_get_server_port(p_pRequestRec);
    if (serverPort==0)
      {
        if (p_pRequestRec->parsed_uri.port_str && p_pRequestRec->parsed_uri.port!=0)
          serverPort=(unsigned)p_pRequestRec->parsed_uri.port;
        else
          serverPort=(unsigned)pServerRec->port;
      };
    pszPort = APR_PSPRINTF(p_pRequestRec->pool,
                           "%u",
                           (unsigned int)serverPort);
  };

  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ServerPort,
			   pszPort);
#ifdef Apache2
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_RemoteHost,
			   (CONST char *)ap_get_remote_host(pConnection,
					        p_pRequestRec->per_dir_config,
						REMOTE_NAME,NULL));
#else /* Apache 1.x */
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_RemoteHost,
			   (CONST char *)ap_get_remote_host(pConnection,
						p_pRequestRec->per_dir_config,
						REMOTE_NAME));
#endif
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_RemoteAddress,
			   pConnection->remote_ip);
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_DocumentRoot,
			   (char *)ap_document_root(p_pRequestRec));
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ServerAdmin,
			   pServerRec->server_admin);
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_ScriptFileName,
			   p_pRequestRec->filename);
  pszPort = APR_PSPRINTF(p_pRequestRec->pool,
                         "%u",
#ifdef Apache2
                         pConnection->remote_addr->port
#else
                         ntohs(pConnection->remote_addr.sin_port)
#endif
                         );
  GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			   g_szServerInfo_RemotePort,
			   pszPort);
  
#ifdef Apache2
//TODO
#else
  if (pConnection->user)
    GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			     g_szServerInfo_RemoteUser,
			     pConnection->user);
  if (pConnection->ap_auth_type)
    GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			     g_szServerInfo_AuthType,//"auth_type",
			     pConnection->ap_auth_type);
#endif
  pszRemoteLogName = (char *)ap_get_remote_logname(p_pRequestRec);
  if (pszRemoteLogName)
    GSWHTTPRequest_AddHeader(p_pGSWHTTPRequest,
			     g_szServerInfo_RemoteIdent,
			     pszRemoteLogName);
  GSWLog(GSW_DEBUG,pServerRec,"Stop copyHeaders");
};

//--------------------------------------------------------------------
// callback fonction to copy an header into p_pRequest
static void
getHeader(GSWDictElem *p_pElem,
	  void        *p_pRequestRec)
{
  request_rec *pRequestRec = (request_rec *)p_pRequestRec;
  server_rec *pServerRec = pRequestRec->server;
#ifdef	DEBUG
  GSWLog(GSW_DEBUG,pServerRec,"Start getHeader key=%s value=%s headers_out=%p",
         p_pElem->pszKey,(char *)p_pElem->pValue,pRequestRec->headers_out);
#endif	
  if (!pRequestRec->content_type &&
      strcasecmp(p_pElem->pszKey,g_szHeader_ContentType)==0)
    {
      pRequestRec->content_type = (char *)ap_pstrdup(pRequestRec->pool,
                                                     (char *)p_pElem->pValue);//TODOVERIFY: strdup or not ?
#ifdef Apache2
      ap_set_content_type(pRequestRec, (char *)p_pElem->pValue);
#endif
    }
  else
    ap_table_add(pRequestRec->headers_out,p_pElem->pszKey,
		 (char *)p_pElem->pValue);
#ifdef	DEBUG
  GSWLog(GSW_DEBUG,pServerRec,"Stop getHeader");
#endif
};

//--------------------------------------------------------------------
// send response

static void
sendResponse(request_rec     *p_pRequestRec,
	     GSWHTTPResponse *p_pHTTPResponse)
{
  server_rec *pServerRec = p_pRequestRec->server;
  GSWLog(GSW_DEBUG,pServerRec,"Start sendResponse");
	
  // Add Headers for processing time information
#ifdef Apache2
  if (GSWConfig_AddTimeHeaders())
    {
      char *pszBuffer= malloc(100);
      apr_time_t tnow=apr_time_now();
      apr_time_t duration=apr_time_as_msec(tnow-p_pRequestRec->request_time); // ms
      strcpy(pszBuffer,"gswadaptor-requestdate: ");            
      FormatAPRTime(pszBuffer+strlen(pszBuffer),p_pRequestRec->request_time);
      GSWHTTPResponse_AddHeader(p_pHTTPResponse,
                                pszBuffer);
      strcpy(pszBuffer,"gswadaptor-sendresponsedate: ");            
      FormatAPRTime(pszBuffer+strlen(pszBuffer),tnow);
      GSWHTTPResponse_AddHeader(p_pHTTPResponse,
                                pszBuffer);
      sprintf(pszBuffer,"gswadaptor-processduration: %d.%d s",
              (int)(duration/1000),(int)(duration%1000));
      GSWHTTPResponse_AddHeader(p_pHTTPResponse,
                                pszBuffer);
      free(pszBuffer);
      pszBuffer=NULL;
  };
#endif
  // Process Headers
  GSWDict_PerformForAllElem(p_pHTTPResponse->pHeaders,getHeader,p_pRequestRec);
	
  GSWLog(GSW_DEBUG,pServerRec,"status message=[%s]",p_pHTTPResponse->pszStatusMessage);
  p_pRequestRec->status_line = APR_PSPRINTF(p_pRequestRec->pool,"%u %s",
                                            p_pHTTPResponse->uStatus,
                                            p_pHTTPResponse->pszStatusMessage);

  p_pRequestRec->status = p_pHTTPResponse->uStatus;
  GSWLog(GSW_DEBUG,pServerRec,"p_pRequestRec->status_line=[%s]",p_pRequestRec->status_line);

  // Set content type if none
  if (!p_pRequestRec->content_type)
    {
      p_pRequestRec->content_type = g_szContentType_TextHtml;
#ifdef Apache2
      ap_set_content_type(p_pRequestRec, g_szContentType_TextHtml);
#endif
    };
  GSWLog(GSW_DEBUG,pServerRec,"p_pRequestRec->content_type=%s",p_pRequestRec->content_type);
	
  // Set content length
  ap_set_content_length(p_pRequestRec, p_pHTTPResponse->uContentLength);

  // Now Send response...

  // send Headers
#ifndef Apache2 // No more needed in Apache2 (?)
  ap_send_http_header(p_pRequestRec);	
#endif

  // If not headers only
  if (!p_pRequestRec->header_only)
    {
      ap_soft_timeout("Send GSWeb response",p_pRequestRec);
      ap_rwrite(p_pHTTPResponse->pContent,p_pHTTPResponse->uContentLength,
		p_pRequestRec);
      ap_kill_timeout(p_pRequestRec);
    };
  GSWLog(GSW_DEBUG,pServerRec,"Stop sendResponse");
};

//--------------------------------------------------------------------
// die/send response
static int
dieSendResponse(request_rec       *p_pRequestRec,
		GSWHTTPResponse  **p_ppHTTPResponse,
		BOOL               p_fDecline)
{
  server_rec *pServerRec = p_pRequestRec->server;
  void       *pLogServerData=pServerRec;

  GSWLog(GSW_DEBUG,pLogServerData,"Start dieSendResponse");
  sendResponse(p_pRequestRec,*p_ppHTTPResponse);
  GSWHTTPResponse_Free(*p_ppHTTPResponse,pLogServerData);
  *p_ppHTTPResponse=NULL;
  GSWLog(GSW_DEBUG,pLogServerData,"Start dieSendResponse");
  return p_fDecline ? DECLINED : OK;
};

//--------------------------------------------------------------------
// die with a message
static int
dieWithMessage(request_rec *p_pRequestRec,
	       CONST char  *p_pszMessage,
	       BOOL         p_fDecline)
{
  int iReturn=0;
  GSWHTTPResponse *pResponse=NULL;	
  server_rec      *pServerRec = p_pRequestRec->server;

  GSWLog(GSW_DEBUG,pServerRec,"Start dieWithMessage");
  GSWLog(GSW_ERROR,pServerRec,"Send Error Response: %s",p_pszMessage);
  pResponse = GSWHTTPResponse_BuildErrorResponse(NULL,p_pszMessage,
						 p_pRequestRec->server);
  iReturn=dieSendResponse(p_pRequestRec,&pResponse,p_fDecline);
  GSWLog(GSW_DEBUG,pServerRec,"Stop dieWithMessage");
  return iReturn;
};

//--------------------------------------------------------------------
//	GSWeb Request Handler
static int
GSWeb_Handler(request_rec *p_pRequestRec)
{
  int               iRetVal=OK;
  GSWURLComponents  stURLComponents;
  GSWHTTPResponse  *pResponse = NULL;
  GSWURLError       eError=GSWURLError_OK;
  CONST char       *pszURLError=NULL;
  server_rec       *pServerRec = p_pRequestRec->server;
  void             *pLogServerData=pServerRec;
  GSWeb_Config     *pConfig=NULL;

  memset(&stURLComponents,0,sizeof(stURLComponents));
  GSWLog(GSW_DEBUG,pLogServerData,"Start GSWeb_Handler");

  pConfig=GSWeb_GetServerConfig(p_pRequestRec->server);

  // Log the request
  GSWLog(GSW_INFO,
	 pLogServerData,
	 "GNUstepWeb New request: %s",
	 p_pRequestRec->uri);

  // Is this for us ?
  if (strncmp(pConfig->pszGSWeb,
	      p_pRequestRec->uri,
	      strlen(pConfig->pszGSWeb))==0) 
    {
      // Parse the uri
      eError=GSWParseURL(&stURLComponents,p_pRequestRec->uri,
			 pLogServerData);
      if (eError!=GSWURLError_OK)
	{
	  pszURLError=GSWURLErrorMessage(eError,
					 pLogServerData);
	  GSWLog(GSW_INFO,pLogServerData,"URL Parsing Error: %s", pszURLError);
	  if (eError==GSWURLError_InvalidAppName)
	    {
	      pResponse = GSWDumpConfigFile(&stURLComponents,
					    p_pRequestRec->server);
	      iRetVal=dieSendResponse(p_pRequestRec,&pResponse,NO);
	    }
	  else
	    iRetVal=dieWithMessage(p_pRequestRec,pszURLError,NO);
	}
      else
	{
	  iRetVal = ap_setup_client_block(p_pRequestRec,REQUEST_CHUNKED_ERROR);
	  if (iRetVal==0) // OK Continue
	    {
	      // Build the GSWHTTPRequest with the method
	      GSWHTTPRequest *pRequest=NULL;
	      CONST char     *pszRequestError=NULL;
	      
	      pRequest=GSWHTTPRequest_New(p_pRequestRec->method,NULL,
					  pLogServerData);
	      
	      // validate the method
	      pszRequestError=GSWHTTPRequest_ValidateMethod(pRequest,
							    pLogServerData);
	      if (pszRequestError)
		{
		  iRetVal=dieWithMessage(p_pRequestRec,pszRequestError,NO);
		}
	      else
		{
		  CONST char *pszDocRoot=NULL;	
		  char* applicationName=NULL;
                  if (stURLComponents.stAppName.pszStart)
                    applicationName=strndup(stURLComponents.stAppName.pszStart,
                                            stURLComponents.stAppName.iLength);//We'll need to release it

		  // copy headers
		  copyHeaders(p_pRequestRec,pRequest);

                  if (applicationName)
                    GSWHTTPRequest_AddHeader(pRequest,
                                             g_szHeader_GSWeb_ApplicationName,
                                             applicationName);
		  // Get Form data if any
		  // POST Method
		  if (pRequest->eMethod==ERequestMethod_Post
		      && pRequest->uContentLength>0
		      && ap_should_client_block(p_pRequestRec))
		    {
		      int iReadLength=0;
		      int iRemainingLength = pRequest->uContentLength;
		      char *pszBuffer = malloc(pRequest->uContentLength);
		      char *pszData = pszBuffer;
		      
		      while (iRemainingLength>0)
			{
			  ap_soft_timeout("reading GSWeb request",
					  p_pRequestRec);
			  iReadLength=ap_get_client_block(p_pRequestRec,
							  pszData,
							  iRemainingLength);
			  ap_kill_timeout(p_pRequestRec);
			  pszData += iReadLength;
			  iRemainingLength-=iReadLength;
			};
		      GSWLog(GSW_INFO,pLogServerData,"pszBuffer(%p)=%.*s",
			     (void *)pszBuffer,
			     (int)pRequest->uContentLength,
			     pszBuffer);
		      pRequest->pContent = pszBuffer;
		    }
		  else if (pRequest->eMethod==ERequestMethod_Get)
		    {
		      // Get the QueryString
		      stURLComponents.stQueryString.pszStart =
			p_pRequestRec->args;
		      stURLComponents.stQueryString.iLength =
			p_pRequestRec->args ? strlen(p_pRequestRec->args) : 0;
		    };
		  
		  // get the document root
		  /*  if (pConfig && pConfig->pszRoot)
		      pszDocRoot = pConfig->pszRoot;
		      else*/
		  pszDocRoot=(char *)ap_document_root(p_pRequestRec);
		  
		  // Build the response 
		  // (Beware: tr_handleRequest free pRequest)
		  ap_soft_timeout("Call GSWeb Application",p_pRequestRec);
		  pRequest->pServerHandle = p_pRequestRec;
		  pResponse=GSWAppRequest_HandleRequest(&pRequest,
                                                        &stURLComponents,
                                                        p_pRequestRec->protocol,
                                                        pszDocRoot,
                                                        g_szGSWeb_StatusResponseAppName, //AppTest name
                                                        pLogServerData);
		  ap_kill_timeout(p_pRequestRec);
		  
		  // Send the response (if any)
		  if (pResponse)
		    {
		      sendResponse(p_pRequestRec,pResponse);
		      GSWHTTPResponse_Free(pResponse,pLogServerData);
		      iRetVal = OK;
		    }
		  else 
		    iRetVal = DECLINED;
                  if (applicationName)
                    free(applicationName);
		};
	    };
	};
    }
  else
    iRetVal = DECLINED;
  GSWLog(GSW_DEBUG,pLogServerData,"Stop GSWeb_Handler");
  return iRetVal;
};



#ifdef Apache2

/*--------------------------------------------------------------------------*/
/*                                                                          */
/* Which functions are responsible for which hooks in the server.           */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/* 
 * Each function our module provides to handle a particular hook is
 * specified here.  The functions are registered using 
 * ap_hook_foo(name, predecessors, successors, position)
 * where foo is the name of the hook.
 *
 * The args are as follows:
 * name         -> the name of the function to call.
 * predecessors -> a list of modules whose calls to this hook must be
 *                 invoked before this module.
 * successors   -> a list of modules whose calls to this hook must be
 *                 invoked after this module.
 * position     -> The relative position of this module.  One of
 *                 APR_HOOK_FIRST, APR_HOOK_MIDDLE, or APR_HOOK_LAST.
 *                 Most modules will use APR_HOOK_MIDDLE.  If multiple
 *                 modules use the same relative position, Apache will
 *                 determine which to call first.
 *                 If your module relies on another module to run first,
 *                 or another module running after yours, use the 
 *                 predecessors and/or successors.
 *
 * The number in brackets indicates the order in which the routine is called
 * during request processing.  Note that not all routines are necessarily
 * called (such as if a resource doesn't have access restrictions).
 * The actual delivery of content to the browser [9] is not handled by
 * a hook; see the handler declarations below.
 */
static void
GSWeb_register_hooks(apr_pool_t *p)
{
/*    ap_hook_pre_config(GSWeb_PreConfig, NULL, NULL, APR_HOOK_MIDDLE);
*/
    ap_hook_post_config(GSWeb_PostConfig, NULL, NULL, APR_HOOK_MIDDLE);
/*
    ap_hook_open_logs(GSWeb_OpenLogs, NULL, NULL, APR_HOOK_MIDDLE);
*/
    ap_hook_child_init(GSWeb_ChildInit, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_handler(GSWeb_Handler, NULL, NULL, APR_HOOK_MIDDLE);
/*    ap_hook_quick_handler(GSWeb_QuickHandler, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_pre_connection(GSWeb_PreConnection, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_process_connection(GSWeb_ProcessConnection, NULL, NULL, APR_HOOK_MIDDLE);
    // [1] post read_request handling 
    ap_hook_post_read_request(GSWeb_PostReadRequest, NULL, NULL,APR_HOOK_MIDDLE);
    ap_hook_log_transaction(GSWeb_Logger, NULL, NULL, APR_HOOK_MIDDLE);
#if 0
    ap_hook_http_method(GSWeb_HttpMethod, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_default_port(GSWeb_DefaultPort, NULL, NULL, APR_HOOK_MIDDLE);
#endif
    ap_hook_translate_name(GSWeb_Translation, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_header_parser(GSWeb_header_ParserHandler, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_check_user_id(GSWeb_CheckUserId, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_fixups(GSWeb_FixerUpper, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_type_checker(GSWeb_TypeChecker, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_access_checker(GSWeb_AccessChecker, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_auth_checker(GSWeb_AuthChecker, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_insert_filter(GSWeb_InsertFilter, NULL, NULL, APR_HOOK_MIDDLE);
*/
}

/*--------------------------------------------------------------------------*/
/*                                                                          */
/* All of the routines have been declared now.  Here's the list of          */
/* directives specific to our module, and information about where they      */
/* may appear and how the command parser should pass them to us for         */
/* processing.  Note that care must be taken to ensure that there are NO    */
/* collisions of directive names between modules.                           */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/* 
 * List of directives specific to our module.
 */
static const command_rec GSWeb_Commands[] =
{
  AP_INIT_TAKE1
  (
   GSWEB_CONF__ALIAS,       /* directive name */
   GSWeb_SetScriptAlias,    /* config action routine */
   NULL,                    /* argument to include in call */
   RSRC_CONF,               /* where available */
   "ScriptAlias for GSWeb"  /* directive description */
   ),
  AP_INIT_TAKE1
  (
   GSWEB_CONF__CONFIG_FILE_PATH,        /* directive name */
   GSWeb_SetConfig,                     /* config action routine */
   NULL,                                /* argument to include in call */
   RSRC_CONF,                           /* where available */
   "Configuration File Path for GSWeb"  /* directive description */
   ),
  {NULL}
};

module AP_MODULE_DECLARE_DATA GSWeb_Module =
{
    STANDARD20_MODULE_STUFF,
    NULL,//x_create_dir_config,    /* per-directory config creator */
    NULL,//x_merge_dir_config,     /* dir config merger */
    GSWeb_CreateServerConfig,      /* server config creator */
    NULL,//x_merge_server_config,  /* server config merger */
    GSWeb_Commands,                /* command table */
    GSWeb_register_hooks,          /* set up other request processing hooks */
};

#else

//--------------------------------------------------------------------
// Module definitions


static command_rec GSWeb_Commands[] =
{
  {
    GSWEB_CONF__ALIAS,    // Command keyword
    GSWeb_SetScriptAlias, // Function
    NULL,                 // Fixed Arg
    RSRC_CONF,            // Type
    TAKE1,                // Args Descr
    "ScriptAlias for GSWeb"
  },
  {
    GSWEB_CONF__CONFIG_FILE_PATH, // Command keyword
    GSWeb_SetConfig,              // Function
    NULL,                         // Fixed Arg
    RSRC_CONF,                    // Type
    TAKE1,                        // Args Descr
    "Configuration File Path for GSWeb"
  },
  {
    NULL
  }
};


handler_rec GSWeb_Handlers[] =
{
  { GSWEB__MIME_TYPE, GSWeb_Handler },
  { GSWEB_HANDLER, GSWeb_Handler },
  { NULL }
};

/*--------------------------------------------------------------------------*/
/*                                                                          */
/* Finally, the list of callback routines and data structures that provide  */
/* the static hooks into our module from the other parts of the server.     */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/* 
 * Module definition for configuration.  If a particular callback is not
 * needed, replace its routine name below with the word NULL.
 */
module GSWeb_Module =
{
  STANDARD_MODULE_STUFF,
  GSWeb_Init,               // Init
  NULL,                     // Create DirectoryConfig
  NULL,                     // Merge DirectoryConfig
  GSWeb_CreateServerConfig, // Create ServerConfig
  NULL,                     // Merge ServerConfig
  GSWeb_Commands,           // Commands List
  GSWeb_Handlers,           // Handlers List
  GSWeb_Translation,        // Fn to Translatie Filename/URI
  NULL,					
  NULL,					
  NULL,					
  NULL,					
  NULL,					
  NULL,					
  NULL					
};

#endif
