codem [AU: 8005 8051] - blog - projects

Zeus and crazy URL rewriting

Recently I had a SilverStripe project go live on a host running the “Zeus” web server. I’ve never worked with this beasty before and I can see why – a pretty bog standard URL rewrite using mod_rewrite in Apache turned into multi-line horror.

Here’s the Apache rewrite, pretty standard stuff that ships with SilverStripe:

<IfModule  mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteCond %{REQUEST_URI} ^(.*)$
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule .* sapphire/main.php?url=%1&%{QUERY_STRING} [L]
<IfModule>

Here’s the Zeus equivalent:

insensitive match URL into $ with ^/.*\.(gif|jpg|jpeg|png|css|js|swf|php|html|htm|pdf)$
if not matched
	insensitive match URL into $ with ^/(.*)$
	if matched
		look for file at $1
		if not exists
			# Set the default page to be displayed if the URL is not a file or resource
			set URL = /sapphire/main.php?url=$1
			goto END
		endif
	endif
endif

Notice the case insensitivity matching, the Leaning Tower of Ifs and the file extension matching. It works, but not very nicely – for instance I missed the “swf” extension and no Flash files loaded, so it seems to automatically shove anything that doesn’t match down the pipe with a 404 header (even though the file exists on the server)

Edit – I’ve found a better way to do this.. which started by reading some Zeus/Apache rewrite translations at this Drupal page.

RULE_0_START:
# get the document root
map path into SCRATCH:DOCROOT from /
# initialize our variables
set SCRATCH:ORIG_URL = %{URL}
set SCRATCH:REQUEST_URI = %{URL}

# see if theres any queries in our URL
match URL into $ with ^(.*)\?(.*)$
if matched then
  set SCRATCH:REQUEST_URI = $1
  set SCRATCH:QUERY_STRING = $2
endif
RULE_0_END:

RULE_1_START:
# prepare to search for file, rewrite if its not found
set SCRATCH:REQUEST_FILENAME = %{SCRATCH:DOCROOT}
set SCRATCH:REQUEST_FILENAME . %{SCRATCH:REQUEST_URI}

# check to see if the file requested is an actual file or
# a directory with possibly an index.  don't rewrite if so
look for file at %{SCRATCH:REQUEST_FILENAME}
if not exists then
  look for dir at %{SCRATCH:REQUEST_FILENAME}
  if not exists then
    set URL = /sapphire/main.php?url=%{SCRATCH:REQUEST_URI}
    goto QSA_RULE_START
  endif
endif

# if we made it here then its a file or dir and no rewrite
goto END
RULE_1_END:

QSA_RULE_START:
# append the query string if there was one originally
# the same as [QSA,L] for apache
match SCRATCH:ORIG_URL into % with \?(.*)$
if matched then
  set URL = %{URL}&%{SCRATCH:QUERY_STRING}
endif
goto END
QSA_RULE_END:

That’s half the problem – after changing this I noticed that the base path in SilverStripe was set to “/index.php” resulting in all the links to various CSS and JS files to be broken. To get around this, in your _config.php file, make this change to force the base path

//force base URL for zeus
Director::setBaseURL('/');

And you should end up with a functioning site mimicking the (simpler) Apache setup.

In any case, even if it does work, my advice: anything that makes mod_rewrite even harder to implement by turning a 4 line rewrite into a 44 line monster should be avoided.

Be the first to comment

Post a comment

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>