I don’t think there exists an application that doesn’t make use of HttpServletResponse
’s sendRedirect
method. Even if
your application doesn’t directly depend on it, I am sure you have one or more frameworks that heavily make use of it.
In one of our projects, we installed Oracle Web Cache to compress HTTP responses generated by our web application. It is physically deployed on another server than that web application. User requests should contain the URL of the web cache in order to perform its job, and then it will pass those requests to the corresponding web application.
Let’s say our web cache is installed on a machine with IP: 10.10.10.1, and our web application (foo
) is deployed to
OC4J instance running on a machine with IP: 10.10.10.2. Therefore, our user requests should be like this:
http:/10.10.10.1/foo/swf.faces?_flowId=login-flow
, so that HTTP communication will be initiated over the web cache and
it will compress HTTP response if required. If user requests were contained 10.10.10.2, then the web cache would be
bypassed totally and no compression would be performed.
The case is not closed once our users submit the correct URL. Our web application and several of the frameworks it uses
make use of HttpServletResponse
’s sendRedirect
method. The below is an excerpt copied from JEE 5 API:
“Sends a temporary redirect response to the client using the specified redirect location URL. This method can accept relative URLs; the servlet container must convert the relative URL to an absolute URL before sending the response to the client. If the location is relative without a leading ‘/’, the container interprets it as relative to the current request URI. If the location is relative with a leading ‘/’, the container interprets it as relative to the servlet container root.”
As stated above, the servlet container translates the redirect location to an absolute URL. Unfortunately, the servlet
container knows nothing about our web cache configuration, and therefore the translated absolute URL contains the servlet
container’s IP, which is 10.10.10.2 in this case. As a result, even though we initiate communication with the correct URL
at first, over time, the web cache will be bypassed at the first redirect if the redirect URL is relative. We need to
provide the sendRedirect
method with absolute URLs, and they should contain the IP of the web cache so that HTTP
communication can flow over the web cache. Unfortunately, it is not a hundred percent possible to achieve this requirement
because we use several frameworks that make use of the sendRedirect
method with relative URLs, and it is not possible
or logical to modify all those places in which sendRedirect
is called.
It would be very nice to have a global place to prepend the correct URL and convert all those relative URLs into absolute
before calling sendRedirect
. Well, actually, this is possible with HttpServletResponseWrapper
. If we code a Filter
that will intercept the current HTTP request before all other parts of our system, and wrap the current HttpServletResponse
object with a HttpServletResponseWrapper
instance and then pass that instance into FilterChain
. Inside that wrapper,
we override the sendRedirect
method and examine the redirect location URL.
public void sendRedirect(String location) throws IOException {
if(StringUtils.isNotEmpty(location)) {
if(!(location.startsWith("http") location.startsWith("https"))) {
if(location.startsWith("/")) {
location = location.substring(1);
}
if(location.startsWith(contextPath)) {
location = location.substring(contextPath.length());
}
if(!location.startsWith("/")) {
location = "/" + location;
}
location = appUrl + location;
}
}
if(logger.isDebugEnabled()) {
logger.debug("Redirecting to url :" + location);
}
super.sendRedirect(location);
}
We first check if the location starts withhttp/https
. If it does, then it means the location is absolute and there is
nothing to do. Otherwise, we check if the location against contextPath
and leading slash, and prepend appUrl
(with 10.10.10.1 IP in it) appropriately.