Forum Moderators: phranque

Message Too Old, No Replies

RewriteRule being ignored with trailing slash or filename

Works on "/dir"; ignored on "/dir/" or "/dir/file.html"

         

Robb

1:00 pm on Feb 24, 2004 (gmt 0)

10+ Year Member



I have created a password protected directory, called "secure", which is itself inside a directory called "test" (so "secure" is actually "/test/secure").

I would like different users who log into the "secure" directory to get automatically sent to different sub directories, e.g. "client1_area" (i.e. "/test/secure/client1_area)

My ".htaccess" file in "secure" is as follows:


AuthUserFile /private/passwords/.htpasswd
AuthGroupFile /dev/null
AuthName "Client Area"
AuthType Basic
ErrorDocument 401 /test/loginfailure.html
<Limit GET>
require valid-user
</Limit>

RewriteEngine on
RewriteRule .*(test/secure)(.*)$ /$1/%{REMOTE_USER}_area$2

(Note: the ".*" at the start of the URL on the last line is necessary to strip off parts of the *file path* that are not parts of the *URL path*.)

If I try to access "/test/secure" then I am correctly prompted for a username and password (if I hadn't already logged in). If I log in as "Client1" I get correctly redirected to "/test/secure/client1_area/".

However, if I try to access "/test/secure/" (note the trailing slash) or "/test/secure/file.htm" then while I am still correctly prompted for a username and password (if I hadn't already logged in) I do not get redirected. It's clear that the RewriteRule is not firing - even if %{REMOTE_USER} was empty for some reason, "_area" would still get added to the URL.

I can only assume there's something wrong with the left hand side of my RewriteRule, but I can't work out what...

Any advice would be much appreciated.

Thanks,

Robb

jdMorgan

3:39 pm on Feb 24, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Robb,

This is a very odd problem. While you *do not* need to precede your RewriteRule pattern with ".*" (because the pattern is unanchored), there is nothing really wrong with your pattern. So, I can't give you a quick-fix.

However, one thing that may not be obvious is that the difference between the URLs that work and those that don't is that the one that works will invoke mod_dir to to a redirect, due to the missing trailing slash (see mod_dir [httpd.apache.org]). Apparently, this redirect is doing some kind of "fix up" on your original URL that is needed to trigger the rule.

That's all the code-related help I can offer. But I'd recommend breaking your problem down by doing the following:

1) Decouple the rewrite problem from the authorization problem -- Create a dummy directory with some dummy subdirectories and files in it, and rewrite/redirect to those until you get the rewrite worked out.

2) Temporarily change the form of the rule to use an external (301/302) redirect, so that you can see the new URL in your browser address bar. Get it working, and then change it back to an internal rewrite.

Also, something in the back of my mind keeps urging me to tell you to check the setting of UseCanonicalName [httpd.apache.org] on your server. There are certain circumstances where having this set to "on" can really mess things up, and this may be one of those cases. This is a server-configuration setting, and may not be something you can get changed. If not, then perhaps using the external redirect method to investigate this problem will yield more information that can be used to come up with a viable work-around.

Jim

Robb

5:37 pm on Feb 24, 2004 (gmt 0)

10+ Year Member



> This is a very odd problem. While you *do not* need to precede your
> RewriteRule pattern with ".*" (because the pattern is unanchored),
> there is nothing really wrong with your pattern. So, I can't give
> you a quick-fix.

Thanks - I thought the pattern looked OK (after all it's not very
complicated!) But if I leave out the ".*" it ends up trying to send
me to [mydomain.com[b]...]
("/www/docs" is part of the file path, but not part of the correct
URL).

> However, one thing that may not be obvious is that the difference
> between the URLs that work and those that don't is that the one that
> works will invoke mod_dir to to a redirect, due to the missing
> trailing slash (see mod_dir). Apparently, this redirect is doing
> some kind of "fix up" on your original URL that is needed to trigger
> the rule.

Interesting. At least there's *some* logic to when it is and isn't
working then. I'll probe this further...

> 1) Decouple the rewrite problem from the authorization problem --

Good idea.

> 2) Temporarily change the form of the rule to use an external
> (301/302) redirect, so that you can see the new URL in your browser
> address bar. Get it working, and then change it back to an internal
> rewrite.

Tried that, but it didn't work as the rule wasn't firing. However,
this will be useful to find out what mod_dir is up to...

> Also, something in the back of my mind keeps urging me to tell you
> to check the setting of UseCanonicalName on your server... This is a
> server-configuration setting, and may not be something you can get
> changed.

You guessed it...

Anyway, will give these ideas a go and post back with the results.

Cheers,

Robb

Robb

6:37 pm on Feb 24, 2004 (gmt 0)

