BenMorel
BenMorel

Reputation: 36514

Rewriting does not stop after matching a RewriteRule with the [L] flag

I want to rewrite the path /health to /health.php.

I currently have have the following .htaccess file, with a catch-all rule:

RewriteEngine On
RewriteRule ^.*$ index.php [L]

So I just added a new rule before the catch-all:

RewriteEngine On
RewriteRule ^health$ health.php [L]
RewriteRule ^.*$ index.php [L]

But to my surprise, it doesn't rewrite to health.php when I request /health in the browser.

However, when I remove the last (catch-all) rule, it works as expected.

Why doesn't mod_rewrite stop processing rules after matching a rule with the [L] flag?

Upvotes: 2

Views: 774

Answers (1)

BenMorel
BenMorel

Reputation: 36514

Found it. I always thought that the [L] flag stopped the processing of all the rules, period. Actually, it just stops processing rules in the current ruleset, but then re-runs the whole ruleset on the rewritten request.

Hence, my catch-all code was finally catching it, as the rewrite log shows:

strip per-dir prefix: [...]/public/health -> health
applying pattern '^health$' to uri 'health'
rewrite 'health' -> 'health.php'
add per-dir prefix: health.php -> [...]/public/health.php
strip document_root prefix: [...]/public/health.php -> /health.php
internal redirect with /health.php [INTERNAL REDIRECT]

strip per-dir prefix: [...]/public/health.php -> health.php
applying pattern '^health$' to uri 'health.php'
strip per-dir prefix: [...]/public/health.php -> health.php
applying pattern '^.*$' to uri 'health.php'
rewrite 'health.php' -> 'index.php'
add per-dir prefix: index.php -> [...]/public/index.php
strip document_root prefix: [...]/public/index.php -> /index.php
internal redirect with /index.php [INTERNAL REDIRECT]

strip per-dir prefix: [...]/public/index.php -> index.php
applying pattern '^health$' to uri 'index.php'
strip per-dir prefix: [...]/public/index.php -> index.php
applying pattern '^.*$' to uri 'index.php'
rewrite 'index.php' -> 'index.php'
add per-dir prefix: index.php -> [...]/public/index.php
initial URL equal rewritten URL: [...]/public/index.php [IGNORING REWRITE]

The solution, found on this blog, involves putting a conditional before the catch-all rule, to only execute it when no internal redirect has been processed before:

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^.*$ index.php [L]

Upvotes: 5

Related Questions