Mansoor
Mansoor

Reputation: 285

Why does mod_rewrite process the rules after the [L] flag

There are the rules:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) dir/index.php?$1 [L]
RewriteRule dir/index\.php.* - [F]

Why the last rule is processed and it returns Forbidden for all requests?

I need that if file or directory is not found then the next rule shouldn't be processed.

The next example isn't working for me as well:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? - [S=1]
RewriteRule dir/index\.php.* - [F]
RewriteRule (.+) dir/index.php?$1

It still returns Forbidden for all requests.

Upvotes: 3

Views: 2896

Answers (2)

Salman Arshad
Salman Arshad

Reputation: 272116

Why the last rule is processed and it returns Forbidden for all requests?

When the URL foobar is requested:

  • The two conditions (line 2, 3) match
2   RewriteCond %{REQUEST_FILENAME} !-f
3   RewriteCond %{REQUEST_FILENAME} !-d
  • Pattern matches, the resulting URL becomes dir/index.php?foobar with (line 4)
4   RewriteRule (.+) dir/index.php?$1 [L]

Note that the [L] flag causes the rewriting to stop; but it does not stop Apache from having another go at the rewritten URL since it has changed (see below about handling .htaccess directives).

With dir/index.php as the input URL:

  • The condition does not match (line 2) since file exists
  • Jumps to line 5
5   RewriteRule dir/index\.php.* - [F]
  • Pattern matches, hence the Forbidden error

When directory or filename changes, Apache has to re-evaluate various configuration sections (e.g. Directory and Files) and the .htaccess file for the "re-written" path. This is why Apache might perform another iteration even when the previous one was ended with the [L] flag.

The last string supposes to restrict the direct access to UFL handler. Direct access means requesting the file through a link like: domain.com/dir/index.php

I think adding another condition before line 5 should work:

RewriteCond %{THE_REQUEST} dir/index\.php\x20HTTP/\d\.\d$
RewriteRule . - [F]

The THE_REQUEST server variable contains the request sent by the browser without any rewriting applied. This could be useful to detect what page was originally requested by the browser.

THE_REQUEST

The full HTTP request line sent by the browser to the server (e.g., "GET /index.html HTTP/1.1"). This does not include any additional headers sent by the browser. This value has not been unescaped (decoded), unlike most other variables below.

Upvotes: 2

ryufly
ryufly

Reputation: 113

I am not exactly sure of what you meant by "the next rule".

But if you don't want some rules to be executed when a non-existent file is requested, then using the following structure may help. (The following piece of code is copied from the Apache RewriteRule Flags Page)

# Is the request for a non-existent file?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# If so, skip these two RewriteRules
RewriteRule .? - [S=2]

    RewriteRule (.*\.gif) images.php?$1
    RewriteRule (.*\.html) docs.php?$1

And also using [R] for redirecting instead of [L] might help with the problem of returning Forbidden for all requests.

Upvotes: 0

Related Questions