]> granicus.if.org Git - apache/blobdiff - modules/mappers/mod_rewrite.c
Clean up some of the includes:
[apache] / modules / mappers / mod_rewrite.c
index b787d65747b11b7656e479b63fe88d2a4d46bcb7..5b716c5075cbfd895f75a1589e10c4ff7533ae52 100644 (file)
 **      www.engelschall.com
 */
 
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_user.h"
+#include "apr_lib.h"
+
+#define APR_WANT_STRFUNC
+#define APR_WANT_IOVEC
+#include "apr_want.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
 #include "ap_config.h"
 #include "httpd.h"
 #include "http_config.h"
 #include "http_log.h"
 #include "http_protocol.h"
 #include "mod_rewrite.h"
-#include "apr_strings.h"
 
-#if !defined(OS2) && !defined(WIN32)
+#if !defined(OS2) && !defined(WIN32) && !defined(BEOS)
 #include "unixd.h"
 #endif
 
-#ifndef NO_WRITEV
-#ifndef NETWARE
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#endif
-#ifdef HAVE_SYS_UIO_H
-#include <sys/uio.h>
-#endif
-#endif
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-#ifdef HAVE_GRP_H
-#include <grp.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
 /*
 ** +-------------------------------------------------------+
 ** |                                                       |
      * MODULE-DEFINITION-END
      */
 
-    /* the apr_table_t of commands we provide */
-static const command_rec command_table[] = {
-    { "RewriteEngine",   cmd_rewriteengine,   NULL, OR_FILEINFO, FLAG,
-      "On or Off to enable or disable (default) the whole rewriting engine" },
-    { "RewriteOptions",  cmd_rewriteoptions,  NULL, OR_FILEINFO, ITERATE,
-      "List of option strings to set" },
-    { "RewriteBase",     cmd_rewritebase,     NULL, OR_FILEINFO, TAKE1,
-      "the base URL of the per-directory context" },
-    { "RewriteCond",     cmd_rewritecond,     NULL, OR_FILEINFO, RAW_ARGS,
-      "an input string and a to be applied regexp-pattern" },
-    { "RewriteRule",     cmd_rewriterule,     NULL, OR_FILEINFO, RAW_ARGS,
-      "an URL-applied regexp-pattern and a substitution URL" },
-    { "RewriteMap",      cmd_rewritemap,      NULL, RSRC_CONF,   TAKE2,
-      "a mapname and a filename" },
-    { "RewriteLock",     cmd_rewritelock,     NULL, RSRC_CONF,   TAKE1,
-      "the filename of a lockfile used for inter-process synchronization"},
-    { "RewriteLog",      cmd_rewritelog,      NULL, RSRC_CONF,   TAKE1,
-      "the filename of the rewriting logfile" },
-    { "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF,   TAKE1,
-      "the level of the rewriting logfile verbosity "
-      "(0=none, 1=std, .., 9=max)" },
-    { NULL }
-};
-
-    /* the apr_table_t of content handlers we provide */
-static const handler_rec handler_table[] = {
-    { "redirect-handler", handler_redirect },
-    { NULL }
-};
-
-static void register_hooks(void)
-{
-    ap_hook_post_config(init_module,NULL,NULL,AP_HOOK_MIDDLE);
-    ap_hook_child_init(init_child,NULL,NULL,AP_HOOK_MIDDLE);
-
-    ap_hook_fixups(hook_fixup,NULL,NULL,AP_HOOK_FIRST);
-    ap_hook_translate_name(hook_uri2file,NULL,NULL,AP_HOOK_FIRST);
-    ap_hook_type_checker(hook_mimetype,NULL,NULL,AP_HOOK_MIDDLE);
-}
-
-    /* the main config structure */
-module MODULE_VAR_EXPORT rewrite_module = {
-   STANDARD20_MODULE_STUFF,
-   config_perdir_create,        /* create per-dir    config structures */
-   config_perdir_merge,         /* merge  per-dir    config structures */
-   config_server_create,        /* create per-server config structures */
-   config_server_merge,         /* merge  per-server config structures */
-   command_table,               /* apr_table_t of config file commands  */
-   handler_table,               /* [#8] MIME-typed-dispatched handlers */
-   register_hooks               /* register hooks                      */
-};
+    /* the module (predeclaration) */
+module AP_MODULE_DECLARE_DATA rewrite_module;
 
     /* the cache */
 static cache *cachep;
 
     /* whether proxy module is available or not */
 static int proxy_available;
-static int once_through = 0;
 
 static const char *lockname;
-static apr_lock_t *rewrite_mapr_lock = NULL;
+static apr_lock_t *rewrite_mapr_lock_aquire = NULL;
 static apr_lock_t *rewrite_log_lock = NULL;
 
 /*
@@ -268,9 +213,9 @@ static void *config_server_create(apr_pool_t *p, server_rec *s)
     a->rewritelogfile  = NULL;
     a->rewritelogfp    = NULL;
     a->rewriteloglevel = 0;
-    a->rewritemaps     = apr_make_array(p, 2, sizeof(rewritemap_entry));
-    a->rewriteconds    = apr_make_array(p, 2, sizeof(rewritecond_entry));
-    a->rewriterules    = apr_make_array(p, 2, sizeof(rewriterule_entry));
+    a->rewritemaps     = apr_array_make(p, 2, sizeof(rewritemap_entry));
+    a->rewriteconds    = apr_array_make(p, 2, sizeof(rewritecond_entry));
+    a->rewriterules    = apr_array_make(p, 2, sizeof(rewriterule_entry));
     a->server          = s;
 
     return (void *)a;
@@ -302,11 +247,11 @@ static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv)
         a->rewritelogfp    = overrides->rewritelogfp != NULL 
                              ? overrides->rewritelogfp 
                              : base->rewritelogfp;
-        a->rewritemaps     = apr_append_arrays(p, overrides->rewritemaps,
+        a->rewritemaps     = apr_array_append(p, overrides->rewritemaps,
                                               base->rewritemaps);
-        a->rewriteconds    = apr_append_arrays(p, overrides->rewriteconds,
+        a->rewriteconds    = apr_array_append(p, overrides->rewriteconds,
                                               base->rewriteconds);
-        a->rewriterules    = apr_append_arrays(p, overrides->rewriterules,
+        a->rewriterules    = apr_array_append(p, overrides->rewriterules,
                                               base->rewriterules);
     }
     else {
@@ -341,8 +286,8 @@ static void *config_perdir_create(apr_pool_t *p, char *path)
     a->state           = ENGINE_DISABLED;
     a->options         = OPTION_NONE;
     a->baseurl         = NULL;
-    a->rewriteconds    = apr_make_array(p, 2, sizeof(rewritecond_entry));
-    a->rewriterules    = apr_make_array(p, 2, sizeof(rewriterule_entry));
+    a->rewriteconds    = apr_array_make(p, 2, sizeof(rewritecond_entry));
+    a->rewriterules    = apr_array_make(p, 2, sizeof(rewriterule_entry));
 
     if (path == NULL) {
         a->directory = NULL;
@@ -375,9 +320,9 @@ static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv)
     a->baseurl   = overrides->baseurl;
 
     if (a->options & OPTION_INHERIT) {
-        a->rewriteconds = apr_append_arrays(p, overrides->rewriteconds,
+        a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
                                            base->rewriteconds);
-        a->rewriterules = apr_append_arrays(p, overrides->rewriterules,
+        a->rewriterules = apr_array_append(p, overrides->rewriterules,
                                            base->rewriterules);
     }
     else {
@@ -396,8 +341,9 @@ static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv)
 */
 
 static const char *cmd_rewriteengine(cmd_parms *cmd,
-                                     rewrite_perdir_conf *dconf, int flag)
+                                     void *in_dconf, int flag)
 {
+    rewrite_perdir_conf *dconf = in_dconf;
     rewrite_server_conf *sconf;
 
     sconf = 
@@ -415,8 +361,9 @@ static const char *cmd_rewriteengine(cmd_parms *cmd,
 }
 
 static const char *cmd_rewriteoptions(cmd_parms *cmd,
-                                      rewrite_perdir_conf *dconf, char *option)
+                                      void *in_dconf, const char *option)
 {
+    rewrite_perdir_conf *dconf = in_dconf;
     rewrite_server_conf *sconf;
     const char *err;
 
@@ -436,7 +383,7 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd,
 }
 
 static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options,
-                                                char *name)
+                                                const char *name)
 {
     if (strcasecmp(name, "inherit") == 0) {
         *options |= OPTION_INHERIT;
@@ -448,7 +395,7 @@ static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options,
     return NULL;
 }
 
-static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, char *a1)
+static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, const char *a1)
 {
     rewrite_server_conf *sconf;
 
@@ -460,7 +407,7 @@ static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, char *a1)
     return NULL;
 }
 
-static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1)
+static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1)
 {
     rewrite_server_conf *sconf;
 
@@ -472,8 +419,8 @@ static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1)
     return NULL;
 }
 
