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

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)