Warm tip: This article is reproduced from stackoverflow.com, please click
.htaccess apache

mod_rewrite debugging shows unexpected REWRITE_COND order of events

发布于 2020-04-11 22:02:17

I noticed something unexpected when debugging rewrite rules: it seems that the order of events is that Apache processes a rule, and then retroactively applies the preceding conditions to it. Is this as-designed, or am I misinterpreting something?

Here's a simple example of a rewrite rule in my .htaccess file. It doesn't really do anything useful -- it's just an example.

    RewriteEngine on
    Options FollowSymLinks
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . / [L]

And here is the resulting trace (heavily redacted for readability)

[...redacted...] init rewrite engine with requested uri /test.html
[...redacted...] pass through /test.html
[...redacted...] [perdir /var/www/html/] strip per-dir prefix: /var/www/html/test.html -> test.html
[...redacted...] [perdir /var/www/html/] applying pattern '.' to uri 'test.html'
[...redacted...] [perdir /var/www/html/] RewriteCond: input='/var/www/html/test.html' pattern='!-f' => not-matched
[...redacted...] [perdir /var/www/html/] pass through /var/www/html/test.html

Notice that "RewriteCond" gets applied after the pattern gets applied. The ultimate result is a pass-through, which is correct (since the file does, in fact exist), so it doesn't really matter. I couldn't find anything about this in the documentation.

Questioner
ericbakes
Viewed
71
04FS 2020-02-03 16:32

it seems that the order of events is that Apache processes a rule, and then retroactively applies the preceding conditions to it. Is this as-designed, or am I misinterpreting something?

Yes, that is how it works.

The RewriteRule has to match first. Only if that is the case, the RewriteCond-itions are evaluated. If these then match, the rewrite is performed.

This is not so clearly mentioned on the manual page that describes the syntax for RewriteCond and -Rule; https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html#rewritecond just says,

The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.

Now you could imply the processing order from this maybe (if you read it in “logical” order, left to right), but it is not very explicit.

But https://httpd.apache.org/docs/2.4/rewrite/intro.html#regex says,

Regex Back-Reference Availability
One important thing here has to be remembered: Whenever you use parentheses in Pattern or in one of the CondPattern, back-references are internally created which can be used with the strings $N and %N (see below). These are available for creating the Substitution parameter of a RewriteRule or the TestString parameter of a RewriteCond.

Captures in the RewriteRule patterns are (counterintuitively) available to all preceding RewriteCond directives, because the RewriteRule expression is evaluated before the individual conditions.

(Highlight at the end by me.)

So in that place you find this behavior explicitly mentioned.