##                      _             _ 
##  _ __ ___   ___   __| |    ___ ___| |  
## | '_ ` _ \ / _ \ / _` |   / __/ __| |  
## | | | | | | (_) | (_| |   \__ \__ \ | mod_ssl - Apache Interface to OpenSSL  
## |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.engelschall.com/sw/mod_ssl/
##                      |_____|         
## ____________________________________________________________________________
##
## Annotated mod_ssl patch file: eapi.patch
## Copyright (c) 1998-1999 Ralf S. Engelschall, All Rights Reserved. 
## Created on: 29-Mar-1999
##
## This file assembles changes to existing Apache source files
## between the original Apache and the patched variant. It can be
## automatically applied to a vanilla Apache source tree with the
## 'patch' tool to upgrade those files.  Each patch snippet is
## annotated with a short description.
##
## This file contains all patches to the Apache source
## tree which add the Extended API (EAPI) support.
##

+---------------------------------------------------------------------------
| Add the EAPI configuration rule which triggers the EAPI patches.
+---------------------------------------------------------------------------
Index: src/Configuration.tmpl
--- src/Configuration.tmpl	1999/01/10 10:46:32	1.1.1.4
+++ src/Configuration.tmpl	1999/03/21 18:29:56	1.15
@@ -160,12 +206,20 @@
 #  is performing this function. If PARANOID is set to yes, it will
 #  actually print-out the code that the modules execute
 #
+# EAPI:
+#  Enable the Extended API which provides more module hooks, a generic
+#  low-level hook mechanism and a generic context mechanism. Please notice
+#  that enabling this rule forces you to recompile (with -DEAPI) all existing
+#  modules which are already built and installed as DSOs.  Because under EAPI
+#  the module configuration structure has a different size.
+#
 
 Rule SOCKS4=no
 Rule SOCKS5=no
 Rule IRIXNIS=no
 Rule IRIXN32=yes
 Rule PARANOID=no
+Rule EAPI=no
 
 # The following rules should be set automatically by Configure. However, if
 # they are not set by Configure (because we don't know the correct value for

+---------------------------------------------------------------------------
| Patch in implementation of the EAPI rule.
+---------------------------------------------------------------------------
Index: src/Configure
--- src/Configure	1999/03/23 08:56:19	1.1.1.7
+++ src/Configure	1999/03/23 09:04:53	1.6
@@ -222,6 +222,7 @@
 RULE_IRIXNIS=`./helpers/CutRule IRIXNIS $file`
 RULE_IRIXN32=`./helpers/CutRule IRIXN32 $file`
 RULE_PARANOID=`./helpers/CutRule PARANOID $file`
+RULE_EAPI=`./helpers/CutRule EAPI $file`
 RULE_SHARED_CORE=`./helpers/CutRule SHARED_CORE $file`
 RULE_SHARED_CHAIN=`./helpers/CutRule SHARED_CHAIN $file`
 
@@ -1530,6 +1531,19 @@
     REGLIB="regex/libregex.a"
     SUBDIRS="regex $SUBDIRS"
     CFLAGS="$CFLAGS -DUSE_HSREGEX"
+fi
+
+####################################################################
+# Extended API support:
+if [ "$RULE_EAPI" = "yes" ]; then
+    echo " + enabling Extended API (EAPI)"
+    CFLAGS="$CFLAGS -DEAPI"
+    #   some vendor compilers are too restrictive
+    case "$OS:$CC" in
+        *IRIX-32*:*/cc|*IRIX-32*:cc )
+            CFLAGS="$CFLAGS -woff 1048,1110,1164"
+            ;;
+    esac
 fi
 
 ####################################################################

+---------------------------------------------------------------------------
| Add the build support for the ap_hook.c and ap_ctx.c sources (Unix)
+---------------------------------------------------------------------------
Index: src/ap/Makefile.tmpl
--- src/ap/Makefile.tmpl	1999/03/21 11:51:52	1.1.1.4
+++ src/ap/Makefile.tmpl	1999/03/21 12:00:10	1.3
@@ -6,7 +6,7 @@
 LIB=libap.a
 
 OBJS=ap_execve.o ap_cpystrn.o ap_signal.o \
-     ap_slack.o ap_snprintf.o ap_fnmatch.o ap_md5c.o
+     ap_slack.o ap_snprintf.o ap_fnmatch.o ap_md5c.o ap_hook.o ap_ctx.o
 
 .c.o:
 	$(CC) -c $(INCLUDES) $(CFLAGS) $<

+---------------------------------------------------------------------------
| Add the build support for the ap_hook.c and ap_ctx.c sources (Win32)
+---------------------------------------------------------------------------
Index: src/ap/ap.mak
--- src/ap/ap.mak	1999/03/21 11:51:52	1.1.1.4
+++ src/ap/ap.mak	1999/03/21 12:00:10	1.3
@@ -47,6 +47,8 @@
 	-@erase "$(INTDIR)\ap_cpystrn.obj"
 	-@erase "$(INTDIR)\ap_fnmatch.obj"
 	-@erase "$(INTDIR)\ap_md5c.obj"
+	-@erase "$(INTDIR)\ap_hook.obj"
+	-@erase "$(INTDIR)\ap_ctx.obj"
 	-@erase "$(INTDIR)\ap_signal.obj"
 	-@erase "$(INTDIR)\ap_slack.obj"
 	-@erase "$(INTDIR)\ap_snprintf.obj"
@@ -102,6 +104,8 @@
 	"$(INTDIR)\ap_cpystrn.obj" \
 	"$(INTDIR)\ap_fnmatch.obj" \
 	"$(INTDIR)\ap_md5c.obj" \
+	"$(INTDIR)\ap_hook.obj" \
+	"$(INTDIR)\ap_ctx.obj" \
 	"$(INTDIR)\ap_signal.obj" \
 	"$(INTDIR)\ap_slack.obj" \
 	"$(INTDIR)\ap_snprintf.obj"
@@ -133,6 +137,8 @@
 	-@erase "$(INTDIR)\ap_cpystrn.obj"
 	-@erase "$(INTDIR)\ap_fnmatch.obj"
 	-@erase "$(INTDIR)\ap_md5c.obj"
