You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by George Stanchev <Gs...@serena.com> on 2016/02/08 20:37:25 UTC

Relative redirects in light of recent changes

Hi,

Recent changes to Tomcat altered the behavior of our applications a bit so I've got couple of questions. The versions in questions are 7.0.64 and 7.0.67. I am aware of which is also described in the changelog for 7.0.67.

I have a filter acts on application "/myapp" that does a redirect in the following manner:

httpResponse.sendRedirect("login?a=b&c=d")

In Tomcat 7.0.65 I can see the following flow (the text after the 302 below is the value of the "Location" header as seen by network sniffer):

GET http://hostname/myapp?m=n&o=p  
              ==> 302: "http://hostname/myapp/?m=n&o=p"
GET http://hostname/myapp/?m=n&o=p 
              ==> 302: "http://hostname/myapp/login?a=b&c=d"

The first redirect adds a trailing slash after "myapp", the second is generated by my redirect

In Tomcat 7.0.67 with no "useRelativeRedirects" set on the context (which defaults it to "true"), I see

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "login?a=b&c=d"

Now, this is expected behavior given the fix for [1]

However, with useRelativeRedirects="false" I see

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "http://hostname/login?a=b&c=d"

The questions I have are 2: First, what happened with the trailing slash redirect. I vaguely remember discussions around it but I couldn't find them on the mailing list search index. And secondly but more importantly, in 7.0.64, the HttpServletRequest.sendRedirect() would use the application name to form the Location header value (as in .../myapp/login...) whereas in 7.0.67 the name of the application is missing from the absolute redirect.

Is there any way to work around this and to have 7.0.67 behave like 7.0.64?

George

[1] http://bz.apache.org/bugzilla/show_bug.cgi?id=56917
[2] https://tomcat.apache.org/tomcat-7.0-doc/changelog.html


RE: Relative redirects in light of recent changes

Posted by George Stanchev <Gs...@serena.com>.
> > However, with useRelativeRedirects="false" I see
> >
> > GET http://hostname/myapp?m=n&o=p
> >               ==> 302: "http://hostname/login?a=b&c=d"
> >
> > The questions I have are 2: First, what happened with the trailing slash
> redirect. I vaguely remember discussions around it but I couldn't find them
> on the mailing list search index. And secondly but more importantly, in 7.0.64,
> the HttpServletRequest.sendRedirect() would use the application name to
> form the Location header value (as in .../myapp/login...) whereas in 7.0.67
> the name of the application is missing from the absolute redirect.
> >
> > Is there any way to work around this and to have 7.0.67 behave like 7.0.64?
> 
> Setting mapperContextRootRedirectEnabled="true" on the Context should
> fix it.
> 
> Mark
> 
> Thanks Mark. So if I understand correctly, 7.0.68 will return to adding the
> trailing slash automatically just like 7.0.64 did. That for now can be worked
> around by setting that attribute above on the context for now.
> 
> With the trailing slash optional though, the code in
> "org.apache.catalina.connector.Response#toAbsolute(String)" still seems will
> yield wrong redirect URLs for the case where someone is running with trailing
> slash redirect disabled:
> 
>                     String relativePath = request.getDecodedRequestURI();
>                     int pos = relativePath.lastIndexOf('/');
>                     ...
>                     } else {
>                         encodedURI = urlEncoder.encodeURL(relativePath, 0, pos);
>                     }
> 
> In case of relativePath being "/myapp" (which will be the case when somone
> runs with traliling-slash-redirect being turned off), encodedURI will be "".
> 
> So it seems to me either TC should *always* force those trailing-slash-
> redirects or fix the code above to correctly calculate the encodedURI from
> the relativePath...

Tomcat is generating 404 if I make a GET on [1] but succeeding on [2]. No mapper attributes are set on the context. I think I am missing something fundamental here but I don't know what. Servlet is mapped as /login in the deployment descriptor. Is there any reference where I can read up on this stuff?

[1] http://hostname/myapp/login/?a=b&c=d
[2] http://hostname/myapp/login?a=b&c=d

RE: Relative redirects in light of recent changes

Posted by George Stanchev <Gs...@serena.com>.
<quote>
> However, with useRelativeRedirects="false" I see
> 
> GET http://hostname/myapp?m=n&o=p 
>               ==> 302: "http://hostname/login?a=b&c=d"
> 
> The questions I have are 2: First, what happened with the trailing slash redirect. I vaguely remember discussions around it but I couldn't find them on the mailing list search index. And secondly but more importantly, in 7.0.64, the HttpServletRequest.sendRedirect() would use the application name to form the Location header value (as in .../myapp/login...) whereas in 7.0.67 the name of the application is missing from the absolute redirect.
> 
> Is there any way to work around this and to have 7.0.67 behave like 7.0.64?

