Monday, April 6, 2015

Using Apache's Swiss Army Knife - mod_rewrite (part II)

This blog was supposed to introduce some tricks to allow you to create a new subdomain for your RESTful endpoints, but I think before we launch into more details about creating your RESTful API endpoints I should share a few relevant discoveries regarding using mod_rewrite that might be of interest.

Redirecting a POST Method

First, you can't redirect a POST.  At least you can't cause an external redirect.  That's because the message body is communicated over STDIN and the browser does not re-POST the data.  You can cause Apache to internally reprocess the request however.

Invalid Redirect when HTTP method is POST

RewriteRule ^foo/?(.*)$ http://someotherhost/bar/$1

Valid Rewrite when HTTP method is POST

RewriteRule ^foo/?(.*)$ /bar/$1
RewriteRule ^foo/?(*.)$ http://someotherhost/bar/$1 [P]

The [P] flag allows will force the substitution URL to be internally sent as a proxy request.

Apache 2.2 v 2.4

Whenever working with Apache, it's important to understand the directives in the context of the version you are working with.  Software changes, and the documentation sometimes contains lies and hazy half truths.

No Loop-dee-loops Please!

You can get yourself into some recursive rewrite rules if you are not careful when crafting rewrite rules in a
.htaccess file or <Directory> section.  There are two flags that mod_rewrite recognizes in rewrite rules that seem to aid in preventing looping. The [L] flag will terminate the current set of rewrite rules and begin processing again.  That's a little deceptive, so I'll repeat.  The flag stops processing the current set of rules and then hands the URI back to Apache's parsing engine for processing...meaning your rules will potentially be reprocessed.

The [END] flag will stop all rewrite rule processing even if the rewrite requires revisiting the section.

Using the [END] flag terminates not only the current round of rewrite processing (like [L]) but also prevents any subsequent rewrite processing from occurring in per-directory (htaccess) context.

Sounds great right?  Well, although it is mentioned in the Apache 2.2 documentation, it is only available in Apache version 2.3.9 and above.  Caveat Emptor.  I told you documentation can lie!

Rewrite Logs

When carefully crafting your rules and creating your regular expressions, it's helpful to see exactly how Apache is interpreting your regexp and matching your URIs.  Apache 2.2 provides the RewriteLog and RewriteLogLevel directives to let you specify the log file and the logging level.   As indicated in Apache's documentation, using the highest levels of logging can impact performance so you probably only want to turn logging on in your development environment.

Apache version 2.4 consolidates rewrite logs into the main Apache logs.  Logging levels are specified as an additional option on the LogLevel directive.

LogLevel debug rewrite:trace8

Use trace1 - trace8 to log at increasing levels of detail.  No rewrite logs are written up to log level debug, so you won't see anything regarding rewrites until trace1.

Who Am I?

Being a webmaster, you obviously know that your virtual host section and directives are processed by Apache whenever the host name requested matches either the names specified for ServerName or ServerAlias (you can have more than one ServerAlias).  In your rewrite rules you can utilize the name of the virtual host in either the RewriteCond or RewriteRule.  Apache exposes the name matched %{SERVER_NAME} variable.  For rewrites however, you might prefer that this value always reflect the ServerName that you set in the directive.  To do this, you must tell Apache to use the canonical name of the virtual host using the UseCanonicalName directive.

This might be useful if you wanted to redirect (externally) a URI using a rewrite rule.

UseCanonicalName On
RewriteCond %{HTTP_HOST} ^api\.mysite\.com
RewriteRule ^foo(/?.*)$ http://%{SERVER_NAME}/bar/$1

Okay, now I promise - in part III we'll discuss creating alternate subdomain names for your endpoints without having to create new virtual hosts.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.