Dealing with HTTP Response Redirects within Oracle Web Cache Deployed Environments

By Kenan Sevindik

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.

Share: X (Twitter) LinkedIn