When I first added a Compression/GZip filter to AppFuse, I used the one from Roller
, which I believe Lance
found in this book
. This has worked fairly well since I added it in July last year. When I discovered that there were issues with it on Resin
, I chaulked it up as "no big deal" since I don't use Resin anyway. But yesterday, when I discovered that it stopped my apps from displaying my 403 <error-code> page, that was the last straw. I remembered seeing the "Two Servlet Filters Every Web Application Should Have
" article on ONJava.com about a different implementation, so decided to download the source
and try it out.
I quickly discovered that this Filter does work on Resin, so that's quite a bonus. I've had issues getting Roller to work on Resin with the Filter enabled, so I might have to replace Roller's CompressionFilter. However, I did still have to change a few things to convince this Filter to satisfy my needs.
Here are a few things I discovered about this GZIPFilter vs. Roller's CompressionFilter:
- Don't download the GZIPFilter from the article. There is a newer version
of the code. Not much has changed, save for an almost completely re-written GZipResponseStream.java file. This one supposedly does better handling of large files.
- This Filter has the same problem I experienced
with Roller's CompressionFilter: JSP pages don't finish rendering when running my Canoo WebTests. I'm assuming that this is because the buffer hasn't finished spitting out HTML. I ended up writing a new isGZIPSupported() method (in GZIPFilter.java) to do the check for GZip support. This allows my webtests to run smoothly by disabling the filter for HttpUnit.
- This Filter shares another issue that I found in the CompressionFilter yesterday. When my webapp returns an HttpServletResponse.SC_FORBIDDEN error code (from trying to access a method that denies the users role), the Filter suppresses the error and the user is not served up the 403 error page defined in my web.xml. To fix this, I overrode sendError() in GZIPResponseWrapper.java and added a check for this error code in the getWriter() method.
Overall, I'm pleased with this code because I love the concept of GZip Filtering, and now it's not causing any conflicts in my app or targeted appservers.
GZIPFilter.isGZIPSupported(HttpServletRequest):
private boolean isGZIPSupported(HttpServletRequest req) {
String browserEncodings = req.getHeader("accept-encoding");
boolean supported =
((browserEncodings != null) &&
(browserEncodings.indexOf("gzip") != -1));
String userAgent = req.getHeader("user-agent");
if (userAgent.startsWith("httpunit")) {
if (log.isDebugEnabled()) {
log.debug("httpunit detected, disabling filter...");
}
return false;
} else {
return supported;
}
}
|
GZIPResponseWrapper.sendError(int, java.lang.String):
public void sendError(int error, String message) throws IOException {
super.sendError(error, message);
this.error = error;
if (log.isDebugEnabled()) {
log.debug("sending error: " + error + " [" + message + "]");
}
}
|
GZIPResponseWrapper.getWriter():
public PrintWriter getWriter() throws IOException {
// If access denied, don't create new stream or write because
// it causes the web.xml's 403 page to not render
if (this.error == HttpServletResponse.SC_FORBIDDEN) {
return super.getWriter();
}
if (writer != null) {
return (writer);
}
|