+	-@erase "$(INTDIR)\ap_hook.obj"
+	-@erase "$(INTDIR)\ap_ctx.obj"
 	-@erase "$(INTDIR)\ap_signal.obj"
 	-@erase "$(INTDIR)\ap_slack.obj"
 	-@erase "$(INTDIR)\ap_snprintf.obj"
@@ -188,6 +194,8 @@
 	"$(INTDIR)\ap_cpystrn.obj" \
 	"$(INTDIR)\ap_fnmatch.obj" \
 	"$(INTDIR)\ap_md5c.obj" \
+	"$(INTDIR)\ap_hook.obj" \
+	"$(INTDIR)\ap_ctx.obj" \
 	"$(INTDIR)\ap_signal.obj" \
 	"$(INTDIR)\ap_slack.obj" \
 	"$(INTDIR)\ap_snprintf.obj"

+---------------------------------------------------------------------------
| Replace the MODULE_MAGIC_COOKIE to allow us to distinguish between
| EAPI-aware modules and standard modules.
+---------------------------------------------------------------------------
Index: src/include/ap_mmn.h
--- src/include/ap_mmn.h	1999/03/21 11:52:04	1.1.1.4
+++ src/include/ap_mmn.h	1999/03/21 12:00:10	1.4
@@ -216,7 +216,23 @@
  * 19990320             - METHODS and M_INVALID symbol values modified
  */
 
+/* 
+ * Under Extended API situations we replace the magic cookie "AP13" with
+ * "EAPI" to let us distinguish between the EAPI module structure (which
+ * contain additional pointers at the end) and standard module structures
+ * (which lack at least NULL's for the pointers at the end).  This is
+ * important because standard ("AP13") modules would dump core when we
+ * dispatch over the additional hooks because NULL's are missing at the end of
+ * the module structure. See also the code in mod_so for details on loading
+ * (we accept both "AP13" and "EAPI").
+ */
+#ifdef EAPI
+#define MODULE_MAGIC_COOKIE_AP13 0x41503133UL /* "AP13" */
+#define MODULE_MAGIC_COOKIE_EAPI 0x45415049UL /* "EAPI" */
+#define MODULE_MAGIC_COOKIE      MODULE_MAGIC_COOKIE_EAPI 
+#else
 #define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
+#endif
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 19990320

+---------------------------------------------------------------------------
| Add the additional context variable `ctx' for BUFF structures.
+---------------------------------------------------------------------------
Index: src/include/buff.h
--- src/include/buff.h	1999/01/10 10:46:41	1.1.1.3
+++ src/include/buff.h	1999/01/10 11:07:22	1.6
@@ -124,6 +124,10 @@
     /* transport handle, for RPC binding handle or some such */
     void *t_handle;
 
+#ifdef EAPI
+    ap_ctx *ctx;
+#endif /* EAPI */
+
 #ifdef B_SFIO
     Sfio_t *sf_in;
     Sfio_t *sf_out;

+---------------------------------------------------------------------------
| Add the four additional Apache API module hooks.
+---------------------------------------------------------------------------
Index: src/include/http_config.h
--- src/include/http_config.h	1999/03/21 11:52:05	1.1.1.5
+++ src/include/http_config.h	1999/03/21 12:00:10	1.7
@@ -273,6 +273,65 @@
     void (*child_exit) (server_rec *, pool *);
 #endif
     int (*post_read_request) (request_rec *);
+
+#ifdef EAPI
+    /*
+     * ANSI C guarantees us that we can at least _extend_ the module structure
+     * with additional hooks without the need to change all existing modules.
+     * Because: ``If there are fewer initializers in the list than members of
+     * the structure, the trailing members are initialized with 0.'' (The C
+     * Programming Language, 2nd Ed., A8.7 Initialization). So we just
+     * have to put our additional hooks here:
+     *
+     * add_module: 
+     *     Called from within ap_add_module() right after the module structure
+     *     was linked into the Apache internal module list.  It is mainly
+     *     intended to be used to define configuration defines (<IfDefine>)
+     *     which have to be available directly after a LoadModule/AddModule.
+     *     Actually this is the earliest possible hook a module can use.
+     *
+     * remove_module: 
+     *     Called from within ap_remove_module() right before the module
+     *     structure is kicked out from the Apache internal module list.
+     *     Actually this is last possible hook a module can use and exists for
+     *     consistency with the add_module hook.
+     *
+     * rewrite_command:
+     *     Called right after a configuration directive line was read and
+     *     before it is processed. It is mainly intended to be used for
+     *     rewriting directives in order to provide backward compatibility to
+     *     old directive variants.
+     *
+     * new_connection:
+     *     Called from within the internal new_connection() function, right
+     *     after the conn_rec structure for the new established connection was
+     *     created and before Apache starts processing the request with
+     *     ap_read_request().  It is mainly intended to be used to setup/run
+     *     connection dependent things like sending start headers for
+     *     on-the-fly compression, etc.
+     *
+     * close_connection:
+     *     Called from within the Apache dispatching loop just before any
+     *     ap_bclose() is performed on the socket connection, but a long time
+     *     before any pool cleanups are done for the connection (which can be
+     *     too late for some applications).  It is mainly intended to be used
+     *     to close/finalize connection dependent things like sending end
+     *     headers for on-the-fly compression, etc.
+     */
+#ifdef ULTRIX_BRAIN_DEATH
+    void  (*add_module) ();
+    void  (*remove_module) ();
+    char *(*rewrite_command) ();
+    void  (*new_connection) ();
+    void  (*close_connection) ();
+#else
+    void  (*add_module) (struct module_struct *);
+    void  (*remove_module) (struct module_struct *);
+    char *(*rewrite_command) (cmd_parms *, void *config, const char *);
+    void  (*new_connection) (conn_rec *);
+    void  (*close_connection) (conn_rec *);
+#endif
+#endif /* EAPI */
 } module;
 
 /* Initializer for the first few module slots, which are only

+---------------------------------------------------------------------------
| Add the additional variable `ap_global_ctx' for holding
| global module context.
+---------------------------------------------------------------------------
Index: src/include/http_conf_globals.h
--- src/include/http_conf_globals.h	1999/01/10 10:46:42	1.1.1.4
+++ src/include/http_conf_globals.h	1999/01/10 11:07:22	1.5
@@ -86,6 +86,9 @@
 extern int ap_listenbacklog;
 extern int ap_dump_settings;
 extern API_VAR_EXPORT int ap_extended_status;
