homepage Welcome to WebmasterWorld Guest from 54.166.100.8
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / Apache Web Server
Forum Library, Charter, Moderators: Ocean10000 & incrediBILL & phranque

Apache Web Server Forum

    
[L] only working for non-rewrites?
Skier88




msg:4299005
 5:20 pm on Apr 16, 2011 (gmt 0)

I've been messing around with what I thought would be a very simple htaccess file (given that I have a decent knowledge of regex) for a long time, and I finally got it working by doing something I expected to be pointless. The recurring problem was that the [L] flag was not stopping the rewriting process. ie, one rule with the last flag would match a url and rewrite it, and then the next rule would match the url that request was rewritten to and rewrite it again.

The only solution I've found is to add in another rule which matches the url the first rule rewrites to, does not modify it, and also has the [L] flag. Here is the complete file - the "INTERNAL REDIRECTS" section should be the only one you need to look at, but since I'm no apache guru I'm not sure that the rest of the code isn't having effects I don't know about.

# ERROR DOCUMENTS
ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 500 /error/500.html

RewriteEngine on

# ACCESS CONTROLS
RewriteRule \.ini$ - [F]
RewriteRule (/|^)\.ht(access|passwd|group)$ - [F]

# EXTERNAL REDIRECTS
RewriteCond %{HTTP_HOST} !^(example\.com)?$
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

# INTERNAL REDIRECTS
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^(s/|(index\.php)?$) - [L]
RewriteRule ^.+?/.+ details.php [L]
RewriteRule details.php - [L]
RewriteRule ^[^/]+$ list.php [L]


The intent (and effect) is to pass through requests for the index page or anything in the /s directory, rewrite everything 2 levels deep (example.com/category/item) to details.php, and rewrite everything 1 level deep (example.com/category) or 0 but with a query string (example.com/?price=10-30) to list.php.

The line matching /s and the index effectively stops execution yet the next line does not (the file fails if the line after that is removed). Why? Does [L] only work for rules that don't do anything (rewrite to "-")?

 

jdMorgan




msg:4303798
 8:25 pm on Apr 25, 2011 (gmt 0)

Due to being executed in the Apache API "fix-up" phaae, mod_rewrite processing is recursive, so [L] only stops processing for this pass through the code.

Using [L] is still worthwhile, since only the last pass through the code will need to process all of the rules (The [L] flag is only applied if the entire rule matches, and so is never applied on the last pass, when no rule matches).

Therefore, all .htaccess mod-rewrite recursion must be explicitly prevented, either by excluding rewrite target paths, or by using %{REDIRECT_STATUS} or %{REQUEST_URI} in rewritconds to see if this request has already been rewritten.

It still appears that "list.php" rewriting will recurse.

Consider using a "wider" exclusion pattern and scope, such as excluding all .php requests (and the others) from being rewritten right a the top. Consider moving the single-rule-specific exclusions into rewriteconds, rather than using a preceding "quit if" rule. Remember that rewriteconds are not processed unless the rewriterule pattern matches. This can be used to eliminate unnecessary processing.

Jim

Skier88




msg:4304970
 7:06 pm on Apr 27, 2011 (gmt 0)

Hi Jim, thanks for your response, it's just what I was missing. I rewrote the "internal redirects" section according to your help and guidelines and it works flawlessly. And I know it's an improvement since it reads like the description of my first attempt. Here's my new code:
RewriteCond %{REQUEST_URI} ^/.+/
RewriteRule !^s/ details.php [L]
RewriteCond %{QUERY_STRING} . [OR]
RewriteCond %{REQUEST_URI} ^/[^/]+$
RewriteRule !\.php$ list.php

My only concern is that requests for example.com/s/resource.jpg?params will be rewritten to list.php. What I need is the equivalent of if((A and B) or C), but I don't know how to do that in apache.

Also, I looked at my previous code again and it looks to me like you're right, list.php recurses indefinitely. However, I tested it and for some reason it works fine. And speaking of things I don't understand, why does a request for a directory appear as both a null string and the default string (index.*)? It behaves as if it runs the file twice, once with the directory request (example.com/category/) and once with an index request (example.com/category/index.html).

g1smd




msg:4304979
 7:20 pm on Apr 27, 2011 (gmt 0)

I guess that happens because folder requests are internally rewritten to add the index filename to the internal pointer (from the DirectoryIndex index.php directive or from an internal rewrite) and the rules are then tested again to see if any further actions are required.

Skier88




msg:4304981
 7:27 pm on Apr 27, 2011 (gmt 0)

That makes sense, and it's not too hard to account for. It just seems to me like there should be a set execution order, not just keep going until there's nothing left to do.

g1smd




msg:4304986
 7:29 pm on Apr 27, 2011 (gmt 0)

Yes, it keeps going until there are no rules left to match.

That's why the [L] flag is so important, in order to stop processing if THIS rule was matched.

Skier88




msg:4304998
 7:40 pm on Apr 27, 2011 (gmt 0)

Well, of this pass anyway, as jdMorgan just informed me. But I was thinking (hoping) the index rewrite would be on some other level of processing and therefore not subject to this somewhat inefficient process. I don't really have a question (about this part) any more, I'm just complaining :p

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / Apache Web Server
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved