]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
backport from 2.x:
authorAndré Malo <nd@apache.org>
Wed, 19 Mar 2003 14:01:08 +0000 (14:01 +0000)
committerAndré Malo <nd@apache.org>
Wed, 19 Mar 2003 14:01:08 +0000 (14:01 +0000)
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 with the new MaxRedirects=n argument.
(The latter required some restructuring of the RewriteOptions
 evaluation code).

PR: 17462
Reviewed by: Will Rowe, Ian Holsman

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@99022 13f79535-47bb-0310-9956-ffa450edef68

src/CHANGES
src/modules/standard/mod_rewrite.c
src/modules/standard/mod_rewrite.h

index 1b026646060aee77a8f7722d0e21f29e4b37975b..a6b9ee40d54e750bf630c0dae36203fb5f961ba1 100644 (file)
@@ -1,5 +1,10 @@
 Changes with Apache 1.3.28
 
+  *) backport from 2.x series: 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]
+
   *) Use the correct locations of srm.conf and access.conf when tailoring
      the httpd.conf during the install process. PR 9446.
      [Stanislav Brabec <utx@penguin.cz>]
index fdac21eae3a012209d881c9d0301242a0e79f3ca..9a905e8474f70892811dc070c8198b034f26e0e5 100644 (file)
@@ -252,6 +252,7 @@ static void *config_server_create(pool *p, server_rec *s)
     a->rewriteconds    = ap_make_array(p, 2, sizeof(rewritecond_entry));
     a->rewriterules    = ap_make_array(p, 2, sizeof(rewriterule_entry));
     a->server          = s;
+    a->redirect_limit  = 0; /* unset (use default) */
 
     return (void *)a;
 }
@@ -267,6 +268,9 @@ static void *config_server_merge(pool *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) {
         /*
@@ -323,6 +327,7 @@ static void *config_perdir_create(pool *p, char *path)
     a->baseurl         = NULL;
     a->rewriteconds    = ap_make_array(p, 2, sizeof(rewritecond_entry));
     a->rewriterules    = ap_make_array(p, 2, sizeof(rewriterule_entry));
+    a->redirect_limit  = 0; /* unset (use server config) */
 
     if (path == NULL) {
         a->directory = NULL;
@@ -353,6 +358,9 @@ static void *config_perdir_merge(pool *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 = ap_append_arrays(p, overrides->rewriteconds,
@@ -395,36 +403,50 @@ 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_server_conf *sconf;
-    const char *err;
+    int options = 0, limit = 0;
+    char *w;
 
-    sconf = (rewrite_server_conf *)
-            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 ap_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(pool *p, int *options,
-                                                char *name)
-{
-    if (strcasecmp(name, "inherit") == 0) {
-        *options |= OPTION_INHERIT;
+        conf->options |= options;
+        conf->redirect_limit = limit;
     }
-    else {
-        return ap_pstrcat(p, "RewriteOptions: unknown option '",
-                          name, "'\n", NULL);
+    else {                  /* is per-directory command */
+        rewrite_perdir_conf *conf = in_dconf;
+
+        conf->options |= options;
+        conf->redirect_limit = limit;
     }
+
     return NULL;
 }
 
@@ -1598,6 +1620,15 @@ static int handler_redirect(request_rec *r)
         return DECLINED;
     }
 
+    if (is_redirect_limit_exceeded(r)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 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(ap_pstrcat(r->pool, r->filename+9,
                                     r->args ? "?" : NULL, r->args, NULL), r);
@@ -1606,6 +1637,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 = ap_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|APLOG_NOERRNO, 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 27806b1335c835250c612e45f2ab7b9028577dc1..47f43917f5abe95eaa19a51174560de43c7d1cfb 100644 (file)
 
 #define MAX_NMATCH    10
 
+/* default maximum number of internal redirects */
+#define REWRITE_REDIRECT_LIMIT 10
+
 /*
 **
 **  our private data structures we handle with
@@ -309,6 +312,7 @@ typedef struct {
     array_header *rewriteconds;    /* the RewriteCond entries (temporary) */
     array_header *rewriterules;    /* the RewriteRule entries */
     server_rec   *server;          /* the corresponding server indicator */
+    int          redirect_limit;   /* maximum number of internal redirects */
 } rewrite_server_conf;
 
 
@@ -322,8 +326,16 @@ typedef struct {
     array_header *rewriterules;    /* the RewriteRule entries */
     char         *directory;       /* the directory where it applies */
     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 table with LRU functionality
@@ -376,10 +388,8 @@ static void *config_perdir_merge (pool *p, void *basev, void *overridesv);
 static const char *cmd_rewriteengine(cmd_parms *cmd,
                                      rewrite_perdir_conf *dconf, int flag);
 static const char *cmd_rewriteoptions(cmd_parms *cmd,
-                                      rewrite_perdir_conf *dconf,
-                                      char *option);
-static const char *cmd_rewriteoptions_setoption(pool *p, int *options,
-                                                char *name);
+                                      void *in_dconf,
+                                      const char *option);
 static const char *cmd_rewritelog     (cmd_parms *cmd, void *dconf, char *a1);
 static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1);
 static const char *cmd_rewritemap     (cmd_parms *cmd, void *dconf, char *a1,
@@ -489,6 +499,7 @@ static int    parseargline(char *str, char **a1, char **a2, char **a3);
 static int    prefix_stat(const char *path, struct stat *sb);
 static void   add_env_variable(request_rec *r, char *s);
 static int    subreq_ok(request_rec *r);
+static int    is_redirect_limit_exceeded(request_rec *r);
 
     /* File locking */
 static void fd_lock(request_rec *r, int fd);