Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RewriteRule Last [L] flag not working?

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.

like image 517
The Surrican Avatar asked Jul 23 '11 03:07

The Surrican


People also ask

What is QSA in htaccess?

QSA means that if there's a query string passed with the original URL, it will be appended to the rewrite ( olle? p=1 will be rewritten as index.

What is RewriteRule * F?

RewriteRule "\.exe" "-" [F] This example uses the "-" syntax for the rewrite target, which means that the requested URI is not modified. There's no reason to rewrite to another URI, if you're going to forbid the request.

What is $1 RewriteRule?

In your rewrite, the ^ signifies the start of the string, the (. *) says to match anything, and the $ signifies the end of the string. So, basically, it's saying grab everything from the start to the end of the string and assign that value to $1.

What is NC in RewriteCond?

The [NC] specifies that the http host is case insensitive. The escapes the "." - because this is a special character (normally, the dot (.) means that one character is unspecified). The final line describes the action that should be executed: RewriteRule ^(.*)$ http://www. example.com/$1 [L,R=301]


2 Answers

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).

like image 103
LazyOne Avatar answered Sep 23 '22 04:09

LazyOne


Put this in front of your cath all rule.

RewriteCond %{ENV:REDIRECT_STATUS} !=200 

The problem is that once the [L] flag is processed, all the next RewriteRules are indeed ignored, however, the file gets processed AGAIN from the begin, now with the new url.

This magic Condition will not process the catch all if the file was already redirected.

PS: If it doesn't work, you might need to tweak the condition a bit: 200, !=200, ^., ^$.
Apparentely the variable gets set to 200 for a redirect, but also other pages (error and stuff) set it to some value. Now that means that you either check if it is empty, is not empty, is 200 or is not 200, depending on what you need.

like image 38
Qwerty Avatar answered Sep 24 '22 04:09

Qwerty