[interchange-cvs] interchange - jon modified 4 files

interchange-core@icdevgroup.org interchange-core@icdevgroup.org
Thu Jan 23 12:14:40 2003


User:      jon
Date:      2003-01-23 17:11:45 GMT
Modified:  dist/src/mod_interchange Tag: STABLE_4_8-branch Makefile
Modified:           README mod_interchange.c mod_interchange.html
Log:
Merge latest mod_interchange from trunk.

Revision  Changes    Path
No                   revision



No                   revision



2.0.2.1   +13 -22    interchange/dist/src/mod_interchange/Makefile


rev 2.0.2.1, prev_rev 2.0
Index: Makefile
===================================================================
RCS file: /var/cvs/interchange/dist/src/mod_interchange/Makefile,v
retrieving revision 2.0
retrieving revision 2.0.2.1
diff -u -u -r2.0 -r2.0.2.1
--- Makefile	18 Jul 2001 02:22:22 -0000	2.0
+++ Makefile	23 Jan 2003 17:11:45 -0000	2.0.2.1
@@ -1,42 +1,33 @@
-##
-##  Makefile -- Build procedure for mod_interchange Apache module
-##  Originally autogenerated via ``apxs -n mod_interchange -g''.
-##
-
-#   the used tools
+#
+#	$Id: Makefile,v 2.0.2.1 2003/01/23 17:11:45 jon Exp $
+#
+#	mod_interchange makefile
+#
 APXS=apxs
 APACHECTL=apachectl
 
-#   additional defines, includes and libraries
-#DEF=-Dmy_define=my_value
-#INC=-Imy/include/dir
-#LIB=-Lmy/lib/dir -lmylib
+#
+#	uncomment if you are running some weird OS that
+#	doesn't have a socklen_t, such as OS/X
+#
+#OSX=-DOSX
 
-#   the default target
 all: mod_interchange.so
 
-#   compile the shared object file
 mod_interchange.so: mod_interchange.c
-	$(APXS) -c $(DEF) $(INC) $(LIB) mod_interchange.c
+	$(APXS) $(OSX) -c $(DEF) $(INC) $(LIB) mod_interchange.c
 
-#   install the shared object file into Apache 
-install: all
-	$(APXS) -i -a -n interchange mod_interchange.so
+#install: all
+#	$(APXS) -i -a -n 'interchange' mod_interchange.so
 
-#   cleanup
 clean:
 	-rm -f mod_interchange.o mod_interchange.so
 
-#   simple test
 test: reload
 	lynx -mime_header http://localhost/mod_interchange
 
-#   install and activate shared object by reloading Apache to
-#   force a reload of the shared object file
 reload: install restart
 
-#   the general Apache start/restart/stop
-#   procedures
 start:
 	$(APACHECTL) start
 restart:



2.0.2.2   +90 -105   interchange/dist/src/mod_interchange/README


rev 2.0.2.2, prev_rev 2.0.2.1
Index: README
===================================================================
RCS file: /var/cvs/interchange/dist/src/mod_interchange/README,v
retrieving revision 2.0.2.1
retrieving revision 2.0.2.2
diff -u -u -r2.0.2.1 -r2.0.2.2
--- README	26 Nov 2002 03:21:09 -0000	2.0.2.1
+++ README	23 Jan 2003 17:11:45 -0000	2.0.2.2
@@ -1,147 +1,132 @@
 mod_interchange
 ===============
 
-Version: 1.04
+$Id: README,v 2.0.2.2 2003/01/23 17:11:45 jon Exp $
+
+Version: 1.29
 
 Description
 -----------
-mod_interchange is designed to replace the vlink and tlink programs that
-come with Interchange. The Interchange link protocol is implemented via
-an Apache module which saves us the (small) overhead of the execution
-of a CGI program.
 
-Requires
---------
-Apache 1.3.6 or later
-Any version of Interchange (all the way back to MiniVend 3.12)
+mod_interchange is designed to replace the vlink and tlink programs
+that comes with Interchange.  The Interchange link protocol has been
+implemented via an Apache module which saves us the (small) overhead
+of the execution of a CGI program.
+
+Note that this module is not compatible with Apache 2.
 
-Installing
-----------
-The included Makefile builds the module as a DSO object. So if your
-Apache has mod_dso.so configured you can do:
+Building the module
+-------------------
 
-make 
-make install
+The included Makefile builds the module as a DSO object. So if
+you're Apache has mod_dso.so configured you can do
 
-If not, you can copy the file mod_interchange.c to src/modules/extra
-and add the option:
+    make
+    make install
 
---activate-module=src/modules/extra/mod_interchange.c
+If not, you should be able to copy the file mod_interchange.c under
+src/modules/extra and add the line when building Apache:
 
-to the 'configure' command when building Apache.
+    --activate-module=src/modules/extra/mod_interchange.c
 
-Configuring Interchange
------------------------
-First you need to decide what URL path you want to point to Interchange,
-and make sure you don't need any files from that same path. For example,
-with the default Construct Something demo you have HTML and images in:
 
-http://www.yourdomain.com/construct/*
+Installing the module as a DSO object
+-------------------------------------
 
-So you can't have mod_interchange take over the /construct path. Instead
-use a different name like /store, so that users will access the site with
-a URL like:
+Copy mod_intercange.so into your Apache DSO library directory and
+add the following lines to your httpd.conf:
 
-http://www.yourdomain.com/store
+    LoadModule interchange_module /wherever/lib/apache/mod_interchange.so
+    AddModule mod_interchange.c
 
-And Apache will still be able to serve images from /construct/* just fine.
 
-To make such a change, you need to modify the Catalog directive in
-interchange.cfg to look like this:
+Documentation
+-------------
 
-Catalog  construct  /var/lib/interchange/construct  /store
+The module understands directives which specify the way to contact the
+primary, and possibly a secondary, Interchange server.  The InterchangeServer
+directive takes either a pathname to the Interchange UNIX socket or a
+host:port specification if you want to use INET mode.
 
-And update the CGI_URL variable in catalog.cfg by uncommenting and changing
-this line:
+The optional InterchangeServerBackup directive takes the same arguments,
+but should obviously point to a different Interchange server than the
+primary.  The InterchangeServerBackup directive is only of any use if
+you have multiple Interchange servers configured in a clustered environment.
 
-Variable  CGI_URL  /store
+Note: The Apache <Location> path should not contain a dot (.) or any
+other characters except A-Z, a-z, 0-9 or a hyphen (-), so:
 
-Configuring Apache
-------------------
-The module understands one directive which specifies the way to contact
-the Interchange server. The directive InterchangeServer takes either a
-full pathname to the Interchange UNIX socket or a host:port specification
-if you want to use INET mode.
+	<Location /shop.name> is invalid, whereas:
+	<Location /shop-name> is valid.
 
-That means you need to add new Location section to your Apache httpd.conf.
-We'll discuss the two kinds of InterchangeServer settings separately.
 
-UNIX socket setup
------------------
-Here is an example httpd.conf section for connecting to Interchange via
-a UNIX socket on the same machine Apache's running on:
+Examples
+--------
+
+UNIX mode local connection:
 
-<Location /store>
+    <Location /shop>
 	SetHandler interchange-handler
-	InterchangeServer /var/run/interchange/socket
-</Location>
+	InterchangeServer /opt/interchange/etc/socket
+    </Location>
 
-Since you're not using the set-UID CGI executable anymore, you need to
-allow the Apache daemon to read from and write to the socket directly.
-This is slightly tricky because Interchange recreates the socket file each
-time it is run, so you can't just modify the ownership and permissions
-of the socket file directly.
+INET mode local connection:
 
-We solve this by setting the group ownership of the directory the socket
-is in to a group Apache is a member of (usually www, apache, http, nobody,
-or similar):
+    <Location /shop>
+	SetHandler interchange-handler
+	InterchangeServer localhost:7786
+    </Location>
 
-chgrp apache /var/run/interchange
+UNIX mode local primary connection and INET mode remote backup connection:
 
-Then we make the directory set-GID so any files created in it will have
-the same group ownership as the directory:
+    <Location /shop>
+	SetHandler interchange-handler
+	InterchangeServer /opt/interchange/etc/socket
+	InterchangeServerBackup another.server.com:7786
+    </Location>
+
+The ConnectTries parameter specifies the number of connection attempts to
+make before giving up.  ConnectRetryDelay specifies the delay, in seconds,
+between each retry attempt.
 
-chmod g+srx /var/run/interchange
+The ConnectTries default is 10 and the ConnectRetryDelay default is 2 seconds.
+Here is an example:
 
-Obviously you'll need to substitute the correct group for 'apache' and the
-right parent directory of the socket where we show '/var/run/interchange'.
-In a non-RPM Interchange installation the directory is 'etc' inside the
-Interchange software directory (perhaps /usr/local/interchange).
+    <Location /shop>
+	SetHandler interchange-handler
+	InterchangeServer localhost:7786
+	ConnectTries 10
+	ConnectRetryDelay 1
+    </Location>
+
+The DropRequestList allows a list of up to 10 space-separated URI components
+to be specified.  If one of the list entries is found anywhere in the
+requested URI, the request will be dropped with a 404 (not found) error,
+without the request being passed to Interchange.  This parameter is useful
+for blocking known Microsoft IIS attacks like "Code Red", so that we don't
+waste any more time processing the (bogus) requests than we have to.
 
-Next you need to add this directive to interchange.cfg:
+    <Location /shop>
+	SetHandler interchange-handler
+	InterchangeServer localhost:7786
+	DropRequestList /default.ida /x.ida /cmd.exe /root.exe
+    </Location>
 
-SocketPerms 0660
 
-This tells Interchange to allow reading from and writing to the socket by
-the group (which our set-GID directory will set to the group the Apache
-daemon is in), instead of the default 0600, which would only allow reading
-and writing by the owner (the Interchange user, usually 'interch').
+Bugs
+----
 
-INET socket setup
------------------
-This is the configuration to connect to Interchange via INET sockets:
+Send bug reports and suggestions to Kevin Walsh <kevin@cursor.biz>
 
-<Location /store>
-	SetHandler interchange-handler
-	InterchangeServer ic.host.com:7786
-</Location>
 
-The port number is optional if you're using the default port 7786.
+Copyright and License
+---------------------
 
-Support
--------
-Visit http://www.icdevgroup.org/ to find information on how you can
-join the Interchange mailing lists, browse documentation and mailing list
-archives, and get other support.
-
-History
--------
-mod_interchange is the direct descendant of mod_minivend, created by
-Francis J. Lacoste <francis.lacoste@iNsu.com> at iNsu Innovations Inc.
-in 1999. Thanks, Francis!
-
-Maintenance of the module was taken over by Red Hat (formerly Akopia)
-in February 2001, with Francis's blessing. The only changes we've made
-so far are to rename occurrences of MiniVend to Interchange, expand the
-documentation, and include it in the standard Interchange distribution
-starting with Interchange 4.6.4.
-
-Copyright
----------
-Copyright (c) 1999 Francis J. Lacoste and iNsu Innovations Inc. 
+Copyright (c) 1999 Francis J. Lacoste and iNsu Innovations Inc.
+Copyright (c) 2000-2003 Cursor Software Limited.
 All rights reserved.
 
-This program is free software; you can redistribute it and/or modify
+This program is free software.  You can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
+the Free Software Foundation.  You may refer to either version 2 of the
+License or (at your option) any later version.



2.0.2.2   +749 -411  interchange/dist/src/mod_interchange/mod_interchange.c


rev 2.0.2.2, prev_rev 2.0.2.1
Index: mod_interchange.c
===================================================================
RCS file: /var/cvs/interchange/dist/src/mod_interchange/mod_interchange.c,v
retrieving revision 2.0.2.1
retrieving revision 2.0.2.2
diff -u -u -r2.0.2.1 -r2.0.2.2
--- mod_interchange.c	26 Nov 2002 03:21:09 -0000	2.0.2.1
+++ mod_interchange.c	23 Jan 2003 17:11:45 -0000	2.0.2.2
@@ -1,31 +1,32 @@
+#define	MODULE_VERSION	"mod_interchange/1.29"
 /*
- *  mod_interchange.c
- *  Apache module implementation of the Interchange link program.
+ *	$Id: mod_interchange.c,v 2.0.2.2 2003/01/23 17:11:45 jon Exp $
  *
- *  $Id: mod_interchange.c,v 2.0.2.1 2002/11/26 03:21:09 jon Exp $
+ *	Apache Module implementation of the Interchange application server
+ *	link programs.
  *
- *  Support: http://www.icdevgroup.org/
+ *	Author: Kevin Walsh <kevin@cursor.biz>
+ *	Based on original code by Francis J. Lacoste <francis.lacoste@iNsu.COM>
  *
- *  Author: Francis J. Lacoste <francis.lacoste@iNsu.COM>
+ *	Copyright (c) 1999 Francis J. Lacoste, iNsu Innovations.
+ *	Copyright (c) 2000-2003 Cursor Software Limited.
+ *	All rights reserved.
  *
- *  Copyright (C) 1999 Francis J. Lacoste, iNsu Innovations
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
  *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
  *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- *  02111-1307 USA
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *	02111-1307 USA
  */
