Mod rewrite/Hide a script
Using mod_rewrite, we'd like to route all requests for a domain sub.example.com/
to be redirected to a single FastCGI script at d/dispatch.fcgi
under the document root. This would be trivial, except that a request to sub.example.com/d/dispatch.fcgi
has to behave differently depending on whether the request came from the browser or from a rewrite rule.
These are a few minimum criteria for success:
Contents
Easy criteria
If the client requests… | then the rewrite must be to… | and PATH_INFO should be… |
---|---|---|
sub.example.com/ | sub.example.com/d/dispatch.fcgi/ | / |
sub.example.com/foo | sub.example.com/d/dispatch.fcgi/foo | /foo |
sub.example.com/foo/ | sub.example.com/d/dispatch.fcgi/foo/ | /foo/ |
sub.example.com/foo/bar | sub.example.com/d/dispatch.fcgi/foo/bar | /foo/bar |
Difficult criteria
If the client requests… | then the rewrite must be to… | and PATH_INFO should be… |
---|---|---|
sub.example.com/d | sub.example.com/d/dispatch.fcgi/d | /d |
sub.example.com/d/ | sub.example.com/d/dispatch.fcgi/d/ | /d/ |
sub.example.com/d/dispatch.fcgi | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi | /d/dispatch.cgi |
sub.example.com/d/dispatch.fcgi/ | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/ | /d/dispatch.fcgi/ |
sub.example.com/d/dispatch.fcgi/foo | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo | /d/dispatch.fcgi/foo |
sub.example.com/d/dispatch.fcgi/foo/ | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo/ | /d/dispatch.fcgi/foo/ |
sub.example.com/d/dispatch.fcgi/foo/bar | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo/bar | /d/dispatch.fcgi/foo/bar |
Test script
This script is placed at d/dispatch.fcgi under the document root.
#!/usr/bin/perl
use FCGI;
my %original_env = %ENV;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
my $counter = 0;
while ( FCGI::accept() >= 0 ) {
$counter++;
print "Content-Type: text/plain\n\n";
print "PATH_INFO: $ENV{PATH_INFO}\n";
print Dumper { '0-counter' => $counter, '1-initial-env' => \%original_env, '2-script-env' => \%ENV };
}
The trivial (and incorrect) answer
This is the answer we'd give if we didn't care about hiding.
Files
/.htaccess
RewriteEngine on
RewriteRule ^(.*)$ d/dispatch.fcgi/$1 [L]
/d/.htaccess
Without at least RewriteEngine on
here, a 500 results. (This is because when this .htaccess is missing, the root .htaccess handles the directory, getting caught in an infinite loop.)
RewriteEngine on
Failures
If the client requests… | then the rewrite must be to… | and PATH_INFO should be… | but instead, PATH_INFO is… |
---|---|---|---|
sub.example.com/d | sub.example.com/d/dispatch.fcgi/d | /d | N/A (The directory listing for /d/ is displayed) |
sub.example.com/d/ | sub.example.com/d/dispatch.fcgi/d/ | /d/ | N/A (The directory listing for /d/ is displayed) |
sub.example.com/d/dispatch.fcgi | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi | /d/dispatch.cgi | (empty string) |
sub.example.com/d/dispatch.fcgi/ | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/ | /d/dispatch.fcgi/ | / |
sub.example.com/d/dispatch.fcgi/foo | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo | /d/dispatch.fcgi/foo | /foo |
sub.example.com/d/dispatch.fcgi/foo/ | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo/ | /d/dispatch.fcgi/foo/ | /foo/ |
sub.example.com/d/dispatch.fcgi/foo/bar | sub.example.com/d/dispatch.fcgi/d/dispatch.fcgi/foo/bar | /d/dispatch.fcgi/foo/bar | /foo/bar |
Almost perfect
/.htaccess
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ d/dispatch.fcgi/$1
/d/.htaccess (omit)
Omit this file so that the directory is also handled by the root .htaccess.
Failures
Everything works as specified except this bit where Apache insistently appends a trailing slash when something looks like a directory.
If the client requests… | then the rewrite must be to… | and PATH_INFO should be… | but instead, PATH_INFO is… |
---|---|---|---|
sub.example.com/d | sub.example.com/d/dispatch.fcgi/d | /d | N/A (server 301s the request to sub.example.com/d/, with a trailing slash) |