mod_rewrite, subfolders and trailing slashes

I’m posting this because I spent many hours debugging this issue and couldn’t find a single site on the internet that provided a solution. I’m not thrilled with the answer I have, so if anyone knows of a better way to do this, I’m all ears.

The goal

I’m currently starting to host multiple web applications on a single domain in separate subfolders. For example, wordify should be served from http://www.snoyman.com/wordify/. Since I’m using Apache on my host, I need to use mod_rewrite to accomplish this. Anyone who has ever dealt with mod_rewrite probably has the same fear of it that I do. However, I’m purposely not going to go into a mod_rewrite rant.

Anyway, the mod_rewrite needs to make an internal redirect (meaning not changing the user’s URL via a 301 redirect) to the CGI script. For example, I want a request to http://www.snoyman.com/wordify/toword/57/ to be treated by Apache as http://www.snoyman.com/wordify/dispatch.cgi/toword/57/. No problem.

The problem

My initial solution gave a problem when people went to http://www.snoyman.com/wordify. In particular, it would redirect them to a URL based on the absolute filename on the system of the request (eg, http://www.snoyman.com/f5/snoyman/public/…). My temporary solution was to set up a 301 redirect from that ugly URL to the correct location, but that’s not an efficient solution since it requires a whole extra round trip for the user to get to the page.

It turns out that mod_rewrite does funny stuff with converting URLs to pathnames, and there’s no way to specify which type of value you would like to deal with.

The solution

Below is my new .htaccess file. Here’s what you need to know to follow this and adapt it to your own purposes:

  • The root of my website is /f5/snoyman/public
  • All of the wordify files are kept in /f5/snoyman/public/wordify
  • The CGI program for generating the content is called dispatch.cgi
Options +ExecCGI
AddHandler cgi-script .cgi

Options +FollowSymlinks

RewriteEngine On
RewriteRule ^/f5/snoyman/public/wordify$ /wordify/ [R=301,S=1]
RewriteCond $1 !^dispatch.cgi
RewriteRule ^(.*) dispatch.cgi/$1 [L]

A few notes:

  • The first two lines are purely for CGI purposes. You might not need them, or may wish to use different file extensions.
  • The follow symlinks is not needed for the rewrite purposes.
  • The first RewriteRule line does the trailing-slash addition. It specifies R=301 so that the user receives a 301 permanent redirect. The S=1 is a skip option so that the following rule is not executed.
  • The RewriteCond applies to the second RewriteRule, and makes sure we don’t end up with an infinite redirect loop. Remember, mod_rewrite will reloop through all your rules each time one of the rules makes a change to the URL.
  • I’m not sure exactly what the L option does, but it definitely doesn’t guarantee that a rule is the last one executed. That’s why we need the S on the first rule.

It’s ugly, but it works. The only downside I’d like to address is to disallow access from http://www.snoyman.com/wordify/dispatch.cgi/…, but I’m not too worried about that. Following good RESTful principles would make information available at precisely one URL, but the dispatch.cgi is unlikely to be stumbled upon by mistake.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: