package com.jrails.modules.webapp.filter; import com.jrails.modules.webapp.http.CharArrayResponseWrapper; import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; /** * Created by arden * User: <a href="mailto:arden.emily@gmail.com">arden</a> * Date: 2009-2-14 14:45:04 * * Filter that compresses output with gzip (assuming that browser supports gzip). */ public class CompressionFilter implements Filter { private FilterConfig config; /** * If browser does not support gzip, invoke resource normally. If browser * <I>does</I> support gzip, set the Content-Encoding response header and * invoke resource with a wrapped response that collects all the output. * Extract the output and write it into a gzipped byte array. Finally, write * that array to the client's output stream. */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (!isGzipSupported(req)) { // Invoke resource normally. chain.doFilter(req, res); } else { // Tell browser we are sending it gzipped data. res.setHeader("Content-Encoding", "gzip"); // Invoke resource, accumulating output in the wrapper. CharArrayResponseWrapper responseWrapper = new CharArrayResponseWrapper(res); chain.doFilter(req, responseWrapper); // Get character array representing output. char[] responseChars = responseWrapper.toCharArray(); // Make a writer that compresses data and puts it into a byte array. ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); GZIPOutputStream zipOut = new GZIPOutputStream(byteStream); OutputStreamWriter tempOut = new OutputStreamWriter(zipOut); // Compress original output and put it into byte array. tempOut.write(responseChars); // Gzip streams must be explicitly closed. tempOut.close(); // Update the Content-Length header. res.setContentLength(byteStream.size()); // Send compressed result to local. OutputStream realOut = res.getOutputStream(); byteStream.writeTo(realOut); } } /** * Store the FilterConfig object in case subclasses want it. */ public void init(FilterConfig config) throws ServletException { this.config = config; } protected FilterConfig getFilterConfig() { return (config); } public void destroy() {} private boolean isGzipSupported(HttpServletRequest req) { String browserEncodings = req.getHeader("Accept-Encoding"); return ((browserEncodings != null) && (browserEncodings.indexOf("gzip") != -1)); } }