• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

How to control redirection: http, https, and trailing slashes

 
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have tomcat running behind a load balancer which removes the https. Tomcat receives http and when it gets a request for a directory without a trailing slash Tomcat issues a 302 to the same (http) url with the forward slash added. This fails since the request comes back from the client and is not https. So I am wondering if there is a configuration to have tomcat either not redirect at all or to do a server-side redirect, or to configure all redirects to use https?
 
Saloon Keeper
Posts: 27763
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
http://tomcat.apache.org/tomcat-5.5-doc/default-servlet.html

This is for Tomcat 5.5, but I don't expect most other Tomcat versions to be much different.

You should find the very last line of the page to be especially informative.
 
David M Peterson
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:http://tomcat.apache.org/tomcat-5.5-doc/default-servlet.html

This is for Tomcat 5.5, but I don't expect most other Tomcat versions to be much different.

You should find the very last line of the page to be especially informative.



Actually I don't see anything on that page that is relevant. The last line says

Use web.xml in each individual webapp. See the security section of the Servlet specification.


Could you be a little more specific? Thanks.
 
Ranch Hand
Posts: 344
Oracle Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm not sure what your load balancer is, but if you're using Apache http server, you can set up rewrite rules to always forward http to https.
 
Tim Holloway
Saloon Keeper
Posts: 27763
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As I've said from time to time, a web server is not a file server. A web server accepts Uniform Resource Locators (URLs). It parses the URL and determines what to do, based on that information.

When a URL doesn't match any of the URL patterns defined in the application's web.xml file, the URL is delegated to Tomcat's own global web.xml file. As shipped, it is set up to send the URL request to Tomcat's built-in default servlet (which is what the web I indicated describes).

The unresolved URL's post-context part is then converted to a resource path relative to the WAR root. It is this process that makes Tomcat "serve files". The resource is located and a check is made to see the resource is a JSP. If so, the JSP cache is checked, and if the JSP hasn't been compiled yet, the JSP is compiled into the cache and the cached JSP code (which is a servlet class) is passed the URL.

If the resource is not a JSP, the default servlet takes the resource location. opens the resource, and copies it to the HTTP Response output stream, after first sending the appropriate response headers. If the resource could not be found, a "404" error response is generated, instead.

But one thing did not ring true about your problem. You assert that Tomcat is generating a "302" response. This didn't make sense, since it would effectively send the request back to the client when in fact, the default behavior for a URL that parses to a directory location is to list the directory (except in cases where listing is suppressed by configuration option).

I've been looking at the DefaultServlet source code. I can see where the directory listing function is, but I cannot see any place at all where the DefaultServlet does a redirection.

In other words, I think the "302" is coming from the software that's front-ending Tomcat, and not Tomcat itself.
 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

this is for anyone else hitting this specific error. I got this same error when using load balancer and Tomcat is indeed generating the 302 response. Tim is correct about the way Tomcat is handling things, but fails to see the ultimate reason why Tomcat generates this error.

So, your web application is behind load balancer that takes in HTTPS from browser and sends the request forward as HTTP. This is the key to understanding our problem.

- user writes url in browser, eg. https://www.domain.com/folder
- load balancer takes in the request and sends it forward as HTTP
- like the HTTP-protocol dictates, Tomcat starts to check if the folder-resource is some predefined file or application and thus checks if there are files such https://www.domain.com/folder.jpg, https://www.domain.com/folder.gif etc.
- Of course, because the folder-path is indeed directory, Tomcat does not find any file
- Tomcat redirects browser and adds slash-character to the end of the url, because the resource probably is directory. The problem is, as Tomcat thinks the browser is using HTTP instead of HTTPS (because the load balancer hides this fact), it redirects the browser to http://www.domain.com/folder/ instead of https://www.domain.com/folder/

And thus we hit the problem. I'm not exactly sure what way would be the best to handle this, but I have requested the person in charge of the load balancer to add the trailing slash if user has omitted it. I have to admit that this offends what the HTTP-protocol dictates but it works for us.

