Forum Moderators: phranque

Message Too Old, No Replies

Variable use in RewriteCond to stop infinite loop

Variable use in RewriteCond to stop infinite loop mod_rewrite

         

sensming

10:13 pm on Feb 5, 2008 (gmt 0)

10+ Year Member



I am looking to rewrite a URL that looks like;

/CLIENT/application?client=CLIENT&arg1=val1&arg2=val2
------ ------

Such that the "client" in the query string will *always* match the "client" defined in the directory that begins that URL, so that you can't do something like;

/CLIENT/application?client=ANOTHERCLIENT&arg1=val1&arg2=val2
------ -------------

Due to the fact that my mod_rewrite is so/so, I wrote a little Perl script that performs the translation exactly as I want, and I call that with RewriteMap;

RewriteMap application prg:/opt/apache/conf/rewrite.application.pl
RewriteRule (.*application.*) ${application:$1?%{QUERY_STRING}} [R]

Which rewrites all possible permutations (client arg anywhere in QS, no client arg in QS, client!= directory, etc) of the URL correctly to;

/CLIENT/application?arg1=val1&arg2=val2&client=CLIENT

...with the client=CLIENT always being the last characters on the line, and always matching the directory that starts the URL.

Problem is, I create an infinite loop because the resulting URL also matches the pattern (.*application.*).

As such, I want to use RewriteCond to capture the ^/(CLIENT)/ into a variable, then test to see first if the URL already ends in the proper client=CLIENT, but I am not having much luck.

I have made this work statically;

RewriteMap application prg:/opt/apache/conf/rewrite.application.pl
RewriteCond %{QUERY_STRING}!client=CLIENT$ [NC]
RewriteRule (.*application.*) ${application:$1?%{QUERY_STRING}} [R]

But have had little luck doing it dynamically, even in a simple test case (the real one would need ^/([^/]+)/.*, or similar);

RewriteMap application prg:/opt/apache/conf/rewrite.application.pl
RewriteCond %{REQUEST_URI} ^/(CLIENT)/.*
RewriteCond %{QUERY_STRING}!client=%1$ [NC]
RewriteRule (.*application.*) ${application:$1?%{QUERY_STRING}} [R]

And the mod_rewrite logs don't show the translation of the %1 into what it represents... I just see;

pattern='!client=%1$' => matched

...which doesn't really help me.

Any advice that anyone has would be great.

Thanks.

jdMorgan

11:13 pm on Feb 6, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



RewriteRule (.*application.*) ${application:$1?%{QUERY_STRING}} [R]
Output from RewriteMap is /<CLIENT>/application?arg1=val1&arg2=val2&client=<CLIENT>

Now, what are the possible URL-path permutations that can exist in the path-prefix to be matched by the first instance of the ".*" subpattern in your RewriteRule?

The solution hinges entirely on the answer to that. If no unique identifier will (or can be made to) occur in that URL-prefix (or possibly in the suffix or in the query string itself), then the problem is unsolvable.

mod_rewrite can only use the information provided in the request -- So *something* has to be different between the URLs to be redirected and those which are not to be redirected.

Also, are you sure you really want a redirect here, and not a 'silent' internal rewrite?

Jim

sensming

11:36 pm on Feb 6, 2008 (gmt 0)

10+ Year Member



Thanks for the response, Jim.

Unfortunately, there is not difference in the before/after URL's except for the Query String, which is why I was trying to stop the loop by seeing if my QS looked "adjusted".

I just could not get the 2nd RewriteCond to use the %1 from the previous RewriteCond (in my last example).

At any rate, I have resorted to using an internal redirect, and it is working as I would expect.

I fear that this may make debugging problems harder in the future (when the displayed url does not match the "real" url), but, alas...

Thanks for you input. This sanity-checked the answer I had come to on my own.

jdMorgan

1:11 am on Feb 7, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The problem is that you cannot compare two variables in a RewriteCond. For example,
RewriteCond %2 ^some_pattern$
is perfectly valid, but the 'thing' on the right side is always a regex pattern, and cannot be a variable.

I'm sorry, but I overlooked this detail when looking at your original post.

It *is* possible to do a compare by using POSIX 1003.2 atomic back-references and a commutativity/concatenation trick; that is, if B+A=A+A, then A=B. Example back-reference code here [webmasterworld.com].

However, the POSIX library is dependent on the OS build, and using these newer POSIX features can pose serious 'portability' risks should you ever need to change or upgrade your server and/or OS.

[added]The only 'real' URLs are the ones published on your pages, and those are only symbolic references in the HTTP namespace; The 'real' things are files, not URLs. [/added]

Jim