[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> </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><Location /store>
- SetHandler interchange-handler
- InterchangeServer /var/run/interchange/socket
-</Location></PRE>
-
-and here is an INET example:
-
-<PRE><Location /store>
- SetHandler interchange-handler
- InterchangeServer ic.host.com:7786
-</Location></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>.
+ It has been tested with all Interchange versions up to and
+ including 4.9.6 (development).
+ 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.
+ <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.
+ 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.
+ 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.
+ 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.
+ 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.
+ Any other entries will be ignored.
+ 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.
+ 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> <<b>Location</b> <i>/shop.name</i>></code> is invalid, whereas:<br>
+ <code> <<b>Location</b> <i>/shop-name</i>></code> is valid.
+ </p><p>
+ Here is an example UNIX-socket configuration:
+ </p>
+ <code>
+ <b><Location</b> <i>/shop</i><b>></b><br>
+ <b>SetHandler interchange-handler</b><br>
+ <b>InterchangeServer</b> <i>/opt/interchange/etc/socket</i><br>
+ <b></Location></b><br>
+ </code>
+ <p>
+ Here is an INET-socket example:
+ </p>
+ <code>
+ <b><Location</b> <i>/shop</i><b>></b><br>
+ <b>SetHandler interchange-handler</b><br>
+ <b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+ <b></Location></b><br>
+ </code>
+ <p>
+ UNIX-socket local primary connection and INET-socket remote backup
+ connection:
+ </p>
+ <code>
+ <b><Location</b> <i>/shop</i><b>></b><br>
+ <b>SetHandler interchange-handler</b><br>
+ <b>InterchangeServer</b> <i>/opt/interchange/etc/socket</i><br>
+ <b>InterchangeServerBackup</b> <i>another.server.com</i>:<i>7786</i><br>
+ <b></Location></b><br>
+ </code>
+ <p>
+ Two parameters control what happens when mod_interchange
+ fails to connect to the Interchange server.
+ 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.
+ The default is 10.
+ <b>ConnectRetryDelay</b> specifies the delay, in seconds, between each
+ retry attempt.
+ The default is 2.
+ Connection retry example:
+ </p>
+ <code>
+ <b><Location</b> <i>/shop</i><b>></b><br>
+ <b>SetHandler interchange-handler</b><br>
+ <b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+ <b>ConnectTries</b> <i>10</i><br>
+ <b>ConnectRetryDelay</b> <i>1</i><br>
+ <b></Location></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.
+ 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.
+ 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.
+ This parameter is useful for blocking known Microsoft IIS attacks,
+ such as "Code Red", so that we don't waste any more time processing
+ these bogus requests than we have to.
+ <b>DropRequestList</b> example:
+ </p>
+ <code>
+ <b><Location</b> <i>/shop</i><b>></b><br>
+ <b>SetHandler interchange-handler</b><br>
+ <b>InterchangeServer</b> <i>localhost</i>:<i>7786</i><br>
+ <b>DropRequestList</b> <i>/default.ida /x.ida /cmd.exe /root.exe</i><br>
+ <b></Location></b><br>
+ </code>
+
+ <br><hr>
+ <h2><a name="changelog">Change Log</a></h2>
+ <ul>
+ <li>
+ 1.29
+ (Thu 09 Jan 2003)
+ Kevin Walsh <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Fixed a bug reported by Jeff Dafoe.
+ The request information enabled Interchange to show the
+ correct page but prevented it from storing the request in
+ the session's history.
+ The problem only showed itself when Interchange's
+ [history-scan] tag was used.
+ As almost no page history was saved, [history-scan] sent
+ the user to the default page (usually index) most of the
+ time.
+ This bug seems to have originated in version 1.28.
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.28
+ (Thu 09 Jan 2003)
+ Kevin Walsh <kevin@cursor.biz><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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Implemented a proper (automatic) URILevels mechanism and
+ removed the URILevels configuration directive.
+ 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 <kevin@cursor.biz><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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Fixed a bug reported by Jeff Dafoe.
+ There are some instances where the socket to Interchange
+ may not be closed upon error.
+ 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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Fixed a bug reported by Shawn Mathews.
+ 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 <kevin@cursor.biz><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.
+ Of course, suitably paranoid system administrators should
+ configure Apache so that it doesn't release unnecessay
+ server information.
+ Any competent adminsitrator should know what module
+ versions they have anyway. :-)
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.22
+ (Mon 05 Aug 2002)
+ Kevin Walsh <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Fixed a bug reported by John Young.
+ 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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Added Support for Solaris 8 with a patch supplied
+ by John Young.
+ Apparently Solaris doesn't have the <code>AF_LOCAL</code>,
+ <code>PF_LOCAL</code> or <code>SUN_LEN</code> macros.
+ 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 <kevin@cursor.biz><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 <kevin@cursor.biz><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 <kevin@cursor.biz><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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Added OS/X patch as it doesn't appear to have a typedef
+ for <code>socklen_t</code>.
+ 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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Added the <code>URILevels</code> parameter to allow for
+ sites that need to specify <code><Location></code>s
+ that have more than one directory level.
+ The default <code>URILevel</code> is 1.
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.10
+ (Tue 27 Feb 2001)
+ Kevin Walsh <kevin@cursor.biz><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.
+ Testing tools used were ab (ApacheBench/1.3) and httperf.
+ We have now lost the "connreset" errors that
+ were reported by httperf as well as the associated
+ "broken pipe" meessages in the Apache error logs.
+ 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 <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Nothing more than a rename from <code>mod_minivend</code>
+ to <code>mod_interchange</code>.
+ (Changed "<code>mv_</code>" function names to
+ "<code>ic_</code>" etc.)
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.04
+ (Tue 23 May 2000)
+ Kevin Walsh <kevin@cursor.biz><br>
+ <ul>
+ <li>
+ Changed to make the module work with Apache name-based
+ <code><VirtualHost></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 <francis.lacoste@iNsu.COM><br>
+ <ul>
+ <li>
+ Last bugfixes.
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.02-1i
+ (Mon 02 Aug 1999)
+ Francis J. Lacoste <francis.lacoste@iNsu.COM><br>
+ <ul>
+ <li>
+ Fixed spec files bugs.
+ </li>
+ </ul>
+ <br>
+ </li><li>
+ 1.00-1i
+ (Mon 02 Aug 1999)
+ Francis J. Lacoste <francis.lacoste@iNsu.COM><br>
+ <ul>
+ <li>
+ Packaged for iNs/linux.
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <br><hr>
+ <h2><a name="copyright">Copyright and License</a></h2>
+ <p>
+ Copyright © 1999 Francis J. Lacoste and iNsu Innovations Inc.<br>
+ Copyright © 2000-2003 Cursor Software Limited.<br>
+ All rights reserved.
+ </p><p>
+ 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.
+ You may refer to either version 2 of the License or (at your option)
+ any later version.
+ </p>
</body>
</html>