-static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1,
-                                  char *a2)
+static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1,
+                                  const char *a2)
 {
     rewrite_server_conf *sconf;
     rewritemap_entry *newmap;
@@ -482,7 +429,7 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1,
     sconf = (rewrite_server_conf *)
             ap_get_module_config(cmd->server->module_config, &rewrite_module);
 
-    newmap = apr_push_array(sconf->rewritemaps);
+    newmap = apr_array_push(sconf->rewritemaps);
 
     newmap->name = a1;
     newmap->func = NULL;
@@ -541,7 +488,8 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1,
     newmap->fpout = NULL;
 
     if (newmap->checkfile && (sconf->state == ENGINE_ENABLED)
-        && (apr_stat(&st, newmap->checkfile, cmd->pool) != APR_SUCCESS)) {
+        && (apr_stat(&st, newmap->checkfile, APR_FINFO_MIN, 
+                     cmd->pool) != APR_SUCCESS)) {
         return apr_pstrcat(cmd->pool,
                           "RewriteMap: map file or program not found:",
                           newmap->checkfile, NULL);
@@ -550,7 +498,7 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1,
     return NULL;
 }
 
-static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, char *a1)
+static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, const char *a1)
 {
     const char *error;
 
@@ -562,9 +510,11 @@ static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, char *a1)
     return NULL;
 }
 
-static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf,
-                                   char *a1)
+static const char *cmd_rewritebase(cmd_parms *cmd, void *in_dconf,
+                                   const char *a1)
 {
+    rewrite_perdir_conf *dconf = in_dconf;
+
     if (cmd->path == NULL || dconf == NULL) {
         return "RewriteBase: only valid in per-directory config files";
     }
@@ -580,9 +530,11 @@ static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf,
     return NULL;
 }
 