-
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
@@ -40,519 +41,856 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-#define IC_DEFAULT_PORT 7786
-#define IC_DEFAULT_ADDR "127.0.0.1"
+#ifdef	OSX
+typedef long socklen_t;
+#endif
+
+#ifndef	AF_LOCAL
+#define	AF_LOCAL	AF_UNIX
+#endif
+
+#ifndef	PF_LOCAL
+#define	PF_LOCAL	PF_UNIX
+#endif
+
+#ifndef SUN_LEN
+#define SUN_LEN(su)	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+#define IC_DEFAULT_PORT			7786
+#define IC_DEFAULT_ADDR			"127.0.0.1"
+#define	IC_DEFAULT_TIMEOUT		10
+#define	IC_DEFAULT_CONNECT_TRIES	10
+#define	IC_DEFAULT_CONNECT_RETRY_DELAY	2
+
+#define	IC_MAX_DROPLIST			10
+#define IC_MAX_SERVERS			2
 
-/* Forward declaration */
 module MODULE_VAR_EXPORT interchange_module;
 
-typedef struct ic_conf_struct
-{
-	struct sockaddr *sockaddr;  /* Socket of Interchange Server */
-	int				family;		/* The socket family of that one */
-	NET_SIZE_T		size;		/* The size of the socket */
-	char			*address;	/* Human readable version of the above */
-} ic_conf_rec;
+typedef struct ic_socket_struct{
+	struct sockaddr *sockaddr; /* socket to the Interchange server */
+	int family;		/* the socket family in use */
+	socklen_t size;		/* the size of the socket structure */
+	char *address;		/* human-readable form of the address */
+}ic_socket_rec;
+
+typedef struct ic_conf_struct{
+	ic_socket_rec *server[IC_MAX_SERVERS];	/* connection to IC server(s) */
+	int connect_tries;	/* number of times to ret to connect to IC */
+	int connect_retry_delay; /* delay this many seconds between retries */
+	int droplist_no;
+	int loclen;			/* size of the location string */
+	char location[HUGE_STRING_LEN];	/* configured <Location> */
+	char droplist[IC_MAX_DROPLIST][HUGE_STRING_LEN];
+}ic_conf_rec;
+
+typedef struct ic_response_buffer_struct{
+	int buff_size;
+	int pos;
+	char buff[HUGE_STRING_LEN];
+}ic_response_buffer;
+
+static void ic_initialise(server_rec *,pool *);
+static void *ic_create_dir_config(pool *,char *);
+static const char *ic_server_cmd(cmd_parms *,void *,const char *);
+static const char *ic_serverbackup_cmd(cmd_parms *,void *,const char *);
+static const char *ic_server_setup(cmd_parms *,void *,int,const char *arg);
+static const char *ic_connecttries_cmd(cmd_parms *,void *,const char *);
+static const char *ic_connectretrydelay_cmd(cmd_parms *,void *,const char *);
+static BUFF *ic_connect(request_rec *,ic_conf_rec *);
+static int ic_select(int,int,int,int);
+static int ic_send_request(request_rec *,ic_conf_rec *,BUFF *);
+static int ic_transfer_response(request_rec *,BUFF *);
+static int ic_handler(request_rec *);
 
-typedef struct ic_response_buffer_struct
+/*
+ *	ic_initialise()
+ *	---------------
+ *	Module initialisation.
+ */
+static void ic_initialise(server_rec *s,pool *p)
 {
-	int  buff_size;
-	int  pos;
-	char buff[HUGE_STRING_LEN];
-} ic_response_buffer;
+	ap_add_version_component(MODULE_VERSION);
+}
 
-static void*
-ic_create_dir_config(pool *p, char *dir)
+/*
+ *	ic_create_dir_config()
+ *	----------------------
+ *	This module's per-directory config creator.
+ *	Sets up the default configuration for this location,
+ *	which can be overridden using the module's configuration
+ *	directives
+ */
+static void *ic_create_dir_config(pool *p,char *dir)
 {
 	struct sockaddr_in *inet_sock;
+	int tmp;
 
-	ic_conf_rec *conf_rec = (ic_conf_rec *)ap_pcalloc(p, sizeof(ic_conf_rec));
+	ic_conf_rec *conf_rec = (ic_conf_rec *)ap_pcalloc(p,sizeof(ic_conf_rec));
+	if (conf_rec == NULL)
+		return NULL;
+
+	/*
+	 *	the default connection method is INET to localhost
+	 */
+	inet_sock = (struct sockaddr_in *)ap_pcalloc(p,sizeof(struct sockaddr_in));
+	if (inet_sock == NULL)
+		return NULL;
 
-	/* Default connection method is INET to localhost */
-	inet_sock =
-		(struct sockaddr_in *)ap_pcalloc( p, sizeof (struct sockaddr_in));
 	inet_sock->sin_family = AF_INET;
-	inet_aton( IC_DEFAULT_ADDR, &inet_sock->sin_addr );
-	inet_sock->sin_port   = htons( IC_DEFAULT_PORT );
+	inet_aton(IC_DEFAULT_ADDR,&inet_sock->sin_addr);
+	inet_sock->sin_port = htons(IC_DEFAULT_PORT);
+
+	conf_rec->server[0] = (ic_socket_rec *)ap_pcalloc(p,sizeof(ic_socket_rec));
+	if (conf_rec->server[0] == NULL)
+		return NULL;
 
-	conf_rec->sockaddr  = (struct sockaddr *)inet_sock;
-	conf_rec->size      = sizeof (struct sockaddr_in);
-	conf_rec->family    = PF_INET;
-	conf_rec->address   = IC_DEFAULT_ADDR ":" "IC_DEFAULT_PORT";
+	conf_rec->server[0]->sockaddr = (struct sockaddr *)inet_sock;
+	conf_rec->server[0]->size = sizeof (struct sockaddr_in);
+	conf_rec->server[0]->family = PF_INET;
+	conf_rec->server[0]->address = IC_DEFAULT_ADDR;
+
+	for (tmp = 1; tmp < IC_MAX_SERVERS; tmp++)
+		conf_rec->server[tmp] = (ic_socket_rec *)NULL;
+
+	if (dir){
+		if (*dir == '/')
+			dir++;
+		strcpy(conf_rec->location,dir);
+		conf_rec->loclen = strlen(conf_rec->location);
+	}else{
+		conf_rec->location[0] = '\0';
+		conf_rec->loclen = 0;
+	}
+	if (conf_rec->location[conf_rec->loclen] != '/'){
+		conf_rec->location[conf_rec->loclen++] = '/';
+		conf_rec->location[conf_rec->loclen] = '\0';
+	}
+	conf_rec->connect_tries = IC_DEFAULT_CONNECT_TRIES;
+	conf_rec->connect_retry_delay = IC_DEFAULT_CONNECT_RETRY_DELAY;
+	conf_rec->droplist_no = 0;
 
 	return conf_rec;
 }
 