Hope this helps someone.

Best regards,
Jukka
 
Tim Holloway
Saloon Keeper
Posts: 27763
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are a couple of problems with this theory. Before I made my last pompous pronouncement, I looked at Tomcat's actual code. If there's a redirect in the directory-listing function I'm too blind to see it (which isn't impossible. ). On the other hand, a protocol negotiation would be done in cases where a URL pattern-matches a transport constraint in web.xml, whether the request targets a directory or not.

Tomcat itself doesn't pay attention to "http" or "https" in the URL as such. That's mainly a convenience for the client. If a client wants a URL whose absolute path begins with "http:", then it knows to send data formatted according to the HTTP protocol, in clear text and aim it at the server's port 80 (unless overridden to something like 8080). If the protocol for the URL is defined as "https:", then the client will negotiate a secure (encrypted) channel, and transmit the request to the server port 443 (again, assuming no override). You can send HTTP to port 443 and HTTPS to port 80 by coding it into your URLs, and Tomcat will complain because the data isn't in the right shape for the indicated target port.

There's nothing inherently "wrong" about a URL ending in a trailing slash, although I admit I don't find it aesthetic. But the URL is not a filesystem path, it's a resource identifier. Some apps even get designed to take the same basic URL and process the "bare" version of it through one code function and the trailing-slash version through a completely different code function. Not something I really recommend, though.

In the cast of Tomcat, as I said before, the "index" function is processed by the DefaultServlet unless you customize Tomcat. According to the J2EE spec, all resources in a WAR are in a ZIP-format file, not independent filesystem objects, so the DefaultServlet doesn't actually use the java.io.File list(), isFile() or isDirectory() methods, but it does do the resource-based equivalent. And, you might be interested to know, it does include a trailing slash when creating a listing URL for a parenting ("directory") resource. It also does a URL rewrite to retain session identity. So even when a URL lacking a trailing slash comes in, if it refers to a directory resource, the sub-directory URLs will be returned with trailing slashes.
 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

I've just got the problem with redirects to slash behind Nginx too. Here's my thought on why this happens
In order the redirects to use proper protocol behind a balancer one should use RemoteIpValve in tomcat. It turns on "isSecure" flag when request comes from the balancer and so regular redirects work properly in webapps.
But it looks like this valve isn't used by tomcat for the /app => /app/ redirects, probably because they are processed before any valves.

Here's an excerpt from AccessValve reference:

"Some requests may be handled by Tomcat before they are passed to a container. These include redirects from /foo to /foo/ and the rejection of invalid requests. "
 
Bartender
Posts: 6663
5
MyEclipse IDE Firefox Browser Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
While this is an old post, I figured it would benefit from an answer since one is not available.

Tomcat is indeed the one that sends back a 302 response when a trailing slash is missing from the URL.



There are a couple of ways to handle this. You can either write a redirect rule when you receive the HTTP request from the browser (due to the location header pointing to HTTP) and convert the request to HTTPS, OR you change the location header on Nginx (that was sent from Tomcat) on the fly so that http is not the scheme that is sent back on the header (to the browser). I prefer the latter since it saves a round trip and does not make a HTTP call where HTTPS is required.

You can take option B by using the proxy_redirect directive from Nginx. This directive will rewrite a location header from an upstream server (such as tomcat) before returning a response to a client. Under an appropriate location, place this directive under a location rule.

proxy_redirect http://localhost:8000/two/ /


Go through the Nginx documentation for more information on using that directive.

Before you can write that rule spend some time analyzing what Location you are actually trying to change. The Tomcat access log value can log the location header in the response.

%{xxx}o for outgoing response headers



Use %{Location}o on the AccessLogValve under server.xml to log the outgoing Location header field and place this in Nginx to avoid redirection to an unwanted HTTP URL.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic