I don’t think there exists an application which doesn’t make use of HttpServletResponse’s sendRedirect method. Even your application doesn’t directly depend on it, I am sure you have one or more frameworks which 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 in another server than that web application. User requests should contain URL of web cache in order to perform its job, and then it will pass those requests to corresponding web application.
Let’s say our web cache is installed on machine with IP: 10.10.10.1, and our web application (foo) is deployed to OC4J instance running on machine with IP: 10.10.10.2. Therefore, our user requests should be like that: http:/10.10.10.1/foo/swf.faces?_flowId=login-flow, so that HTTP communication will be initiated over web cache and it will compress HTTP response if required. If user requests were contained 10.10.10.2, then web cache would be bypassed totally and no comporession would be performed.
The case is not closed once our users submit to 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 it is stated above, servlet container translates redirect location to an absolute URL. Servlet container unfortunately knows nothing about our web cache configuration, and therefore translated absolute URL contains servlet container’s IP, which is 10.10.10.2 in this case. As a result, even though we initiate communication with correct URL at first, over time web cache will be bypassed at first redirect if redirect URL is relative. We need to provide sendRedirect method with absolute URLs and they should contain IP of web cache so that HTTP communication can flow over web cache. Unfortunately, it is not hundred percent possible to achieve this requirement, because we use several frameworks which make use of 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 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 which will intercept current HTTP request before all other parts of our system, and wrap current HttpServletResponse object with a HttpServletResponseWrapper instance and then pass that instance into FilterChain. Inside that wrapper we override sendRedirect method and examine 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 location starts with http/https. If it is, then it means location is absolute and there is nothing to do. Otherwise, we check if location against contextPath and leading slash, and prepend appUrl (with 10.10.10.1 IP in it) appropriately.