Trivial mod_rewrite: Redirect to another file in the same directory
Wednesday, March 19. 2014
I found a funny quote at Htaccess Rewrites - Rewrite Tricks and Tips, it says:
``Despite the tons of examples and docs, mod_rewrite is voodoo. Damned cool voodoo, but still voodoo. ''
-- Brian Moore
bem@news.cmc.net
The quote is originally at http://httpd.apache.org/docs/2.0/rewrite/. Now obsoleted documentation for old Apache version.
I'll have to second Brian's opinion. I've touched the subject earlier at Advanced mod_rewrite: FastCGI Ruby on Rails /w HTTPS.
My YUM-repo definition RPM had a bug in it (see: CentOS 6 PHP 5.4 and 5.5 yum repository) and I had to release a new version of it. There exist already couple of links to the file. Why didn't I think of a situation where an update is released? Darn! So, let's keep the URL alive, even if a new version of the file with different name is released. That way everybody stays happy.
Attempt 1: Failure
An over enthusiastic "hey, that should be simple!" -type of naive solution. Create a .htaccess-file into the appropriate directory with content:
RedirectPermanent oldname.rpm newname.rpm
Well ... no. The result is a HTTP/500 and in the error log there was a:
/home/the/entire/path/here/.htaccess: Redirect to non-URL
Ok. It didn't work.
Attempt 2: Failure
Let's ramp this up. Forget the simple tools, hit it with mod_rewrite! Make .htaccess contain:
RewriteEngine on
RewriteRule ^oldname\.rpm$ newname.rpm [R=301]
Well ... no. The result is a HTTP/404, because the redirect goes really wrong. The result will be http://my.server.name/home/the/entire/path/here/newname.rpm, which is pretty far from being correct. There is a funny mix of URL and the actual filesystem storage.
The reason can be found from the Apache docs at RewriteRule PT-flag:
"The target (or substitution string) in a RewriteRule is assumed to be a file path, by default. The use of the [PT] flag causes it to be treated as a URI instead."
and
"Note that the PT flag is implied in per-directory contexts such as <Directory> sections or in .htaccess files."
That phrase can be translated as:
- Internally RewriteRule works with filesystem paths
- When using RewriteRule from a .htaccess-file it does not use filesystem paths, but URLs
- A .htaccess-file really messes things up
Something more elegant is obviously needed.
Attempt 3: Failure
I studied the Apache docs and found a perfect solution! What about if there was a way to discard the filesystem path entirely. Nice! Let's go that way, make .htaccess contain:
RewriteEngine on
RewriteRule ^oldname\.rpm$ newname.rpm [R=301,DPI]
Well ... no. I have the DiscardPathInfo-flag there, but it changes absolutely nothing. It is the same with or without the flag. It clearly says that "The DPI flag causes the PATH_INFO portion of the rewritten URI to be discarded" in the docs. Apparently the flag is used for completely different thing (which I'm having hard time to comprehend), but the thing is that I cannot use it to fix my redirect.
Attempt 4: Success!
After browsing the Apache-docs even more I struck gold. The docs for RewriteBase-directive say:
"This directive is required when you use a relative path in a substitution in per-directory (htaccess) context"
and
"This misconfiguration would normally cause the server to look for an "opt" directory under the document root."
That's exactly what I'm doing here. I have a relative path. I'm using a substitution in a .htaccess-file. It even mis-behaves precisely like in the example from the docs.
The solution is to make .htaccess contain:
RewriteEngine on
RewriteBase /path/here/
RewriteRule ^oldname\.rpm$ newname.rpm [R=301]
Now it works exactly as I want it to do! Nice!
When a request is done for the old filename, Apache will do an external redirect and notify browser about the new version. wget fails to save the file with the new name (it will use the old name), but for example Firefox does that correctly.
Conclusion
Darn that voodoo is hard.
The mod_rewrite's complexity simply laughs at any system administrator. I consider myself to be one of the experienced ones, but still ... I find myself struggling with the subject.