views:

75

answers:

2

I want to set the Expires header for all image/* and text/css. I'm doing this in a Filter. However:

  • before calling chain.doFilter(..) the Content-type is not yet "realized"
  • after calling chain.doFilter(..) the Content-type is set, but so is content-length, which forbids adding new headers (at least in Tomcat implementation)

I can use the extensions of the requested resource, but since some of the css files are generated by richfaces by taking them from inside jar-files, the name of the file isn't x.css, but is /xx/yy/zz.xcss/DATB/....

So, is there a way to get the Content-type before the response is committed.

+1  A: 

You should subclass HttpServletResponseWrapper and override addHeader and setHeader to add the newly desired header when "Content-Type" is passed in as the header name. Make sure to not forget to call super in those overridden methods too. Wrap the Response sent in the doFilter method argument with this new Wrapper and pass the Wrapper to the call to doFilter.

laz
(+1) yours and BalusC's answers are both correct solutions, but his is a bit cleaner (at least for me, because a not-so-general method is overridden)
Bozho
Yes I missed the setContentType method. You might want to consider doing the same for setHeader and addHeader as you never know how it might be coded. Unless of course you own all of the code.
laz
+2  A: 

Yes, implement HttpServletResponseWrapper and override setContentType().

class AddExpiresHeader extends HttpServletResponseWrapper {
    private static final long ONE_WEEK_IN_MILLIS = 604800000L;

    public AddExpiresHeader(HttpServletResponse response) {
        super(response);
    }

    public void setContentType(String type) {
        if (type.startsWith("text") || type.startsWith("image")) {
            super.setDateHeader("Expires", System.currentTimeMillis() + ONE_WEEK_IN_MILLIS);
        }
        super.setContentType(type);
    }
}

and use it as follows:

chain.doFilter(request, new AddExpiresHeader((HttpServletResponse) response));
BalusC
of course.. I should've thought of this.. especially when using another wrapper in the same filter (for another reason).. :)
Bozho
(only, it wouldn't be 0, but a time in the future)
Bozho
Yes, of course. Or do you use JodaTime? ;)
BalusC
no, a `Calendar` - `inTwoMonths.add(Calendar.MONTH, 2);` and then `getTimeInMillis()`. I don't hate the Calendar API that much ;)
Bozho