]> granicus.if.org Git - apache/commitdiff
Prevent endless loops of internal redirects in mod_rewrite by
authorAndre Malo <nd@apache.org>
Sat, 1 Mar 2003 18:35:50 +0000 (18:35 +0000)
committerAndre Malo <nd@apache.org>
Sat, 1 Mar 2003 18:35:50 +0000 (18:35 +0000)
aborting after exceeding a limit of internal redirects. The
limit defaults to 10 and can be changed using the RewriteOptions
directive with the new MaxRedirects=n argument.
(The latter required some restructuring of the RewriteOptions
 evaluation code).

(Documentation patch follows asap)

PR: 17462

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98863 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
modules/mappers/mod_rewrite.c
modules/mappers/mod_rewrite.h

diff --git a/CHANGES b/CHANGES
index 636a780066e591c7e497966c401064ea46e782cb..559c0787381e479b4c2c10c118434dba4d6f7cd7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,12 +2,17 @@ Changes with Apache 2.1.0-dev
 
   [Remove entries to the current 2.0 section below, when backported]
 
+  *) Prevent endless loops of internal redirects in mod_rewrite by
+     aborting after exceeding a limit of internal redirects. The
+     limit defaults to 10 and can be changed using the RewriteOptions
+     directive. PR 17462.  [AndrĂ© Malo]
+
   *) mod_rewrite: Fix some problems reporting errors with mapping
      programs (RewriteMap prg:/something).  [Jeff Trawick]
 
   *) Win32: Avoid busy wait (consuming all the CPU idle cycles) when
      all worker threads are busy. 
-    [Igor Nazarenko <igor_nazarenko@hotmail.com>]
+     [Igor Nazarenko <igor_nazarenko@hotmail.com>]
 
   *) When using Redirect in directory context, append requested query
      string if there's no one supplied by configuration. PR 10961.
index 2d38bccdd22eafece384537f3b0c4c1c0b398cc8..a5b8fdc7ef184fb4102cba1c54f572bf7b92c6e0 100644 (file)
@@ -206,6 +206,7 @@ static void *config_server_create(apr_pool_t *p, server_rec *s)
     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 @@ static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv)
     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 @@ static void *config_perdir_create(apr_pool_t *p, char *path)
     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 @@ static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv)
     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_rewriteengine(cmd_parms *cmd,
 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,6 +1678,15 @@ static int handler_redirect(request_rec *r)
         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);
@@ -1664,6 +1695,60 @@ static int handler_redirect(request_rec *r)
     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);
+}
+
 
 /*
 ** +-------------------------------------------------------+
index 5a4b904354142826b6fd83f124d8b52dce751593..2a46b6199b712582c6fb60b8a90ce7fc8e8b1f91 100644 (file)
 
 #define MAX_NMATCH    10
 
+/* default maximum number of internal redirects */
+#define REWRITE_REDIRECT_LIMIT 10
 
 
 /*
@@ -271,6 +273,7 @@ typedef struct {
     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 @@ typedef struct {
     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
      */
@@ -343,8 +355,6 @@ static const char *cmd_rewriteengine(cmd_parms *cmd,
 static const char *cmd_rewriteoptions(cmd_parms *cmd,
                                       void *dconf,
                                       const char *option);
-static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options,
-                                                const char *name);
 static const char *cmd_rewritelog     (cmd_parms *cmd, void *dconf, const char *a1);
 static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1);
 static const char *cmd_rewritemap     (cmd_parms *cmd, void *dconf, 
@@ -467,6 +477,7 @@ static int    prefix_stat(const char *path, apr_pool_t *pool);
 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);