+#ifdef EAPI
+extern API_VAR_EXPORT ap_ctx *ap_global_ctx;
+#endif /* EAPI */
 
 extern char *ap_pid_fname;
 extern char *ap_scoreboard_fname;

+---------------------------------------------------------------------------
| Export the ap_set_callback_and_alarm() function because this
| first is a useful thing and second we need it because all
| other API/timeout functions deal with a request_rec while
| mod_ssl needs a generic timeout mechanism.
+---------------------------------------------------------------------------
Index: src/include/http_main.h
--- src/include/http_main.h	1999/01/10 10:46:43	1.1.1.3
+++ src/include/http_main.h	1999/01/10 11:07:22	1.3
@@ -124,7 +124,11 @@
 API_EXPORT(void) ap_sync_scoreboard_image(void);
 int ap_update_child_status(int child_num, int status, request_rec *r);
 void ap_time_process_request(int child_num, int status);
+#ifdef EAPI
+API_EXPORT(unsigned int) ap_set_callback_and_alarm(void (*fn) (int), int x);
+#else
 unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x);
+#endif
 API_EXPORT(int) ap_check_alarm(void);
 
 #ifndef NO_OTHER_CHILD

+---------------------------------------------------------------------------
| First add support for the HTTPS protocol scheme via hooks,
| second add the additional context variable `ctx' for the
| conn_rec, server_rec and request_rec structures. And third
| add a prototype for the additional ap_add_config_define()
| function.
+---------------------------------------------------------------------------
Index: src/include/httpd.h
--- src/include/httpd.h	1999/03/23 08:56:25	1.1.1.7
+++ src/include/httpd.h	1999/03/23 09:04:53	1.14
@@ -70,6 +70,15 @@
 
 #include "ap_config.h"
 #include "alloc.h"
+/*
+ * Include the Extended API headers.
+ * Don't move the position. It has to be after alloc.h because it uses the
+ * pool stuff but before buff.h because the buffer stuff uses the EAPI, too. 
+ */
+#ifdef EAPI
+#include "ap_hook.h"
+#include "ap_ctx.h"
+#endif /* EAPI */
 #include "buff.h"
 #include "ap.h"
 
@@ -136,8 +145,13 @@
 #define DEFAULT_HTTP_PORT	80
 #define DEFAULT_HTTPS_PORT	443
 #define ap_is_default_port(port,r)	((port) == ap_default_port(r))
+#ifdef EAPI
+#define ap_http_method(r)   (ap_ctx_get((r)->ctx, "ap::http::method") != NULL ? ((char *)ap_ctx_get((r)->ctx, "ap::http::method")) : "http")
+#define ap_default_port(r)  (ap_ctx_get((r)->ctx, "ap::default::port") != NULL ? atoi((char *)ap_ctx_get((r)->ctx, "ap::default::port")) : DEFAULT_HTTP_PORT)
+#else /* EAPI */
 #define ap_http_method(r)	"http"
 #define ap_default_port(r)	DEFAULT_HTTP_PORT
+#endif /* EAPI */
 
 /* --------- Default user name and group name running standalone ---------- */
 /* --- These may be specified as numbers by placing a # before a number --- */
@@ -424,6 +438,9 @@
 API_EXPORT(const char *) ap_get_server_version(void);
 API_EXPORT(void) ap_add_version_component(const char *component);
 API_EXPORT(const char *) ap_get_server_built(void);
+#ifdef EAPI
+API_EXPORT(void) ap_add_config_define(const char *define);
+#endif /* EAPI */
 
 /* Numeric release version identifier: MMNNFFRBB: major minor fix final beta
  * Always increases along the same track as the source branch.
@@ -778,6 +795,10 @@
  * record to improve 64bit alignment the next time we need to break
  * binary compatibility for some other reason.
  */
+
+#ifdef EAPI
+    ap_ctx *ctx;
+#endif /* EAPI */
 };
 
 
@@ -822,6 +843,10 @@
     signed int double_reverse:2;/* have we done double-reverse DNS?
 				 * -1 yes/failure, 0 not yet, 1 yes/success */
     int keepalives;		/* How many times have we used it? */
+
+#ifdef EAPI
+    ap_ctx *ctx;
+#endif /* EAPI */
 };
 
 /* Per-vhost config... */
@@ -894,6 +919,10 @@
     int limit_req_line;      /* limit on size of the HTTP request line    */
     int limit_req_fieldsize; /* limit on size of any request header field */
     int limit_req_fields;    /* limit on number of request header fields  */
+
+#ifdef EAPI
+    ap_ctx *ctx;
+#endif /* EAPI */
 };
 
 /* These are more like real hosts than virtual hosts */

+---------------------------------------------------------------------------
| Patch the low-level buffer routines to additionally allow
| modules to intercept the I/O processing via hooks.
+---------------------------------------------------------------------------
Index: src/main/buff.c
--- src/main/buff.c	1999/03/21 11:51:54	1.1.1.6
+++ src/main/buff.c	1999/03/21 12:00:11	1.14
@@ -125,7 +125,11 @@
   select() sometimes returns 1 even though the write will block. We must work around this.
 */
 
+#ifdef EAPI
+API_EXPORT(int) sendwithtimeout(int sock, const char *buf, int len, int flags)
+#else /* EAPI */
 int sendwithtimeout(int sock, const char *buf, int len, int flags)
+#endif /* EAPI */
 {
     int iostate = 1;
     fd_set fdset;
@@ -183,8 +187,11 @@
     return (rv);
 }
 
-
+#ifdef EAPI
+API_EXPORT(int) recvwithtimeout(int sock, char *buf, int len, int flags)
+#else /* EAPI */
 int recvwithtimeout(int sock, char *buf, int len, int flags)
+#endif /* EAPI */
 {
     int iostate = 1;
     fd_set fdset;
@@ -242,6 +249,9 @@
     }
     else
 #endif
+#ifdef EAPI
+	if (!ap_hook_call("ap::buff::read", &rv, fb, buf, nbyte))
+#endif /* EAPI */
 	rv = read(fb->fd_in, buf, nbyte);
     
     return rv;
@@ -253,6 +263,9 @@
 
 #if defined (WIN32)
     if (fb->flags & B_SOCKET) {
+#ifdef EAPI
+	if (!ap_hook_call("ap::buff::recvwithtimeout", &rv, fb, buf, nbyte))
+#endif /* EAPI */
 	rv = recvwithtimeout(fb->fd_in, buf, nbyte, 0);
 	if (rv == SOCKET_ERROR)
 	    errno = WSAGetLastError();
@@ -295,6 +308,9 @@
     }
     else
 #endif
+#ifdef EAPI
+	if (!ap_hook_call("ap::buff::write", &rv, fb, buf, nbyte))
+#endif /* EAPI */
 #if defined (B_SFIO)
 	rv = sfwrite(fb->sf_out, buf, nbyte);
 #else
@@ -310,6 +326,9 @@
 
 #if defined(WIN32)
     if (fb->flags & B_SOCKET) {
+#ifdef EAPI
+	if (!ap_hook_call("ap::buff::sendwithtimeout", &rv, fb, buf, nbyte))
+#endif /* EAPI */
 	rv = sendwithtimeout(fb->fd, buf, nbyte, 0);
 	if (rv == SOCKET_ERROR)
 	    errno = WSAGetLastError();
@@ -385,6 +404,10 @@
 		       (size_t) SF_UNBOUND, 1, SF_WRITE);
 #endif
 
+#ifdef EAPI
+    fb->ctx = ap_ctx_new(p);
+#endif /* EAPI */
+
     return fb;
 }
 
@@ -1041,6 +1064,9 @@
     i = 0;
     while (i < nvec) {
 	do
+#ifdef EAPI
+	    if (!ap_hook_call("ap::buff::writev", &rv, fb, &vec[i], nvec -i))
+#endif /* EAPI */
 	    rv = writev(fb->fd, &vec[i], nvec - i);
 	while (rv == -1 && (errno == EINTR || errno == EAGAIN)
 	       && !(fb->flags & B_EOUT));

+---------------------------------------------------------------------------
| Add the implementation of the additional `add_module' and
| `rewrite_command' module hooks. Additionally the `ctx'
| variables are initialized.
+---------------------------------------------------------------------------
Index: src/main/http_config.c
--- src/main/http_config.c	1999/03/21 11:51:55	1.1.1.6
+++ src/main/http_config.c	1999/03/21 12:00:11	1.9
@@ -583,6 +583,20 @@
 	m->name = tmp;
     }
 #endif /*_OSD_POSIX*/
