* Mads Toftum wrote:

> On second thought (after looking through my odd collection of rewrite examples)
> I do tend to agree with you, since I'm having a very hard time imagining
> any case where even more than a couple would be useful. So I'm all for
> limiting to 10 (or even 5 for that matter) as long as it will result in an
> explanatory message to the error_log (LogLevel debug).

Well, attached a patch to limit the redirects. I'm just unsure before 
committing: One can use

RewriteOptions MaxRedirects=n

to change the limit (also during a redirect, seems to make sense for me 
anyway). In contrast to all the other mod_rewrite config stuff it's 
inherited all the time regardless of the RewriteOptions inherit setting. Is 
that behaviour okay or should we respect the inherit option here, too?

Just FYI: my little testsuite. Put the following into the document root 
directory container ... (after applying the patch ;-)

RewriteEngine On
#RewriteOptions MaxRedirects=20
RewriteBase /
RewriteRule (.*) / [L]

TIA, nd
-- 
die (eval q-qq[Just Another Perl Hacker
]
;-)
# Andr� Malo, <http://pub.perlig.de/> #
diff -Nur httpd-2.1/modules/mappers/mod_rewrite.c 
httpd-2.1.rewriteloop/modules/mappers/mod_rewrite.c
--- httpd-2.1/modules/mappers/mod_rewrite.c     Thu Feb 27 04:08:06 2003
+++ httpd-2.1.rewriteloop/modules/mappers/mod_rewrite.c Fri Feb 28 01:56:46 2003
@@ -206,6 +206,7 @@
     a->rewriteconds    = apr_array_make(p, 2, sizeof(rewritecond_entry));
     a->rewriterules    = apr_array_make(p, 2, sizeof(rewriterule_entry));
     a->server          = s;
+    a->redirect_limit  = 0; /* unset (use default) */
 
     return (void *)a;
 }
@@ -222,6 +223,9 @@
     a->state   = overrides->state;
     a->options = overrides->options;
     a->server  = overrides->server;