10+ Year Member



Excellent. Thanks for the help. Problem now solved.

However another has been created in the solution...

Getting my .htaccess file to rewrite *everything* showed exactly what was going on with mod_dir.

With:


RewriteRule (.*) http://www.my_other_domain.com/$1

"/secure" redirected me to
[my_other_domain.com...]

whereas
"/secure/" redirected me to
[my_other_domain.com...]

So it's no wonder my pattern didn't match!

So I changed my rules to the following:


RewriteRule ^/www/docs/test/secure$ ""
RewriteRule (.*) /test/secure/%{REMOTE_USER}_area$1 [L]

This meant that "/secure" was effectively converted to "/secure/" giving me a common base to work from.

However, what now happens is this...

I ask for /secure
This gets rewritten to /secure/client1_area
This then gets rewritten as /secure/client1_area/client1_area
etc. until it falls over.

So now what I need to do is stop this recursion.

I've tried putting in a condition something like:


RewriteCond %{REQUEST_URI} %(REMOTE_USER}

but it seems I can't have an environment variable on the right hand side of a condition (I always get a 500 error when I try).

I've also tried something like:


RewriteRule (%(REMOTE_USER}) .* [L]
RewriteRule (.*) /test/secure/%{REMOTE_USER}_area$1 [L]

but it seems I can't have an environment variable on the left hand side of a rule (again I always get a 500 error when I try).

How can I say, "don't do this if the path already contains their username"?

Thanks again,

Robb

Robb

7:18 pm on Feb 24, 2004 (gmt 0)

10+ Year Member



I'd still be interested to know the answer, but I've got around it by moving the client directories out of "secure" and giving them their own .htaccess files that don't do any re-writing.

Thanks again.

jdMorgan

8:50 pm on Feb 24, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Robb,

This regex, including a back-reference declaration:
.*(foo)
is entirely equivalent to
(foo)
because neither pattern is anchored.

If the patterns were anchored, then
^(foo)
would match only strings starting with the letter "f" and continuing "oo"
So, if there might be something in front of that substring, you could change the pattern to
^.*(foo)
But that is redundant, so you might as well just use
(foo)

It is possible that some change that you made for the purpose of publicly posting your code is hiding something important in this case. But if not, and you really must put .* on the front-end of an unanchored pattern to make your code work, then there is something very wrong with your mod_rewrite or regex-processing modules, and you may need to recompile them.

---
On to the "real" problem...

You could try this:


RewriteCond %{REMOTE_USER} (.+)
RewriteRule (.*) /test/secure/%1_area$1 [L]

-or-

RewriteCond %{REQUEST_URI} !^/test/secure/.+_area
RewriteRule (.*) /test/secure/%{REMOTE_USER}_area$1 [L]

to require that REMOTE_USER be provided and stop the recursion.

However:
I suggest you look into the RewriteBase directive of mod_rewrite. The symtoms you are seeing indicate that you may need to use


RewriteBase /www/docs
after your [i]RewriteEngine on[/i] directive.

This may remove the need to do all those work-arounds.

Jim

Robb

3:07 am on Feb 25, 2004 (gmt 0)

10+ Year Member



I see your point on the regex now. I was somehow imagining that if I used (foo) I'd be getting the same as I would if I'd used (.*foo) - though obviously I wouldn't. (Though, I thought I remembered it not working without the ".*"...)

> RewriteCond %{REMOTE_USER} (.+)
> RewriteRule (.*) /test/secure/%1_area$1 [L]

Hmm, I'll have to give that a go. I can't immediately see why that wouldn't recur when my version does, but I'm no expert at these rules (as you may have guessed!)

> RewriteCond %{REQUEST_URI}!^/test/secure/.+_area
> RewriteRule (.*) /test/secure/%{REMOTE_USER}_area$1 [L]

This one wouldn't do. I need to make sure the user can't just change the URL and avoid the rewrite. I don't want someone looking at "client1_area" to be able to change the "1" to a "2" int the URL and avoid the rewrite (if they made this change they should get sent to "client1_area/client2_area").

> I suggest you look into the RewriteBase directive of mod_rewrite. The symtoms you are
> seeing indicate that you may need to use
>
> RewriteBase /www/docs
> after your RewriteEngine on directive.

I did try that - but it didn't help. But the server is set up kind of strangely... (not my doing!)

Thanks again for all your help.

jdMorgan

4:19 am on Feb 25, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You can use both RewriteConds with the RewriteRule as well. Just make sure that the RewriteCond which defines the %1 (user) backreference is placed immediately before the RewriteRule.

I won't claim that what I posted is finished, highly-polished code. It's just intended to give you some ideas. :)

Jim