+
+#ifdef EAPI
+    /*
+     * Invoke the `add_module' hook inside the now existing set
+     * of modules to let them all now that this module was added.
+     */
+    {
+        module *m2;
+        for (m2 = top_module; m2 != NULL; m2 = m2->next)
+            if (m2->magic == MODULE_MAGIC_COOKIE_EAPI)
+                if (m2->add_module != NULL)
+                    (*m2->add_module)(m);
+    }
+#endif /* EAPI */
 }
 
 /* 
@@ -597,6 +611,21 @@
 {
     module *modp;
 
+#ifdef EAPI
+    /*
+     * Invoke the `remove_module' hook inside the now existing
+     * set of modules to let them all now that this module is
+     * beeing removed.
+     */
+    {
+        module *m2;
+        for (m2 = top_module; m2 != NULL; m2 = m2->next)
+            if (m2->magic == MODULE_MAGIC_COOKIE_EAPI)
+                if (m2->remove_module != NULL)
+                    (*m2->remove_module)(m);
+    }
+#endif /* EAPI */
+
     modp = top_module;
     if (modp == m) {
 	/* We are the top module, special case */
@@ -966,6 +995,27 @@
     const command_rec *cmd;
     module *mod = top_module;
 
+#ifdef EAPI
+    /*
+     * Invoke the `rewrite_command' of modules to allow
+     * they to rewrite the directive line before we
+     * process it.
+     */
+    {
+        module *m;
+        char *cp;
+        for (m = top_module; m != NULL; m = m->next) {
+            if (m->magic == MODULE_MAGIC_COOKIE_EAPI) {
+                if (m->rewrite_command != NULL) {
+                    cp = (m->rewrite_command)(parms, config, l);
+                    if (cp != NULL)
+                        l = cp;
+                }
+            }
+        }
+    }
+#endif /* EAPI */
+
     if ((l[0] == '#') || (!l[0]))
 	return NULL;
 
@@ -1325,6 +1375,10 @@
     s->limit_req_fieldsize = main_server->limit_req_fieldsize;
     s->limit_req_fields = main_server->limit_req_fields;
 
+#ifdef EAPI
+    s->ctx = ap_ctx_new(p);
+#endif /* EAPI */
+
     *ps = s;
 
     return ap_parse_vhost_addrs(p, hostname, s);
@@ -1435,6 +1489,10 @@
 
     s->module_config = create_server_config(p, s);
     s->lookup_defaults = create_default_per_dir_config(p);
+
+#ifdef EAPI
+    s->ctx = ap_ctx_new(p);
+#endif /* EAPI */
 
     return s;
 }

+---------------------------------------------------------------------------
| Add the ap_global_ctx variable and the new
| ap_add_config_define() function. Additionally the
| implementation of the additional `new_connection' module hook
| is added plus the initialization of one more `ctx' variable.
+---------------------------------------------------------------------------
Index: src/main/http_main.c
--- src/main/http_main.c	1999/03/21 11:51:56	1.1.1.6
+++ src/main/http_main.c	1999/03/21 12:00:11	1.21
@@ -249,6 +249,9 @@
 int ap_listenbacklog;
 int ap_dump_settings = 0;
 API_VAR_EXPORT int ap_extended_status = 0;
