Hank
Hank

Reputation: 4716

Grails redirect - why is it always absolute?

I have two Jetty AppServers running a Grails Web App behind Apache 2.2 reverse proxies. SSL termination is done by the apaches, who pass on HTTP to the Jetty AppServers.

When the Grails Web application does a redirect like so

redirect(action:'index')

the end-user receives a HTTP 302 redirect request with a full URL, which is using http:// protocol, not https://:

HTTP/1.1 302 Found
Date: Tue, 08 Mar 2011 17:50:46 GMT
Server: Jetty(6.1.17)
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Location: http://hostname.domain/web/?lang=en

This is annoying, since all HTTP requests get caught by the proxy and redirected to HTTPS requests. So it's an unnecessary roundtrip.

I see two solutions:

  1. Apache's mod_proxy could rewrite that Location-header to https:// before passing the response on to the user. (Can it?)
  2. Grails could simply not use absolute URLs when redirecting: Location: /web/?lang=en

The first option is a bit stupid I think, right?

Do you have any idea how I can get grails to send non-absolute redirect headers (ideally without having to switch every redirect to use uri:)?

EDIT: For the moment I have a workaround following the first approach by modifying the response headers (a2enmod headers, then add Header edit Location ^http://(.*)$ https://$1 in the <Location>). Inspiration comes from this serverfault post. I'd still like to know why this is necessary in the first place.

Upvotes: 4

Views: 2318

Answers (2)

bernhof
bernhof

Reputation: 6320

This question is now almost 10 years old. Since then, the specification has been updated in RFC 7231, section 7.1.2. Relative references in Location header are now allowed:

When [Location] has the form of a relative reference ([RFC3986], Section 4.2), the final value is computed by resolving it against the effective request URI ([RFC3986], Section 5).

Grails supports this type of redirect, but you have to apply an extra absolute: false argument when redirecting:

redirect action: 'index', absolute: false

Note: at the time of writing, this feature does not (yet) support servlet context paths, see grails-core issue #11673

Upvotes: 0

Ted Naleid
Ted Naleid

Reputation: 26801

302 redirects are required by the HTTP 1.1 RFC to be absolute, not relative locations. Even if it worked in some browsers, those are going outside the spec and I'm sure some implementations wouldn't work right if you did a relative url.

The reason you're seeing this issue is because the SSL termination is happening on apache, and apache is making a vanilla HTTP request to Jetty. So Jetty is getting a vanilla, non-HTTPS request so it doesn't know to send out HTTPS responses, instead of regular HTTP responses. If you were doing the SSL termination in Jetty, you wouldn't have the problem (but Jetty isn't that great at SSL termination).

We've handled this in our app (apache/HA Proxy->Tomcat) by having a per environment config value that hard codes the response protocol (we need to mess with the url anyway because it's a multi-tenant system with many potential hostnames coming in, long story... :), but your solution with apache works too.

Upvotes: 6

Related Questions