It’s a two-for-one today – a “gotcha” and a “how to” all rolled into one, this time about redirecting in a Grails filter.
Much like my favicon woes my initial attempt to redirect to a primary domain (a .com without the “www” prefix) had some unexpected consequences when deployed to a live server on CloudFoundry – I started getting warnings that my site had gone down!
In this post I’ll hopefully save you the panic of CloudFoundry telling you that your site’s not responding when you try to rationalise your domain names!
www? It’s so last century
Here’s the problem: you’ve got your domain, let’s say it’s lourish.com and you want to set up your site so that if people go to http://www.lourish.com, they’re immediately redirected to http://lourish.com, dropping the www.
If you’ve also been on a spending spree and bought the .org, .co.uk and a host of other domains all of which just point back to your .com site then, without a redirect you’ll find search engines can list each domain separately, ruining your search ranking.
(Not) Fixing it with a Filter
We’re talking Grails here (though the principles are the same in Java too) so creating a filter to make the redirect work is simple stuff. Here’s a snippet of code from my filter class:
def filters = { redirectToDotCom(uri: '/**') { before = { if(request.serverName != "lourish.com") { def reqUrl = request.requestURL def redirectTo = reqUrl.toString() .replace(request.serverName, "lourish.com") redirect(url: redirectTo) return false } } } ...
So what we do is
- Intercept all requests (
uri: '/**'/
) - Check the server name
- If it’s not the primary .com address (lourish.com), replace the server name in the incoming request with the .com server name
- Perform the redirect
Simple enough and it works in most cases – it doesn’t cope with upper case or request parameters, but then if the redirect works, parameters should never be generated!
Confusing CloudFoundry
If you’re deploying to CloudFoundry you’ll find that this simple filter causes big problems.
CloudFoundry has a great little monitoring feature which will check that your site’s up by not only checking your Apache server on localhost port 80 but also your tcserver’s servlet manager on localhost port 8080 – testing for a 200 status.
But take a look at what that filter’s doing, it’s redirecting absolutely everything to our .com address. This is ok for the Apache test – the 302 leads to a 200 eventually, but it also affects the call to tcserver on localhost:8080 which should check the management console, but we’re redirecting to .com:8080 and that port’s blocked!
So the filter causes a false reading on the monitoring tool and potentially unexpected problems, like the app being restarted to “fix” the problem!
Fixing the Filter
To fix this we could test the port but the solution I chose was simply to add a few “pass-through” urls to the filter:
static final List ALLOWED_SERVER_NAMES = ["lourish.com", "localhost", "127.0.0.1"] static isLive = Environment.current == Environment.PRODUCTION def filters = { redirectToDotCom(uri: '/**') { before = { if (isLive && !ALLOWED_SERVER_NAMES.contains(request.serverName)){ def reqUrl = request.requestURL def redirectTo = reqUrl.toString() .replace(request.serverName, "lourish.com") redirect(url: redirectTo) return false } } }
I’ve added ALLOWED_SERVER_NAMES
which contains the host names which won’t be not redirected and I’ve also added an isLive
check to let me test on my beta and local servers without constantly being redirected to the live site!
So that’s how to redirect to one address in a Grails app and still keep CloudFoundry happy!
Dave
Since you have some expertise on cloudfoundry, would you be able to tell me how I can turn off all http access to my application deployed on cloudfoundry? I have SSL turned on and want only https access. But I can’t shutdown the http access. I’ve tried Apache HTTP server redirects but that doesn’t work either:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}