java – HTTP cache headers in Servlets

Question:

I would like to know if there are libraries or solutions to handle requests containing headers like Last-Modified , If-Modified-Since , If-Range (for download summary), If-None-Match , Cache-Control , Pragma , etc and produce responses with code 304 , ETags , Expires , Last-Modified , Content-Range , etc. in Servlets.

While I know that these cache and download control headers are more relevant to static resources, I've come across a situation (which I think is quite common) where supporting these headers increases performance and lowers an application's costs.

In my specific case, I'm building an open-source application for creating collages on Facebook with a colleague (link if relevant: http://sfcb.7rtc.com ). This application is hosted on GAE which imposes limits and charges for external requests .

In our case we coded a Servlet that acts as a proxy and a Facebook image resizer (link: ProxyServlet ). The proxy is needed to bypass security exceptions when exporting Canvas content related to Policy from the same origin as Facebook's static resource servers do not implement CORS headers.

In this proxy case we could simply delegate the Servlet request headers to Facebook:

public static final ImmutableSet<String> excludedHeaders = 
    ImmutableSet.of("Cookie", "Host");

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
    final HttpURLConnection connection;
    try {
       // código para abrir o request
       final Enumeration<String> headerNames = request.getHeaderNames();
       while (headerNames.hasMoreElements()) {
           final String headerName = headerNames.nextElement();
           final String headerValue = request.getHeader(headerName);

           if (!excludedHeaders.contains(headerName)) {
               log.info(headerName + " : " + headerValue);
               connection.setRequestProperty(headerName, headerValue);
           }
       }
    }
    // Restante do código
}

And copy the Facebook response headers and status code back to the Servlet.

final int httpCode = connection.getResponseCode();
response.setStatus(httpCode);
for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
    final String header = entry.getKey();
    log.info(entry.getKey() + " = " + entry.getValue());
    for (String headerValue : entry.getValue()) {
        response.addHeader(header, headerValue);
    }
}
// Código para tratar o corpo da resposta, e em caso de status 200, redimensioná-la.

This was enough to make the application more responsive and greatly alleviate the amount of external requests (repeated images are cached in the browser and consecutive requests don't match the Servlet).

However, I do not consider this a complete or generic solution (since it is specific to proxy servlets).

On Stack Overflow in English I found references to FileServlet bo BalusC which implements the Servlets issue for local downloads quite completely (his code handles all the headers mentioned "on the nail", besides supporting GZIP compression ).

But I was wondering if there isn't a more generic library or solution to handle this kind of problem (for example, with the use of filters and/or a simplified API to abstract implementation details).

Has anyone heard of something like this? (And if not, does anyone apply to start writing something like that? :D).

Answer:

There is the Java EE Cache Filter library, which consists of a set of filters for manipulating headers.

As filters can be mapped via web.xml , I believe there should not be much difficulty in their application.

The filter to add the cache is the CacheFilter . See an example of usage:

<filter>
    <filter-name>imagesCache</filter-name>
    <filter-class>com.samaxes.filter.CacheFilter</filter-class>
    <init-param>
        <param-name>static</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>expirationTime</param-name>
        <param-value>2592000</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>imagesCache</filter-name>
    <url-pattern>/img/*</url-pattern>
</filter-mapping>

Note : personally I have not performed tests with this library to find out the details of its functioning. But I believe that the solution using filters is adequate.

On the other hand, depending on your data volume, you might need to use a more specialized service like Amazon S3 or CloudFlare . In this scenario, you feed the image to the service and it is responsible for resizing and distributing it quickly, efficiently, and with a configurable cache.

Scroll to Top