RewriteRule Last [L] flag not working?

The Surrican picture The Surrican · Jul 23, 2011 · Viewed 37.2k times · Source
php_flag display_errors 1
php_value auto_prepend_file init.php
RewriteEngine on 
RewriteRule ^$  /id/authenticate [R]
RewriteRule ^login_openid$  /id/login_openid.php [QSA,L]
RewriteRule ^authenticate$  /id/authenticate.php [QSA,L]
RewriteRule ^facebook$  /id/facebook.php [QSA,L]
RewriteRule ^createfromopenid$  /id/createfromopenid.php [QSA,L]

RewriteRule .* - [L,R=403]

This is my .htaccess file. In the serverconfig I just have AllowOVerride all.

If I request the URL http://mydomain.com/id/authenticate I get a 403 Error. If I remove the last rule, it works. Shouldnt the [L] flat prevent any further rules from happening?

Edit:

My htaccess file is in the subfolder "id", so the rules work.

Answer

LazyOne picture LazyOne · Jul 23, 2011

The [L] rule works fine -- you just do not know how it actually works.

When Apache sees the [L] flag and rule matches (rewrite occurs), Apache will go to next iteration and will start matching all rules again from top. The [L] flag means "do not process any rules below in this iteration".

Yes, the Apache documentation is not 100% clear on this (which means it can be improved), but provides enough info to figure it out eventually.


Apache will stop rewrite cycle in few situations:

  1. No rules matched at all (no rewrite occurred);

  2. "exit now" rule matched (e.g. RewriteRule .* - [L]);

  3. Rewrite occurs, but input URL and final URLs are the same (happens on 2nd-3rd iteration when "badly" written rule rewrites the same URL to the same URL.

    For example RewriteRule (.*) /index.php?page=$1 [L]:

    • /hello => /index.php?page=hello
    • on next iteration it will rewrite /index.php => /index.php?page=index.php
    • and on 3rd iteration it will be /index.php => /index.php?page=index.php .. which makes no sense now);
  4. Rewrite iteration limit is reached (by default = 10) -- that's if you entered infinite rewrite cycle (the value is controlled by LimitInternalRecursion Directive).


With all aforementioned information I can say that your current rules do work as expected. This means that you have to change the logic and get rid of the last rule (maybe handle this moment in parent .htaccess .. or handle it differently -- all depends on how your application is built, I do not want to make wild guesses).