Bug 56917 - Create a configuration to write relative 302 responses instead of absolute
Create a configuration to write relative 302 responses instead of absolute
Product: Tomcat 8
Classification: Unclassified
Component: Catalina
All All
: P2 enhancement (vote)
: ----
Assigned To: Tomcat Developers Mailing List
Depends on:
  Show dependency tree
Reported: 2014-09-05 16:46 UTC by Ajay Sindwani
Modified: 2015-12-01 20:34 UTC (History)
0 users


Note You need to log in before you can comment on or make changes to this bug.
Description Ajay Sindwani 2014-09-05 16:46:31 UTC
Create a Tomcat configuration to force tomcat to write relative location headers in 301/302 responses instead of absolute location headers.

Today Tomcat always writes an absolute response for redirects per RFC2616 standards.  However as many modern browsers support 302s to relative Locations as explained in https://en.wikipedia.org/wiki/HTTP_location , our friendly Tomcat application server should allow configuration to write back 302s in the more friendly form.

The ripple effect of this where applications choose to use this setting, will be very good for cpu cycles of web servers and load balancers all over the world.   This can greatly reduce the need for ProxyPassReverse in the Apache web server, and also for URL rewriting happenin in physical load balancers.

See this example where another gentleman has been compelled to recompile Tomcat to achieve the same thing
Comment 1 Mark Thomas 2014-09-05 18:26:04 UTC
This would be contrary to the requirements of the Servlet specification.

See https://java.net/jira/browse/SERVLET_SPEC-100 for the request to change that (and some other stuff).
Comment 2 Ajay Sindwani 2014-09-05 22:06:07 UTC
Both the servlet spec and Tomcat need to be updated then.  Tomcat doesn't have to wait for the servlet spec, unless the update is already accepted.

The expense of doing 302 rewriting can be cleaned from numerous webserver environments.
Comment 3 Christopher Schultz 2014-09-15 18:54:35 UTC
(In reply to Ajay Sindwani from comment #2)
> Both the servlet spec and Tomcat need to be updated then.  Tomcat doesn't
> have to wait for the servlet spec, unless the update is already accepted.

Tomcat, being spec-compliant, must maintain spec-compliance.

There are certainly examples of out-of-spec behavior in Tomcat which are usually controllable via certain configuration options. It seems like this could be one of them. Patches are always welcome.

> The expense of doing 302 rewriting can be cleaned from numerous webserver
> environments.

Are you sure? If not all clients support it, then you can't remove that capability. It's one of the awful things about the web: you can't force users to upgrade. ;)
Comment 4 Mark Thomas 2015-11-27 21:21:20 UTC
Good news. RFC2616 has been obsoleted by RFC7231 and friends. RFC7231 allows redirects to be relative. This looks like it could turn into my favourite type of bug report - one I can fix by deleting code :)
Comment 5 Remy Maucherat 2015-11-30 14:36:12 UTC
Similar to 58660, I think the behavior change may not be such a good idea. It could be done in 9, but not elsewhere by default.
Comment 6 Mark Thomas 2015-11-30 15:40:47 UTC
Allowing relative URIs should be low risk and it is consistent with RFC7231.

I know the commit is large but 99% of that is for testing. My first approach replaced the encodeXXX methods so I added some tests. While I eventually dropped that approach (we need Java 9 for the URI performance to be better than the current one) I wanted to keep the tests.

The main reason for back-porting this beyond 9.0.x is that we need this to be able to fix bug 58655 without duplicating huge amounts of code. Hence back-porting as far as 7.0.x which is the earliest version we need to fix 58655.

Would you like to see a configuration option for this in 7.0.x and 8.0.x. And if so, which what default?
Comment 7 Remy Maucherat 2015-11-30 16:33:41 UTC
I verified the behavior with a telnet. If it is known all clients are compatible, then it should be fine. I read in the original description "many modern browsers support 302s to relative Locations", so what are the "non modern" browsers or clients that would not support it ?
Comment 8 Remy Maucherat 2015-11-30 16:40:37 UTC
Not really related, the processing for session id encoding in the URL (encodeRedirectURL and encodeURL) is extraordinarily complex and expensive. I don't remember why it looks like that.
Comment 9 Mark Thomas 2015-11-30 16:43:44 UTC
The complexity is to ensure that the session ID only gets added if the redirect is to a location within the current web application.

In nearly all cases it will get skipped anyway since the session will have been provided by a cookie.
Comment 10 Mark Thomas 2015-11-30 21:20:21 UTC
I haven't found a client that doesn't support it yet. I did find one reference for curl [1] that suggests back then all browsers supported various forms of relative redirects.

[1] http://daniel.haxx.se/blog/2011/12/31/top-3-curl-bugs-in-2011/
Comment 11 Ajay Sindwani 2015-12-01 02:48:02 UTC
@Mark Thomas

Logically since 7/8 backports, existing app servers, will receive your patch through minor upgrades, the defaults should maintain the existing behavior to prevent wasted labor and troubleshooting for the majority of people.

I'd recommend in 9 and up that the the default become the more efficient behavior and inline with RFC-7231.  

Doing this CR is a good deed!  Imagine all the CPU cycles saved when the world no longer has all these Tomcats adding base URLs to redirects and Apache Httpd no longer has ProxyPassReverse added to every ProxyPass.  This is a good "green" eco-friendly change.
Comment 12 Konstantin Kolinko 2015-12-01 09:54:36 UTC
1. I think this feature must be configurable.

a. Regardless of browsers, this may affect configuration of reverse proxies.

I guess that ProxyPassReverse may fail to rewrite some of redirects.


b. There may be some old / dumb clients.

I am REOPENING this.

2. I agree that this is a nice feature and I think that enabling this feature by default is better from security point of view.
Comment 13 Mark Thomas 2015-12-01 11:04:34 UTC
It appears that ProxyPassReverse only rewrites absolute URLs. That will be a problem for redirects of the form /some/path

Tomcat generates redirects like this in a few places and we can fix those but it does look like an option is going to be required for the reverse proxy case where the context path is changed in the proxy.

Something else to add to the long list of reasons why changing the context path in the reverse proxy is a bad idea.
Comment 14 Mark Thomas 2015-12-01 11:38:56 UTC
I can get Tomcat to send a suitable relative redirect for directories but not context roots. I don't see a way around this. Any relative redirect from from /foo to /foo/ is going to have to have 'foo/' in it and that won't be caught by ProxyPassReverse. If the context name has been changed the redirect will break.

At the point where the redirect is generated, we have access to the context so adding a per context option for this should be fairly simple. I don't like adding configuration options unless we have to but the case for doing so here is strong, even if it does depend on a configuration (changing context paths in the proxy) that we know is generally problematic.

I should be able to get this option added shortly.
Comment 15 Mark Thomas 2015-12-01 13:08:28 UTC
Configuration option added.
Comment 16 Konstantin Kolinko 2015-12-01 16:56:35 UTC
Thank you.

Minor things

1. JMX

2. As Servlet Specification javadoc [1] explicitly says "servlet container must convert the relative URL to an absolute URL before sending the response to the client" and references RFC 3986 ("absolute" is defined there), I think the default value of this option should depend on STRICT_SERVLET_COMPLIANCE.

It is not yet known what will be for Servlet 4.0, we can change the default later. The [1] link is for Servlet 3.1.

[1] http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletResponse.html#sendRedirect-java.lang.String-
Comment 17 Mark Thomas 2015-12-01 20:34:17 UTC
Review comments fixed.