+#ifdef EAPI
+API_VAR_EXPORT ap_ctx *ap_global_ctx;
+#endif /* EAPI */
 
 /*
  * The max child slot ever assigned, preserved across restarts.  Necessary
@@ -413,6 +416,30 @@
     }
 }
 
+#ifdef EAPI
+API_EXPORT(void) ap_add_config_define(const char *define)
+{
+    char **var;
+    var = (char **)ap_push_array(ap_server_config_defines);
+    *var = ap_pstrdup(pcommands, define);
+    return;
+}
+
+/*
+ * Invoke the `close_connection' hook of modules to let them do
+ * some connection dependent actions before we close it.
+ */
+static void ap_call_close_connection_hook(conn_rec *c)
+{
+    module *m;
+    for (m = top_module; m != NULL; m = m->next)
+        if (m->magic == MODULE_MAGIC_COOKIE_EAPI)
+            if (m->close_connection != NULL)
+                (*m->close_connection)(c);
+    return;
+}
+#endif /* EAPI */
+
 static APACHE_TLS int volatile exit_after_unblock = 0;
 
 #ifdef GPROF
@@ -1071,6 +1098,10 @@
 	if (!current_conn->keptalive)
 	    ap_log_transaction(log_req);
 
+#ifdef EAPI
+	ap_call_close_connection_hook(save_req->connection);
+#endif /* EAPI */
+
 	ap_bsetflag(save_req->connection->client, B_EOUT, 1);
 	ap_bclose(save_req->connection->client);
 
@@ -1080,6 +1111,9 @@
 	ap_longjmp(jmpbuffer, 1);
     }
     else {			/* abort the connection */
+#ifdef EAPI
+	ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 	ap_bsetflag(current_conn->client, B_EOUT, 1);
 	ap_bclose(current_conn->client);
 	current_conn->aborted = 1;
@@ -1136,7 +1170,11 @@
 }
 #endif
 
+#ifdef EAPI
+API_EXPORT(unsigned int) ap_set_callback_and_alarm(void (*fn) (int), int x)
+#else
 unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x)
+#endif
 {
     unsigned int old;
 
@@ -1351,10 +1389,16 @@
     /* Send any leftover data to the client, but never try to again */
 
     if (ap_bflush(r->connection->client) == -1) {
+#ifdef EAPI
+	ap_call_close_connection_hook(r->connection);
+#endif /* EAPI */
 	ap_kill_timeout(r);
 	ap_bclose(r->connection->client);
 	return;
     }
+#ifdef EAPI
+    ap_call_close_connection_hook(r->connection);
+#endif /* EAPI */
     ap_bsetflag(r->connection->client, B_EOUT, 1);
 
     /* Close our half of the connection --- send the client a FIN */
@@ -2972,7 +3016,25 @@
     conn->remote_addr = *remaddr;
     conn->remote_ip = ap_pstrdup(conn->pool,
 			      inet_ntoa(conn->remote_addr.sin_addr));
+#ifdef EAPI
+    conn->ctx = ap_ctx_new(conn->pool);
+#endif /* EAPI */
 
+#ifdef EAPI
+    /*
+     * Invoke the `new_connection' hook of modules to let them do
+     * some connection dependent actions before we go on with
+     * processing the request on this connection.
+     */
+    {
+        module *m;
+        for (m = top_module; m != NULL; m = m->next)
+            if (m->magic == MODULE_MAGIC_COOKIE_EAPI)
+                if (m->new_connection != NULL)
+                    (*m->new_connection)(conn);
+    }
+#endif /* EAPI */
+
     return conn;
 }
 
@@ -3342,6 +3404,9 @@
     printf("Server's Module Magic Number: %u:%u\n",
 	   MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR);
     printf("Server compiled with....\n");
+#ifdef EAPI
+    printf(" -D EAPI\n");
+#endif
 #ifdef BIG_SECURITY_HOLE
     printf(" -D BIG_SECURITY_HOLE\n");
 #endif
@@ -3487,6 +3552,22 @@
     ap_server_pre_read_config  = ap_make_array(pcommands, 1, sizeof(char *));
     ap_server_post_read_config = ap_make_array(pcommands, 1, sizeof(char *));
     ap_server_config_defines   = ap_make_array(pcommands, 1, sizeof(char *));
