[Date Prev][Date Next][Thread Prev][Thread Next][Interchange by date
][Interchange by thread
]
[ic] 2002-07-30 debian unstable w/mod_ssl breaks vanilla mod_interchange
Today's apt-get upgrade broke apache/mod_ssl and the vanilla
mod_interchange setup our our debian linux unstable machines.
The infamous:
Tue Jul 30 12:05:56 2002] [error] mod_ssl: SSL error on writing data (OpenSSL library error follows)
[Tue Jul 30 12:05:56 2002] [error] OpenSSL: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
[Tue Jul 30 12:05:56 2002] [error] access to /Catalog/slash.cgi/order failed for 68.10.169.9, reason: error while sending response
The catalogs worked just fine for Mozilla, but broke in random places
on IE. Go figure.
The fix was the new mod_interchange from kevin@cursor.
We had to modify that, however, **removing** a number of fixups from
the code, breaking at least the URILevels. The version we got working
is below sig.
--
Christopher F. Miller, Publisher cfm@maine.com
MaineStreet Communications, Inc 208 Portland Road, Gray, ME 04039
1.207.657.5078 http://www.maine.com/
Content/site management, online commerce, internet integration, Debian linux
/*
* $Id: mod_interchange.c,v 1.5 2002/04/23 04:15:37 kevin Exp $
*
* Apache Module implementation of the Interchange application server
* link programs.
*
* Version: 1.21
*
* Author: Kevin Walsh <kevin@cursor.biz>
* Based on original code by Francis J. Lacoste <francis.lacoste@iNsu.COM>
*
* Copyright (c) 1999 Francis J. Lacoste, iNsu Innovations.
* Copyright (c) 2000-2002 Cursor Software Limited.
* All rights reserved.
*
* 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.
*
* 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"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "util_script.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#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_LEVELS 1
#define IC_DEFAULT_CONNECT_TRIES 10
#define IC_DEFAULT_CONNECT_RETRY_DELAY 2
#define IC_MAX_DROPLIST 10
#define IC_MAX_SERVERS 2
module MODULE_VAR_EXPORT interchange_module;
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 levels; /* URI directory levels to pass to IC */
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;
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_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_urilevels_cmd(cmd_parms *,void *,const char *);
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 *);
/*
* 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 i;
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;
inet_sock->sin_family = AF_INET;
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->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 (i = 1; i < IC_MAX_SERVERS; i++)
conf_rec->server[i] = (ic_socket_rec *)NULL;
conf_rec->levels = 1;
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;
}
/*
* ic_server_cmd()
* ---------------
* Handle the "InterchangeServer" module configuration directive
*/
static const char *ic_server_cmd(cmd_parms *parms,void *mconfig,const char *arg)
{
return ic_server_setup(parms,mconfig,0,arg);
}
/*
* 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;
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";
return ic_server_setup(parms,mconfig,1,arg);
}
/*
* 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];
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;
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->sin_family = AF_INET;
hostaddress = &(sock_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";
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 <= 100 || port > 65535)
return "invalid port specification";
inet_sock->sin_port = htons(port);
}else{
inet_sock->sin_port = htons(IC_DEFAULT_PORT);
}
sock_rec->sockaddr = (struct sockaddr *)inet_sock;
sock_rec->family = PF_INET;
sock_rec->size = sizeof(struct sockaddr_in);
}
return NULL;
}
/*
* ic_urilevels_cmd()
* ------------------
* Handle the "URILevels" module configuration directive
*/
static const char *ic_urilevels_cmd(cmd_parms *parms,void *mconfig,const char *arg)
{
ic_conf_rec *conf_rec = (ic_conf_rec *)mconfig;
conf_rec->levels = atoi(arg);
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;
}
/*
* ic_connect()
* ------------
* Connect to the Interchange server
*/
static BUFF *ic_connect(request_rec *r,ic_conf_rec *conf_rec)
{
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);
}
/*
* 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);
}
ap_kill_timeout(r);
if (retry == conf_rec->connect_tries){
ap_log_reason("Connection failed",r->uri,r);
return NULL;
}
/*
* 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);
return 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)
{
fd_set sock_set_rd,sock_set_wr;
fd_set *rd = NULL,*wr = NULL;
struct timeval tv;
int rc;
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;
}
/*
* 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;
int env_count,rc,level;
char request_uri[HUGE_STRING_LEN],*rurip = request_uri;
request_uri[0] = '\0';
/*
* send the Interchange-link arg parameter
* (this is always empty for a CGI request)
*/
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);
/*
* 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);
/*
* count the number of environment variables present
* (ignore the PATH_INFO and REDIRECT_* variables)
*/
for (e = env,env_count = 0; *e != NULL; e++,env_count++){
;
}
/* env_count++; cfm or do we need one for the count below? */
/*
* send the actual environment variables to Interchange
*
* 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);
level = conf_rec->levels;
for (e = env; *e != NULL; ++e){
/* ap_log_reason("ENV ",*e,r); */ /* cfm */
if (ap_bprintf(ic_buff,"%d %s\n",strlen(*e),*e) < 0){
ap_log_reason("error writing to Interchange",r->uri,r);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
ap_reset_timeout(r);
/*
* send the request body, if any
*/
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;
}
/*
* 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);
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;
}
/*
* 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;
}
}
/*
* all data has been sent, so send the "end" marker
*/
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;
}
ap_reset_timeout(r);
if (ap_bflush(ic_buff) < 0){
ap_log_reason("error flushing data to Interchange",r->uri,r);
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_kill_timeout(r);
/* ap_log_reason("DEBUG 99",r->uri,r); */
return OK;
}
/*
* 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;
BUFF *client_buff = r->connection->client;
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("Timeout on Interchange header read",r->uri,r);
return HTTP_INTERNAL_SERVER_ERROR;
}
/*
* 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;
}
/*
* 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;
/*
* check if we need to do an external redirect
* (this is usually the case if an Interchange
* [bounce] tag has been used)
*/
if (*location != '/')
return REDIRECT;
/*
* 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("Select timeout on Interchange socket read",r->uri,r);
return HTTP_INTERNAL_SERVER_ERROR;
}
/*
* 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_handler(location,r);
return OK;
}
/*
* 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);
/*
* close the Interchange socket and return
*/
ap_bclose(ic_buff);
return OK;
}
/*
* ic_handler()
* ------------
* module content handler
*/
static int ic_handler(request_rec *r)
{
ic_conf_rec *conf_rec;
BUFF *ic_buff;
int i,result;
if (r->method_number == M_OPTIONS){
r->allowed |= (1 << M_GET);
r->allowed |= (1 << M_POST);
return DECLINED;
}
if ((result = ap_setup_client_block(r,REQUEST_CHUNKED_ERROR)) != OK)
return result;
/*
* 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;
}
/*
* 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;
/*
* send the client's request to Interchange
*/
result = ic_send_request(r,conf_rec,ic_buff);
if (result != OK)
return result;
/*
* receive the response from the Interchange server
* and relay that response to the client
*/
return ic_transfer_response(r,ic_buff);
}
/*
* 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 */
},
{
"URILevels", /* directive name */
ic_urilevels_cmd, /* config action routine */
NULL, /* argument to include in call */
ACCESS_CONF, /* where available */
TAKE1, /* arguments */
"The number of URI directory levels to pass on to Interchange"
/* 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}
};
/*
* 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 */
};