+    a->redirect_limit = overrides->redirect_limit
+                          ? overrides->redirect_limit
+                          : base->redirect_limit;
 
     if (a->options & OPTION_INHERIT) {
         /*
@@ -278,6 +282,7 @@
     a->baseurl         = NULL;
     a->rewriteconds    = apr_array_make(p, 2, sizeof(rewritecond_entry));
     a->rewriterules    = apr_array_make(p, 2, sizeof(rewriterule_entry));
+    a->redirect_limit  = 0; /* unset (use server config) */
 
     if (path == NULL) {
         a->directory = NULL;
@@ -308,6 +313,9 @@
     a->options   = overrides->options;
     a->directory = overrides->directory;
     a->baseurl   = overrides->baseurl;
+    a->redirect_limit = overrides->redirect_limit
+                          ? overrides->redirect_limit
+                          : base->redirect_limit;
 
     if (a->options & OPTION_INHERIT) {
         a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
@@ -351,34 +359,48 @@
 static const char *cmd_rewriteoptions(cmd_parms *cmd,
                                       void *in_dconf, const char *option)
 {
-    rewrite_perdir_conf *dconf = in_dconf;
-    rewrite_server_conf *sconf;
-    const char *err;
+    int options = 0, limit = 0;
+    char *w;
 
-    sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
+    while (*option) {
+        w = ap_getword_conf(cmd->pool, &option);
 
-    if (cmd->path == NULL) { /* is server command */
-        err = cmd_rewriteoptions_setoption(cmd->pool,
-                                           &(sconf->options), option);
-    }
-    else {                 /* is per-directory command */
-        err = cmd_rewriteoptions_setoption(cmd->pool,
-                                           &(dconf->options), option);
+        if (!strcasecmp(w, "inherit")) {
+            options |= OPTION_INHERIT;
+        }
+        else if (!strncasecmp(w, "MaxRedirects=", 13)) {
+            limit = atoi(&w[13]);
+            if (limit <= 0) {
+                return "RewriteOptions: MaxRedirects takes a number greater "
+                       "than zero.";
+            }
+        }
+        else if (!strcasecmp(w, "MaxRedirects")) { /* be nice */
+            return "RewriteOptions: MaxRedirects has the format MaxRedirects"
+                   "=n.";
+        }
+        else {
+            return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '",
+                               w, "'", NULL);
+        }
     }
 
-    return err;
-}
+    /* put it into the appropriate config */
+    if (cmd->path == NULL) { /* is server command */
+        rewrite_server_conf *conf =
+            ap_get_module_config(cmd->server->module_config,
+                                 &rewrite_module);
 
-static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options,
-                                                const char *name)
-{
-    if (strcasecmp(name, "inherit") == 0) {
-        *options |= OPTION_INHERIT;
+        conf->options |= options;
+        conf->redirect_limit = limit;
     }
-    else {
-        return apr_pstrcat(p, "RewriteOptions: unknown option '",
-                          name, "'", NULL);
+    else {                  /* is per-directory command */
+        rewrite_perdir_conf *conf = in_dconf;
+
+        conf->options |= options;
+        conf->redirect_limit = limit;
     }
+
     return NULL;
 }
 
@@ -1656,12 +1678,75 @@
         return DECLINED;
     }
 
+    if (is_redirect_limit_exceeded(r)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "mod_rewrite: maximum number of internal redirects "
+                      "reached. Assuming configuration error. Use "
+                      "'RewriteOptions MaxRedirects' to increase the limit "
+                      "if neccessary.");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     /* now do the internal redirect */
     ap_internal_redirect(apr_pstrcat(r->pool, r->filename+9,
                                      r->args ? "?" : NULL, r->args, NULL), r);
 
     /* and return gracefully */
     return OK;
+}
+
+/*
+ * check whether redirect limit is reached
+ */
+static int is_redirect_limit_exceeded(request_rec *r)
+{
+    request_rec *top = r;
+    rewrite_request_conf *reqc;
+    rewrite_perdir_conf *dconf;
+
+    /* we store it in the top request */
+    while (top->main) {
+        top = top->main;
+    }
+    while (top->prev) {
+        top = top->prev;
+    }
+
+    /* fetch our config */
+    reqc = (rewrite_request_conf *) ap_get_module_config(top->request_config,
+                                                         &rewrite_module);
+
+    /* no config there? create one. */
+    if (!reqc) {
+        rewrite_server_conf *sconf;
+
+        reqc = apr_palloc(top->pool, sizeof(rewrite_request_conf));
+        sconf = ap_get_module_config(r->server->module_config, &rewrite_module);
+
+        reqc->redirects = 0;
+        reqc->redirect_limit = sconf->redirect_limit
+                                 ? sconf->redirect_limit
+                                 : REWRITE_REDIRECT_LIMIT;
+
+        /* associate it with this request */
+        ap_set_module_config(top->request_config, &rewrite_module, reqc);
+    }
+
+    /* allow to change the limit during redirects. */
+    dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
+                                                        &rewrite_module);
+
+    /* 0 == unset; take server conf ... */
+    if (dconf->redirect_limit) {
+        reqc->redirect_limit = dconf->redirect_limit;
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                  "mod_rewrite's internal redirect status: %d/%d.",
+                  reqc->redirects, reqc->redirect_limit);
+
+    /* and now give the caller a hint */
+    return (reqc->redirects++ >= reqc->redirect_limit);
 }
 
 
diff -Nur httpd-2.1/modules/mappers/mod_rewrite.h 
httpd-2.1.rewriteloop/modules/mappers/mod_rewrite.h
--- httpd-2.1/modules/mappers/mod_rewrite.h     Thu Feb 27 04:08:06 2003
+++ httpd-2.1.rewriteloop/modules/mappers/mod_rewrite.h Fri Feb 28 00:34:47 2003
@@ -212,6 +212,8 @@
 
 #define MAX_NMATCH    10
 
+/* default maximum number of internal redirects */
+#define REWRITE_REDIRECT_LIMIT 10
 
 
 /*
@@ -271,6 +273,7 @@
     apr_array_header_t *rewriteconds;    /* the RewriteCond entries (temporary) */
     apr_array_header_t *rewriterules;    /* the RewriteRule entries */
     server_rec   *server;          /* the corresponding server indicator */
+    int          redirect_limit;   /* maximum number of internal redirects */
 } rewrite_server_conf;
 
 
@@ -284,9 +287,18 @@
     apr_array_header_t *rewriterules;    /* the RewriteRule entries */
     char         *directory;       /* the directory where it applies */
     const char   *baseurl;         /* the base-URL  where it applies */
+    int          redirect_limit;   /* maximum number of internal redirects */
 } rewrite_perdir_conf;
 
 
+    /* the per-request configuration
+     */
+typedef struct {
+    int           redirects;       /* current number of redirects */
+    int           redirect_limit;  /* maximum number of redirects */
+} rewrite_request_conf;
+
+
     /* the cache structures,
      * a 4-way hash apr_table_t with LRU functionality
      */
@@ -467,6 +479,7 @@
 static void   add_env_variable(request_rec *r, char *s);
 static void   add_cookie(request_rec *r, char *s);
 static int    subreq_ok(request_rec *r);
+static int    is_redirect_limit_exceeded(request_rec *r);
 
     /* Lexicographic Comparison */
 static int compare_lexicography(char *cpNum1, char *cpNum2);

Reply via email to