-static const char *cmd_rewritecond(cmd_parms *cmd, rewrite_perdir_conf *dconf,
-                                   char *str)
+static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
+                                   const char *in_str)
 {
+    rewrite_perdir_conf *dconf = in_dconf;
+    char *str = apr_pstrdup(cmd->pool, in_str);
     rewrite_server_conf *sconf;
     rewritecond_entry *newcond;
     regex_t *regexp;
@@ -598,10 +550,10 @@ static const char *cmd_rewritecond(cmd_parms *cmd, rewrite_perdir_conf *dconf,
 
     /*  make a new entry in the internal temporary rewrite rule list */
     if (cmd->path == NULL) {   /* is server command */
-        newcond = apr_push_array(sconf->rewriteconds);
+        newcond = apr_array_push(sconf->rewriteconds);
     }
     else {                     /* is per-directory command */
-        newcond = apr_push_array(dconf->rewriteconds);
+        newcond = apr_array_push(dconf->rewriteconds);
     }
 
     /*  parse the argument line ourself */
@@ -723,9 +675,11 @@ static const char *cmd_rewritecond_setflag(apr_pool_t *p, rewritecond_entry *cfg
     return NULL;
 }
 
-static const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf,
-                                   char *str)
+static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
+                                   const char *in_str)
 {
+    rewrite_perdir_conf *dconf = in_dconf;
+    char *str = apr_pstrdup(cmd->pool, in_str);
     rewrite_server_conf *sconf;
     rewriterule_entry *newrule;
     regex_t *regexp;
@@ -741,10 +695,10 @@ static const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf,
 
     /*  make a new entry in the internal rewrite rule list */
     if (cmd->path == NULL) {   /* is server command */
-        newrule = apr_push_array(sconf->rewriterules);
+        newrule = apr_array_push(sconf->rewriterules);
     }
     else {                     /* is per-directory command */
-        newrule = apr_push_array(dconf->rewriterules);
+        newrule = apr_array_push(dconf->rewriterules);
     }
 
     /*  parse the argument line ourself */
@@ -789,6 +743,8 @@ static const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf,
     /*  arg2: the output string
      *  replace the $<N> by \<n> which is needed by the currently
      *  used Regular Expression library
+     *
+     * TODO: Is this still required for PCRE?  If not, does it *work* with PCRE?
      */
     newrule->output = apr_pstrdup(cmd->pool, a2);
 
@@ -798,12 +754,12 @@ static const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf,
      */
     if (cmd->path == NULL) {  /* is server command */
         newrule->rewriteconds   = sconf->rewriteconds;
-        sconf->rewriteconds = apr_make_array(cmd->pool, 2,
+        sconf->rewriteconds = apr_array_make(cmd->pool, 2,
                                             sizeof(rewritecond_entry));
     }
     else {                    /* is per-directory command */
         newrule->rewriteconds   = dconf->rewriteconds;
-        dconf->rewriteconds = apr_make_array(cmd->pool, 2,
+        dconf->rewriteconds = apr_array_make(cmd->pool, 2,
                                             sizeof(rewritecond_entry));
     }
 
@@ -881,7 +837,7 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, rewriterule_entry *cfg
             else if (strcasecmp(val, "seeother") == 0) {
                 status = HTTP_SEE_OTHER;
             }
-            else if (ap_isdigit(*val)) {
+            else if (apr_isdigit(*val)) {
                 status = atoi(val);
             }
             if (!ap_is_HTTP_REDIRECT(status)) {
@@ -972,17 +928,31 @@ static void init_module(apr_pool_t *p,
                         apr_pool_t *ptemp,
                         server_rec *s)
 {
+    apr_status_t rv;
+    void *data;
+    int first_time = 0;
+    const char *userdata_key = "rewrite_init_module";
+
+    apr_pool_userdata_get(&data, userdata_key, s->process->pool);
+    if (!data) {
+        first_time = 1;
+        apr_pool_userdata_set((const void *)1, userdata_key,
+                         apr_pool_cleanup_null, s->process->pool);
+    }
+
     /* check if proxy module is available */
     proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL);
 
     /* create the rewriting lockfiles in the parent */
-    if (apr_create_lock (&rewrite_log_lock, APR_MUTEX, APR_INTRAPROCESS,
-                        NULL, NULL) != APR_SUCCESS)
-        exit(1);    /* ugly but I can't log anything yet. This is what */
-                    /*   the pre-existing rewritelock_create code did. */
+    if ((rv = apr_lock_create (&rewrite_log_lock, APR_MUTEX, APR_LOCKALL,
+                               NULL, p)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                     "mod_rewrite: could not create rewrite_log_lock");
+        exit(1);
+    }
 
     rewritelock_create(s, p);
-    apr_register_cleanup(p, (void *)s, rewritelock_remove, apr_null_cleanup);
+    apr_pool_cleanup_register(p, (void *)s, rewritelock_remove, apr_pool_cleanup_null);
 
     /* step through the servers and
      * - open each rewriting logfile
@@ -990,11 +960,9 @@ static void init_module(apr_pool_t *p,
      */
     for (; s; s = s->next) {
         open_rewritelog(s, p);
-        if (once_through > 0)
+        if (!first_time)
            run_rewritemap_programs(s, p);
     }
-
-    once_through++;
 }
 
 
@@ -1007,9 +975,17 @@ static void init_module(apr_pool_t *p,
 
 static void init_child(apr_pool_t *p, server_rec *s)
 {
+    apr_status_t rv;
 
     if (lockname != NULL && *(lockname) != '\0')
-        apr_child_init_lock (&rewrite_mapr_lock, lockname, p);
+    {
+        rv = apr_lock_child_init (&rewrite_mapr_lock_aquire, lockname, p);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                         "mod_rewrite: could not init rewrite_mapr_lock_aquire "
+                         "in child");
+        }
+    }
 
     /* create the lookup cache */
     cachep = init_cache(p);
@@ -1168,20 +1144,7 @@ static int hook_uri2file(request_rec *r)
                        r->filename);
             return OK;
         }
-        else if (  (strlen(r->filename) > 7 &&
-                    strncasecmp(r->filename, "http://",   7) == 0)
-                || (strlen(r->filename) > 8 &&
-                    strncasecmp(r->filename, "https://",  8) == 0)
-                || (strlen(r->filename) > 9 &&
-                    strncasecmp(r->filename, "gopher://", 9) == 0)
-                || (strlen(r->filename) > 6 &&
-                    strncasecmp(r->filename, "ftp://",    6) == 0)
-                || (strlen(r->filename) > 5 &&
-                    strncasecmp(r->filename, "ldap:",     5) == 0)
-                || (strlen(r->filename) > 5 &&
-                    strncasecmp(r->filename, "news:",     5) == 0)
-                || (strlen(r->filename) > 7 &&
-                    strncasecmp(r->filename, "mailto:",   7) == 0)) {
+        else if (is_absolute_uri(r->filename)) {
             /* it was finally rewritten to a remote URL */
 
             /* skip 'scheme:' */
@@ -1246,7 +1209,7 @@ static int hook_uri2file(request_rec *r)
             /* it was finally rewritten to a local path */
 
             /* expand "/~user" prefix */
-#if !defined(WIN32) && !defined(NETWARE)
+#if APR_HAS_USER
             r->filename = expand_tildepaths(r, r->filename);
 #endif
             rewritelog(r, 2, "local path result: %s", r->filename);
@@ -1432,20 +1395,7 @@ static int hook_fixup(request_rec *r)
                        "%s [OK]", dconf->directory, r->filename);
             return OK;
         }
-        else if (  (strlen(r->filename) > 7 &&
-                    strncasecmp(r->filename, "http://",   7) == 0)
-                || (strlen(r->filename) > 8 &&          
-                    strncasecmp(r->filename, "https://",  8) == 0)
-                || (strlen(r->filename) > 9 &&
-                    strncasecmp(r->filename, "gopher://", 9) == 0)
-                || (strlen(r->filename) > 6 &&
-                    strncasecmp(r->filename, "ftp://",    6) == 0)
-                || (strlen(r->filename) > 5 &&
-                    strncasecmp(r->filename, "ldap:",     5) == 0)
-                || (strlen(r->filename) > 5 &&
-                    strncasecmp(r->filename, "news:",     5) == 0)
-                || (strlen(r->filename) > 7 &&
-                    strncasecmp(r->filename, "mailto:",   7) == 0)) {
+        else if (is_absolute_uri(r->filename)) {
             /* it was finally rewritten to a remote URL */
 
             /* because we are in a per-dir context
@@ -1619,6 +1569,10 @@ static int hook_fixup(request_rec *r)
 
 static int handler_redirect(request_rec *r)
 {
+    if (strcmp(r->handler, "redirect-handler")) {
+        return DECLINED;
+    }
+
     /* just make sure that we are really meant! */
     if (strncmp(r->filename, "redirect:", 9) != 0) {
         return DECLINED;
@@ -1783,7 +1737,6 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
     char *output;
     const char *vary;
     char newuri[MAX_STRING_LEN];
-    char env[MAX_STRING_LEN];
     regex_t *regexp;
     regmatch_t regmatch[MAX_NMATCH];
     backrefinfo *briRR = NULL;
@@ -1951,20 +1904,7 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
      *  (`RewriteRule <pat> - [E=...]')
      */
     if (strcmp(output, "-") == 0) {
-        for (i = 0; p->env[i] != NULL; i++) {
-            /*  1. take the string  */
-            apr_cpystrn(env, p->env[i], sizeof(env));
-            /*  2. expand $N (i.e. backrefs to RewriteRule pattern)  */
-            expand_backref_inbuffer(r->pool, env, sizeof(env), briRR, '$');
-            /*  3. expand %N (i.e. backrefs to latest RewriteCond pattern)  */
-            expand_backref_inbuffer(r->pool, env, sizeof(env), briRC, '%');
-            /*  4. expand %{...} (i.e. variables) */
-            expand_variables_inbuffer(r, env, sizeof(env));
-            /*  5. expand ${...} (RewriteMap lookups)  */
-            expand_map_lookups(r, env, sizeof(env));
-            /*  and add the variable to Apache's structures  */
-            add_env_variable(r, env);
-        }
+       do_expand_env(r, p->env, briRR, briRC);
         if (p->forced_mimetype != NULL) {
             if (perdir == NULL) {
                 /* In the per-server context we can force the MIME-type
@@ -1999,17 +1939,7 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
      *  that there is something to replace, so we create the
      *  substitution URL string in `newuri'.
      */
-    /*  1. take the output string  */
-    apr_cpystrn(newuri, output, sizeof(newuri));
-    /*  2. expand $N (i.e. backrefs to RewriteRule pattern)  */
-    expand_backref_inbuffer(r->pool, newuri, sizeof(newuri), briRR, '$');
-    /*  3. expand %N (i.e. backrefs to latest RewriteCond pattern)  */
-    expand_backref_inbuffer(r->pool, newuri, sizeof(newuri), briRC, '%');
-    /*  4. expand %{...} (i.e. variables) */
-    expand_variables_inbuffer(r, newuri, sizeof(newuri));
-    /*  5. expand ${...} (RewriteMap lookups)  */
-    expand_map_lookups(r, newuri, sizeof(newuri));
-    /*  and log the result... */
+    do_expand(r, output, newuri, sizeof(newuri), briRR, briRC);
     if (perdir == NULL) {
         rewritelog(r, 2, "rewrite %s -> %s", uri, newuri);
     }
@@ -2021,20 +1951,7 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
      *  Additionally do expansion for the environment variable
      *  strings (`RewriteRule .. .. [E=<string>]').
      */
-    for (i = 0; p->env[i] != NULL; i++) {
-        /*  1. take the string  */
-        apr_cpystrn(env, p->env[i], sizeof(env));
-        /*  2. expand $N (i.e. backrefs to RewriteRule pattern)  */
-        expand_backref_inbuffer(r->pool, env, sizeof(env), briRR, '$');
-        /*  3. expand %N (i.e. backrefs to latest RewriteCond pattern)  */
-        expand_backref_inbuffer(r->pool, env, sizeof(env), briRC, '%');
-        /*  4. expand %{...} (i.e. variables) */
-        expand_variables_inbuffer(r, env, sizeof(env));
-        /*  5. expand ${...} (RewriteMap lookups)  */
-        expand_map_lookups(r, env, sizeof(env));
-        /*  and add the variable to Apache's structures  */
-        add_env_variable(r, env);
-    }
+    do_expand_env(r, p->env, briRR, briRC);
 
     /*
      *  Now replace API's knowledge of the current URI:
@@ -2050,16 +1967,8 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
      *   location, i.e. if it's not starting with either a slash
      *   or a fully qualified URL scheme.
      */
-    i = strlen(r->filename);
-    if (   prefixstrip
-        && !(   r->filename[0] == '/'
-             || (   (i > 7 && strncasecmp(r->filename, "http://",   7) == 0)
-                 || (i > 8 && strncasecmp(r->filename, "https://",  8) == 0)
-                 || (i > 9 && strncasecmp(r->filename, "gopher://", 9) == 0)
-                 || (i > 6 && strncasecmp(r->filename, "ftp://",    6) == 0)
-                 || (i > 5 && strncasecmp(r->filename, "ldap:",     5) == 0)
-                 || (i > 5 && strncasecmp(r->filename, "news:",     5) == 0)
-                 || (i > 7 && strncasecmp(r->filename, "mailto:",   7) == 0)))) {
+    if (prefixstrip && r->filename[0] != '/'
+       && !is_absolute_uri(r->filename)) {
         rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s",
                    perdir, r->filename, perdir, r->filename);
         r->filename = apr_pstrcat(r->pool, perdir, r->filename, NULL);
@@ -2123,14 +2032,7 @@ static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
      *  redirection (`RewriteRule .. <scheme>://...') then
      *  directly force an external HTTP redirect.
      */
-    i = strlen(r->filename);
-    if (   (i > 7 && strncasecmp(r->filename, "http://",   7) == 0)
-        || (i > 8 && strncasecmp(r->filename, "https://",  8) == 0)
-        || (i > 9 && strncasecmp(r->filename, "gopher://", 9) == 0)
-        || (i > 6 && strncasecmp(r->filename, "ftp://",    6) == 0)
-        || (i > 5 && strncasecmp(r->filename, "ldap:",     5) == 0)
-        || (i > 5 && strncasecmp(r->filename, "news:",     5) == 0)
-        || (i > 7 && strncasecmp(r->filename, "mailto:",   7) == 0) ) {
+    if (is_absolute_uri(r->filename)) {
         if (perdir == NULL) {
             rewritelog(r, 2,
                        "implicitly forcing redirect (rc=%d) with %s",
@@ -2201,16 +2103,7 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
      *   Construct the string we match against
      */
 
-    /*  1. take the string  */
-    apr_cpystrn(input, p->input, sizeof(input));
-    /*  2. expand $N (i.e. backrefs to RewriteRule pattern)  */
-    expand_backref_inbuffer(r->pool, input, sizeof(input), briRR, '$');
-    /*  3. expand %N (i.e. backrefs to latest RewriteCond pattern)  */
-    expand_backref_inbuffer(r->pool, input, sizeof(input), briRC, '%');
-    /*  4. expand %{...} (i.e. variables) */
-    expand_variables_inbuffer(r, input, sizeof(input));
-    /*  5. expand ${...} (RewriteMap lookups)  */
-    expand_map_lookups(r, input, sizeof(input));
+    do_expand(r, p->input, input, sizeof(input), briRR, briRC);
 
     /*
      *   Apply the patterns
@@ -2218,22 +2111,22 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
 
     rc = 0;
     if (strcmp(p->pattern, "-f") == 0) {
-        if (apr_stat(&sb, input, r->pool) == APR_SUCCESS) {
+        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
             if (sb.filetype == APR_REG) {
                 rc = 1;
             }
         }
     }
     else if (strcmp(p->pattern, "-s") == 0) {
-        if (apr_stat(&sb, input, r->pool) == APR_SUCCESS) {
+        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
             if ((sb.filetype == APR_REG) && sb.size > 0) {
                 rc = 1;
             }
         }
     }
     else if (strcmp(p->pattern, "-l") == 0) {
-#if !defined(OS2) && !defined(WIN32)
-        if (apr_lstat(&sb, input, r->pool) == APR_SUCCESS) {
+#if !defined(OS2)
+        if (apr_lstat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
             if (sb.filetype == APR_LNK) {
                 rc = 1;
             }
@@ -2241,7 +2134,7 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
 #endif
     }
     else if (strcmp(p->pattern, "-d") == 0) {
-        if (apr_stat(&sb, input, r->pool) == APR_SUCCESS) {
+        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
             if (sb.filetype == APR_DIR) {
                 rc = 1;
             }
@@ -2249,15 +2142,10 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
     }
     else if (strcmp(p->pattern, "-U") == 0) {
         /* avoid infinite subrequest recursion */
-        if (strlen(input) > 0               /* nonempty path, and            */
-            && (   r->main == NULL          /* - either not in a subrequest  */
-                || (   r->main->uri != NULL /* - or in a subrequest...       */
-                    && r->uri != NULL       /*   ...and URIs aren't NULL...  */
-                                            /*   ...and sub/main URIs differ */
-                    && strcmp(r->main->uri, r->uri) != 0) ) ) {
+        if (strlen(input) > 0 && subreq_ok(r)) {
 
             /* run a URI-based subrequest */
-            rsub = ap_sub_req_lookup_uri(input, r);
+            rsub = ap_sub_req_lookup_uri(input, r, NULL);
 
             /* URI exists for any result up to 3xx, redirects allowed */
             if (rsub->status < 400)
@@ -2273,22 +2161,18 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
     }
     else if (strcmp(p->pattern, "-F") == 0) {
         /* avoid infinite subrequest recursion */
-        if (strlen(input) > 0               /* nonempty path, and            */
-            && (   r->main == NULL          /* - either not in a subrequest  */
-                || (   r->main->uri != NULL /* - or in a subrequest...       */
-                    && r->uri != NULL       /*   ...and URIs aren't NULL...  */
-                                            /*   ...and sub/main URIs differ */
-                    && strcmp(r->main->uri, r->uri) != 0) ) ) {
+        if (strlen(input) > 0 && subreq_ok(r)) {
 
             /* process a file-based subrequest:
              * this differs from -U in that no path translation is done.
              */
-            rsub = ap_sub_req_lookup_file(input, r);
+            rsub = ap_sub_req_lookup_file(input, r, NULL);
 
             /* file exists for any result up to 2xx, no redirects */
             if (rsub->status < 300 &&
                 /* double-check that file exists since default result is 200 */
-                apr_stat(&sb, rsub->filename, r->pool) == APR_SUCCESS) {
+                apr_stat(&sb, rsub->filename, APR_FINFO_MIN, 
+                         r->pool) == APR_SUCCESS) {
                 rc = 1;
             }
 
@@ -2352,6 +2236,162 @@ static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
 ** +-------------------------------------------------------+
 */
 
+
+/*
+**
+**  perform all the expansions on the input string
+**  leaving the result in the supplied buffer
+**
+*/
+
+static void do_expand(request_rec *r, char *input, char *buffer, int nbuf,
+                      backrefinfo *briRR, backrefinfo *briRC)
+{
+    char *inp, *outp;
+    size_t span, space;
+
+    /*
+     * for security reasons this expansion must be perfomed in a
+     * single pass, otherwise an attacker can arrange for the result
+     * of an earlier expansion to include expansion specifiers that
+     * are interpreted by a later expansion, producing results that
+     * were not intended by the administrator.
+     */
+
+    inp = input;
+    outp = buffer;
+    space = nbuf - 1; /* room for '\0' */
+
+    for (;;) {
+       span = strcspn(inp, "$%");
+       if (span > space) {
+           span = space;
+       }
+       memcpy(outp, inp, span);
+       inp += span;
+       outp += span;
+       space -= span;
+       if (space == 0 || *inp == '\0') {
+           break;
+       }
+       /* now we have a '$' or a '%' */
+       if (inp[1] == '{') {
+           char *endp;
+           endp = find_closing_bracket(inp+2, '{', '}');
+           if (endp == NULL) {
+               goto skip;
+           }
+           /*
+            * These lookups may be recursive in a very convoluted
+            * fashion -- see the LA-U and LA-F variable expansion
+            * prefixes -- so we copy lookup keys to a separate buffer
+            * rather than adding zero bytes in order to use them in
+            * place.
+            */
+           if (inp[0] == '$') {
+               /* ${...} map lookup expansion */
+               /*
+                * To make rewrite maps useful the lookup key and
+                * default values must be expanded, so we make
+                * recursive calls to do the work. For security
+                * reasons we must never expand a string that includes
+                * verbatim data from the network. The recursion here
+                * isn't a problem because the result of expansion is
+                * only passed to lookup_map() so it cannot be
+                * re-expanded, only re-looked-up. Another way of
+                * looking at it is that the recursion is entirely
+                * driven by the syntax of the nested curly brackets.
+                */
+               char *map, *key, *dflt, *result;
+               char xkey[MAX_STRING_LEN];
+               char xdflt[MAX_STRING_LEN];
+               key = find_char_in_brackets(inp+2, ':', '{', '}');
+               if (key == NULL)
+                   goto skip;
+               map  = apr_pstrndup(r->pool, inp+2, key-inp-2);
+               dflt = find_char_in_brackets(key+1, '|', '{', '}');
+               if (dflt == NULL) {
+                   key  = apr_pstrndup(r->pool, key+1, endp-key-1);
+                   dflt = "";
+               } else {
+                   key  = apr_pstrndup(r->pool, key+1, dflt-key-1);
+                   dflt = apr_pstrndup(r->pool, dflt+1, endp-dflt-1);
+               }
+               do_expand(r, key,  xkey,  sizeof(xkey),  briRR, briRC);
+               result = lookup_map(r, map, xkey);
+               if (result) {
+                   span = apr_cpystrn(outp, result, space) - outp;
+               } else {
+                   do_expand(r, dflt, xdflt, sizeof(xdflt), briRR, briRC);
+                   span = apr_cpystrn(outp, xdflt, space) - outp;
+               }
+           }
+           else if (inp[0] == '%') {
+               /* %{...} variable lookup expansion */
+               char *var;
+               var  = apr_pstrndup(r->pool, inp+2, endp-inp-2);
+               span = apr_cpystrn(outp, lookup_variable(r, var), space) - outp;
+           }
+           else {
+               span = 0;
+           }
+           inp = endp+1;
+           outp += span;
+           space -= span;
+           continue;
+       }
+       else if (apr_isdigit(inp[1])) {
+           int n = inp[1] - '0';
+           backrefinfo *bri = NULL;
+           if (inp[0] == '$') {
+               /* $N RewriteRule regexp backref expansion */
+               bri = briRR;
+           }
+           else if (inp[0] == '%') {
+               /* %N RewriteCond regexp backref expansion */
+               bri = briRC;
+           }
+           /* see ap_pregsub() in src/main/util.c */
+            if (bri && n <= bri->nsub &&
+               bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) {
+               span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so;
+               if (span > space) {
+                   span = space;
+               }
+               memcpy(outp, bri->source + bri->regmatch[n].rm_so, span);
+               outp += span;
+               space -= span;
+           }
+           inp += 2;
+           continue;
+       }
+    skip:
+       *outp++ = *inp++;
+       space--;
+    }
+    *outp++ = '\0';
+}
+
+
+/*
+**
+**  perform all the expansions on the environment variables
+**
+*/
+
+static void do_expand_env(request_rec *r, char *env[],
+                         backrefinfo *briRR, backrefinfo *briRC)
+{
+    int i;
+    char buf[MAX_STRING_LEN];
+
+    for (i = 0; env[i] != NULL; i++) {
+       do_expand(r, env[i], buf, sizeof(buf), briRR, briRC);
+       add_env_variable(r, buf);
+    }
+}
+
+
 /*
 **
 **  split out a QUERY_STRING part from
@@ -2480,20 +2520,12 @@ static void reduce_uri(request_rec *r)
 
 static void fully_qualify_uri(request_rec *r)
 {
-    int i;
     char buf[32];
     const char *thisserver;
     char *thisport;
     int port;
 
-    i = strlen(r->filename);
-    if (!(   (i > 7 && strncasecmp(r->filename, "http://",   7) == 0)
-          || (i > 8 && strncasecmp(r->filename, "https://",  8) == 0)
-          || (i > 9 && strncasecmp(r->filename, "gopher://", 9) == 0)
-          || (i > 6 && strncasecmp(r->filename, "ftp://",    6) == 0)
-          || (i > 5 && strncasecmp(r->filename, "ldap:",     5) == 0)
-          || (i > 5 && strncasecmp(r->filename, "news:",     5) == 0)
-          || (i > 7 && strncasecmp(r->filename, "mailto:",   7) == 0))) {
+    if (!is_absolute_uri(r->filename)) {
 
         thisserver = ap_get_server_name(r);
         port = ap_get_server_port(r);
@@ -2522,62 +2554,41 @@ static void fully_qualify_uri(request_rec *r)
 
 /*
 **
-**  Expand the %0-%9 or $0-$9 regex backreferences
+**  return non-zero if the URI is absolute (includes a scheme etc.)
 **
 */
 
-static void expand_backref_inbuffer(apr_pool_t *p, char *buf, int nbuf,
-                                    backrefinfo *bri, char c)
+static int is_absolute_uri(char *uri)
 {
-    register int i;
-
-    /* protect existing $N and & backrefs and replace <c>N with $N backrefs */
-    for (i = 0; buf[i] != '\0' && i < nbuf; i++) {
-        if (buf[i] == '\\' && (buf[i+1] != '\0' && i < (nbuf-1))) {
-            i++; /* protect next */
-        }
-        else if (buf[i] == '&') {
-            buf[i] = '\001';
-        }
-        else if (c != '$' && buf[i] == '$' && (buf[i+1] >= '0' && buf[i+1] <= '9')) {
-            buf[i] = '\002';
-            i++; /* speedup */
-        }
-        else if (buf[i] == c && (buf[i+1] >= '0' && buf[i+1] <= '9')) {
-            buf[i] = '$';
-            i++; /* speedup */
-        }
+    int i = strlen(uri);
+    if (   (i > 7 && strncasecmp(uri, "http://",   7) == 0)
+        || (i > 8 && strncasecmp(uri, "https://",  8) == 0)
+        || (i > 9 && strncasecmp(uri, "gopher://", 9) == 0)
+        || (i > 6 && strncasecmp(uri, "ftp://",    6) == 0)
+        || (i > 5 && strncasecmp(uri, "ldap:",     5) == 0)
+        || (i > 5 && strncasecmp(uri, "news:",     5) == 0)
+        || (i > 7 && strncasecmp(uri, "mailto:",   7) == 0) ) {
+       return 1;
     }
-
-    /* now apply the standard regex substitution function */
-    apr_cpystrn(buf, ap_pregsub(p, buf, bri->source,
-                               bri->nsub+1, bri->regmatch), nbuf);
-
-    /* restore the original $N and & backrefs */
-    for (i = 0; buf[i] != '\0' && i < nbuf; i++) {
-        if (buf[i] == '\001') {
-            buf[i] = '&';
-        }
-        else if (buf[i] == '\002') {
-            buf[i] = '$';
-        }
+    else {
+       return 0;
     }
 }
 
 
 /*
 **
-**  Expand tilde-paths (/~user) through
-**  Unix /etc/passwd database information
+**  Expand tilde-paths (/~user) through Unix /etc/passwd 
+**  database information (or other OS-specific database)
 **
 */
-#if !defined(WIN32) && !defined(NETWARE)
+#if APR_HAS_USER
 static char *expand_tildepaths(request_rec *r, char *uri)
 {
     char user[LONG_STRING_LEN];
-    struct passwd *pw;
     char *newuri;
     int i, j;
+    char *homedir;
 
     newuri = uri;
     if (uri != NULL && strlen(uri) > 2 && uri[0] == '/' && uri[1] == '~') {
@@ -2590,137 +2601,24 @@ static char *expand_tildepaths(request_rec *r, char *uri)
         user[j] = '\0';
 
         /* lookup username in systems passwd file */
-        if ((pw = getpwnam(user)) != NULL) {
+        if (apr_get_home_directory(&homedir, user, r->pool) == APR_SUCCESS) {
             /* ok, user was found, so expand the ~user string */
             if (uri[i] != '\0') {
                 /* ~user/anything...  has to be expanded */
-                if (pw->pw_dir[strlen(pw->pw_dir)-1] == '/') {
-                    pw->pw_dir[strlen(pw->pw_dir)-1] = '\0';
+                if (homedir[strlen(homedir)-1] == '/') {
+                    homedir[strlen(homedir)-1] = '\0';
                 }
-                newuri = apr_pstrcat(r->pool, pw->pw_dir, uri+i, NULL);
+                newuri = apr_pstrcat(r->pool, homedir, uri+i, NULL);
             }
             else {
                 /* only ~user has to be expanded */
-                newuri = apr_pstrdup(r->pool, pw->pw_dir);
+                newuri = homedir;
             }
         }
     }
     return newuri;
 }
-#endif
-
-/*
-**
-**  mapfile expansion support
-**  i.e. expansion of MAP lookup directives
-**  ${<mapname>:<key>} in RewriteRule rhs
-**
-*/
-
-#define limit_length(n) (n > LONG_STRING_LEN-1 ? LONG_STRING_LEN-1 : n)
-
-static void expand_map_lookups(request_rec *r, char *uri, int uri_len)
-{
-    char newuri[MAX_STRING_LEN];
-    char *cpI;
-    char *cpIE;
-    char *cpO;
-    char *cpT;
-    char *cpT2;
-    char mapname[LONG_STRING_LEN];
-    char mapkey[LONG_STRING_LEN];
-    char defaultvalue[LONG_STRING_LEN];
-    int n;
-
-    cpI = uri;
-    cpIE = cpI+strlen(cpI);
-    cpO = newuri;
-    while (cpI < cpIE) {
-        if (cpI+6 < cpIE && strncmp(cpI, "${", 2) == 0) {
-            /* missing delimiter -> take it as plain text */
-            if (   strchr(cpI+2, ':') == NULL
-                || strchr(cpI+2, '}') == NULL) {
-                memcpy(cpO, cpI, 2);
-                cpO += 2;
-                cpI += 2;
-                continue;
-            }
-            cpI += 2;
-
-            cpT = strchr(cpI, ':');
-            n = cpT-cpI;
-            memcpy(mapname, cpI, limit_length(n));
-            mapname[limit_length(n)] = '\0';
-            cpI += n+1;
-
-            cpT2 = strchr(cpI, '|');
-            cpT = strchr(cpI, '}');
-            if (cpT2 != NULL && cpT2 < cpT) {
-                n = cpT2-cpI;
-                memcpy(mapkey, cpI, limit_length(n));
-                mapkey[limit_length(n)] = '\0';
-                cpI += n+1;
-
-                n = cpT-cpI;
-                memcpy(defaultvalue, cpI, limit_length(n));
-                defaultvalue[limit_length(n)] = '\0';
-                cpI += n+1;
-            }
-            else {
-                n = cpT-cpI;
-                memcpy(mapkey, cpI, limit_length(n));
-                mapkey[limit_length(n)] = '\0';
-                cpI += n+1;
-
-                defaultvalue[0] = '\0';
-            }
-
-            cpT = lookup_map(r, mapname, mapkey);
-            if (cpT != NULL) {
-                n = strlen(cpT);
-                if (cpO + n >= newuri + sizeof(newuri)) {
-                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
-                                 0, r, "insufficient space in "
-                                 "expand_map_lookups, aborting");
-                    return;
-                }
-                memcpy(cpO, cpT, n);
-                cpO += n;
-            }
-            else {
-                n = strlen(defaultvalue);
-                if (cpO + n >= newuri + sizeof(newuri)) {
-                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 
-                                 0, r, "insufficient space in "
-                                 "expand_map_lookups, aborting");
-                    return;
-                }
-                memcpy(cpO, defaultvalue, n);
-                cpO += n;
-            }
-        }
-        else {
-            cpT = strstr(cpI, "${");
-            if (cpT == NULL)
-                cpT = cpI+strlen(cpI);
-            n = cpT-cpI;
-            if (cpO + n >= newuri + sizeof(newuri)) {
-                ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 
-                             0, r, "insufficient space in "
-                             "expand_map_lookups, aborting");
-                return;
-            }
-            memcpy(cpO, cpI, n);
-            cpO += n;
-            cpI += n;
-        }
-    }
-    *cpO = '\0';
-    apr_cpystrn(uri, newuri, uri_len);
-    return;
-}
-
-#undef limit_length
+#endif  /* if APR_HAS_USER */
 
 
 
@@ -2742,6 +2640,7 @@ static char *lookup_map(request_rec *r, char *name, char *key)
     rewritemap_entry *s;
     char *value;
     apr_finfo_t st;
+    apr_status_t rv;
     int i;
 
     /* get map configuration */
@@ -2755,8 +2654,9 @@ static char *lookup_map(request_rec *r, char *name, char *key)
         s = &entries[i];
         if (strcmp(s->name, name) == 0) {
             if (s->type == MAPTYPE_TXT) {
-                if (apr_stat(&st, s->checkfile, r->pool) != APR_SUCCESS) {
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                if ((rv = apr_stat(&st, s->checkfile, 
+                                   APR_FINFO_MIN, r->pool)) != APR_SUCCESS) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                                  "mod_rewrite: can't access text RewriteMap "
                                  "file %s", s->checkfile);
                     rewritelog(r, 1, "can't open RewriteMap file, "
@@ -2792,8 +2692,9 @@ static char *lookup_map(request_rec *r, char *name, char *key)
             }
             else if (s->type == MAPTYPE_DBM) {
 #ifndef NO_DBM_REWRITEMAP
-                if (apr_stat(&st, s->checkfile, r->pool) != APR_SUCCESS) {
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                if ((rv = apr_stat(&st, s->checkfile,
+                                   APR_FINFO_MIN, r->pool)) != APR_SUCCESS) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                                  "mod_rewrite: can't access DBM RewriteMap "
                                  "file %s", s->checkfile);
                     rewritelog(r, 1, "can't open DBM RewriteMap file, "
@@ -2854,8 +2755,9 @@ static char *lookup_map(request_rec *r, char *name, char *key)
                 }
             }
             else if (s->type == MAPTYPE_RND) {
-                if (apr_stat(&st, s->checkfile, r->pool) == -1) {
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                if ((rv = apr_stat(&st, s->checkfile,
+                                   APR_FINFO_MIN, r->pool)) != APR_SUCCESS) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                                  "mod_rewrite: can't access text RewriteMap "
                                  "file %s", s->checkfile);
                     rewritelog(r, 1, "can't open RewriteMap file, "
@@ -2900,7 +2802,7 @@ static char *lookup_map(request_rec *r, char *name, char *key)
     return NULL;
 }
 
-static char *lookup_map_txtfile(request_rec *r, char *file, char *key)
+static char *lookup_map_txtfile(request_rec *r, const char *file, char *key)
 {
     apr_file_t *fp = NULL;
     apr_status_t rc;
@@ -2911,12 +2813,12 @@ static char *lookup_map_txtfile(request_rec *r, char *file, char *key)
     char *curkey;
     char *curval;
 
-    rc = apr_open(&fp, file, APR_READ, APR_OS_DEFAULT, r->pool);
+    rc = apr_file_open(&fp, file, APR_READ, APR_OS_DEFAULT, r->pool);
     if (rc != APR_SUCCESS) {
        return NULL;
     }
 
-    while (apr_fgets(line, sizeof(line), fp) == APR_SUCCESS) {
+    while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) {
         if (line[0] == '#')
             continue; /* ignore comments */
         cpT = line;
@@ -2942,12 +2844,12 @@ static char *lookup_map_txtfile(request_rec *r, char *file, char *key)
         value = apr_pstrdup(r->pool, curval);
         break;
     }
-    apr_close(fp);
+    apr_file_close(fp);
     return value;
 }
 
 #ifndef NO_DBM_REWRITEMAP
-static char *lookup_map_dbmfile(request_rec *r, char *file, char *key)
+static char *lookup_map_dbmfile(request_rec *r, const char *file, char *key)
 {
     DBM *dbmfp = NULL;
     datum dbmkey;
@@ -2978,7 +2880,7 @@ static char *lookup_map_program(request_rec *r, apr_file_t *fpin,
     char buf[LONG_STRING_LEN];
     char c;
     int i;
-    apr_ssize_t nbytes;
+    apr_size_t nbytes;
 
 #ifndef NO_WRITEV
     struct iovec iova[2];
@@ -2996,14 +2898,16 @@ static char *lookup_map_program(request_rec *r, apr_file_t *fpin,
 
     /* take the lock */
 
-    apr_lock(rewrite_mapr_lock);
+    if (rewrite_mapr_lock_aquire) {
+        apr_lock_aquire(rewrite_mapr_lock_aquire);
+    }
 
     /* write out the request key */
 #ifdef NO_WRITEV
     nbytes = strlen(key);
-    apr_write(fpin, key, &nbytes);
+    apr_file_write(fpin, key, &nbytes);
     nbytes = 1;
-    apr_write(fpin, "\n", &nbytes);
+    apr_file_write(fpin, "\n", &nbytes);
 #else
     iova[0].iov_base = key;
     iova[0].iov_len = strlen(key);
@@ -3011,25 +2915,27 @@ static char *lookup_map_program(request_rec *r, apr_file_t *fpin,
     iova[1].iov_len = 1;
 
     niov = 2;
-    apr_writev(fpin, iova, niov, &nbytes);
+    apr_file_writev(fpin, iova, niov, &nbytes);
 #endif
 
     /* read in the response value */
     i = 0;
     nbytes = 1;
-    apr_read(fpout, &c, &nbytes);
+    apr_file_read(fpout, &c, &nbytes);
     while (nbytes == 1 && (i < LONG_STRING_LEN-1)) {
         if (c == '\n') {
             break;
         }
         buf[i++] = c;
 
-        apr_read(fpout, &c, &nbytes);
+        apr_file_read(fpout, &c, &nbytes);
     }
     buf[i] = '\0';
 
     /* give the lock back */
-    apr_unlock(rewrite_mapr_lock);
+    if (rewrite_mapr_lock_aquire) {
+        apr_lock_release(rewrite_mapr_lock_aquire);
+    }
 
     if (strcasecmp(buf, "NULL") == 0) {
         return NULL;
@@ -3054,7 +2960,7 @@ static char *rewrite_mapfunc_toupper(request_rec *r, char *key)
 
     for (cp = value = apr_pstrdup(r->pool, key); cp != NULL && *cp != '\0';
          cp++) {
-        *cp = ap_toupper(*cp);
+        *cp = apr_toupper(*cp);
     }
     return value;
 }
@@ -3065,7 +2971,7 @@ static char *rewrite_mapfunc_tolower(request_rec *r, char *key)
 
     for (cp = value = apr_pstrdup(r->pool, key); cp != NULL && *cp != '\0';
          cp++) {
-        *cp = ap_tolower(*cp);
+        *cp = apr_tolower(*cp);
     }
     return value;
 }
@@ -3181,7 +3087,7 @@ static void open_rewritelog(server_rec *s, apr_pool_t *p)
 
     if (*conf->rewritelogfile == '|') {
         if ((pl = ap_open_piped_log(p, conf->rewritelogfile+1)) == NULL) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, 
                          "mod_rewrite: could not open reliable pipe "
                          "to RewriteLog filter %s", conf->rewritelogfile+1);
             exit(1);
@@ -3189,9 +3095,9 @@ static void open_rewritelog(server_rec *s, apr_pool_t *p)
         conf->rewritelogfp = ap_piped_log_write_fd(pl);
     }
     else if (*conf->rewritelogfile != '\0') {
-        rc = apr_open(&conf->rewritelogfp, fname, rewritelog_flags, rewritelog_mode, p);
+        rc = apr_file_open(&conf->rewritelogfp, fname, rewritelog_flags, rewritelog_mode, p);
         if (rc != APR_SUCCESS)  {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, 
                          "mod_rewrite: could not open RewriteLog "
                          "file %s", fname);
             exit(1);
@@ -3211,7 +3117,7 @@ static void rewritelog(request_rec *r, int level, const char *text, ...)
     char redir[20];
     va_list ap;
     int i;
-    apr_ssize_t nbytes;
+    apr_size_t nbytes;
     request_rec *req;
     char *ruser;
     const char *rhost;
@@ -3279,10 +3185,10 @@ static void rewritelog(request_rec *r, int level, const char *text, ...)
                 (unsigned long)(r->server), (unsigned long)r,
                 type, redir, level, str2);
 
-    apr_lock(rewrite_log_lock);
+    apr_lock_aquire(rewrite_log_lock);
     nbytes = strlen(str3);
-    apr_write(conf->rewritelogfp, str3, &nbytes);
-    apr_unlock(rewrite_log_lock);
+    apr_file_write(conf->rewritelogfp, str3, &nbytes);
+    apr_lock_release(rewrite_log_lock);
 
     va_end(ap);
     return;
@@ -3290,11 +3196,11 @@ static void rewritelog(request_rec *r, int level, const char *text, ...)
 
 static char *current_logtime(request_rec *r)
 {
-    ap_exploded_time_t t;
+    apr_exploded_time_t t;
     char tstr[80];
     apr_size_t len;
 
-    apr_explode_localtime(&t, apr_now());
+    apr_explode_localtime(&t, apr_time_now());
 
     apr_strftime(tstr, &len, 80, "[%d/%b/%Y:%H:%M:%S ", &t);
     apr_snprintf(tstr + strlen(tstr), 80-strlen(tstr), "%c%.2d%.2d]",
@@ -3329,9 +3235,9 @@ static void rewritelock_create(server_rec *s, apr_pool_t *p)
     lockname = ap_server_root_relative(p, lockname);
 
     /* create the lockfile */
-    rc = apr_create_lock (&rewrite_mapr_lock, APR_MUTEX, APR_LOCKALL, lockname, p);
+    rc = apr_lock_create (&rewrite_mapr_lock_aquire, APR_MUTEX, APR_LOCKALL, lockname, p);
     if (rc != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+        ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
                      "mod_rewrite: Parent could not create RewriteLock "
                      "file %s", lockname);
         exit(1);
@@ -3348,8 +3254,8 @@ static apr_status_t rewritelock_remove(void *data)
     }
 
     /* destroy the rewritelock */
-    apr_destroy_lock (rewrite_mapr_lock);
-    rewrite_mapr_lock = NULL;
+    apr_lock_destroy (rewrite_mapr_lock_aquire);
+    rewrite_mapr_lock_aquire = NULL;
     lockname = NULL;
     return(0);
 }
@@ -3373,7 +3279,7 @@ static void run_rewritemap_programs(server_rec *s, apr_pool_t *p)
     rewritemap_entry *entries;
     rewritemap_entry *map;
     int i;
-    int rc;
+    apr_status_t rc;
 
     conf = ap_get_module_config(s->module_config, &rewrite_module);
 
@@ -3402,9 +3308,9 @@ static void run_rewritemap_programs(server_rec *s, apr_pool_t *p)
         rc = rewritemap_program_child(p, map->datafile,
                                      &fpout, &fpin, &fperr);
         if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+            ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
                          "mod_rewrite: could not fork child for "
-                         "RewriteMap process. %d", rc);
+                         "RewriteMap process");
             exit(1);
         }
         map->fpin  = fpin;
@@ -3415,11 +3321,11 @@ static void run_rewritemap_programs(server_rec *s, apr_pool_t *p)
 }
 
 /* child process code */
-static int rewritemap_program_child(apr_pool_t *p, char *progname,
-                                    apr_file_t **fpout, apr_file_t **fpin,
-                                    apr_file_t **fperr)
+static apr_status_t rewritemap_program_child(apr_pool_t *p, const char *progname,
+                                             apr_file_t **fpout, apr_file_t **fpin,
+                                             apr_file_t **fperr)
 {
-    int rc = -1;
+    apr_status_t rc;
     apr_procattr_t *procattr;
     apr_proc_t *procnew;
 
@@ -3428,22 +3334,22 @@ static int rewritemap_program_child(apr_pool_t *p, char *progname,
 #endif
 
     
-    if ((apr_createprocattr_init(&procattr, p)           != APR_SUCCESS) ||
-        (apr_setprocattr_io(procattr, APR_FULL_BLOCK,
-                                     APR_FULL_NONBLOCK,
-                                     APR_FULL_NONBLOCK) != APR_SUCCESS) ||
-        (apr_setprocattr_dir(procattr, ap_make_dirstr_parent(p, progname))
-                                                        != APR_SUCCESS) ||
-        (apr_setprocattr_cmdtype(procattr, APR_PROGRAM)  != APR_SUCCESS)) {
+    if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||
+        ((rc = apr_procattr_io_set(procattr, APR_FULL_BLOCK,
+                                  APR_FULL_NONBLOCK,
+                                  APR_FULL_NONBLOCK)) != APR_SUCCESS) ||
+        ((rc = apr_procattr_dir_set(procattr, 
+                                   ap_make_dirstr_parent(p, progname)))
+         != APR_SUCCESS) ||
+        ((rc = apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS)) {
         /* Something bad happened, give up and go away. */
-        rc = -1;
     }
     else {
         procnew = apr_pcalloc(p, sizeof(*procnew));
-        rc = apr_create_process(procnew, progname, NULL, NULL, procattr, p);
+        rc = apr_proc_create(procnew, progname, NULL, NULL, procattr, p);
     
         if (rc == APR_SUCCESS) {
-            apr_note_subprocess(p, procnew, kill_after_timeout);
+            apr_pool_note_subprocess(p, procnew, kill_after_timeout);
 
             if (fpin) {
                 (*fpin) = procnew->in;
@@ -3474,64 +3380,12 @@ static int rewritemap_program_child(apr_pool_t *p, char *progname,
 */
 
 
-static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len)
-{
-    char *newbuf;
-    newbuf = expand_variables(r, buf);
-    if (strcmp(newbuf, buf) != 0) {
-        apr_cpystrn(buf, newbuf, buf_len);
-    }
-    return;
-}
-
-static char *expand_variables(request_rec *r, char *str)
-{
-    char output[MAX_STRING_LEN];
-    char input[MAX_STRING_LEN];
-    char *cp;
-    char *cp2;
-    char *cp3;
-    int expanded;
-    char *outp;
-    char *endp;
-
-    apr_cpystrn(input, str, sizeof(input));
-    output[0] = '\0';
-    outp = output;
-    endp = output + sizeof(output);
-    expanded = 0;
-    for (cp = input; cp < input+MAX_STRING_LEN; ) {
-        if ((cp2 = strstr(cp, "%{")) != NULL) {
-            if ((cp3 = strstr(cp2, "}")) != NULL) {
-                *cp2 = '\0';
-                outp = apr_cpystrn(outp, cp, endp - outp);
-
-                cp2 += 2;
-                *cp3 = '\0';
-                outp = apr_cpystrn(outp, lookup_variable(r, cp2), endp - outp);
-
-                cp = cp3+1;
-                expanded = 1;
-                continue;
-            }
-        }
-        outp = apr_cpystrn(outp, cp, endp - outp);
-        break;
-    }
-    return expanded ? apr_pstrdup(r->pool, output) : str;
-}
-
 static char *lookup_variable(request_rec *r, char *var)
 {
     const char *result;
     char resultbuf[LONG_STRING_LEN];
-    ap_exploded_time_t tm;
+    apr_exploded_time_t tm;
     request_rec *rsub;
-#ifndef WIN32
-    struct passwd *pw;
-    struct group *gr;
-    apr_finfo_t finfo;
-#endif
 
     result = NULL;
 
@@ -3636,12 +3490,12 @@ static char *lookup_variable(request_rec *r, char *var)
 /* XXX: wow this has gotta be slow if you actually use it for a lot, recalculates exploded time for each variable */
     /* underlaying Unix system stuff */
     else if (strcasecmp(var, "TIME_YEAR") == 0) {
-        apr_explode_localtime(&tm, apr_now());
+        apr_explode_localtime(&tm, apr_time_now());
         apr_snprintf(resultbuf, sizeof(resultbuf), "%04d", tm.tm_year + 1900);
         result = resultbuf;
     }
 #define MKTIMESTR(format, tmfield) \
-    apr_explode_localtime(&tm, apr_now()); \
+    apr_explode_localtime(&tm, apr_time_now()); \
     apr_snprintf(resultbuf, sizeof(resultbuf), format, tm.tmfield); \
     result = resultbuf;
     else if (strcasecmp(var, "TIME_MON") == 0) {
@@ -3663,7 +3517,7 @@ static char *lookup_variable(request_rec *r, char *var)
         MKTIMESTR("%d", tm_wday)
     }
     else if (strcasecmp(var, "TIME") == 0) {
-        apr_explode_localtime(&tm, apr_now());
+        apr_explode_localtime(&tm, apr_time_now());
         apr_snprintf(resultbuf, sizeof(resultbuf),
                    "%04d%02d%02d%02d%02d%02d", tm.tm_year + 1900,
                    tm.tm_mon+1, tm.tm_mday,
@@ -3697,7 +3551,7 @@ static char *lookup_variable(request_rec *r, char *var)
                         /*   ...and sub and main paths differ */ \
                         && strcmp(r->main->uri, r->uri) != 0))) { \
             /* process a file-based subrequest */ \
-            rsub = subrecfunc(r->filename, r); \
+            rsub = subrecfunc(r->filename, r, NULL); \
             /* now recursively lookup the variable in the sub_req */ \
             result = lookup_variable(rsub, var+5); \
             /* copy it up to our scope before we destroy sub_req's apr_pool_t */ \
@@ -3720,42 +3574,19 @@ static char *lookup_variable(request_rec *r, char *var)
         LOOKAHEAD(ap_sub_req_lookup_file)
     }
 
-#if !defined(WIN32) && !defined(NETWARE)
-    /* Win32 has a rather different view of file ownerships.
-       For now, just forget it */
-
     /* file stuff */
     else if (strcasecmp(var, "SCRIPT_USER") == 0) {
         result = "<unknown>";
-        if (r->finfo.protection != 0) {
-            if ((pw = getpwuid(r->finfo.user)) != NULL) {
-                result = pw->pw_name;
-            }
-        }
-        else {
-            if (apr_stat(&finfo, r->filename, r->pool) == APR_SUCCESS) {
-                if ((pw = getpwuid(finfo.user)) != NULL) {
-                    result = pw->pw_name;
-                }
-            }
+        if (r->finfo.valid & APR_FINFO_USER) {
+            apr_get_username((char **)&result, r->finfo.user, r->pool);
         }
     }
     else if (strcasecmp(var, "SCRIPT_GROUP") == 0) {
         result = "<unknown>";
-        if (r->finfo.protection != 0) {
-            if ((gr = getgrgid(r->finfo.group)) != NULL) {
-                result = gr->gr_name;
-            }
-        }
-        else {
-            if (apr_stat(&finfo, r->filename, r->pool) == 0) {
-                if ((gr = getgrgid(finfo.group)) != NULL) {
-                    result = gr->gr_name;
-                }
-            }
+        if (r->finfo.valid & APR_FINFO_GROUP) {
+            apr_get_groupname((char **)&result, r->finfo.group, r->pool);
         }
     }
-#endif /* ndef WIN32 && NETWARE*/
 
     if (result == NULL) {
         return apr_pstrdup(r->pool, "");
@@ -3771,7 +3602,7 @@ static char *lookup_header(request_rec *r, const char *name)
     apr_table_entry_t *hdrs;
     int i;
 
-    hdrs_arr = ap_table_elts(r->headers_in);
+    hdrs_arr = apr_table_elts(r->headers_in);
     hdrs = (apr_table_entry_t *)hdrs_arr->elts;
     for (i = 0; i < hdrs_arr->nelts; ++i) {
         if (hdrs[i].key == NULL) {
@@ -3802,13 +3633,13 @@ static cache *init_cache(apr_pool_t *p)
     cache *c;
 
     c = (cache *)apr_palloc(p, sizeof(cache));
-    if (apr_create_pool(&c->pool, p) != APR_SUCCESS)
+    if (apr_pool_create(&c->pool, p) != APR_SUCCESS)
                return NULL;
-    c->lists = apr_make_array(c->pool, 2, sizeof(cachelist));
+    c->lists = apr_array_make(c->pool, 2, sizeof(cachelist));
     return c;
 }
 
-static void set_cache_string(cache *c, char *res, int mode, time_t t,
+static void set_cache_string(cache *c, const char *res, int mode, time_t t,
                              char *key, char *value)
 {
     cacheentry ce;
@@ -3820,7 +3651,7 @@ static void set_cache_string(cache *c, char *res, int mode, time_t t,
     return;
 }
 
-static char *get_cache_string(cache *c, char *res, int mode,
+static char *get_cache_string(cache *c, const char *res, int mode,
                               time_t t, char *key)
 {
     cacheentry *ce;
@@ -3886,7 +3717,7 @@ static void cache_tlb_replace(cachetlbentry *tlb, cacheentry *elt,
     tlb->t[0] = e - elt;
 }
 
-static void store_cache_string(cache *c, char *res, cacheentry *ce)
+static void store_cache_string(cache *c, const char *res, cacheentry *ce)
 {
     int i;
     int j;
@@ -3925,10 +3756,10 @@ static void store_cache_string(cache *c, char *res, cacheentry *ce)
 
     /* create a needed new list */
     if (!found_list) {
-        l = apr_push_array(c->lists);
+        l = apr_array_push(c->lists);
         l->resource = apr_pstrdup(c->pool, res);
-        l->entries  = apr_make_array(c->pool, 2, sizeof(cacheentry));
-        l->tlb      = apr_make_array(c->pool, CACHE_TLB_ROWS,
+        l->entries  = apr_array_make(c->pool, 2, sizeof(cacheentry));
+        l->tlb      = apr_array_make(c->pool, CACHE_TLB_ROWS,
                                     sizeof(cachetlbentry));
         for (i=0; i<CACHE_TLB_ROWS; ++i) {
             t = &((cachetlbentry *)l->tlb->elts)[i];
@@ -3941,7 +3772,7 @@ static void store_cache_string(cache *c, char *res, cacheentry *ce)
     for (i = 0; i < c->lists->nelts; i++) {
         l = &(((cachelist *)c->lists->elts)[i]);
         if (strcmp(l->resource, res) == 0) {
-            e = apr_push_array(l->entries);
+            e = apr_array_push(l->entries);
             e->time  = ce->time;
             e->key   = apr_pstrdup(c->pool, ce->key);
             e->value = apr_pstrdup(c->pool, ce->value);
@@ -3955,7 +3786,7 @@ static void store_cache_string(cache *c, char *res, cacheentry *ce)
     return;
 }
 
-static cacheentry *retrieve_cache_string(cache *c, char *res, char *key)
+static cacheentry *retrieve_cache_string(cache *c, const char *res, char *key)
 {
     int i;
     int j;
@@ -3994,7 +3825,7 @@ static cacheentry *retrieve_cache_string(cache *c, char *res, char *key)
 */
 
 static char *subst_prefix_path(request_rec *r, char *input, char *match,
-                               char *subst)
+                               const char *subst)
 {
     char matchbuf[LONG_STRING_LEN];
     char substbuf[LONG_STRING_LEN];
@@ -4135,6 +3966,23 @@ static void add_env_variable(request_rec *r, char *s)
 }
 
 
+/*
+**
+**  check that a subrequest won't cause infinite recursion
+**
+*/
+
+static int subreq_ok(request_rec *r)
+{
+    /*
+     * either not in a subrequest, or in a subrequest
+     * and URIs aren't NULL and sub/main URIs differ
+     */
+    return (r->main == NULL ||
+           (r->main->uri != NULL && r->uri != NULL &&
+            strcmp(r->main->uri, r->uri) != 0));
+}
+
 
 /*
 **
@@ -4154,7 +4002,7 @@ static int prefix_stat(const char *path, apr_finfo_t *sb)
     if ((cp = strchr(curpath+1, '/')) != NULL) {
         *cp = '\0';
     }
-    if (apr_stat(sb, curpath, NULL) == 0) {
+    if (apr_stat(sb, curpath, APR_FINFO_MIN, NULL) == APR_SUCCESS) {
         return 1;
     }
     else {
@@ -4193,11 +4041,105 @@ static int compare_lexicography(char *cpNum1, char *cpNum2)
     return 0;
 }
 
+/*
+**
+**  Bracketed expression handling
+**  s points after the opening bracket
+**
+*/
+
+static char *find_closing_bracket(char *s, int left, int right)
+{
+    int depth;
+
+    for (depth = 1; *s; ++s) {
+       if (*s == right && --depth == 0) {
+           return s;
+       }
+       else if (*s == left) {
+           ++depth;
+       }
+    }
+    return NULL;
+}
+
+static char *find_char_in_brackets(char *s, int c, int left, int right)
+{
+    int depth;
+
+    for (depth = 1; *s; ++s) {
+       if (*s == c && depth == 1) {
+           return s;
+       }
+       else if (*s == right && --depth == 0) {
+           return NULL;
+       }
+       else if (*s == left) {
+           ++depth;
+       }
+    }
+    return NULL;
+}
+
+/*
+**
+** Module paraphernalia
+**
+*/
+
 #ifdef NETWARE
 int main(int argc, char *argv[]) 
 {
     ExitThread(TSR_THREAD, 0);
 }
 #endif
+
+    /* the apr_table_t of commands we provide */
+static const command_rec command_table[] = {
+    AP_INIT_FLAG(    "RewriteEngine",   cmd_rewriteengine,  NULL, OR_FILEINFO,
+                     "On or Off to enable or disable (default) the whole "
+                     "rewriting engine"),
+    AP_INIT_ITERATE( "RewriteOptions",  cmd_rewriteoptions,  NULL, OR_FILEINFO,
+                     "List of option strings to set"),
+    AP_INIT_TAKE1(   "RewriteBase",     cmd_rewritebase,     NULL, OR_FILEINFO, 
+                     "the base URL of the per-directory context"),
+    AP_INIT_RAW_ARGS("RewriteCond",     cmd_rewritecond,     NULL, OR_FILEINFO,
+                     "an input string and a to be applied regexp-pattern"),
+    AP_INIT_RAW_ARGS("RewriteRule",     cmd_rewriterule,     NULL, OR_FILEINFO,
+                     "an URL-applied regexp-pattern and a substitution URL"),
+    AP_INIT_TAKE2(   "RewriteMap",      cmd_rewritemap,      NULL, RSRC_CONF,
+                     "a mapname and a filename"),
+    AP_INIT_TAKE1(   "RewriteLock",     cmd_rewritelock,     NULL, RSRC_CONF,
+                     "the filename of a lockfile used for inter-process "
+                     "synchronization"),
+    AP_INIT_TAKE1(   "RewriteLog",      cmd_rewritelog,      NULL, RSRC_CONF,
+                     "the filename of the rewriting logfile"),
+    AP_INIT_TAKE1(   "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF,
+                     "the level of the rewriting logfile verbosity "
+                     "(0=none, 1=std, .., 9=max)"),
+    { NULL }
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+    ap_hook_handler(handler_redirect, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_post_config(init_module,NULL,NULL,APR_HOOK_MIDDLE);
+    ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
+
+    ap_hook_fixups(hook_fixup,NULL,NULL,APR_HOOK_FIRST);
+    ap_hook_translate_name(hook_uri2file,NULL,NULL,APR_HOOK_FIRST);
+    ap_hook_type_checker(hook_mimetype,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+    /* the main config structure */
+module AP_MODULE_DECLARE_DATA rewrite_module = {
+   STANDARD20_MODULE_STUFF,
+   config_perdir_create,        /* create per-dir    config structures */
+   config_perdir_merge,         /* merge  per-dir    config structures */
+   config_server_create,        /* create per-server config structures */
+   config_server_merge,         /* merge  per-server config structures */
+   command_table,               /* apr_table_t of config file commands  */
+   register_hooks               /* register hooks                      */
+};
  
 /*EOF*/