Setting mapperContextRootRedirectEnabled="true" on the Context should fix it.

Mark
</quote>

Thanks Mark. So if I understand correctly, 7.0.68 will return to adding the trailing slash automatically just like 7.0.64 did. That for now can be worked around by setting that attribute above on the context for now.

With the trailing slash optional though, the code in "org.apache.catalina.connector.Response#toAbsolute(String)" still seems will yield wrong redirect URLs for the case where someone is running with trailing slash redirect disabled:

                    String relativePath = request.getDecodedRequestURI();
                    int pos = relativePath.lastIndexOf('/');
                    ...
                    } else {
                        encodedURI = urlEncoder.encodeURL(relativePath, 0, pos);
                    }

In case of relativePath being "/myapp" (which will be the case when somone runs with traliling-slash-redirect being turned off), encodedURI will be "".

So it seems to me either TC should *always* force those trailing-slash-redirects or fix the code above to correctly calculate the encodedURI from the relativePath...

George

Re: Relative redirects in light of recent changes

Posted by Mark Thomas <ma...@apache.org>.
On 08/02/2016 21:55, George Stanchev wrote:
> <quote>
> 
> Hi,
> 
> Recent changes to Tomcat altered the behavior of our applications a bit so I've got couple of questions. The versions in questions are 7.0.64 and 7.0.67. I am aware of which is also described in the changelog for 7.0.67.

There are two changes that are interacting here.

The first is moving the directory redirect from the Mapper to the
default servlet. This is:
mapperContextRootRedirectEnabled
and
mapperDirectoryRedirectEnabled

The default for both of these in 7.0.67 was false. In 7.0.68 the default
for mapperContextRootRedirectEnabled is going to change to true because
of issues like those you describe.

The second is allowing relative redirects.

> I have a filter acts on application "/myapp" that does a redirect in the following manner:
> 
> httpResponse.sendRedirect("login?a=b&c=d")
> 
> In Tomcat 7.0.65 I can see the following flow (the text after the 302 below is the value of the "Location" header as seen by network sniffer):
> 
> GET http://hostname/myapp?m=n&o=p  
>               ==> 302: "http://hostname/myapp/?m=n&o=p"
> GET http://hostname/myapp/?m=n&o=p 
>               ==> 302: "http://hostname/myapp/login?a=b&c=d"
> 
> The first redirect adds a trailing slash after "myapp", the second is generated by my redirect

So here the flow is
- request 1 received
- Mapper adds / and redirects
- request 2 (with trailing /) received
- Filter redirects (absolute)

> In Tomcat 7.0.67 with no "useRelativeRedirects" set on the context (which defaults it to "true"), I see

Here the flow is
- request 1 received
- Filter redirects

The problem is that the filter generates the wrong redirect because it
expects the trailing / to be present.

Now you could argue that the Filter should handle this but most Filters
won't.

> GET http://hostname/myapp?m=n&o=p 
>               ==> 302: "login?a=b&c=d"
> 
> Now, this is expected behavior given the fix for [1]
> 
> However, with useRelativeRedirects="false" I see
> 
> GET http://hostname/myapp?m=n&o=p 
>               ==> 302: "http://hostname/login?a=b&c=d"
> 
> The questions I have are 2: First, what happened with the trailing slash redirect. I vaguely remember discussions around it but I couldn't find them on the mailing list search index. And secondly but more importantly, in 7.0.64, the HttpServletRequest.sendRedirect() would use the application name to form the Location header value (as in .../myapp/login...) whereas in 7.0.67 the name of the application is missing from the absolute redirect.
> 
> Is there any way to work around this and to have 7.0.67 behave like 7.0.64?

Setting mapperContextRootRedirectEnabled="true" on the Context should
fix it.

Mark


