Mod rewrite/Hide a script

From HalfgeekKB
Jump to navigation Jump to search

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:

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

Perfection

/.htaccess

RewriteEngine on

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ d/dispatch.fcgi/$1

/d/.htaccess

This .htaccess doesn't do any rewriting, but a directive needs to be added here to prevent /d from being 301ed to /d/ (with a trailing slash).

DirectorySlash Off