Hi all.In mod_rewrite, we have the RewriteEngine directive, that in theory is able to switch the engine on and off. In practise however, you can switch it on, but once on globally, you cannot switch it off again - the directive has no effect.
This directive stores this flag in two places - the server config, or the directory config, leading to the server contradicting itself - one RewriteEngine directive, two places where this is stored:
if (cmd->path == NULL) { /* is server command */
sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
}
else /* is per-directory command */ {
dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
}
When an attempt is made to turn the engine off in the directory scope,
the server scope stays active, you can't switch it off.
mod_rewrite hooks into two different hooks to do its magic, the translate_name hook for global rewrite rules, and the fixups hook for per-directory rewrite rules. In turn, the translate_name hook only looks for the flag in the global content, while the fixups hook only looks up the flag in the directory context. An attempt to turn off RewriteEngine in a directory leaves the engine on globally.
By way of example, this leads to this confusion: # turn engine on in global scope RewriteEngine on RewriteRule ... <Location /foo># turn off engine in directory scope (but contradictory global scope stays enabled)
RewriteEngine off # at this point, global rewrites are still on (!!!) </Location>This leads to the extremely (for us) undesirable situation where we cannot turn off global rewrite rules, they run on every single subrequest, including subrequests where we explicitly want the engine switched off.
Turns out we do need two copies of the flags - mod_rewrite has code that runs at the server scope only (specifically the code inside run_rewritemap_programs()). What we're doing wrong, when we set the flag at server scope, is that we're forgetting to also set the flag at directory scope at the same time, removing the contradiction.
This still doesn't fix the problem. Turns out that mod_rewrite suffers the config-merge bug, where if RewriteOption is set, RewriteEngine is also reset at the same time. This has been masked to date because the RewriteEngine directive didn't work as above.
The attached fix does two things, both are required or the problem isn't fixed:
- Adds *_set variables, so that config merge works properly.- Sets the server-and-directory flags at the same time, or the directory flag only, and uses the directory flag were possible, and the server flag in run_rewritemap_programs(). This makes RewriteEngine and RewriteOption work properly.
Looking in bugzilla it looks like the following reports may be affected by this: PR46743, PR50004, PR39313.
Does this patch make sense? Regards, Graham --
httpd-mod_rewrite-rewriteengine-fix.patch
Description: Binary data
