You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by an...@apache.org on 2001/06/25 11:16:24 UTC

cvs commit: jakarta-tomcat-connectors/jk/native/isapi tomcat_redirector.reg poolbuf.h poolbuf.c jk_isapi_plugin.c isapi.dsw isapi.dsp inifile.h inifile.c config.h

andya       01/06/25 02:16:24

  Added:       jk/native/isapi tomcat_redirector.reg poolbuf.h poolbuf.c
                        jk_isapi_plugin.c isapi.dsw isapi.dsp inifile.h
                        inifile.c config.h
  Log:
  Experimental new ISAPI connector. Should build but not functional.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/tomcat_redirector.reg
  
  Index: tomcat_redirector.reg
  ===================================================================
  REGEDIT4
  
  [HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\2.0]
  "log_file"="D:\\tomcat\\logs\\domino.log"
  "log_level"="debug"
  "worker_file"="D:\\tomcat\\conf\\workers.properties"
  "worker_mount_file"="D:\\tomcat\\conf\\uriworkermap.properties"
  "tomcat_start"="D:\\tomcat\\bin\\tomcat.bat start"
  "tomcat_stop"="D:\\tomcat\\bin\\tomcat.bat stop"
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/poolbuf.h
  
  Index: poolbuf.h
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: ISAPI plugin for Tomcat                                    *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #ifndef __poolbuf_h
  #define __poolbuf_h
  
  #include <stddef.h>
  #include "jk_pool.h"
  
  #define poolbuf__MINCHUNK 2048
  
  typedef struct poolbuf__chunk
  {
  	size_t					size;
  	struct poolbuf__chunk	*next;
  
  } poolbuf__chunk;
  
  typedef enum { WRITE, READ } poolbuf__state;
  
  typedef struct
  {
  	jk_pool_t				*p;
  	poolbuf__chunk			*head;
  	poolbuf__chunk			*current;
  
  	/* current state */
  	poolbuf__state			state;
  
  	/* total number of bytes available to read */
  	size_t					avail;
  
  	/* offsets within the current chunk */
  	unsigned int			writePos;
  	unsigned int			readPos;
  
  } poolbuf;
  
  /* Initialise a poolbuf. */
  void poolbuf_init(poolbuf *pb, jk_pool_t *p);
  size_t poolbuf_write(poolbuf *pb, const void *buf, size_t size);
  size_t poolbuf_read(poolbuf *pb, void *buf, size_t size);
  size_t poolbuf_available(poolbuf *pb);
  void poolbuf_destroy(poolbuf *pb);
  
  
  #endif /* __poolbuf_h */
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/poolbuf.c
  
  Index: poolbuf.c
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be avail  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: ISAPI plugin for Tomcat                                    *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #include "poolbuf.h"
  
  /* Macro to return the address of the first byte in a poolbuf__chunk on
   * the understanding that the buffer follows the structure in memory.
   */
  #define poolbuf__buf(chnk) \
  	((char *) ((poolbuf__chunk *) chnk + 1))
  
  void poolbuf_init(poolbuf *pb, jk_pool_t *p)
  {
  	pb->p			= p;
  	pb->head		=
  	pb->current		= NULL;
  	pb->readPos		=
  	pb->writePos	= 0;
  	pb->avail		= 0;
  	pb->state		= WRITE;
  }
  
  /* Write bytes to the buffer returning the number of bytes successfully
   * written. Can't be called again once poolbuf_read() has been called.
   */
  size_t poolbuf_write(poolbuf *pb, const void *buf, size_t size)
  {
  	const char *cbuf = (const char *) buf;
  	size_t left = size;
  
  	if (READ == pb->state)
  		return 0;
  
  	/* first work out what we can write into the current buffer */
  	if (pb->current != NULL && pb->writePos < pb->current->size)
  	{
  		char *chbuf = poolbuf__buf(pb->current) + pb->writePos;
  		size_t sz = pb->current->size - pb->writePos;
  		if (sz > left) sz = left;
  		memcpy(chbuf, cbuf, sz);
  		pb->writePos += sz;
  		pb->avail += sz;
  		cbuf += sz;
  		left -= sz;
  	}
  
  	/* something left that we couldn't fit in the last chunk */
  	if (left > 0)
  	{
  		poolbuf__chunk *chnk;
  		size_t sz = size;
  
  		if (sz < poolbuf__MINCHUNK)
  			sz = poolbuf__MINCHUNK;
  		if (NULL == pb->p || NULL == (chnk = jk_pool_alloc(pb->p, sz + sizeof(poolbuf__chunk))))
  			return size - left;
  
  		chnk->next = NULL;
  		chnk->size = sz;
  		if (NULL == pb->head) pb->head = chnk;
  		if (NULL != pb->current) pb->current->next = chnk;
  		pb->current = chnk;
  		memcpy(poolbuf__buf(chnk), cbuf, left);
  		pb->avail += left;
  		pb->writePos = left;
  	}
  
  	return size;
  }
  
  /* Read bytes from the buffer returning the number of bytes read (which
   * will be less than desired when the end of the buffer is reached). Once
   * poolbuf_read() has been called poolbuf_write() may not be called again.
   */
  size_t poolbuf_read(poolbuf *pb, void *buf, size_t size)
  {
  	char *cbuf = (char *) buf;
  	size_t nread = 0;
  
  	if (WRITE == pb->state)
  	{
  		/* Move to read mode. Once we've done this subsequent
  		 * writes are not allowed.
  		 */
  		pb->current = pb->head;
  		pb->readPos	= 0;
  		pb->state	= READ;
  	}
  
  	while (size > 0 && pb->avail > 0)
  	{
  		size_t sz = pb->current->size - pb->readPos;
  		if (sz > pb->avail) sz = pb->avail;
  		if (sz > size) sz = size;
  		memcpy(cbuf, poolbuf__buf(pb->current) + pb->readPos, sz);
  		pb->readPos += sz;
  		if (pb->readPos == pb->current->size)
  		{
  			pb->current = pb->current->next;
  			pb->readPos = 0;
  		}
  		pb->avail -= sz;
  		nread += sz;
  	}
  
  	return nread;
  }
  
  /* Find out how many bytes are available for reading.
   */
  size_t poolbuf_available(poolbuf *pb)
  {
  	return pb->avail;
  }
  
  /* Destroy the buffer. This doesn't actually free any memory
   * because the jk_pool functions don't support freeing individual
   * chunks, but it does recycle the buffer for subsequent use.
   */
  void poolbuf_destroy(poolbuf *pb)
  {
  	pb->p			= NULL;
  	pb->head		=
  	pb->current		= NULL;
  	pb->readPos		=
  	pb->writePos	= 0;
  	pb->avail		= 0;
  	pb->state		= WRITE;
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/jk_isapi_plugin.c
  
  Index: jk_isapi_plugin.c
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: ISAPI plugin for Tomcat                                    *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  /* Based on the the server redirector which was, in turn, based on the IIS 
   * redirector by Gal Shachor <sh...@il.ibm.com>
   */
  
  #include "config.h"
  #include "inifile.h"
  #include "poolbuf.h"
  
  /* ISAPI stuff */
  #include <httpext.h>
  #include <httpfilt.h>
  #include <wininet.h>
  
  /* JK stuff */
  #include "jk_global.h"
  #include "jk_util.h"
  #include "jk_map.h"
  #include "jk_pool.h"
  #include "jk_service.h"
  #include "jk_worker.h"
  #include "jk_ajp12_worker.h"
  #include "jk_uri_worker_map.h"
  
  #include <stdarg.h>
  #define NOERROR 0
  
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  
  #if !defined(DLLEXPORT)
  #ifdef WIN32
  #define DLLEXPORT __declspec(dllexport)
  #else
  #define DLLEXPORT
  #endif
  #endif
  
  #define VERSION				"2.0"
  #define VERSION_STRING		"Jakarta/ISAPI/" VERSION
  
  /* What we call ourselves */
  #define FILTERDESC			"Apache Tomcat Interceptor (" VERSION_STRING ")"
  #define SERVERDFLT			"Microsoft IIS"
  
  /* Registry location of configuration data */
  #define REGISTRY_LOCATION	"Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\2.0"
  
  /* Name of INI file relative to whatever the 'current' directory is when the filter is
   * loaded. Certainly on Linux this is the the server data directory -- it seems likely that
   * it's the same on other platforms
   */
  #define ININAME				"libtomcat.ini"
  
  /* Names of registry keys/ini items that contain commands to start, stop Tomcat */
  #define TOMCAT_START		"tomcat_start"
  #define TOMCAT_STOP			"tomcat_stop"
  #define TOMCAT_STARTSTOP_TO	30000				/* 30 seconds */
  
  static int					initDone	= JK_FALSE;
  static jk_uri_worker_map_t	*uw_map		= NULL;
  static jk_logger_t			*logger		= NULL;
  
  static int					logLevel	= JK_LOG_EMERG_LEVEL;
  static jk_pool_t			cfgPool;
  
  static const char *logFile;
  static const char *workerFile;
  static const char *workerMountFile;
  static const char *tomcatStart;
  static const char *tomcatStop;
  
  #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
  static jk_worker_env_t   worker_env;
  #endif
  
  static char					*crlf		= "\r\n";
  
  typedef enum { HDR, BODY } rq_state;
  
  typedef struct private_ws
  {
  	jk_pool_t			p;
  
  	/* Passed in by server, used to access various methods and data.
  	 */
      LPEXTENSION_CONTROL_BLOCK  lpEcb;
  
  	/* True iff the response headers have been sent
  	 */
  	int					responseStarted;
  
  	rq_state			state;
  
  	poolbuf				hdr;
  	poolbuf				body;
  
  } private_ws_t;
  
  /* These three functions are called back (indirectly) by
   * Tomcat during request processing. StartResponse() sends
   * the headers associated with the response.
   */
  static int JK_METHOD StartResponse(jk_ws_service_t * s, int status, const char *reason,
  									const char *const *hdrNames,
  									const char *const *hdrValues, unsigned hdrCount);
  /* Read() is called by Tomcat to read from the request body (if any).
   */
  static int JK_METHOD Read(jk_ws_service_t * s, void *b, unsigned l, unsigned *a);
  /* Write() is called by Tomcat to send data back to the client.
   */
  static int JK_METHOD Write(jk_ws_service_t * s, const void *b, unsigned l);
  
  static int ReadInitData(void);
  
  #ifndef USE_INIFILE
  static const char *GetRegString(HKEY hkey, const char *key);
  #endif
  
  //static unsigned int ParsedRequest(PHTTP_FILTER_CONTEXT *context, FilterParsedRequest *reqData);
  
  /* Case insentive memcmp() clone
   */
  #ifdef HAVE_MEMICMP
  #define NoCaseMemCmp(ci, cj, l) _memicmp((void *) (ci), (void *) (cj), (l))
  #else
  static int NoCaseMemCmp(const char *ci, const char *cj, int len)
  {
  	if (0 == memcmp(ci, cj, len))
  		return 0;
  	while (len > 0)
  	{
  		int cmp = tolower(*ci) - tolower(*cj);
  		if (cmp != 0) return cmp;
  		ci++;
  		cj++;
  		len--;
  	}
  	return 0;
  }
  #endif
  
  /* Case insentive strcmp() clone
   */
  #ifdef HAVE_STRICMP
  #define NoCaseStrCmp(si, sj) _stricmp((void *) (si), (void *) (sj))
  #else
  static int NoCaseStrCmp(const char *si, const char *sj)
  {
  	if (0 == strcmp(si, sj))
  		return 0;
  
  	while (*si && tolower(*si) == tolower(*sj))
  		si++, sj++;
  
  	return tolower(*si) - tolower(*sj);
  }
  #endif
  
  /* Case insensitive substring search.
   * str		string to search
   * slen		length of string to search
   * ptn		pattern to search for
   * plen		length of pattern
   * returns	1 if there's a match otherwise 0
   */
  static int FindPathElem(const char *str, int slen, const char *ptn, int plen)
  {
  	const char *sp = str;
  
  	while (slen >= plen)
  	{
  		/* We're looking for a match for the specified string bounded by
  		 * the start of the string, \ or / at the left and the end of the
  		 * string, \ or / at the right. We look for \ as well as / on the
  		 * suspicion that a Windows hosted server might accept URIs
  		 * containing \.
  		 */
  		if (NoCaseMemCmp(sp, ptn, plen) == 0 &&
  			(sp == str || *sp == '\\' || *sp == '/') &&
  			(*sp == '\0' || *sp == '\\' || *sp == '/'))
  			return 1;
  		slen--;
  		sp++;
  	}
  	return 0;
  }
  
  static void LogMessage(char *msg, unsigned short code, ...)
  {
  	va_list ap;
  
  	if (code != NOERROR)
  		printf("Error %d: ", code);
  
  	va_start(ap, code);
  	vprintf(msg, ap);
  	va_end(ap);
  	printf("\n");
  }
  
  /* Get the value of a server (CGI) variable as a string
   */
  static int GetVariable(private_ws_t *ws, char *hdrName,
  					 char *buf, DWORD bufsz, char **dest, const char *dflt)
  {
  	LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
  
  	if (lpEcb->GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) &bufsz))
  	{
  		if (bufsz > 0) buf[bufsz-1] = '\0';
  		*dest = jk_pool_strdup(&ws->p, buf);
  		return JK_TRUE;
  	}
  
  	*dest = jk_pool_strdup(&ws->p, dflt);
  	return JK_FALSE;
  }
  
  /* Get the value of a server (CGI) variable as an integer
   */
  static int GetVariableInt(private_ws_t *ws, char *hdrName,
  						char *buf, DWORD bufsz, int *dest, int dflt)
  {
  	LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
  
  	if (lpEcb->GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) &bufsz))
  	{
  		if (bufsz > 0) buf[bufsz-1] = '\0';
  		*dest = atoi(buf);
  		return JK_TRUE;
  	}
  
  	*dest = dflt;
  	return JK_FALSE;
  }
  /* Get the value of a server (CGI) variable as a boolean switch
   */
  static int GetVariableBool(private_ws_t *ws, char *hdrName,
  						char *buf, DWORD bufsz, int *dest, int dflt)
  {
  	LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
  
  	if (lpEcb->GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) &bufsz))
  	{
  		if (bufsz > 0) buf[bufsz-1] = '\0';
  		if (isdigit(buf[0]))
  			*dest = atoi(buf) != 0;
  		else if (NoCaseStrCmp(buf, "yes") == 0 || NoCaseStrCmp(buf, "on") == 0)
  			*dest = 1;
  		else
  			*dest = 0;
  		return JK_TRUE;
  	}
  
  	*dest = dflt;
  	return JK_FALSE;
  }
  
  /* A couple of utility macros to supply standard arguments to GetVariable() and
   * GetVariableInt().
   */
  #define GETVARIABLE(name, dest, dflt)		GetVariable(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
  #define GETVARIABLEINT(name, dest, dflt)	GetVariableInt(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
  #define GETVARIABLEBOOL(name, dest, dflt)	GetVariableBool(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
  
  /* Return 1 iff the supplied string contains "web-inf" (in any case
   * variation. We don't allow URIs containing web-inf, although
   * FindPathElem() actually looks for the string bounded by path punctuation
   * or the ends of the string, so web-inf must appear as a single element
   * of the supplied URI
   */
  static int BadURI(const char *uri)
  {
  	static char *wi = "web-inf";
  	return FindPathElem(uri, strlen(uri), wi, strlen(wi));
  }
  
  /* Replacement for strcat() that updates a buffer pointer. It's
   * probably marginal, but this should be more efficient that strcat()
   * in cases where the string being concatenated to gets long because
   * strcat() has to count from start of the string each time.
   */
  static void Append(char **buf, const char *str)
  {
  	int l = strlen(str);
  	memcpy(*buf, str, l);
  	(*buf)[l] = '\0';
  	*buf += l;
  }
  
  /* Start the response by sending any headers. Invoked by Tomcat. I don't
   * particularly like the fact that this always allocates memory, but
   * perhaps jk_pool_alloc() is efficient.
   */
  static int JK_METHOD StartResponse(jk_ws_service_t *s, int status, const char *reason,
  									const char *const *hdrNames,
  									const char *const *hdrValues, unsigned hdrCount)
  {
  	DEBUG(("StartResponse()\n"));
  	jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::StartResponse\n");
  
  	if (status < 100 || status > 1000)
  	{
  		jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::StartResponse, invalid status %d\n", status);
  		return JK_FALSE;
  	}
  
  	if (s && s->ws_private)
  	{
  		private_ws_t *p = s->ws_private;
  
  		if (!p->responseStarted)
  		{
  			char *statBuf;
  			char *hdrBuf;
  			size_t statLen;
  
  			p->responseStarted = JK_TRUE;
  
  			if (NULL == reason)
  				reason = "";
  
  			/* TODO: coallesce the to jk_pool_alloc() calls into a single
  			 * buffer alloc
  			 */
  			statLen = 4 + strlen(reason);
  			statBuf = jk_pool_alloc(&p->p, statLen + 1);
  
  			/* slightly quicker than sprintf() we hope */
  			statBuf[0] = (status / 100) % 10 + '0';
  			statBuf[1] = (status /  10) % 10 + '0';
  			statBuf[2] = (status /   1) % 10 + '0';
  			statBuf[3] = ' ';
  			strcpy(statBuf + 4, reason);
  
  			/* Build a single string containing all the headers
  			 * because that's what the server needs.
  			 */
  			if (hdrCount > 0)
  			{
  				unsigned i;
  				unsigned hdrLen;
  				char *bufp;
  
  				for (i = 0, hdrLen = 3; i < hdrCount; i++)
  					hdrLen += strlen(hdrNames[i]) + strlen(hdrValues[i]) + 4;
  
  				hdrBuf = jk_pool_alloc(&p->p, hdrLen);
  				bufp = hdrBuf;
  
  				for (i = 0; i < hdrCount; i++)
  				{
  					Append(&bufp, hdrNames[i]);
  					Append(&bufp, ": ");
  					Append(&bufp, hdrValues[i]);
  					Append(&bufp, crlf);
  				}
  
  				Append(&bufp, crlf);
  			}
  			else
  			{
  				hdrBuf = crlf;
  			}
  
  			DEBUG(("%d %s\n%s", status, reason, hdrBuf));
  
  			/* TODO: check API docs for this */
  			if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
  						HSE_REQ_SEND_RESPONSE_HEADER,
  						statBuf, (LPDWORD) &statLen, (LPDWORD) hdrBuf))
  			{
                  jk_log(logger, JK_LOG_ERROR, 
                         "jk_ws_service_t::start_response, ServerSupportFunction failed\n");
                  return JK_FALSE;
              }       
  
  		}
  		return JK_TRUE;
  	}
  
  	jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::StartResponse, NULL parameters\n");
  
  	return JK_FALSE;
  }
  
  static int JK_METHOD Read(jk_ws_service_t * s, void *bytes, unsigned len, unsigned *countp)
  {
  #if 0
  	DEBUG(("Read(%p, %p, %u, %p)\n", s, bytes, len, countp));
  	jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::Read\n");
  
  	if (s && s->ws_private && bytes && countp)
  	{
  		private_ws_t *p = s->ws_private;
  
  		/* Copy data from the server's buffer. Although it seems slightly
  		 * improbably we're believing that the server always buffers the
  		 * entire request in memory. Not properly tested yet.
  		 */
  		if (len > p->reqSize) len = p->reqSize;
  		memcpy(bytes, p->reqBuffer, len);
  		p->reqBuffer += len;
  		p->reqSize -= len;
  		*countp = len;
  		return JK_TRUE;
  	}
  
  	jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::Read, NULL parameters\n");
  
  #endif
  	return JK_FALSE;
  }
  
  static int JK_METHOD Write(jk_ws_service_t *s, const void *bytes, unsigned len)
  {
  	DEBUG(("Write(%p, %p, %u)\n", s, bytes, len));
  	jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::Write\n");
  
  	if (s && s->ws_private && bytes)
  	{
  		private_ws_t *p = s->ws_private;
  		DWORD dwLen = len;
  
  		/* Make sure the response has really started. I'm almost certain
  		 * this isn't necessary, but it was in the ISAPI code, so it's in
  		 * here too.
  		 */
  		if (!p->responseStarted)
  			StartResponse(s, 200, NULL, NULL, NULL, 0);
  
  		DEBUG(("Writing %d bytes of content\n", len));
  
  		/* Send the data */
  		if (len > 0)
  		{
  			if (!p->lpEcb->WriteClient(p->lpEcb->ConnID, (LPVOID) bytes, &dwLen, 0))
  			{
                  jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::Write, WriteClient failed\n");
                  return JK_FALSE;
  			}
  		}
  		
  		return JK_TRUE;
  	}
  
  	jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::Write, NULL parameters\n");
  
  	return JK_FALSE;
  }
  
  static int RunProg(const char *cmd)
  {
  #ifdef WIN32
      STARTUPINFO si;
      PROCESS_INFORMATION pi;
  
  	ZeroMemory(&si, sizeof(si));
      si.cb			= sizeof(si);    // Start the child process.
  	si.dwFlags		= STARTF_USESHOWWINDOW;
  	si.wShowWindow	= SW_SHOWMAXIMIZED;
  
  	if (!CreateProcess(NULL, (char *) cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  	{
  		DWORD err = GetLastError();
  		LogMessage("Command \"%s\" (error %u)", NOERROR, cmd, err);
  		return FALSE;
  	}
  
  	if (WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, TOMCAT_STARTSTOP_TO))
  		return TRUE;
  
  	LogMessage("Command \"%s\" didn't complete in time", NOERROR, cmd);
  	return FALSE;
  
  #else
  	int err = system(cmd);
  	if (0 == err) return 1;
  	LogMessage("Command \"%s\" failed (error %d)", NOERROR, cmd, err);
  	return 0;
  #endif
  }
  
  /* Called when the filter is unloaded. Free various resources and
   * display a banner.
   */
  BOOL WINAPI TerminateFilter(DWORD dwFlags)
  {
  	if (initDone)
  	{
  		uri_worker_map_free(&uw_map, logger);
  		wc_close(logger);
  		if (logger)
  			jk_close_file_logger(&logger);
  
  		initDone = JK_FALSE;
  	}
  
  	if (NULL != tomcatStop && '\0' != *tomcatStop)
  	{
  		LogMessage("Attempting to stop Tomcat: %s", NOERROR, tomcatStop);
  		RunProg(tomcatStop);
  	}
  
  	LogMessage(FILTERDESC " unloaded", NOERROR);
  
  	jk_close_pool(&cfgPool);
  
  	return TRUE;
  }
  
  /* Called when the server loads the filter. Reads a load of config data from
   * the registry and elsewhere and displays a banner.
   */
  BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
  {    
  	jk_open_pool(&cfgPool, NULL, 0);		/* empty pool for config data */
  
  	if (!ReadInitData())
  		goto initFailed;
  
  	if (!jk_open_file_logger(&logger, logFile, logLevel))
  		logger = NULL;
  
  	if (NULL != tomcatStart && '\0' != *tomcatStart)
  	{
  		LogMessage("Attempting to start Tomcat: %s", NOERROR, tomcatStart);
  		RunProg(tomcatStart);
  	}
  
      pVer->dwFilterVersion = pVer->dwServerFilterVersion;
                          
      //if (pVer->dwFilterVersion > HTTP_FILTER_REVISION)
      //    pVer->dwFilterVersion = HTTP_FILTER_REVISION;
  
  	/* Come back and check these... */
      pVer->dwFlags = SF_NOTIFY_ORDER_HIGH        | 
                      SF_NOTIFY_SECURE_PORT       | 
                      SF_NOTIFY_NONSECURE_PORT    |
                      SF_NOTIFY_PREPROC_HEADERS;
                      
      strcpy(pVer->lpszFilterDesc, FILTERDESC);
  
  	/* Banner */
  	LogMessage("%s loaded", NOERROR, pVer->lpszFilterDesc);
  
  	return TRUE;
  
  initFailed:
  	LogMessage("Error loading %s", NOERROR, FILTERDESC);
  
  	return FALSE;
  }
  
  /* Read parameters from the registry
   */
  static int ReadInitData(void)
  {
  	int ok = JK_TRUE;
  	const char *v;
  
  #ifdef USE_INIFILE
  // Using an INIFILE
  
  #define GETV(key) inifile_lookup(key)
  
  	ERRTYPE e;
  
  	if (e = inifile_read(&cfgPool, ININAME), ERRNONE != e)
  	{
  		LogMessage("Error reading: %s, %s", NOERROR, ININAME, ERRTXT(e));
  		return JK_FALSE;
  	}
  
  #else
  // Using the registry
  #define GETV(key) GetRegString(hkey, key)
  
  	HKEY hkey;
  	long rc;
  
  	rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_LOCATION, (DWORD) 0, KEY_READ, &hkey);
  	if (ERROR_SUCCESS != rc) return JK_FALSE;
  
  #endif
  
  #define GETVNB(tag, var) \
  	var = GETV(tag); \
  	if (NULL == var) \
  	{ \
  		LogMessage("%s not defined in %s", NOERROR, tag, ININAME); \
  		ok = JK_FALSE; \
  	}
  
  	GETVNB(JK_LOG_FILE_TAG, logFile)
  	GETVNB(JK_LOG_LEVEL_TAG, v);
  	GETVNB(JK_WORKER_FILE_TAG, workerFile);
  	GETVNB(JK_MOUNT_FILE_TAG, workerMountFile);
  
  	logLevel = (NULL == v) ? 0 : jk_parse_log_level(v);
  
  	tomcatStart	= GETV(TOMCAT_START);
  	tomcatStop	= GETV(TOMCAT_STOP);
  
  #ifndef USE_INIFILE
  	RegCloseKey(hkey);
  #endif
  
  	return ok;
  }
  
  #ifndef USE_INIFILE
  static const char *GetRegString(HKEY hkey, const char *key)
  {
  	DWORD type = 0;
  	DWORD sz = 0;
  	LONG rc;
  	char *val;
  
  	rc = RegQueryValueEx(hkey, key, (LPDWORD) 0, &type, NULL, &sz);
  	if (rc != ERROR_SUCCESS || type != REG_SZ)
  		return NULL;
  
  	if (val = jk_pool_alloc(&cfgPool, sz), NULL == val)
  		return NULL;
  
  	rc = RegQueryValueEx(hkey, key, (LPDWORD) 0, &type, val, &sz);
  	if (rc == ERROR_SUCCESS)
  		return val;
  
  	return NULL;
  }
  #endif
  
  /* Main entry point for the filter. Called by the server for every HTTP request.
   */
  DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
                              DWORD dwNotificationType, 
                              LPVOID pvNotification)
  {
  #if 0
  	switch (dwNotificationType)
  	{
  	case kFilterParsedRequest:
  		return ParsedRequest(context, (FilterParsedRequest *) eventData);
  	default:
  		break;
  	}
  	return kFilterNotHandled;
  #endif
  
  	return SF_STATUS_REQ_NEXT_NOTIFICATION;
  }
  
  /* Send a simple response. Used when we don't want to bother Tomcat,
   * which in practice means for various error conditions that we can
   * detect internally.
   */
  static void SimpleResponse(PHTTP_FILTER_CONTEXT *context, int status, char *reason, char *body)
  {
  #if 0
  	FilterResponseHeaders frh;
  	int rc, errID;
  	char hdrBuf[35];
  
  	sprintf(hdrBuf, "Content-type: text/html%s%s", crlf, crlf);
  
  	frh.responseCode = status;
  	frh.reasonText = reason;
  	frh.headerText = hdrBuf;
  
  	rc = context->ServerSupport(context, kWriteResponseHeaders, &frh, NULL, 0, &errID);
  	rc = context->WriteClient(context, body, strlen(body), 0, &errID);
  #endif
  }
  
  /* Called to reject a URI that contains the string "web-inf". We block
   * these because they may indicate an attempt to invoke arbitrary code.
   */
  static DWORD RejectBadURI(PHTTP_FILTER_CONTEXT *context)
  {
  	static char *msg = "<HTML><BODY><H1>Access is Forbidden</H1></BODY></HTML>";
  
  	SimpleResponse(context, 403, "Forbidden", msg);
  	return SF_STATUS_REQ_NEXT_NOTIFICATION;
  }
  
  /* Allocate space for a string given a start pointer and an end pointer
   * and return a pointer to the allocated, copied string.
   */
  static char *MemDup(private_ws_t *ws, const char *start, const char *end)
  {
  	char *out = NULL;
  
  	if (start != NULL && end != NULL && end > start)
  	{
  		int len = end - start;
  		out = jk_pool_alloc(&ws->p, len + 1);
  		memcpy(out, start, len);
  		out[len] = '\0';
  	}
  
  	return out;
  }
  
  /* Given all the HTTP headers as a single string parse them into individual
   * name, value pairs. Called twice: once to work out how many headers there
   * are, then again to copy them.
   */
  static int ParseHeaders(private_ws_t *ws, const char *hdrs, int hdrsz, jk_ws_service_t *s)
  {
  	int hdrCount = 0;
  	const char *limit = hdrs + hdrsz;
  	const char *name, *nameEnd;
  	const char *value, *valueEnd;
  
  	while (hdrs < limit)
  	{
  		/* Skip line *before* doing anything, cos we want to lose the first line which
  		 * contains the request.
  		 */
  		while (hdrs < limit && (*hdrs != '\n' && *hdrs != '\r'))
  			hdrs++;
  		while (hdrs < limit && (*hdrs == '\n' || *hdrs == '\r'))
  			hdrs++;
  
  		if (hdrs >= limit)
  			break;
  
  		name = nameEnd = value = valueEnd = NULL;
  
  		name = hdrs;
  		while (hdrs < limit && *hdrs >= ' ' && *hdrs != ':')
  			hdrs++;
  		nameEnd = hdrs;
  
  		if (hdrs < limit && *hdrs == ':')
  		{
  			hdrs++;
  			while (hdrs < limit && (*hdrs == ' ' || *hdrs == '\t'))
  				hdrs++;
  			value = hdrs;
  			while (hdrs < limit && *hdrs >= ' ')
  				hdrs++;
  			valueEnd = hdrs;
  		}
  
  		if (s->headers_names != NULL && s->headers_values != NULL)
  		{
  			s->headers_names[hdrCount]	= MemDup(ws, name, nameEnd);
  			s->headers_values[hdrCount] = MemDup(ws, value, valueEnd);
  			DEBUG(("%s = %s\n", s->headers_names[hdrCount], s->headers_values[hdrCount]));
  		}
  		hdrCount++;
  	}
  
  	return hdrCount;
  }
  
  #if 0
  /* Set up all the necessary jk_* workspace based on the current HTTP request.
   */
  static int InitService(private_ws_t *ws, jk_ws_service_t *s)
  {
  	/* This is the only fixed size buffer left. It won't be overflowed
  	 * because the the server API that reads into the buffer accepts a length
  	 * constraint, and it's unlikely ever to be exhausted because the
  	 * strings being will typically be short, but it's still aesthetically
  	 * troublesome.
  	 */
  	char workBuf[16 * 1024];
  	FilterRequest fr;
  	char *hdrs, *qp;
  	int hdrsz;
  	int errID;
  	int hdrCount;
  	int rc /*, dummy*/;
  
  	static char *methodName[] = { "", "HEAD", "GET", "POST", "PUT", "DELETE" };
  
  	rc = ws->context->GetRequest(ws->context, &fr, &errID);
  
  	s->jvm_route		= NULL;
  	s->start_response	= StartResponse;
  	s->read				= Read;
  	s->write			= Write;
  
  	s->req_uri = jk_pool_strdup(&ws->p, fr.URL);
  	s->query_string = NULL;
  	if (qp = strchr(s->req_uri, '?'), qp != NULL)
  	{
  		*qp++ = '\0';
  		if (strlen(qp))
  			s->query_string = qp;
  	}
  
  	GETVARIABLE("AUTH_TYPE", &s->auth_type, "");
  	GETVARIABLE("REMOTE_USER", &s->remote_user, "");
  	GETVARIABLE("SERVER_PROTOCOL", &s->protocol, "");
  	GETVARIABLE("REMOTE_HOST", &s->remote_host, "");
  	GETVARIABLE("REMOTE_ADDR", &s->remote_addr, "");
  	GETVARIABLE("SERVER_NAME", &s->server_name, "");
  	GETVARIABLEINT("SERVER_PORT", &s->server_port, 80);
  	GETVARIABLE("SERVER_SOFTWARE", &s->server_software, SERVERDFLT);
  	GETVARIABLEINT("CONTENT_LENGTH", &s->content_length, 0);
  
  
  	/* SSL Support
  	 */
  	GETVARIABLEBOOL("HTTPS", &s->is_ssl, 0);
  
  	if (ws->reqData->requestMethod < 0 ||
  		ws->reqData->requestMethod >= sizeof(methodName) / sizeof(methodName[0]))
  		return JK_FALSE;
  
  	s->method = methodName[ws->reqData->requestMethod];
  
  	s->headers_names	= NULL;
  	s->headers_values	= NULL;
  	s->num_headers		= 0;
  
  	s->ssl_cert_len	= fr.clientCertLen;
  	s->ssl_cert		= fr.clientCert;
  	s->ssl_cipher	= NULL;		/* required by Servlet 2.3 Api */
  	s->ssl_session	= NULL;
  
  #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
  	s->ssl_key_size = -1;       /* required by Servlet 2.3 Api, added in jtc */
  #endif
  
  	if (s->is_ssl)
  	{
  		int dummy;
  #if 0
  		char *sslNames[] =
  		{
  			"CERT_ISSUER", "CERT_SUBJECT", "CERT_COOKIE", "CERT_FLAGS", "CERT_SERIALNUMBER",
  			"HTTPS_SERVER_SUBJECT", "HTTPS_SECRETKEYSIZE", "HTTPS_SERVER_ISSUER", "HTTPS_KEYSIZE"
  		};
  
  		char *sslValues[] =
  		{
  			NULL, NULL, NULL, NULL, NULL,
  			NULL, NULL, NULL, NULL
  		};
  
  
  		unsigned i, varCount = 0;
  #endif
  
  		DEBUG(("SSL request\n"));
  
  #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
  		/* Read the variable into a dummy variable: we do this for the side effect of
  		 * reading it into workBuf.
  		 */
  		GETVARIABLEINT("HTTPS_KEYSIZE", &dummy, 0);
  		if (workBuf[0] == '[')
  			s->ssl_key_size = atoi(workBuf+1);
  #else
  		(void) dummy;
  #endif
  
  #if 0
  		for (i = 0; i < sizeof(sslNames)/sizeof(sslNames[0]); i++)
  		{
  			GETVARIABLE(sslNames[i], &sslValues[i], NULL);
  			if (sslValues[i]) varCount++;
  		}
  
  		/* Andy, some SSL vars must be mapped directly in  s->ssl_cipher,
           * ssl->session and s->ssl_key_size
  		 * ie:
  		 * Cipher could be "RC4-MD5"
  		 * KeySize 128 (bits)
  	     * SessionID a string containing the UniqID used in SSL dialogue
           */
  		if (varCount > 0)
  		{
  			unsigned j;
  
  			s->attributes_names = jk_pool_alloc(&ws->p, varCount * sizeof (char *));
  			s->attributes_values = jk_pool_alloc(&ws->p, varCount * sizeof (char *));
  
  			j = 0;
  			for (i = 0; i < sizeof(sslNames)/sizeof(sslNames[0]); i++)
  			{
  				if (sslValues[i])
  				{
  					s->attributes_names[j] = sslNames[i];
  					s->attributes_values[j] = sslValues[i];
  					j++;
  				}
  			}
  			s->num_attributes = varCount;
  		}
  #endif
  	}
  
  	/* Duplicate all the headers now */
  
  	hdrsz = ws->reqData->GetAllHeaders(ws->context, &hdrs, &errID);
  	DEBUG(("\nGot headers (length %d)\n--------\n%s\n--------\n\n", hdrsz, hdrs));
  
  	s->headers_names =
  	s->headers_values = NULL;
  	hdrCount = ParseHeaders(ws, hdrs, hdrsz, s);
  	DEBUG(("Found %d headers\n", hdrCount));
  	s->num_headers = hdrCount;
  	s->headers_names	= jk_pool_alloc(&ws->p, hdrCount * sizeof(char *));
  	s->headers_values	= jk_pool_alloc(&ws->p, hdrCount * sizeof(char *));
  	hdrCount = ParseHeaders(ws, hdrs, hdrsz, s);
  
  	return JK_TRUE;
  }
  #endif
  
  #if 0
  /* Handle an HTTP request. Works out whether Tomcat will be interested then either
   * despatches it to Tomcat or passes it back to the server.
   */
  static unsigned int ParsedRequest(PHTTP_FILTER_CONTEXT *context, FilterParsedRequest *reqData)
  {
  	unsigned int errID;
  	int rc;
  	FilterRequest fr;
  	int result = kFilterNotHandled;
  
  	DEBUG(("\nParsedRequest starting\n"));
  
  	rc = context->GetRequest(context, &fr, &errID);
  
  	if (fr.URL && strlen(fr.URL))
  	{
  		char *uri = fr.URL;
  		char *workerName, *qp;
  
  		if (!initDone)
  		{
  			/* One time initialisation which is deferred so that we have the name of
  			 * the server software to plug into worker_env
  			 */
  			int ok = JK_FALSE;
  			jk_map_t *map = NULL;
  
  			DEBUG(("Initialising worker map\n"));
  
  			if (map_alloc(&map))
  			{
  				if (map_read_properties(map, workerMountFile))
  					if (uri_worker_map_alloc(&uw_map, map, logger))
  						ok = JK_TRUE;
  				map_free(&map);
  			}
  
  			DEBUG(("Got the URI worker map\n"));
  
  			if (ok)
  			{
  				ok = JK_FALSE;
  				DEBUG(("About to allocate map\n"));
  				if (map_alloc(&map))
  				{
  					DEBUG(("About to read %s\n", workerFile));
  					if (map_read_properties(map, workerFile))
  					{
  #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
  						char server[256];
  
  						worker_env.uri_to_worker = uw_map;
  						if (context->GetServerVariable(context, "SERVER_SOFTWARE", server, sizeof(server)-1, &errID))
  							worker_env.server_name = jk_pool_strdup(&cfgPool, server);
  						else
  							worker_env.server_name = SERVERDFLT;
  
  						DEBUG(("Server name %s\n", worker_env.server_name));
  
  						if (wc_open(map, &worker_env, logger))
  							ok = JK_TRUE;
  #else
  						if (wc_open(map, logger))
  							ok = JK_TRUE;
  #endif
  						DEBUG(("OK = %d\n", ok));
  					}
  
  					DEBUG(("Read %s, OK = %d\n", workerFile, ok));
  					map_free(&map);
  				}
  			}
  
  			if (!ok) return kFilterError;
  			initDone = JK_TRUE;
  		}
  
  
  		if (qp = strchr(uri, '?'), qp != NULL) *qp = '\0';
  		workerName = map_uri_to_worker(uw_map, uri, logger);
  		if (qp) *qp = '?';
  
  		DEBUG(("Worker for this URL is %s\n", workerName));
  
  		if (NULL != workerName)
  		{
  			private_ws_t ws;
  			jk_ws_service_t s;
  			jk_pool_atom_t buf[SMALL_POOL_SIZE];
  
  			if (BadURI(uri))
  				return RejectBadURI(context);
  
  			/* Go dispatch the call */
  
  			jk_init_ws_service(&s);
  			jk_open_pool(&ws.p, buf, sizeof (buf));
  
  			ws.responseStarted	= JK_FALSE;
  			ws.context			= context;
  			ws.reqData			= reqData;
  
  			ws.reqSize = context->GetRequestContents(context, &ws.reqBuffer, &errID);
  
  			s.ws_private = &ws;
  			s.pool = &ws.p;
  
  			if (InitService(&ws, &s))
  			{
  				jk_worker_t *worker = wc_get_worker_for_name(workerName, logger);
  
  				jk_log(logger, JK_LOG_DEBUG, "HttpExtensionProc %s a worker for name %s\n",
  					   worker ? "got" : "could not get", workerName);
  
  				if (worker)
  				{
  					jk_endpoint_t *e = NULL;
  
  					if (worker->get_endpoint(worker, &e, logger))
  					{
  						int recover = JK_FALSE;
  
  						if (e->service(e, &s, logger, &recover))
  						{
  							result = kFilterHandledRequest;
  							jk_log(logger, JK_LOG_DEBUG, "HttpExtensionProc service() returned OK\n");
  							DEBUG(("HttpExtensionProc service() returned OK\n"));
  						}
  						else
  						{
  							result = kFilterError;
  							jk_log(logger, JK_LOG_ERROR, "HttpExtensionProc error, service() failed\n");
  							DEBUG(("HttpExtensionProc error, service() failed\n"));
  						}
  						e->done(&e, logger);
  					}
  				}
  				else
  				{
  					jk_log(logger, JK_LOG_ERROR,
  						   "HttpExtensionProc error, could not get a worker for name %s\n",
  						   workerName);
  				}
  			}
  
  			jk_close_pool(&ws.p);
  		}
  	}
  
  	return result;
  }
  #endif
  
  BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, LPVOID lpReserved)
  {
      BOOL fReturn = TRUE;
  
      switch (ulReason) {
  
      case DLL_PROCESS_DETACH:
          TerminateFilter(HSE_TERM_MUST_UNLOAD);
          break;
  
      default:
          break;
      } 
  
      return fReturn;
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/isapi.dsw
  
  Index: isapi.dsw
  ===================================================================
  Microsoft Developer Studio Workspace File, Format Version 6.00
  # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
  
  ###############################################################################
  
  Project: "isapi"=".\isapi.dsp" - Package Owner=<4>
  
  Package=<5>
  {{{
  }}}
  
  Package=<4>
  {{{
  }}}
  
  ###############################################################################
  
  Global:
  
  Package=<5>
  {{{
  }}}
  
  Package=<3>
  {{{
  }}}
  
  ###############################################################################
  
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/isapi.dsp
  
  Index: isapi.dsp
  ===================================================================
  # Microsoft Developer Studio Project File - Name="isapi" - Package Owner=<4>
  # Microsoft Developer Studio Generated Build File, Format Version 6.00
  # ** DO NOT EDIT **
  
  # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
  
  CFG=isapi - Win32 Debug
  !MESSAGE This is not a valid makefile. To build this project using NMAKE,
  !MESSAGE use the Export Makefile command and run
  !MESSAGE 
  !MESSAGE NMAKE /f "isapi.mak".
  !MESSAGE 
  !MESSAGE You can specify a configuration when running NMAKE
  !MESSAGE by defining the macro CFG on the command line. For example:
  !MESSAGE 
  !MESSAGE NMAKE /f "isapi.mak" CFG="isapi - Win32 Debug"
  !MESSAGE 
  !MESSAGE Possible choices for configuration are:
  !MESSAGE 
  !MESSAGE "isapi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
  !MESSAGE "isapi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
  !MESSAGE 
  
  # Begin Project
  # PROP AllowPerConfigDependencies 0
  # PROP Scc_ProjName ""
  # PROP Scc_LocalPath ""
  CPP=cl.exe
  MTL=midl.exe
  RSC=rc.exe
  
  !IF  "$(CFG)" == "isapi - Win32 Release"
  
  # PROP BASE Use_MFC 0
  # PROP BASE Use_Debug_Libraries 0
  # PROP BASE Output_Dir "Release"
  # PROP BASE Intermediate_Dir "Release"
  # PROP BASE Target_Dir ""
  # PROP Use_MFC 0
  # PROP Use_Debug_Libraries 0
  # PROP Output_Dir "Release"
  # PROP Intermediate_Dir "Release"
  # PROP Ignore_Export_Lib 0
  # PROP Target_Dir ""
  # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "isapi_EXPORTS" /Yu"stdafx.h" /FD /c
  # ADD CPP /nologo /MT /W3 /GX /O2 /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "..\common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ISAPI_EXPORTS" /D "NT" /FR /FD /c
  # SUBTRACT CPP /YX /Yc /Yu
  # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
  # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
  # ADD BASE RSC /l 0x809 /d "NDEBUG"
  # ADD RSC /l 0x809 /d "NDEBUG"
  BSC32=bscmake.exe
  # ADD BASE BSC32 /nologo
  # ADD BSC32 /nologo
  LINK32=link.exe
  # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
  # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib notes.lib /nologo /dll /machine:I386 /out:"Release/tomcat_redirector.dll" /libpath:"C:\notesapi\lib\mswin32"
  
  !ELSEIF  "$(CFG)" == "isapi - Win32 Debug"
  
  # PROP BASE Use_MFC 0
  # PROP BASE Use_Debug_Libraries 1
  # PROP BASE Output_Dir "Debug"
  # PROP BASE Intermediate_Dir "Debug"
  # PROP BASE Target_Dir ""
  # PROP Use_MFC 0
  # PROP Use_Debug_Libraries 1
  # PROP Output_Dir "Debug"
  # PROP Intermediate_Dir "Debug"
  # PROP Ignore_Export_Lib 0
  # PROP Target_Dir ""
  # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "isapi_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
  # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "..\common" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ISAPI_EXPORTS" /D "NT" /FR /FD /GZ /c
  # SUBTRACT CPP /YX /Yc /Yu
  # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
  # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
  # ADD BASE RSC /l 0x809 /d "_DEBUG"
  # ADD RSC /l 0x809 /d "_DEBUG"
  BSC32=bscmake.exe
  # ADD BASE BSC32 /nologo
  # ADD BSC32 /nologo
  LINK32=link.exe
  # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
  # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib notes.lib /nologo /dll /debug /machine:I386 /out:"Debug/tomcat_redirector.dll" /pdbtype:sept /libpath:"C:\notesapi\lib\mswin32"
  
  !ENDIF 
  
  # Begin Target
  
  # Name "isapi - Win32 Release"
  # Name "isapi - Win32 Debug"
  # Begin Group "Source Files"
  
  # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
  # Begin Source File
  
  SOURCE=.\inifile.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp12_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp13.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp13_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp14.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp14_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp_common.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_connect.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_context.c
  # End Source File
  # Begin Source File
  
  SOURCE=.\jk_isapi_plugin.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_jni_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_lb_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_map.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_md5.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_msg_buff.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_nwmain.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_pool.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_sockbuf.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_uri_worker_map.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_util.c
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_worker.c
  # End Source File
  # Begin Source File
  
  SOURCE=.\poolbuf.c
  # End Source File
  # End Group
  # Begin Group "Header Files"
  
  # PROP Default_Filter "h;hpp;hxx;hm;inl"
  # Begin Source File
  
  SOURCE=.\config.h
  # End Source File
  # Begin Source File
  
  SOURCE=.\inifile.h
  # End Source File
  # Begin Source File
  
  SOURCE=.\isapifilter.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp12_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp13.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp13_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp14.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp14_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_ajp_common.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_connect.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_context.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_global.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_jni_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_lb_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_logger.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_map.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_md5.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_msg_buff.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_mt.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_pool.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_service.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_sockbuf.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_uri_worker_map.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_util.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_worker.h
  # End Source File
  # Begin Source File
  
  SOURCE=..\common\jk_worker_list.h
  # End Source File
  # Begin Source File
  
  SOURCE=.\poolbuf.h
  # End Source File
  # End Group
  # Begin Group "Resource Files"
  
  # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
  # End Group
  # Begin Source File
  
  SOURCE=.\ReadMe.txt
  # End Source File
  # End Target
  # End Project
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/inifile.h
  
  Index: inifile.h
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: DSAPI plugin for Lotus Domino                              *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #ifndef __inifile_h
  #define __inifile_h
  
  #include "jk_pool.h"
  
  #define ERRTYPE const char *
  #define ERRFMT  "%s"			/* natural printf format for errors */
  #define ERRTXT(e) (e)			/* macro to return text for an error */
  #define ERRNONE NULL
  extern ERRTYPE inifile_outofmemory;
  extern ERRTYPE inifile_filenotfound;
  extern ERRTYPE inifile_readerror;
  
  /* Read an INI file from disk
   */
  ERRTYPE inifile_read(jk_pool_t *pool, const char *name);
  
  /* Find the value associated with the given key returning it or NULL
   * if no match is found. Key name matching is case insensitive.
   */
  const char *inifile_lookup(const char *key);
  
  #endif /* __inifile_h */
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/inifile.c
  
  Index: inifile.c
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: DSAPI plugin for Lotus Domino                              *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Date:        20010603                                                   *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #include "config.h"
  #include "inifile.h"
  #include <ctype.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  
  /* We have one of these for each ini file line. Once we've read the
   * file and parsed it we'll have an array in key order containing one
   * of these for each configuration item in file.
   */
  typedef struct
  {
  	const char *key;
  	const char *value;
  
  } inifile_key;
  
  static char *file;			/* the text of the ini file				*/
  static inifile_key *keys;	/* an array of keys, one per item		*/
  static size_t klen;			/* length of the key array				*/
  
  /* Text that will prefix all of our error messages */
  #define ERRPFX "INIFILE: "
  /* Various error messages that we can return */
  ERRTYPE inifile_outofmemory		= ERRPFX "Out of memory";
  ERRTYPE inifile_filenotfound	= ERRPFX "File not found";
  ERRTYPE inifile_readerror		= ERRPFX "Error reading file";
  #define SYNFMT ERRPFX "File %s, line %d: %s"
  
  /* Case insensitive string comparison, works like strcmp() */
  static int inifile__stricmp(const char *s1, const char *s2)
  {
  	while (*s1 && tolower(*s1) == tolower(*s2))
  		s1++, s2++;
  	return tolower(*s1) - tolower(*s2);
  }
  
  /* Compare keys, suitable for passing to qsort() */
  static int inifile__cmp(const void *k1, const void *k2)
  {
  	const inifile_key *kk1 = (const inifile_key *) k1;
  	const inifile_key *kk2 = (const inifile_key *) k2;
  	return inifile__stricmp(kk1->key, kk2->key);
  }
  
  /* Return a new syntax error message. */
  static ERRTYPE inifile__syntax(jk_pool_t *p, const char *file, int line, const char *msg)
  {
  	static const char synfmt[] = SYNFMT;
  	size_t len = sizeof(synfmt) + strlen(msg) + strlen(file) + 10 /* fudge for line number */;
  	char *buf = jk_pool_alloc(p, len);
  	sprintf(buf, synfmt, file, line, msg);
  	return buf;
  }
  
  /* Various macros to tidy up the parsing code */
  
  /* Characters that are OK in the keyname */
  #define KEYCHR(c) \
  	(isalnum(c) || (c) == '.' || (c) == '_')
  
  /* Skip whitespace */
  #define SKIPSPC() \
  	while (*fp == '\t' || *fp == ' ') fp++
  
  /* Skip to the end of the current line */
  #define SKIPLN() \
  	while (*fp != '\0' && *fp != '\r' && *fp != '\n') fp++
  
  /* Move from the end of the current line to the start of the next, learning what the
   * newline character is and counting lines
   */
  #define NEXTLN() \
  	do { while (*fp == '\r' || *fp == '\n') { if (nlc == -1) nlc = *fp; if (*fp == nlc) ln++; fp++; } } while (0)
  
  /* Build the index. Called when the inifile is loaded by inifile_load()
   */
  static ERRTYPE inifile__index(jk_pool_t *p, const char *name)
  {
  	int pass;
  	int ln = 1;
  	int nlc = -1;
  
  	/* Make two passes over the data. First time we're just counting
  	 * the lines that contain values so we can allocate the index, second
  	 * time we build the index.
  	 */
  	for (pass = 0; pass < 2; pass++)
  	{
  		char *fp = file;
  		char *ks = NULL, *ke;	/* key start, end */
  		char *vs = NULL, *ve;	/* value start, end */
  		klen = 0;
  
  		while (*fp != '\0')
  		{
  			SKIPSPC();
  
  			/* turn a comment into an empty line by moving to the next \r|\n */
  			if (*fp == '#' || *fp == ';')
  				SKIPLN();
  
  			if (*fp != '\0' && *fp != '\r' && *fp != '\n')
  			{
  				ks = fp;		/* start of key */
  				while (KEYCHR(*fp)) fp++;
  				ke = fp;		/* end of key */
  				SKIPSPC();
  
  				if (*fp != '=')
  					return inifile__syntax(p, name, ln, "Missing '=' or illegal character in key");
  
  				fp++; /* past the = */
  				SKIPSPC();
  				vs = fp;
  				SKIPLN();
  				ve = fp;
  				/* back up over any trailing space */
  				while (ve > vs && (ve[-1] == ' ' || ve[-1] == '\t')) ve--;
  				NEXTLN(); /* move forwards *before* we trash the eol characters */
  
  				if (NULL != keys) /* second pass? if so stash a pointer */
  				{
  					*ke = '\0';
  					*ve = '\0';
  					keys[klen].key = ks;
  					keys[klen].value = vs;
  				}
  
  				klen++;
  			}
  			else
  			{
  				NEXTLN();
  			}
  		}
  
  		if (NULL == keys && (keys = jk_pool_alloc(p, sizeof(inifile_key) * klen), NULL == keys))
  			return inifile_outofmemory;
  	}
  
  	/* got the index now, sort it so we can search it quickly */
  	qsort(keys, klen, sizeof(inifile_key), inifile__cmp);
  
  	return ERRNONE;
  }
  
  /* Read an INI file from disk
   */
  ERRTYPE inifile_read(jk_pool_t *p, const char *name)
  {
  	FILE *fl;
  	size_t flen;
  	int ok;
  
  	if (fl = fopen(name, "rb"), NULL == fl)
  		return inifile_filenotfound;
  
  	fseek(fl, 0L, SEEK_END);
  	flen = (size_t) ftell(fl);
  	fseek(fl, 0L, SEEK_SET);
  
  	/* allocate one extra byte for trailing \0
  	 */
  	if (file = jk_pool_alloc(p, flen+1), NULL == file)
  	{
  		fclose(fl);
  		return inifile_outofmemory;
  	}
  
  	ok = (fread(file, flen, 1, fl) == 1);
  	fclose(fl);
  	if (!ok) return inifile_readerror;
  
  	file[flen] = '\0';	/* terminate it to simplify parsing */
  
  	return inifile__index(p, name);
  }
  
  /* Find the value associated with the given key returning it or NULL
   * if no match is found. Key name matching is case insensitive.
   */
  const char *inifile_lookup(const char *key)
  {
  	int lo, mid, hi, cmp;
  
  	if (NULL == keys)
  		return NULL;
  
  	for (lo = 0, hi = klen-1; lo <= hi; )
  	{
  		mid = (lo + hi) / 2;
  		cmp = inifile__stricmp(key, keys[mid].key);
  		if (cmp < 0)	/* key in array is greater */
  			hi = mid-1;
  		else if (cmp > 0)
  			lo = mid+1;
  		else
  			return keys[mid].value;
  	}
  
  	return NULL;
  }
  
  #ifdef TEST
  
  static jk_pool_t pool;
  extern void jk_dump_pool(jk_pool_t *p, FILE *f); /* not declared in header */
  
  int main(void)
  {
  	ERRTYPE e;
  	unsigned k;
  	int rc = 0;
  
  	jk_open_pool(&pool, NULL, 0);
  
  	e = inifile_read(&pool, "ok.ini");
  	if (e == ERRNONE)
  	{
  		printf("%u keys in ok.ini\n", klen);
  		for (k = 0; k < klen; k++)
  		{
  			const char *val = inifile_lookup(keys[k].key);
  			printf("Key: \"%s\", value: \"%s\"\n", keys[k].key, val);
  		}
  	}
  	else
  	{
  		printf("Error reading ok.ini: %s\n", e);
  		rc = 1;
  	}
  
  	e = inifile_read(&pool, "bad.ini");
  	if (e == ERRNONE)
  	{
  		printf("%u keys in bad.ini\n", klen);
  		for (k = 0; k < klen; k++)
  		{
  			const char *val = inifile_lookup(keys[k].key);
  			printf("Key: \"%s\", value: \"%s\"\n", keys[k].key, val);
  		}
  		rc = 1;		/* should be a syntax error */
  	}
  	else
  	{
  		printf("Error reading bad.ini: %s (which is OK: that's what we expected)\n", e);
  	}
  
  	jk_dump_pool(&pool, stdout);
  	jk_close_pool(&pool);
  
  	return rc;
  }
  #endif
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native/isapi/config.h
  
  Index: config.h
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /***************************************************************************
   * Description: ISAPI plugin for Tomcat                                    *
   * Author:      Andy Armstrong <an...@tagish.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #ifndef __config_h
  #define __config_h
  
  #define MAKEVERSION(a, b, c, d) \
  	(((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
  
  /* the _memicmp() function is available */
  #if defined(WIN32)
  
  #define HAVE_MEMICMP
  #undef USE_INIFILE
  
  #elif defined(LINUX)
  
  #undef HAVE_MEMICMP
  #define USE_INIFILE
  
  #else
  #error Please define either WIN32 or LINUX
  #endif
  
  #define DEBUG(args) \
  	do { /*printf args ;*/ } while (0)
  
  #endif /* __config_h */