Reputation: 1441
I don't want to blame RewriteRule, but so it looks to me.
Minimal example. In the real code, the first Rule does some prepending, so it has some meaning, as opposed to this.
RewriteRule ^(.*)$ $1
RewriteCond %{REQUEST_URI} ^/pre
RewriteRule ^(.*)$ /post=$1 [R=301,L]
When submitted URL is example.com/pre/sub
, I am getting 301 to example.com/post=pre/sub/sub
. I have no idea where that second sub is coming from.
The way I think this should work. First rule $1
is pre/sub
and so it rewrites pre/sub
to pre/sub
. The cond checks whether REQUEST_URI starts with /pre and prevents looping and the last rule matches everything so $1
is pre/sub
and it appends it creating /post=pre/sub
, to which it is then redirected. But the browser gets /post=/pre/sub/sub
.
Some testing I have done:
Submitting only example.com/pre
results in expected /post=pre
;
When I modify the example to
RewriteRule ^(.*)$ -$1-
RewriteCond %{REQUEST_URI} ^/pre
RewriteRule ^(.*)$ /post=&$1& [R=301,L]
The resulting redirect is to /post=&-pre/sub-/sub&
meaning it is appended "after" the first rule, but "before" the second one. But where and how?
Upvotes: 1
Views: 127
Reputation: 1441
Pheeew... this took some headache. After some digging around I decided to turn on logging for mod_rewrite. <my-docroot-path>
is, well, absolute path to document root on my machine.
add path info postfix: <my-docroot-path>/pre -> <my-docroot-path>/pre/sub
strip per-dir prefix: <my-docroot-path>/pre/sub -> pre/sub
applying pattern '^(.*)$' to uri 'pre/sub'
rewrite 'pre/sub' -> 'pre/sub'
add per-dir prefix: pre/sub -> <my-docroot-path>/pre/sub
add path info postfix: <my-docroot-path>/pre/sub -> <my-docroot-path>/pre/sub/sub
strip per-dir prefix: <my-docroot-path>/pre/sub/sub -> pre/sub/sub
applying pattern '^(.*)$' to uri 'pre/sub/sub'
As you can see on line 1 and 6, there is some postfixing going on. It apparently appends path components above the current processed directory. The current processed directory (location of .htaccess) is document root (/
) so, so it "expects" you to process current directory level entries (/pre
). After you are done processing (with RewriteRule) it appends the nested path components to that result.
That is why when you are handling request, that is on the same directory level, it creates no problems, because there is nothing to append.
It can be (and is officially recommended to be) fixed by adding DPI
flag, to that RewriteRule directive. DPI means "Discard Path Info", which discards the nested path components, which would be postfixed and therefor appends nothing.
OR... if you don't want to change the nested path, just include only the current level directory/file name in the substitution string. The remainder will be postfixed. This is (at least for me) somewhat misleading, since the pattern is matched against the whole path, but it expects you to change (include in substitution string) only the current level dir/filename. But it makes sense... it gives you the context to make a decision and expects you to change only the part, for the directory level, that the .htaccess belongs to.
This is the official bug report for it.
https://bz.apache.org/bugzilla/show_bug.cgi?id=38642
Doc for DPI
flag
https://httpd.apache.org/docs/current/rewrite/flags.html#flag_dpi
And some other SO topic, that was helpful
https://stackoverflow.com/a/5520004/2468189
Upvotes: 1