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;
}
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) {
/*
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;
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,
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;
}
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);
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);
+}
+
/*
** +-------------------------------------------------------+
#define MAX_NMATCH 10
+/* default maximum number of internal redirects */
+#define REWRITE_REDIRECT_LIMIT 10
/*
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;
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
*/
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,
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);