+
+#ifdef EAPI
+    ap_hook_init();
+    ap_hook_configure("ap::buff::read", 
+                      AP_HOOK_SIG4(int,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_configure("ap::buff::write",  
+                      AP_HOOK_SIG4(int,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_configure("ap::buff::writev",  
+                      AP_HOOK_SIG4(int,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_configure("ap::buff::sendwithtimeout", 
+                      AP_HOOK_SIG4(int,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_configure("ap::buff::recvwithtimeout", 
+                      AP_HOOK_SIG4(int,ptr,ptr,int), AP_HOOK_TOPMOST);
+
+    ap_global_ctx = ap_ctx_new(NULL);
+#endif /* EAPI */
 }
 
 #ifndef MULTITHREAD
@@ -3862,6 +3943,9 @@
 
 	    ap_sync_scoreboard_image();
 	    if (ap_scoreboard_image->global.running_generation != ap_my_generation) {
+#ifdef EAPI
+		ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 		ap_bclose(conn_io);
 		clean_child_exit(0);
 	    }
@@ -3890,6 +3974,9 @@
 	 */
 
 #ifdef NO_LINGCLOSE
+#ifdef EAPI
+	ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 	ap_bclose(conn_io);	/* just close it */
 #else
 	if (r && r->connection
@@ -3900,6 +3987,9 @@
 	    lingering_close(r);
 	}
 	else {
+#ifdef EAPI
+	    ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 	    ap_bsetflag(conn_io, B_EOUT, 1);
 	    ap_bclose(conn_io);
 	}
@@ -4684,6 +4774,10 @@
 	    ap_destroy_pool(r->pool);
 	}
 
+#ifdef EAPI
+	ap_call_close_connection_hook(conn);
+#endif /* EAPI */
+
 	ap_bclose(cio);
     }
     exit(0);
@@ -5012,6 +5106,9 @@
 	ap_kill_cleanups_for_socket(ptrans, csd);
 
 #ifdef NO_LINGCLOSE
+#ifdef EAPI
+	ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 	ap_bclose(conn_io);	/* just close it */
 #else
 	if (r && r->connection
@@ -5022,6 +5119,9 @@
 	    lingering_close(r);
 	}
 	else {
+#ifdef EAPI
+	    ap_call_close_connection_hook(current_conn);
+#endif /* EAPI */
 	    ap_bsetflag(conn_io, B_EOUT, 1);
 	    ap_bclose(conn_io);
 	}

+---------------------------------------------------------------------------
| Just add the initialization of the `ctx' variable for
| conn_rec structures.
+---------------------------------------------------------------------------
Index: src/main/http_request.c
--- src/main/http_request.c	1999/03/21 11:51:57	1.1.1.6
+++ src/main/http_request.c	1999/03/21 12:00:11	1.5
@@ -1312,6 +1312,9 @@
     new->no_local_copy   = r->no_local_copy;
     new->read_length     = r->read_length;     /* We can only read it once */
     new->vlist_validator = r->vlist_validator;
+#ifdef EAPI
+    new->ctx             = r->ctx;
+#endif /* EAPI */
 
     ap_table_setn(new->subprocess_env, "REDIRECT_STATUS",
 	ap_psprintf(r->pool, "%d", r->status));

+---------------------------------------------------------------------------
| Just add the initialization of the `ctx' variable for
| request_rec structures.
+---------------------------------------------------------------------------
Index: src/main/http_protocol.c
--- src/main/http_protocol.c	1999/03/21 11:51:57	1.1.1.6
+++ src/main/http_protocol.c	1999/03/21 12:00:11	1.6
@@ -935,6 +935,10 @@
     r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
     r->the_request     = NULL;
 
+#ifdef EAPI
+    r->ctx = ap_ctx_new(r->pool);
+#endif /* EAPI */
+
 #ifdef CHARSET_EBCDIC
     ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1);
 #endif
@@ -1084,6 +1088,11 @@
     rnew->read_body       = REQUEST_NO_BODY;
 
     rnew->main = (request_rec *) r;
+
+#ifdef EAPI
+    rnew->ctx = r->ctx;
+#endif /* EAPI */
+
 }
 
 void ap_finalize_sub_req_protocol(request_rec *sub)

+---------------------------------------------------------------------------
| Add support for loading both EAPI and AP13 modules.
+---------------------------------------------------------------------------
Index: src/modules/standard/mod_so.c
--- src/modules/standard/mod_so.c	1999/03/21 11:52:27	1.1.1.4
+++ src/modules/standard/mod_so.c	1999/03/21 12:00:12	1.3
@@ -257,7 +257,12 @@
      * Make sure the found module structure is really a module structure
      * 
      */
+#ifdef EAPI
+    if (   modp->magic != MODULE_MAGIC_COOKIE_AP13 
+        && modp->magic != MODULE_MAGIC_COOKIE_EAPI) {
+#else
     if (modp->magic != MODULE_MAGIC_COOKIE) {
+#endif
         return ap_pstrcat(cmd->pool, "API module structure `", modname,
                           "' in file ", szModuleFile, " is garbled -"
                           " perhaps this is not an Apache module DSO?", NULL);

+---------------------------------------------------------------------------
| Add additional logging functions to the CustomLog directive
| which can be used by other modules to create additional
| logfile tags. Actually we add two types of hooks: One hook
| for intercepting the new and generic %x (eXtension) tag and
| one hook for creating new %x tags at all.
+---------------------------------------------------------------------------
Index: src/modules/standard/mod_log_config.c
--- src/modules/standard/mod_log_config.c	1999/03/21 11:52:25	1.1.1.6
+++ src/modules/standard/mod_log_config.c	1999/03/21 12:00:12	1.19
@@ -251,6 +251,9 @@
 typedef const char *(*item_key_func) (request_rec *, char *);
 
 typedef struct {
+#ifdef EAPI
+    char ch;
+#endif
     item_key_func func;
     char *arg;
     int condition_sense;
@@ -504,15 +507,36 @@
     }
 };
 
+#ifdef EAPI
+static struct log_item_list *find_log_func(pool *p, char k)
+#else /* EAPI */
 static struct log_item_list *find_log_func(char k)
+#endif /* EAPI */
 {
     int i;
+#ifdef EAPI
+    struct log_item_list *lil;
+#endif /* EAPI */
 
     for (i = 0; log_item_keys[i].ch; ++i)
         if (k == log_item_keys[i].ch) {
             return &log_item_keys[i];
         }
 
+#ifdef EAPI
+    if (ap_hook_status(ap_psprintf(p, "ap::mod_log_config::log_%c", k)) 
+        != AP_HOOK_STATE_NOTEXISTANT) {
+        lil = (struct log_item_list *)
+              ap_pcalloc(p, sizeof(struct log_item_list));
+        if (lil == NULL)
+            return NULL;
+        lil->ch = k;
+        lil->func = NULL;
+        lil->want_orig_default = 0;
+        return lil;
+    }
+#endif /* EAPI */
+
     return NULL;
 }
 
@@ -638,7 +662,11 @@
             break;
 
         default:
+#ifdef EAPI
+            l = find_log_func(p, *s++);
+#else /* EAPI */
             l = find_log_func(*s++);
+#endif /* EAPI */
             if (!l) {
                 char dummy[2];
 
@@ -647,6 +675,9 @@
                 return ap_pstrcat(p, "Unrecognized LogFormat directive %",
                                dummy, NULL);
             }
+#ifdef EAPI
+            it->ch = s[-1];
+#endif
             it->func = l->func;
             if (it->want_orig == -1) {
                 it->want_orig = l->want_orig_default;
@@ -708,6 +739,15 @@
 
     /* We do.  Do it... */
 
+#ifdef EAPI
+    if (item->func == NULL) {
+        cp = NULL;
+        ap_hook_use(ap_psprintf(r->pool, "ap::mod_log_config::log_%c", item->ch),
+                    AP_HOOK_SIG3(ptr,ptr,ptr), AP_HOOK_DECLINE(NULL),
+                    &cp, r, item->arg);
+    }
+    else
+#endif
     cp = (*item->func) (item->want_orig ? orig : r, item->arg);
     return cp ? cp : "-";
 }

+---------------------------------------------------------------------------
| Allow RewriteCond and RewriteRule directives to lookup SSL
| variables via mod_ssl.
+---------------------------------------------------------------------------
Index: src/modules/standard/mod_rewrite.c
--- src/modules/standard/mod_rewrite.c	1999/03/21 11:52:26	1.1.1.5
+++ src/modules/standard/mod_rewrite.c	1999/03/21 12:00:12	1.3
@@ -3754,6 +3754,15 @@
     }
 #endif /* ndef WIN32 */
 
+#ifdef EAPI
+    else {
+        ap_hook_use("ap::mod_rewrite::lookup_variable",
+                    AP_HOOK_SIG3(ptr,ptr,ptr), 
+                    AP_HOOK_DECLINE(NULL),
+                    &result, r, var);
+    }
+#endif
+
     if (result == NULL) {
         return ap_pstrdup(r->pool, "");
     }

+---------------------------------------------------------------------------
| Add an EAPI hook to allow other modules to add content to 
| the status HTML page.
+---------------------------------------------------------------------------
Index: src/modules/standard/mod_status.c
--- src/modules/standard/mod_status.c	1999/03/21 11:52:27	1.1.1.6
+++ src/modules/standard/mod_status.c	1999/03/21 18:29:56	1.2
@@ -716,6 +753,12 @@
     ap_rputs("you need to use the <code>ExtendedStatus On</code> directive. \n", r);
 
     }
+
+#ifdef EAPI
+    ap_hook_use("ap::mod_status::display",
+                AP_HOOK_SIG4(void,ptr,int,int), AP_HOOK_ALL,
+                r, no_table_report, short_report);
+#endif
 
     if (!short_report) {
 	ap_rputs(ap_psignature("<HR>\n",r), r);

+---------------------------------------------------------------------------
| Add hooks to the scheme processing to allow other modules to
| recognize more schemes by intercepting this processing.
+---------------------------------------------------------------------------
Index: src/modules/proxy/mod_proxy.c
--- src/modules/proxy/mod_proxy.c	1999/03/21 11:52:19	1.1.1.5
+++ src/modules/proxy/mod_proxy.c	1999/03/21 12:00:11	1.11
@@ -214,6 +214,9 @@
 static int proxy_fixup(request_rec *r)
 {
     char *url, *p;
+#ifdef EAPI
+    int rc;
+#endif /* EAPI */
 
     if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
 	return DECLINED;
@@ -221,6 +224,14 @@
     url = &r->filename[6];
 
 /* canonicalise each specific scheme */
+#ifdef EAPI
+    if (ap_hook_use("ap::mod_proxy::canon",
+                    AP_HOOK_SIG3(int,ptr,ptr),
+                    AP_HOOK_DECLINE(DECLINED),
+                    &rc, r, url) && rc != DECLINED)
+        return rc;  
+    else
+#endif /* EAPI */
     if (strncasecmp(url, "http:", 5) == 0)
 	return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
     else if (strncasecmp(url, "ftp:", 4) == 0)
@@ -237,8 +248,39 @@
 {
     ap_proxy_garbage_init(r, p);
 }
-
 
+#ifdef EAPI
+static void proxy_addmod(module *m)
+{
+    /* export: ap_proxy_http_canon() as `ap::mod_proxy::http::canon' */
+    ap_hook_configure("ap::mod_proxy::http::canon", 
+                      AP_HOOK_SIG5(int,ptr,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_register("ap::mod_proxy::http::canon", 
+                     ap_proxy_http_canon, AP_HOOK_NOCTX);
+
+    /* export: ap_proxy_http_handler() as `ap::mod_proxy::http::handler' */
+    ap_hook_configure("ap::mod_proxy::http::handler", 
+                      AP_HOOK_SIG6(int,ptr,ptr,ptr,ptr,int), AP_HOOK_TOPMOST);
+    ap_hook_register("ap::mod_proxy::http::handler", 
+                     ap_proxy_http_handler, AP_HOOK_NOCTX);
+
+    /* export: ap_proxyerror() as `ap::mod_proxy::error' */
+    ap_hook_configure("ap::mod_proxy::error", 
+                      AP_HOOK_SIG3(int,ptr,ptr), AP_HOOK_TOPMOST);
+    ap_hook_register("ap::mod_proxy::error", 
+                     ap_proxyerror, AP_HOOK_NOCTX);
+    return;
+}
+
+static void proxy_remmod(module *m)
+{
+	/* remove the hook references */
+    ap_hook_unregister("ap::mod_proxy::http::canon", ap_proxy_http_canon);
+    ap_hook_unregister("ap::mod_proxy::http::handler", ap_proxy_http_handler);
+    ap_hook_unregister("ap::mod_proxy::error", ap_proxyerror);
+    return;
+}
+#endif /* EAPI */
 
 /* Send a redirection if the request contains a hostname which is not */
 /* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
@@ -368,6 +410,14 @@
 		/* CONNECT is a special method that bypasses the normal
 		 * proxy code.
 		 */
+#ifdef EAPI
+		if (!ap_hook_use("ap::mod_proxy::handler",
+				 AP_HOOK_SIG7(int,ptr,ptr,ptr,ptr,int,ptr),
+				 AP_HOOK_DECLINE(DECLINED),
+				 &rc, r, cr, url, 
+				 ents[i].hostname, ents[i].port, 
+				 ents[i].protocol) || rc == DECLINED) {
+#endif /* EAPI */
 		if (r->method_number == M_CONNECT)
 		    rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
 					       ents[i].port);
@@ -377,6 +427,9 @@
 					    ents[i].port);
 		else
 		    rc = DECLINED;
+#ifdef EAPI
+		}
+#endif /* EAPI */
 
 		/* an error or success */
 		if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
@@ -390,6 +443,14 @@
  * give up??
  */
     /* handle the scheme */
+#ifdef EAPI
+    if (ap_hook_use("ap::mod_proxy::handler",
+		    AP_HOOK_SIG7(int,ptr,ptr,ptr,ptr,int,ptr),
+		    AP_HOOK_DECLINE(DECLINED),
+		    &rc, r, cr, url, 
+                    NULL, 0, scheme) && rc != DECLINED)
+        return rc;
+#endif /* EAPI */
     if (r->method_number == M_CONNECT)
 	return ap_proxy_connect_handler(r, cr, url, NULL, 0);
     if (strcasecmp(scheme, "http") == 0)
@@ -895,4 +956,10 @@
     NULL,			/* child_init */
     NULL,			/* child_exit */
     proxy_detect		/* post read-request */
+#ifdef EAPI
+   ,proxy_addmod,		/* EAPI: add_module */
+    proxy_remmod,		/* EAPI: remove_module */
+    NULL,			/* EAPI: rewrite_command */
+    NULL			/* EAPI: new_connection  */
+#endif
 };

+---------------------------------------------------------------------------
| Add hooks to the HTTP processing to allow other modules
| to enhance it by intercepting this processing.
+---------------------------------------------------------------------------
Index: src/modules/proxy/proxy_http.c
--- src/modules/proxy/proxy_http.c	1999/03/21 11:52:20	1.1.1.5
+++ src/modules/proxy/proxy_http.c	1999/03/21 12:33:14	1.12
@@ -206,6 +206,12 @@
 	return HTTP_BAD_REQUEST;
     urlptr += 3;
     destport = DEFAULT_HTTP_PORT;
+#ifdef EAPI
+    ap_hook_use("ap::mod_proxy::http::handler::set_destport", 
+                AP_HOOK_SIG2(int,ptr), 
+                AP_HOOK_TOPMOST,
+                &destport, r);
+#endif /* EAPI */
     strp = strchr(urlptr, '/');
     if (strp == NULL) {
 	desthost = ap_pstrdup(p, urlptr);
@@ -302,13 +308,41 @@
     f = ap_bcreate(p, B_RDWR | B_SOCKET);
     ap_bpushfd(f, sock, sock);
 
+#ifdef EAPI
+    {
+        char *errmsg = NULL;
+        ap_hook_use("ap::mod_proxy::http::handler::new_connection", 
+                    AP_HOOK_SIG3(ptr,ptr,ptr), 
+                    AP_HOOK_DECLINE(NULL),
+                    &errmsg, r, f);
+        if (errmsg != NULL)
+            return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg);
+    }
+#endif /* EAPI */
+
     ap_hard_timeout("proxy send", r);
     ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF,
 	   NULL);
+#ifdef EAPI
+    {
+	int rc = DECLINED;
+	ap_hook_use("ap::mod_proxy::http::handler::write_host_header", 
+		    AP_HOOK_SIG6(int,ptr,ptr,ptr,int,ptr), 
+		    AP_HOOK_DECLINE(DECLINED),
+		    &rc, r, f, desthost, destport, destportstr);
+        if (rc == DECLINED) {
+	    if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
+		ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
+	    else
+		ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
+        }
+    }
+#else /* EAPI */
     if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
 	ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
     else
 	ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
+#endif /* EAPI */
 
     if (conf->viaopt == via_block) {
 	/* Block all outgoing Via: headers */

+---------------------------------------------------------------------------
| Add EAPI hooks in module structure for APXS generated samples.
+---------------------------------------------------------------------------
Index: src/support/apxs.pl
--- src/support/apxs.pl	1999/03/21 11:52:31	1.1.1.4
+++ src/support/apxs.pl	1999/03/21 12:00:12	1.4
@@ -622,5 +622,11 @@
     NULL,                  /* child_init                          */
     NULL,                  /* child_exit                          */
     NULL                   /* [#0] post read-request              */
+#ifdef EAPI
+   ,NULL,                  /* EAPI: add_module                    */
+    NULL,                  /* EAPI: remove_module                 */
+    NULL,                  /* EAPI: rewrite_command               */
+    NULL                   /* EAPI: new_connection                */
+#endif
 };
 

+---------------------------------------------------------------------------
| Add the EAPI functions, so mod_ssl can be built under AIX
| and similar braindead platforms as DSO.
+---------------------------------------------------------------------------
Index: src/support/httpd.exp
--- src/support/httpd.exp	1999/03/21 11:52:32	1.1.1.5
+++ src/support/httpd.exp	1999/03/21 12:00:13	1.5
@@ -361,3 +361,16 @@
 ap_vsnprintf
 core_module
 top_module
+ap_add_config_define
+ap_global_ctx
+ap_ctx_new
+ap_ctx_get
+ap_ctx_set
+ap_hook_init
+ap_hook_kill
+ap_hook_configure
+ap_hook_register_I
+ap_hook_unregister_I
+ap_hook_status
+ap_hook_use
+ap_hook_call

+---------------------------------------------------------------------------
| Add the EAPI functions, so mod_ssl can be built under Windows 95
| and similar braindead platforms as DDL.
+---------------------------------------------------------------------------
Index: src/ApacheCore.def
--- src/ApacheCore.def	1999/03/21 11:51:48	1.1.1.3
+++ src/ApacheCore.def	1999/03/21 12:00:09	1.4
@@ -343,4 +343,17 @@
 	ap_standalone   @337
 	ap_server_confname   @338
 	ap_sub_req_method_uri   @339
+	ap_add_config_define   @340
+	ap_global_ctx   @341
+	ap_ctx_new   @342
+	ap_ctx_get   @343
+	ap_ctx_set   @344
+	ap_hook_init   @345
+	ap_hook_kill   @346
+	ap_hook_configure   @347
+	ap_hook_register_I   @348
+	ap_hook_unregister_I   @349
+	ap_hook_status   @350
+	ap_hook_use   @351
+	ap_hook_call   @352
 