-static const char*
-ic_server_cmd(cmd_parms *parms, void *mconfig, const char *arg)
+/*
+ *	ic_server_cmd()
+ *	---------------
+ *	Handle the "InterchangeServer" module configuration directive
+ */
+static const char *ic_server_cmd(cmd_parms *parms,void *mconfig,const char *arg)
 {
-	ic_conf_rec *conf_rec   = (ic_conf_rec *)mconfig;
+	return ic_server_setup(parms,mconfig,0,arg);
+}
 
-	conf_rec->address		= ap_pstrdup( parms->pool, arg );
-	if ( conf_rec->address == NULL )
-		return "not enough memory";
-
-	/* Verify type of the argument */
-	if ( *arg == '/' ) {
-		/* This is a UNIX socket specification */
-		struct sockaddr_un *unix_sock;
+/*
+ *	ic_serverbackup_cmd()
+ *	---------------------
+ *	Handle the "InterchangeServerBackup" module configuration directive
+ */
+static const char *ic_serverbackup_cmd(cmd_parms *parms,void *mconfig,const char *arg)
+{
+	ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
 
-		unix_sock	= (struct sockaddr_un *)
-			ap_pcalloc( parms->pool, sizeof( struct sockaddr_un ) );
-		if (unix_sock == NULL)
-			return "not enough memory";
+	conf_rec->server[1] = (ic_socket_rec *)ap_pcalloc(parms->pool,sizeof(ic_socket_rec));
+	if (conf_rec->server[1] == NULL)
+		return "not enough memory for backup socket record";
 
-		unix_sock->sun_family = AF_LOCAL;
-		ap_cpystrn( unix_sock->sun_path, conf_rec->address,
-				 sizeof (unix_sock->sun_path));
+	return ic_server_setup(parms,mconfig,1,arg);
+}
 
-		conf_rec->family   = PF_LOCAL;
-		conf_rec->size     = SUN_LEN( unix_sock );
-		conf_rec->sockaddr = (struct sockaddr *)unix_sock;
-	} else {
-		/* INET Socket
+/*
+ *	ic_server_setup()
+ *	-----------------
+ *	Do the actual primary/backup server setup on behalf of the
+ *	ic_server_cmd() and ic_serverbackup_cmd() functions.
+ */
+static const char *ic_server_setup(cmd_parms *parms,void *mconfig,int server,const char *arg)
+{
+	static char errmsg[100];
+
+	ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
+	ic_socket_rec *sock_rec = conf_rec->server[server];
 
-		   The argument is an IP address or hostname followed by
-		   an optional port specification.
+	sock_rec->address = ap_pstrdup(parms->pool,arg);
+	if (sock_rec->address == NULL)
+		return "not enough memory for the socket address";
+
+	/*
+	 *	verify type of the argument, which will indicate
+	 *	whether we should be using a UNIX or Inet socket
+	 *	to connect to the Interchange server
+	 */
+	if (*arg == '/'){
+		/*
+		 *	this is to be a UNIX socket
+		 */
+		struct sockaddr_un *unix_sock;
+
+		unix_sock = (struct sockaddr_un *)ap_pcalloc(parms->pool,sizeof(struct sockaddr_un));
+		if (unix_sock == NULL){
+			sprintf(errmsg,"not enough memory for %s UNIX socket structure",server ? "primary" : "backup");
+			return errmsg;
+		}
+
+		unix_sock->sun_family = AF_LOCAL;
+		ap_cpystrn(unix_sock->sun_path,sock_rec->address,sizeof(unix_sock->sun_path));
+		sock_rec->sockaddr = (struct sockaddr *)unix_sock;
+		sock_rec->size = SUN_LEN(unix_sock);
+		sock_rec->family = PF_LOCAL;
+	}else{
+		/*
+		 *	this is to be an INET socket
+		 *
+		 *	the argument is an IP address or hostname followed by
+		 *	an optional port specification
 		 */
 		struct sockaddr_in *inet_sock;
-		char **hostaddress, *hostname;
+		char **hostaddress;
+		char *hostname;
+
+		inet_sock = (struct sockaddr_in *)ap_pcalloc(parms->pool,sizeof(struct sockaddr_in));
+		if (inet_sock == NULL){
+			sprintf(errmsg,"not enough memory for %s INET socket structure",server ? "primary" : "backup");
+			return errmsg;
+		}
 
-		inet_sock	= (struct sockaddr_in *)
-			ap_pcalloc( parms->pool, sizeof( struct sockaddr_in ) );
-		if (inet_sock == NULL)
-			return "not enough memory";
 		inet_sock->sin_family = AF_INET;
+		hostaddress = &(sock_rec->address);
+		hostname = ap_getword_nc(parms->temp_pool,hostaddress,':');
 
-		hostaddress = &(conf_rec->address);
-		hostname    = ap_getword_nc( parms->temp_pool, hostaddress, ':');
+		if (!inet_aton(hostname,&inet_sock->sin_addr)){
+			/*
+			 *	address must point to a hostname
+			 */
+			struct hostent *host = ap_pgethostbyname(parms->temp_pool,hostname);
+			if (!host)
+				return "invalid hostname specification";
 
-		if ( ! inet_aton( hostname, &inet_sock->sin_addr ) )
-		{
-			/* Address must be a host */
-			struct hostent * host;
-			host = ap_pgethostbyname( parms->temp_pool, hostname );
-			if ( ! host )
-				return "invalid host specification";
-
-			memcpy(&inet_sock->sin_addr, host->h_addr,
-				   sizeof(inet_sock->sin_addr) );
-		}
-
-		/* Check if there is a port spec */
-		if ( **hostaddress ) {
-			int port = atoi( *hostaddress );
+			memcpy(&inet_sock->sin_addr,host->h_addr,sizeof(inet_sock->sin_addr));
+		}
+
+		/*
+		 *	check if a port number has been specified
+		 */
+		if (**hostaddress){
+			int port = atoi(*hostaddress);
 
-			if ( port < 1 || port > 65535 )
+			if (port <= 100 || port > 65535)
 				return "invalid port specification";
 
-			inet_sock->sin_port = htons( port );
-		} else {
-			inet_sock->sin_port = htons( IC_DEFAULT_PORT );
+			inet_sock->sin_port = htons(port);
+		}else{
+			inet_sock->sin_port = htons(IC_DEFAULT_PORT);
 		}
 
-		conf_rec->sockaddr = (struct sockaddr *)inet_sock;
-		conf_rec->family   = PF_INET;
-		conf_rec->size     = sizeof( struct sockaddr_in );
-		conf_rec->sockaddr = (struct sockaddr *)inet_sock;
+		sock_rec->sockaddr = (struct sockaddr *)inet_sock;
+		sock_rec->family = PF_INET;
+		sock_rec->size = sizeof(struct sockaddr_in);
 	}
+	return NULL;
+}
+
+/*
+ *	ic_connecttries_cmd()
+ *	---------------------
+ *	Handle the "ConnectTries" module configuration directive
+ */
+static const char *ic_connecttries_cmd(cmd_parms *parms,void *mconfig,const char *arg)
+{
+	ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
+
+	conf_rec->connect_tries = atoi(arg);
+	return NULL;
+}
+
+/*
+ *	ic_connectretrydelay_cmd()
+ *	--------------------------
+ *	Handle the "ConnectRetries" module configuration directive
+ */
+static const char *ic_connectretrydelay_cmd(cmd_parms *parms,void *mconfig,const char *arg)
+{
+	ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
+
+	conf_rec->connect_retry_delay = atoi(arg);
+	return NULL;
+}
+
+/*
+ *	ic_droprequest_cmd()
+ *	--------------------
+ *	Handle the "DropRequestList" module configuration directive
+ */
+static const char *ic_droprequestlist_cmd(cmd_parms *parms,void *mconfig,const char *arg)
+{
+	ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
+
+	if (conf_rec->droplist_no < IC_MAX_DROPLIST)
+		strcpy(conf_rec->droplist[conf_rec->droplist_no++],arg);
 
 	return NULL;
 }
 
-static BUFF *
-ic_connect( request_rec *r, ic_conf_rec *conf_rec )
+/*
+ *	ic_connect()
+ *	------------
+ *	Connect to the Interchange server
+ */
+static BUFF *ic_connect(request_rec *r,ic_conf_rec *conf_rec)
 {
-	int ic_sock;
 	BUFF *ic_buff;
+	ic_socket_rec *sock_rec;
+	int ic_sock,retry,srv;
+	int connected = 0;
+
+	/*
+	 *	connect the new socket to the Interchange server
+	 *
+	 *	if the connection to the Interchange server fails then
+	 *	retry IC_DEFAULT_CONNECT_TRIES times, sleeping for
+	 *	IC_DEFAULT_CONNECT_RETRY_DELAY seconds between each retry
+	 */
+	for (retry = 0; retry != conf_rec->connect_tries; retry++){
+		for (srv = 0; srv != IC_MAX_SERVERS; srv++){
+			if ((sock_rec = conf_rec->server[srv]) == NULL)
+				break;
+			if (srv){
+				ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Attempting to connect to backup server %d",srv);
+			}
 
-	/* Open connection to the server */
-	ic_sock = ap_psocket( r->pool, conf_rec->family, SOCK_STREAM, 0 );
-	if ( ic_sock < 0 ) {
-		ap_log_reason( "socket", r->uri, r);
-		return NULL;
+			/*
+			 *	attempt to connect to the Interchange server
+			 */
+			ic_sock = ap_psocket(r->pool,sock_rec->family,SOCK_STREAM,0);
+			if (ic_sock < 0){
+				ap_log_reason("socket",r->uri,r);
+				return NULL;
+			}
+			ap_hard_timeout("ic_connect",r);
+			if (connect(ic_sock,sock_rec->sockaddr,sock_rec->size) >= 0){
+				connected++;
+				break;
+			}
+			ap_kill_timeout(r);
+			ap_pclosesocket(r->pool,ic_sock);
+		}
+		if (connected)
+		    break;
+		sleep(conf_rec->connect_retry_delay);
 	}
-
-	/* Initialize a timeout */
-	ap_hard_timeout( "ic_connect", r );
-	if ( connect( ic_sock, conf_rec->sockaddr, conf_rec->size ) < 0 )
-	{
-		ap_log_reason( "Connection failed", r->uri, r );
+	ap_kill_timeout(r);
+	if (retry == conf_rec->connect_tries){
+		ap_log_reason("Connection failed",r->uri,r);
 		return NULL;
 	}
-	ap_kill_timeout( r );
 
-	/* Create a BUFF struct of that socket */
-	ic_buff = ap_bcreate( r->pool, B_RDWR | B_SOCKET );
-	if ( !ic_buff) {
-		ap_log_reason( "failed to create BUFF", r->uri, r );
+	/*
+	 *	create an Apache BUFF structure for our new connection
+	 */
+	ic_buff = ap_bcreate(r->pool,B_RDWR|B_SOCKET);
+	if (!ic_buff){
+		ap_log_reason("failed to create BUFF",r->uri,r);
 		return NULL;
 	}
-	ap_bpushfd( ic_buff, ic_sock, ic_sock );
-
+	ap_bpushfd(ic_buff,ic_sock,ic_sock);
 	return ic_buff;
 }
 
-static int
-ic_send_request( request_rec *r, ic_conf_rec *conf_rec, BUFF *ic_buff )
+/*
+ *	ic_select()
+ *	-----------
+ *	Convenient wrapper for select().
+ *	Wait for data to become available on the socket, or
+ *	for an error to occur, and return the appropriate status
+ *	code to the calling function.
+ */
+static int ic_select(int sock_rd,int sock_wr,int secs,int usecs)
 {
-	char **env, **e;
-	int env_count, rc;
+	fd_set sock_set_rd,sock_set_wr;
+	fd_set *rd = NULL,*wr = NULL;
+	struct timeval tv;
+	int rc;
 
-	/* Initialize a timeout */
-	ap_hard_timeout( "ic_send_request", r );
+	do{
+		if (sock_rd > 0){
+			FD_ZERO(&sock_set_rd);
+			FD_SET(sock_rd,&sock_set_rd);
+			rd = &sock_set_rd;
+		}
+		if (sock_wr > 0){
+			FD_ZERO(&sock_set_wr);
+			FD_SET(sock_wr,&sock_set_wr);
+			wr = &sock_set_wr;
+		}
+
+		tv.tv_sec = secs;
+		tv.tv_usec = usecs;
+		rc = ap_select(((sock_rd > sock_wr) ? sock_rd : sock_wr) + 1,rd,wr,NULL,&tv);
+	}while (rc == 0);
+	return rc;
+}
 
-	/* Send the arg param
-	   This is always empty for a CGI request
+/*
+ *	ic_send_request()
+ *	-----------------
+ *	Send the client's page/form request to the Interchange server
+ */
+static int ic_send_request(request_rec *r,ic_conf_rec *conf_rec,BUFF *ic_buff)
+{
+	char **env,**e,*rp;
+	int env_count,rc;
+	char request_uri[HUGE_STRING_LEN];
+	char redirect_url[HUGE_STRING_LEN];
+
+	/*
+	 *	send the Interchange-link arg parameter
+	 *	(this is always empty for a CGI request)
 	 */
-	if ( ap_bputs( "arg 0\n", ic_buff ) < 0 ) {
-		ap_log_reason( "error writing to Interchange", r->uri, r );
+	ap_hard_timeout("ic_send_request",r);
+	if (ap_bputs("arg 0\n",ic_buff) < 0){
+		ap_log_reason("error writing to Interchange",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	ap_reset_timeout( r );
-
-	/* Now on with the environment */
+	ap_reset_timeout(r);
 
-	/* Initialize Environment to send to Interchange */
-	ap_add_common_vars( r );
-	ap_add_cgi_vars( r );
+	/*
+	 *	initialize the environment to send to Interchange
+	 */
+	ap_add_common_vars(r);
+	ap_add_cgi_vars(r);
+	env = ap_create_environment(r->pool,r->subprocess_env);
 
-	env = ap_create_environment( r->pool, r->subprocess_env );
+	/*
+	 *	count the number of environment variables present
+	 */
+	for (e = env,env_count = 0; *e != NULL; e++,env_count++){
+		if (strncmp(*e,"PATH_INFO=",10) == 0)
+			env_count--;
+	}
+	env_count++;
 
-	/* Send the count */
-	for (e = env, env_count = 0;  *e != NULL;  ++e, ++env_count);
-	if ( ap_bprintf( ic_buff, "env %d\n", env_count ) < 0 ) {
-		ap_log_reason( "error writing to Interchange", r->uri, r );
+	/*
+	 *	send the environment variable count to Interchange
+	 */
+	if (ap_bprintf(ic_buff,"env %d\n",env_count) < 0){
+		ap_log_reason("error writing to Interchange",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	ap_reset_timeout( r );
+	ap_reset_timeout(r);
 
-	/* Now the vars */
-	for ( e = env;  *e != NULL;  ++e) {
-		if ( ap_bprintf(ic_buff, "%d %s\n", strlen(*e), *e ) < 0 ) {
-			ap_log_reason( "error writing to Interchange", r->uri, r );
+	/*
+	 *	ignore the PATH_INFO variable and fix the SCRIPT_NAME,
+	 *	REQUEST_URI and REDIRECT_URL variable content
+	 */
+	request_uri[0] = '\0';
+	redirect_url[0] = '\0';
+	for (e = env; *e != NULL; e++){
+		int len;
+
+		if (strncmp(*e,"PATH_INFO=",10) == 0)
+			continue;
+		if (strncmp(*e,"REDIRECT_URL=",13) == 0){
+			strcpy(redirect_url,(*e) + 13);
+			continue;
+		}
+		if (strncmp(*e,"REQUEST_URI=",12) == 0)
+			strcpy(request_uri,(*e) + 12);
+		else if (strncmp(*e,"SCRIPT_NAME=",12) == 0){
+			*(*e + 12) = '/';
+			strcpy(*e + 13,conf_rec->location);
+			if (*(*e + 12 + conf_rec->loclen) == '/')
+				*(*e + 12 + conf_rec->loclen) = '\0';
+		}
+		len = strlen(*e);
+		if (len && ap_bprintf(ic_buff,"%d %s\n",len,*e) < 0){
+			ap_log_reason("error writing to Interchange",r->uri,r);
 			return HTTP_INTERNAL_SERVER_ERROR;
 		}
-		ap_reset_timeout( r );
+		ap_reset_timeout(r);
 	}
 
-	/* Send the request body if any */
-	if ( r->method_number == M_POST ) {
-		if ( (rc = ap_setup_client_block( r, REQUEST_CHUNKED_ERROR) ) != OK)
-			return rc;
-
-		if ( ap_should_client_block(r) ) {
-			char buffer[HUGE_STRING_LEN];
-			int  len_read;
-			long length = r->remaining;
-
-			if (ap_bprintf( ic_buff, "entity\n%ld ", length ) < 0 ) {
-				ap_log_reason( "error writing to Interchange", r->uri, r );
-				return HTTP_INTERNAL_SERVER_ERROR;
-			}
-
-			while ( (len_read =
-					 ap_get_client_block(r, buffer, sizeof(buffer ))
-					 ) > 0 )
-			{
-				ap_reset_timeout(r);
-
-				/* Send that to Interchange */
-				if ( ap_bwrite( ic_buff, buffer, len_read ) != len_read ) {
-					ap_log_reason( "error writing to Interchange", r->uri, r );
-					return HTTP_INTERNAL_SERVER_ERROR;
-				}
-				ap_reset_timeout(r);
-			}
-			if ( len_read < 0 ) {
-				ap_log_reason( "error reading from client", r->uri, r );
-				return HTTP_INTERNAL_SERVER_ERROR;
-			}
-			/* Send end of line */
-			if ( ap_bputc( '\n', ic_buff ) < 0 ) {
-				ap_log_reason( "error writing to Interchange", r->uri, r );
-				return HTTP_INTERNAL_SERVER_ERROR;
-			}
+	rp = request_uri;
+	while (*rp == '/')
+		rp++;
+
+	if (strncmp(rp,conf_rec->location,conf_rec->loclen) == 0)
+		rp += (conf_rec->loclen - 1);
+
+	strcpy(request_uri,rp);
+	for (rp = request_uri; *rp != '\0'; rp++){
+		if (*rp == '?'){
+			*rp = '\0';
+			break;
 		}
 	}
-
-	/* We are done */
-	if ( ap_bputs( "end\n", ic_buff ) < 0 ) {
-		ap_log_reason( "error writing to Interchange", r->uri, r );
+	switch (ap_unescape_url(request_uri)){
+	case BAD_REQUEST:
+	case NOT_FOUND:
+		ap_log_reason("Bad URI entities found",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	ap_reset_timeout( r );
-	if ( ap_bflush( ic_buff ) < 0 ) {
-		ap_log_reason( "error writing to Interchange", r->uri, r );
+
+	/*
+	 *	send the PATH_INFO variable as our "fixed" REQUEST_URI
+	 */
+	if (ap_bprintf(ic_buff,"%d PATH_INFO=%s\n",strlen(request_uri) + 10,request_uri) < 0){
+		ap_log_reason("error writing to Interchange",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
 
-	ap_kill_timeout( r );
+	/*
+	 *	check if we have a REDIRECT_URL
+	 *	if so then give it the same "fixes" as PATH_INFO (REQUEST_URI)
+	 */
+	if (redirect_url[0] != '\0'){
+		rp = redirect_url;
+		while (*rp == '/')
+			rp++;
+
+		if (strncmp(rp,conf_rec->location,conf_rec->loclen) == 0)
+			rp += (conf_rec->loclen - 1);
+
+		strcpy(redirect_url,rp);
+		for (rp = redirect_url; *rp != '\0'; rp++){
+			if (*rp == '?'){
+				*rp = '\0';
+				break;
+			}
+		}
+		switch (ap_unescape_url(redirect_url)){
+		case BAD_REQUEST:
+		case NOT_FOUND:
+			ap_log_reason("Bad URI entities found",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
 
-	return OK;
-}
+		if (ap_bprintf(ic_buff,"%d REDIRECT_URL=%s\n",strlen(redirect_url) + 13,redirect_url) < 0){
+			ap_log_reason("error writing to Interchange",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
+	}
+	ap_reset_timeout(r);
 
-static int
-ic_transfer_response( request_rec *r, ic_conf_rec *conf_rec,
-					  BUFF *ic_buff )
-{
-	char error_buff[MAX_STRING_LEN];
-	BUFF *client_buff;
-	int rc;
+	/*
+	 *	send the request body, if any
+	 */
+	if (ap_should_client_block(r)){
+		char buffer[HUGE_STRING_LEN];
+		int len_read;
+		long length = r->remaining;
 
-	array_header *resp_buff_arr;
-	int cur_reading_elt;
-	int cur_writing_elt;
-
-	/* For ap_select */
-	fd_set readers,writers;
-	int client_fd,ic_fd,maxfd;
-	int reading,writing;
+		if (ap_bprintf(ic_buff,"entity\n%ld ",length) < 0){
+			ap_log_reason("error writing to Interchange",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
 
-	ap_hard_timeout( "ic_transfer_response", r );
+		/*
+		 *	read a block of data from the client and send
+		 *	it to the Interchange server, until there
+		 *	is nothing more to read from the client
+		 */
+		while ((len_read = ap_get_client_block(r,buffer,sizeof(buffer))) > 0){
+			ap_reset_timeout(r);
 
-	/* Scan the request response for CGI headers */
-	if ( ap_scan_script_header_err_buff( r, ic_buff, error_buff ) != OK )
-	{
-		ap_log_rerror( APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
-					   "Error while scanning response headers: %s",
-					   error_buff );
+			if (ap_bwrite(ic_buff,buffer,len_read) != len_read){
+				ap_log_reason("error writing client block to Interchange",r->uri,r);
+				return HTTP_INTERNAL_SERVER_ERROR;
+			}
+			ap_reset_timeout(r);
+		}
+		if (len_read < 0){
+			ap_log_reason("error reading block from client",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
 
-		return HTTP_INTERNAL_SERVER_ERROR;
+		/*
+		 *	send an end of line character to Interchange
+		 */
+		if (ap_bputc('\n',ic_buff) < 0){
+			ap_log_reason("error writing to Interchange",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
 	}
 
-	/* Send beggining of the response */
-	ap_reset_timeout( r );
-	ap_send_http_header( r );
-	/* Make sure all headers are flushed */
-	if ( ap_rflush( r ) < 0 ) {
-		ap_log_reason( "error sending headers to client", r->uri, r );
-		return HTTP_INTERNAL_SERVER_ERROR;
-	}
+	/*
+	 *	all data has been sent, so send the "end" marker
+	 */
 	ap_reset_timeout(r);
-
-	/* OK, now turn on non blocking IO */
-	client_buff = r->connection->client;
-	if ( (rc = ap_bnonblock( client_buff, B_WR ) ) != 0 )
-	{
-		ap_log_reason( "error turning non blocking I/O on client",
-					   r->uri, r );
+	if (ap_bputs("end\n",ic_buff) < 0){
+		ap_log_reason("error writing the end marker to Interchange",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	if ( (rc = ap_bnonblock( ic_buff, B_RD ) ) != 0 )
-	{
-		ap_log_reason( "error turning non blocking I/O on Interchange",
-					   r->uri, r );
+	if (ap_bflush(ic_buff) < 0){
+		ap_log_reason("error flushing data to Interchange",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	ap_bsetflag( ic_buff, B_SAFEREAD, 1 );
 
-	reading = 1, writing = 1;
-	client_fd    = ap_bfileno( client_buff, B_WR );
-	ic_fd		 = ap_bfileno( ic_buff, B_RD );
-	maxfd       = client_fd > ic_fd ? client_fd : ic_fd;
-	maxfd++;
+	ap_kill_timeout(r);
+	return OK;
+}
 
-	/* Allocate array for response */
-	resp_buff_arr = ap_make_array(r->pool, 5, sizeof(ic_response_buffer ) );
-	if ( !resp_buff_arr ) {
-		ap_log_reason( "failed to allocate response buffer", r->uri, r );
+/*
+ *	ic_transfer_response()
+ *	----------------------
+ *	Read the response from the Interchange server
+ *	and relay it to the client
+ */
+static int ic_transfer_response(request_rec *r,BUFF *ic_buff)
+{
+	const char *location;
+	int rc,ic_sock;
+	char sbuf[MAX_STRING_LEN],argsbuffer[HUGE_STRING_LEN];
+
+	/*
+	 *	get the socket we are using to talk to the
+	 *	Interchange server, and wait for Interchange to
+	 *	send us some data
+	 */
+	ic_sock = ap_bfileno(ic_buff,B_RD);
+	rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
+	if (rc < 0){
+		ap_log_reason("Failed to select the response header",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	/* Create the first element */
-	if ( ap_push_array( resp_buff_arr ) == NULL ) {
-		ap_log_reason( "failed to allocate first element", r->uri, r );
+
+	/*
+	 *	check the HTTP header to make sure that it looks valid
+	 */
+	if (ap_scan_script_header_err_buff(r,ic_buff,sbuf)){
+		ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Malformed header return by Interchange: %s",sbuf);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
-	cur_reading_elt = 0, cur_writing_elt = 0;
-
-	while (1) {
-		int i;
-
-		FD_ZERO(&readers);
-		FD_ZERO(&writers);
-
-		if ( !reading && !writing) {
-			break;
-		}
 
-		if ( reading )
-			FD_SET( ic_fd, &readers );
+	/*
+	 *	check the header for an HTTP redirect request
+	 */
+	location = ap_table_get(r->headers_out,"Location");
+	if (r->status == 200 && location){
+		fd_set sock_set;
 
-		if ( writing )
-			FD_SET(client_fd, &writers);
+		/*
+		 *	check if we need to do an external redirect
+		 */
+		if (*location != '/')
+			return REDIRECT;
 
-		if ( ( rc = ap_select( maxfd, &readers, &writers, NULL, NULL ) ) < 0 )
-		{
-			ap_log_reason( "error in ap_select", r->uri, r );
+		/*
+		 *	we are here because we need to do an internal redirect
+		 *
+		 *	soak up any data from the Interchange socket
+		 */
+		rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
+		if (rc < 0){
+			ap_log_reason("Failed to select the response text",r->uri,r);
 			return HTTP_INTERNAL_SERVER_ERROR;
 		}
 
-		if ( reading && FD_ISSET( ic_fd, &readers ) )
-		{
-			int read_len,left;
-			ic_response_buffer *resp_buff;
-			char *buff;
-
-			resp_buff = ((ic_response_buffer *)resp_buff_arr->elts);
-			for ( i=0; i< cur_reading_elt; i++)
-				resp_buff++;
-
-			buff = resp_buff->buff;
-			buff += resp_buff->buff_size;
-			left = HUGE_STRING_LEN - resp_buff->buff_size;
-
-			read_len = ap_bread( ic_buff, buff, left );
-			if ( read_len < 0 ) {
-				ap_log_reason( "error while reading Interchange response",
-							   r->uri, r );
-				return HTTP_INTERNAL_SERVER_ERROR;
-			} else if ( read_len == 0 ) {
-				reading = 0;
-			} else {
-				resp_buff->buff_size += read_len;
-				writing = 1; /* Flag to indicate that there is now
-								writing to do */
-
-				if ( resp_buff->buff_size == HUGE_STRING_LEN ) {
-					/* Create a new response buffer in the array */
-					resp_buff =
-						(ic_response_buffer *)ap_push_array(resp_buff_arr);
-					if ( !resp_buff ) {
-						ap_log_reason( "error while allocating "
-									   "response buffer", r->uri, r );
-						return HTTP_INTERNAL_SERVER_ERROR;
-					}
-					cur_reading_elt++;
-				}
-			}
-		}
-		if ( writing && FD_ISSET( client_fd, &writers ) )
-		{
-			int write_len,left;
-			ic_response_buffer *resp_buff;
-			char *buff;
-
-			resp_buff = (ic_response_buffer *)resp_buff_arr->elts;
-			for ( i=0; i< cur_writing_elt; i++)
-				resp_buff++;
-
-			buff = resp_buff->buff;
-			buff += resp_buff->pos;
-			left = resp_buff->buff_size - resp_buff->pos;
-			if ( left > 0 ) {
-				write_len = ap_bwrite( client_buff, buff, left );
-				if ( write_len < 0 ) {
-					ap_log_reason( "error while sending response",
-								   r->uri, r );
-					return HTTP_INTERNAL_SERVER_ERROR;
-				}
-				resp_buff->pos += write_len;
-
-				if ( resp_buff->pos == resp_buff->buff_size ) {
-					if ( ! reading && cur_writing_elt ==
-						 cur_reading_elt )
-					{
-						/* Done */
-						writing = 0;
-					} else if ( resp_buff->pos == HUGE_STRING_LEN )
-					{
-						/* No remaining space in the buffer
-						 */
-						cur_writing_elt++;
-					} else {
-						/*
-						  It seems that all that was read has been
-						  sent, so wait for more data.
-						 */
-						writing = 0;
-					}
-				}
-			} else {
-				writing = 0;
-			}
-		}
-
-		ap_reset_timeout(r);
+		/*
+		 *	soak up any body-text sent by the Interchange server
+		 */
+		ap_soft_timeout("mod_interchange: Interchange read",r);
+		while (ap_bgets(argsbuffer,HUGE_STRING_LEN,ic_buff) > 0)
+			;
+		ap_kill_timeout(r);
+
+		/*
+		 *	always use the GET method for internal redirects
+		 *	also, unset the Content-Length so that nothing
+		 *	else tries to re-read the text we just soaked up
+		 */
+		r->method = ap_pstrdup(r->pool,"GET");
+		r->method_number = M_GET;
+		ap_table_unset(r->headers_in,"Content-Length");
+		ap_internal_redirect(location,r);
+		return OK;
 	}
 
-	/* Push everything to the client */
-	if ( ap_bflush( client_buff ) < 0 ) {
-		ap_log_reason( "error sending response to client", r->uri, r);
+	/*
+	 *	we were not redirected, so send the HTTP headers
+	 *	to the client
+	 */
+	ap_hard_timeout("mod_interchange: Client write",r);
+	ap_send_http_header(r);
+	if (ap_rflush(r) < 0){
+		ap_log_reason("error sending headers to client",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
 
+	/*
+	 *	if Interchange is sending body text (HTML), then
+	 *	relay this to the client
+	 */
+	if (!r->header_only){
+		ap_reset_timeout(r);
+		if ((rc = ap_bnonblock(ic_buff,B_RD)) != 0){
+			ap_log_reason("error turning non blocking I/O on Interchange socket",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
+		ap_bsetflag(ic_buff,B_SAFEREAD,1);
+		if (ap_send_fb(ic_buff,r) <= 0){
+			ap_log_reason("error sending response body to client",r->uri,r);
+			return HTTP_INTERNAL_SERVER_ERROR;
+		}
+	}
 	ap_kill_timeout(r);
 	return OK;
 }
 
-static int
-ic_handler( request_rec *r)
+/*
+ *	ic_handler()
+ *	------------
+ *	module content handler
+ */
+static int ic_handler(request_rec *r)
 {
 	ic_conf_rec *conf_rec;
 	BUFF *ic_buff;
-	int result;
+	int i,rc;
+
+	if (r->method_number == M_OPTIONS){
+		r->allowed |= (1 << M_GET);
+		r->allowed |= (1 << M_PUT);
+		r->allowed |= (1 << M_POST);
+		return DECLINED;
+	}
+
+	if ((rc = ap_setup_client_block(r,REQUEST_CHUNKED_ERROR)) != OK)
+		return rc;
 
-	/* Grab our configuration */
-	conf_rec = (ic_conf_rec *)ap_get_module_config( r->per_dir_config,
-													&interchange_module );
-	if ( ! conf_rec ) {
-		ap_log_reason( "interchange-handler not configured properly",
-					   r->uri, r);
+	/*
+	 *	get our configuration
+	 */
+	conf_rec = (ic_conf_rec *)ap_get_module_config(r->per_dir_config,&interchange_module);
+	if (!conf_rec){
+		ap_log_reason("interchange-handler not configured properly",r->uri,r);
 		return HTTP_INTERNAL_SERVER_ERROR;
 	}
 
-	ic_buff = ic_connect( r, conf_rec );
-	if ( !ic_buff )
+	/*
+	 *	check if the requested URI matches strings
+	 *	in the drop list
+	 */
+	for (i = 0; i < conf_rec->droplist_no; i++){
+		if (strstr(r->uri,conf_rec->droplist[i])){
+			ap_log_reason("interchange-handler match found in the drop list",r->uri,r);
+			ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Requested URI (%s) matches drop list entry (%s)",r->uri,conf_rec->droplist[i]);
+			return DECLINED;
+		}
+	}
+
+	/*
+	 *	connect to the Interchange server
+	 */
+	ic_buff = ic_connect(r,conf_rec);
+	if (!ic_buff)
 		return HTTP_INTERNAL_SERVER_ERROR;
 
-	result = ic_send_request( r, conf_rec, ic_buff );
-	if ( result != OK )
-		return result;
+	/*
+	 *	send the client's request to Interchange
+	 */
+	rc = ic_send_request(r,conf_rec,ic_buff);
 
-	return ic_transfer_response( r, conf_rec, ic_buff );
+	/*
+	 *	receive the response from the Interchange server
+	 *	and relay that response to the client
+	 */
+	if (rc == OK)
+		rc = ic_transfer_response(r,ic_buff);
+
+	/*
+	 *	close the Interchange socket and return
+	 */
+	ap_bclose(ic_buff);
+	return rc;
 }
 
-/* Our configuration directives */
-static command_rec ic_cmds[] =
-{
-    {
-    "InterchangeServer",			/* directive name */
-    ic_server_cmd,					/* config action routine */
-    NULL,							/* argument to include in call */
-    ACCESS_CONF,					/* where available */
-    TAKE1,							/* arguments */
-    "address of Interchange server"	/* directive description */
-    },
+/*
+ *	the module's configuration directives
+ */
+static command_rec ic_cmds[] ={
+	{
+		"InterchangeServer",	/* directive name */
+		ic_server_cmd,		/* config action routine */
+		NULL,			/* argument to include in call */
+		ACCESS_CONF,		/* where available */
+		TAKE1,			/* arguments */
+		"Address of the primary Interchange server - for use in a <Location> block"
+					/* directive description */
+	},
+	{
+		"InterchangeServerBackup",	/* directive name */
+		ic_serverbackup_cmd,		/* config action routine */
+		NULL,			/* argument to include in call */
+		ACCESS_CONF,		/* where available */
+		TAKE1,			/* arguments */
+		"Address of the backup Interchange server - for use in a <Location> block"
+					/* directive description */
+	},
+	{
+		"ConnectTries",		/* directive name */
+		ic_connecttries_cmd,	/* config action routine */
+		NULL,			/* argument to include in call */
+		ACCESS_CONF,		/* where available */
+		TAKE1,			/* arguments */
+		"The number of connection attempts to make before giving up"
+					/* directive description */
+	},
+	{
+		"ConnectRetryDelay",	/* directive name */
+		ic_connectretrydelay_cmd, /* config action routine */
+		NULL,			/* argument to include in call */
+		ACCESS_CONF,		/* where available */
+		TAKE1,			/* arguments */
+		"The number of connection attempts to make before giving up"
+					/* directive description */
+	},
+	{
+		"DropRequestList",	/* directive name */
+		ic_droprequestlist_cmd,	/* config action routine */
+		NULL,			/* argument to include in call */
+		ACCESS_CONF,		/* where available */
+		ITERATE,		/* arguments */
+		"Drop the URI request if it contains the specified string"
+					/* directive description */
+	},
 	{NULL}
 };
 
-/* Make the name of the content handler known to Apache */
-static handler_rec ic_handlers[] = {
-    {"interchange-handler", ic_handler},
-    {NULL}
+/*
+ *	make the name of the content handler known to Apache
+ */
+static handler_rec ic_handlers[] ={
+	{"interchange-handler",ic_handler},
+	{NULL}
 };
 
-/* Tell Apache what phases of the transaction we handle */
-module MODULE_VAR_EXPORT interchange_module =
-{
-		STANDARD_MODULE_STUFF,
-		NULL,					/* module initializer                 */
-		ic_create_dir_config,	/* per-directory config creator       */
-		NULL,					/* dir config merger                  */
-		NULL,					/* server config creator              */
-		NULL,					/* server config merger               */
-		ic_cmds,				/* command table                      */
-		ic_handlers,			/* [7]  content handlers              */
-		NULL,					/* [2]  URI-to-filename translation   */
-		NULL,					/* [5]  check/validate user_id        */
-		NULL,					/* [6]  check user_id is valid *here* */
-		NULL,					/* [4]  check access by host address  */
-		NULL,					/* [7]  MIME type checker/setter      */
-		NULL,					/* [8]  fixups                        */
-		NULL,					/* [9]  logger                        */
-		NULL,					/* [3]  header parser                 */
-		NULL,					/* process initialization             */
-		NULL,					/* process exit/cleanup               */
-		NULL					/* [1]  post read_request handling    */
+/*
+ *	tell Apache what phases of the transaction we handle
+ */
+module MODULE_VAR_EXPORT interchange_module ={
+	STANDARD_MODULE_STUFF,
+	ic_initialise,		/* module initialiser                 */
+	ic_create_dir_config,	/* per-directory config creator       */
+	NULL,			/* dir config merger                  */
+	NULL,			/* server config creator              */
+	NULL,			/* server config merger               */
+	ic_cmds,		/* command table                      */
+	ic_handlers,		/* [7]  content handlers              */
+	NULL,			/* [2]  URI-to-filename translation   */
+	NULL,			/* [5]  check/validate user_id        */
+	NULL,			/* [6]  check user_id is valid *here* */
+	NULL,			/* [4]  check access by host address  */
+	NULL,			/* [7]  MIME type checker/setter      */
+	NULL,			/* [8]  fixups                        */
+	NULL,			/* [9]  logger                        */
+	NULL,			/* [3]  header parser                 */
+	NULL,			/* process initialization             */
+	NULL,			/* process exit/cleanup               */
+	NULL			/* [1]  post read_request handling    */
 };
+
+/*
+ *	vim:ts=8:sw=8
+ */



2.0.2.2   +481 -54   interchange/dist/src/mod_interchange/mod_interchange.html


rev 2.0.2.2, prev_rev 2.0.2.1
Index: mod_interchange.html
===================================================================
RCS file: /var/cvs/interchange/dist/src/mod_interchange/mod_interchange.html,v
retrieving revision 2.0.2.1
retrieving revision 2.0.2.2
diff -u -u -r2.0.2.1 -r2.0.2.2
--- mod_interchange.html	26 Nov 2002 03:21:09 -0000	2.0.2.1
+++ mod_interchange.html	23 Jan 2003 17:11:45 -0000	2.0.2.2
@@ -1,56 +1,483 @@
-<HTML>
-<HEAD>
-   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
-   <TITLE>Module mod_interchange</TITLE>
-</HEAD>
-<BODY>
-
-<H1>Module mod_interchange</H1>
-
-<H2>Interchange link module</H2>
-
-<p>This module replaces the <tt>tlink</tt> and <tt>vlink</tt> programs
-that come with <a href="http://www.icdevgroup.org/">Interchange</a>.</p>
-
-<P>This modules requires Apache 1.3.6 or greater, and works with any
-version of Interchange (back to MiniVend 3.12).</p>
-
-<P>&nbsp;</P>        
-
-<P><A href="#example">Configuration example</A></p>
-
-<H2>Directives</H2>
-
-<ul>
-<li><A href="#server">InterchangeServer</A></li>
-</ul>
-
-<hr>
-<h2>
-<A name="server"></A>InterchangeServer</H2>
-<B>Syntax:</B> InterchangeServer <I>address</I>
-<BR><B>Context:</B> Directory
-<BR><B>Override:</B> None
-<BR><B>Status:</B> Extension
-
-<p>Specifies the way to connect to the Interchange server.</p>
-
-<HR>
-<H2>
-<A NAME="example"></A>Example</H2>
-Here is an example UNIX configuration:
-
-<PRE>&lt;Location /store&gt;
-   SetHandler interchange-handler
-   InterchangeServer /var/run/interchange/socket
-&lt;/Location&gt;</PRE>
-
-and here is an INET example:
-
-<PRE>&lt;Location /store&gt;
-   SetHandler interchange-handler
-   InterchangeServer ic.host.com:7786
-&lt;/Location&gt;</PRE>
-
+<!-- $Id: mod_interchange.html,v 2.0.2.2 2003/01/23 17:11:45 jon Exp $ -->
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Apache module: mod_interchange (version 1.29)</title>
+</head>
+<body bgcolor="#FFFFFF" text="#000000">
+    <h1>Apache module: mod_interchange (version 1.29)</h1>
+    <h2>Apache link module for Interchange</h2>
+    <p>
+	This module replaces the <i>tlink</i> and <i>vlink</i> programs
+	that come with <a href="http://www.icdevgroup.org/">Interchange</a>.&nbsp;
+	It has been tested with all Interchange versions up to and
+	including 4.9.6 (development).&nbsp;
+	Although this module is known to have worked with MiniVend versions 3
+	and 4, its current compatibility has not been tested.
+    </p>
+    <p>
+	This module has been tested with Apache versions 1.3.6
+	through 1.3.26.&nbsp;
+	<b>Note that this module is not compatible with Apache 2.</b>
+    </p>
+
+    <h2>Contents</h2>
+    <ol>
+	<li>Module Directives:
+	    <ul>
+		<li><a href="#server">InterchangeServer</a></li>
+		<li><a href="#serverbackup">InterchangeServerBackup</a></li>
+		<li><a href="#tries">ConnectTries</a></li>
+		<li><a href="#retrydelay">ConnectRetryDelay</a></li>
+		<li><a href="#droplist">DropRequestList</a></li>
+	    </ul>
+	    <br>
+	</li>
+	<li><a href="#example">Configuration Examples</a></li>
+	<li><a href="#copyright">Copyright and License</a></li>
+    </ol>
+
+    <hr>
+    <h2><a name="server">InterchangeServer</a></h2>
+    <b>Syntax:</b> <code>InterchangeServer <i>address</i></code>
+    <br><b>Context:</b> Location
+    <br><b>Override:</b> None
+    <br><b>Status:</b> Extension
+    <p>
+	Specifies the way Apache should connect to the primary
+	Interchange server.
+    </p>
+
+    <h2><a name="serverbackup">InterchangeServerBackup</a></h2>
+    <b>Syntax:</b> <code>InterchangeServerBackup <i>address</i></code>
+    <br><b>Context:</b> Location
+    <br><b>Override:</b> None
+    <br><b>Status:</b> Extension
+    <p>
+	Specifies the way Apache should connect to the backup
+	Interchange server in the event that the primary server is
+	unavailable for any reason.
+    </p><p>
+	InterchangeServerBackup takes the same arguments as the
+	InterchangeServer directive but should obviously point to a
+	different Interchange server than the primary.&nbsp;
+	The InterchangeServerBackup directive is only of any use if you
+	have multiple Interchange servers configured in a clustered
+	environment.
+    </p>
+
+    <h2><a name="tries">ConnectTries</a></h2>
+    <b>Syntax:</b> <code>ConnectTries <i>number</i></code>
+    <br><b>Context:</b> Location
+    <br><b>Override:</b> None
+    <br><b>Status:</b> Extension
+    <p>
+	Number of connection attempts to make before giving up.&nbsp;
+	The default is 10.
+    </p>
+
+    <h2><a name="retrydelay">ConnectRetryDelay</a></h2>
+    <b>Syntax:</b> <code>ConnectRetryDelay <i>seconds</i></code>
+    <br><b>Context:</b> Location
+    <br><b>Override:</b> None
+    <br><b>Status:</b> Extension
+    <p>
+	Delay, in seconds, between each retry attempt.&nbsp;
+	The default is 2.
+    </p>
+
+    <h2><a name="droplist">DropRequestList</a></h2>
+    <b>Syntax:</b> <code>DropRequestList <i>entry entry entry</i></code>
+    <br><b>Context:</b> Location
+    <br><b>Override:</b> None
+    <br><b>Status:</b> Extension
+    <p>
+	Space-separated list of URI path components to deny access to.&nbsp;
+	Various attacks are made on Microsoft IIS systems and, while they
+	don't affect Apache, they do tend to waste valuable processor time.
+    </p><p>
+	If any of the entries in the list are found anywhere in the requested
+	URI, the request will be dropped with a 404 (not found) error.
+    </p><p>
+	A maximum of 10 entries may be present in the list.&nbsp;
+	Any other entries will be ignored.&nbsp;
+	If you need more than 10 entries, edit the <code>IC_DROPLIST_NO</code>
+	value in <code>mod_interchange.c</code> and recompile the module.&nbsp;
+	See the example below for a common use of this directive.
+    </p>
+
+    <hr>
+    <h2><a name="example">Configuration Examples</a></h2>
+    <p>
+	Note: The Apache <Location> URI path should not contain a dot (.) or
+	any other characters except A-Z, a-z, 0-9 or a hyphen (-), so:
+    </p><p>
+	<code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<b>Location</b> <i>/shop.name</i>&gt</code>&nbsp; is invalid, whereas:<br>
+	<code>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<b>Location</b> <i>/shop-name</i>&gt</code>&nbsp; is valid.
+    </p><p>
+	Here is an example UNIX-socket configuration:
+    </p>
+    <code>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;Location</b> <i>/shop</i><b>&gt;</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>SetHandler interchange-handler</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServer</b> <i>/opt/interchange/etc/socket</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/Location&gt;</b><br>
+    </code>
+    <p>
+	Here is an INET-socket example:
+    </p>
+    <code>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;Location</b> <i>/shop</i><b>&gt;</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>SetHandler interchange-handler</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/Location&gt;</b><br>
+    </code>
+    <p>
+	UNIX-socket local primary connection and INET-socket remote backup
+	connection:
+    </p>
+    <code>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;Location</b> <i>/shop</i><b>&gt;</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>SetHandler interchange-handler</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServer</b> <i>/opt/interchange/etc/socket</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServerBackup</b> <i>another.server.com</i>:<i>7786</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/Location&gt;</b><br>
+    </code>
+    <p>
+	Two parameters control what happens when mod_interchange
+	fails to connect to the Interchange server.&nbsp;
+	The most likely reason for a failure to connect is that Interchange
+	is being restarted by the administrator.
+    </p><p>
+	<b>ConnectTries</b> specifies the number of connection attempts
+	to make before giving up.&nbsp;
+	The default is 10.&nbsp;
+	<b>ConnectRetryDelay</b> specifies the delay, in seconds, between each
+	retry attempt.&nbsp;
+	The default is 2.&nbsp;
+	Connection retry example:
+    </p>
+    <code>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;Location</b> <i>/shop</i><b>&gt;</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>SetHandler interchange-handler</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>ConnectTries</b> <i>10</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>ConnectRetryDelay</b> <i>1</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/Location&gt;</b><br>
+    </code>
+    <p>
+	If an <b>InterchangeServerBackup</b> directive has been specified
+	then the backup server will be tried immediately after an attempt
+	to contact the primary server fails.&nbsp;
+	The <b>ConnectTries</b> and <b>ConnectRetryDelay</b> paramaters will
+	only come into affect if both the primary and backup Interchange
+	servers are found to be unavailable.
+    </p><p>
+	The <b>DropRequestList</b> allows a list of up to 10 space-separated URI
+	components to be specified.&nbsp;
+	If any of the list entries is found anywhere in the requested URI,
+	the request will be dropped with a 404 (not found) error, without
+	the request being passed to Interchange.&nbsp;
+	This parameter is useful for blocking known Microsoft IIS attacks,
+	such as &quot;Code Red&quot;, so that we don't waste any more time processing
+	these bogus requests than we have to.&nbsp;
+	<b>DropRequestList</b> example:
+    </p>
+    <code>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;Location</b> <i>/shop</i><b>&gt;</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>SetHandler interchange-handler</b><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>DropRequestList</b> <i>/default.ida /x.ida /cmd.exe /root.exe</i><br>
+	&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/Location&gt;</b><br>
+    </code>
+
+    <br><hr>
+    <h2><a name="changelog">Change Log</a></h2>
+    <ul>
+	<li>
+	    1.29
+	    (Thu 09 Jan 2003)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Fixed a bug reported by Jeff Dafoe.&nbsp;
+		    The request information enabled Interchange to show the
+		    correct page but prevented it from storing the request in
+		    the session's history.&nbsp;
+		    The problem only showed itself when Interchange's
+		    [history-scan] tag was used.&nbsp;
+		    As almost no page history was saved, [history-scan] sent
+		    the user to the default page (usually index) most of the
+		    time.&nbsp;
+		    This bug seems to have originated in version 1.28.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.28
+	    (Thu 09 Jan 2003)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Fixed a weird bug where empty HTTP variables were being
+		    passed under certain circumstances.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.27
+	    (Wed 27 Nov 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Implemented a proper (automatic) URILevels mechanism and
+		    removed the URILevels configuration directive.&nbsp;
+		    This also fixes a bug, reported by Philip Hempel in the
+		    interchange-users mail list, where [PT] redirects were
+		    not being handled correctly.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.26
+	    (Sun 03 Nov 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added proper support for internal redirects which will
+		    help with the security of "soft product" delivery.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.25
+	    (Sat 02 Nov 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Fixed a bug reported by Jeff Dafoe.&nbsp;
+		    There are some instances where the socket to Interchange
+		    may not be closed upon error.&nbsp;
+		    While I'm reasonably certain that Apache will handle
+		    this for us, it doesn't hurt to ensure that the socket
+		    is closed.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.24
+	    (Mon 31 Oct 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Fixed a bug reported by Shawn Mathews.&nbsp;
+		    The URILevels directive was not taken into account when
+		    munging the PATH_INFO HTTP environment variable.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.23
+	    (Wed 02 Oct 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added the module identification to the Apache version
+		    string so that it shows up in the "Server:" response
+		    header field when Apache is configured to show version
+		    information.&nbsp;
+		    Of course, suitably paranoid system administrators should
+		    configure Apache so that it doesn't release unnecessay
+		    server information.&nbsp;
+		    Any competent adminsitrator should know what module
+		    versions they have anyway. :-)
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.22
+	    (Mon 05 Aug 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Fixed a bug reported by John Young.&nbsp;
+		    Mod_interchange was not decoding entities in the
+		    REQUEST_URI, which caused Interchange searches (scan)
+		    with encoded spaces to fail.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.21
+	    (Mon 01 Apr 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added Support for Solaris 8 with a patch supplied
+		    by John Young.&nbsp;
+		    Apparently Solaris doesn't have the <code>AF_LOCAL</code>,
+		    <code>PF_LOCAL</code> or <code>SUN_LEN</code> macros.&nbsp;
+		    John's patch conditionally <code>#define</code>s the
+		    missing <code>_LOCAL</code> macros as aliases for
+		    <code>AF_UNIX</code> and <code>PF_UNIX</code>, and
+		    conditionally <code>#define</code>s a <code>SUN_LEN</code>
+		    macro.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.20
+	    (Fri 15 Mar 2002)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added the <code>InterchangeServerBackup</code> module
+		    parameter to allow the module to automatically try a
+		    backup Interchange server if the primary is unavailable.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.14
+	    (Wed 26 Sep 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added the <code>DropRequestList</code> module parameter
+		    to stop Interchange from having to waste its time
+		    processing known IIS exploits.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.13
+	    (Wed 22 Aug 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added a retry loop so that connections delay for a while,
+		    instead of failing, while the Interchange server is being
+		    restarted.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.12
+	    (Sun 10 Aug 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added OS/X patch as it doesn't appear to have a typedef
+		    for <code>socklen_t</code>.&nbsp;
+		    The poor Apple <nobr>OS/X</nobr> users must un-comment the OSX line
+		    in the Makefile to the module to compile the definition in.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.11
+	    (Fri 20 Apr 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Added the <code>URILevels</code> parameter to allow for
+		    sites that need to specify <code>&lt;Location&gt;</code>s
+		    that have more than one directory level.&nbsp;
+		    The default <code>URILevel</code> is 1.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.10
+	    (Tue 27 Feb 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Rewrote the <code>ic_send_request()</code> and
+		    <code>ic_transfer_response()</code> functions because
+		    they were giving all sorts of <code>EPIPE</code> errors
+		    when writing data to clients during a concurrent-user
+		    test.&nbsp;
+		    Testing tools used were ab (ApacheBench/1.3) and httperf.&nbsp;
+		    We have now lost the &quot;connreset&quot; errors that
+		    were reported by httperf as well as the associated
+		    &quot;broken pipe&quot; meessages in the Apache error logs.&nbsp;
+		    The module now stands up properly when placed under a heavy
+		    load.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.05
+	    (Mon 29 Jan 2001)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Nothing more than a rename from <code>mod_minivend</code>
+		    to <code>mod_interchange</code>.&nbsp;
+		    (Changed &quot;<code>mv_</code>&quot; function names to
+		    &quot;<code>ic_</code>&quot; etc.)
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.04
+	    (Tue 23 May 2000)
+	    Kevin Walsh &lt;kevin@cursor.biz&gt;<br>
+	    <ul>
+		<li>
+		    Changed to make the module work with Apache name-based
+		    <code>&lt;VirtualHost&gt;</code> entries that have been
+		    configured with the Apache <code>ServerPath</code>
+		    directive.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.03-1i
+	    (Mon 02 Aug 1999)
+	    Francis J. Lacoste &lt;francis.lacoste@iNsu.COM&gt;<br>
+	    <ul>
+		<li>
+		    Last bugfixes.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.02-1i
+	    (Mon 02 Aug 1999)
+	    Francis J. Lacoste &lt;francis.lacoste@iNsu.COM&gt;<br>
+	    <ul>
+		<li>
+		    Fixed spec files bugs.
+		</li>
+	    </ul>
+	    <br>
+	</li><li>
+	    1.00-1i
+	    (Mon 02 Aug 1999)
+	    Francis J. Lacoste &lt;francis.lacoste@iNsu.COM&gt;<br>
+	    <ul>
+		<li>
+		    Packaged for iNs/linux.
+		</li>
+	    </ul>
+	</li>
+    </ul>
+
+    <br><hr>
+    <h2><a name="copyright">Copyright and License</a></h2>
+    <p>
+	Copyright &copy; 1999 Francis J. Lacoste and iNsu Innovations Inc.<br>
+	Copyright &copy; 2000-2003 Cursor Software Limited.<br>
+	All rights reserved.
+    </p><p>
+	This program is free software.&nbsp;
+	You can redistribute it and/or modify it under the terms of the
+	GNU General Public License as published by the Free Software
+	Foundation.&nbsp;
+	You may refer to either version 2 of the License or (at your option)
+	any later version.
+    </p>
 </body>
 </html>