> 
> George
> 
> [1] http://bz.apache.org/bugzilla/show_bug.cgi?id=56917
> [2] https://tomcat.apache.org/tomcat-7.0-doc/changelog.html
> 
> </quote>
> 
> Stepped through the code, and what I thought it is an irrelevant question (what happened to the trailing slash redirect) might hold the key to the problem.
> 
> In org.apache.catalina.connector.Response#toAbsolute(String location="login?a=b&c=d")
> ...
> boolean leadingSlash = location.startsWith("/"); // evaluates to false since it’s a relative URI
> ...
> if (!leadingSlash) { // false so we go in
>                     String relativePath = request.getDecodedRequestURI(); // evaluates to "/myapp"
>                     int pos = relativePath.lastIndexOf('/'); // evaluates to 0
> ...
> encodedURI = urlEncoder.encodeURL(relativePath, 0, pos); // pos is 0 so encodedURI is empty
> ...
> redirectURLCC.append(encodedURI);  // " http://hostname + "" => same URL
> redirectURLCC.append('/');
> redirectURLCC.append(location, 0, location.length()); final: "http://hostname/login?a=b&c=d" which is a wrong URL...
> 
> "http://hostname/myapp/?m=n&o=p" (with trailing slash before ?) works just fine.
> 
> So my question becomes - how do I make it add the trailing slash as in 7.0.64...
> 
> George
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


RE: Relative redirects in light of recent changes

Posted by George Stanchev <Gs...@serena.com>.
<quote>

Hi,

Recent changes to Tomcat altered the behavior of our applications a bit so I've got couple of questions. The versions in questions are 7.0.64 and 7.0.67. I am aware of which is also described in the changelog for 7.0.67.

I have a filter acts on application "/myapp" that does a redirect in the following manner:

httpResponse.sendRedirect("login?a=b&c=d")

In Tomcat 7.0.65 I can see the following flow (the text after the 302 below is the value of the "Location" header as seen by network sniffer):

GET http://hostname/myapp?m=n&o=p  
              ==> 302: "http://hostname/myapp/?m=n&o=p"
GET http://hostname/myapp/?m=n&o=p 
              ==> 302: "http://hostname/myapp/login?a=b&c=d"

The first redirect adds a trailing slash after "myapp", the second is generated by my redirect

In Tomcat 7.0.67 with no "useRelativeRedirects" set on the context (which defaults it to "true"), I see

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "login?a=b&c=d"

Now, this is expected behavior given the fix for [1]

However, with useRelativeRedirects="false" I see

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "http://hostname/login?a=b&c=d"

The questions I have are 2: First, what happened with the trailing slash redirect. I vaguely remember discussions around it but I couldn't find them on the mailing list search index. And secondly but more importantly, in 7.0.64, the HttpServletRequest.sendRedirect() would use the application name to form the Location header value (as in .../myapp/login...) whereas in 7.0.67 the name of the application is missing from the absolute redirect.

Is there any way to work around this and to have 7.0.67 behave like 7.0.64?

George

[1] http://bz.apache.org/bugzilla/show_bug.cgi?id=56917
[2] https://tomcat.apache.org/tomcat-7.0-doc/changelog.html

</quote>

Stepped through the code, and what I thought it is an irrelevant question (what happened to the trailing slash redirect) might hold the key to the problem.

In org.apache.catalina.connector.Response#toAbsolute(String location="login?a=b&c=d")
...
boolean leadingSlash = location.startsWith("/"); // evaluates to false since it’s a relative URI
...
if (!leadingSlash) { // false so we go in
                    String relativePath = request.getDecodedRequestURI(); // evaluates to "/myapp"
                    int pos = relativePath.lastIndexOf('/'); // evaluates to 0
...
encodedURI = urlEncoder.encodeURL(relativePath, 0, pos); // pos is 0 so encodedURI is empty
...
redirectURLCC.append(encodedURI);  // " http://hostname + "" => same URL
redirectURLCC.append('/');
redirectURLCC.append(location, 0, location.length()); final: "http://hostname/login?a=b&c=d" which is a wrong URL...

"http://hostname/myapp/?m=n&o=p" (with trailing slash before ?) works just fine.

So my question becomes - how do I make it add the trailing slash as in 7.0.64...

George




RE: Relative redirects in light of recent changes

Posted by George Stanchev <Gs...@serena.com>.
<quote>
In Tomcat 7.0.67 with no "useRelativeRedirects" set on the context (which defaults it to "true"), I see

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "login?a=b&c=d"

Now, this is expected behavior given the fix for [1]

[1] http://bz.apache.org/bugzilla/show_bug.cgi?id=56917
</quote>

I reread my email, and it is incorrect that is expected behavior. I guess an expected behavior would be 

GET http://hostname/myapp?m=n&o=p 
              ==> 302: "myapp/login?a=b&c=d"

unless I am missing something badly...

George