package com.fpcms.common.web.filter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Enumeration; import java.util.zip.GZIPOutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.WriteListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.filter.OncePerRequestFilter; public class GzipFilter extends OncePerRequestFilter implements Filter{ private static final Log log = LogFactory.getLog(GzipFilter.class); @Override protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain chain)throws ServletException,IOException { if (isSupportsGzip(request)) { HttpServletResponse httpResp = (HttpServletResponse) response; // This does NOT work for Tomcat! // Tomcat JSP does not close the output stream upon finishing, so we // have to close it explicitly. // chain.doFilter(req, new GZIPServletResponseWrapper(httpResp)); GZIPServletResponseWrapper wrapper = new GZIPServletResponseWrapper(httpResp); chain.doFilter(request, wrapper); wrapper.finishResponse(); } else { chain.doFilter(request, response); } } private boolean isSupportsGzip(ServletRequest req) { Enumeration e = ((HttpServletRequest) req).getHeaders("Accept-Encoding"); while (e.hasMoreElements()) { String name = (String) e.nextElement(); if (StringUtils.contains(name,"gzip")) { return true; } } return false; } class GZIPServletResponseWrapper extends HttpServletResponseWrapper { private GZIPOutputStream gzipStream; private ServletOutputStream servletOutputStream; private PrintWriter printWriter; GZIPServletResponseWrapper(HttpServletResponse resp) throws IOException { super(resp); } @Override public void flushBuffer() throws IOException { if(printWriter != null) { printWriter.flush(); } if (gzipStream != null) { gzipStream.flush(); } } @Override public void setContentLength(int length) { } final static String HEADER_CONTENT_LENGTH = "Content-Length"; @Override public void addIntHeader(String name, int value) { if(name != null && HEADER_CONTENT_LENGTH.equalsIgnoreCase(name.trim())) { return; } super.addIntHeader(name, value); } @Override public void addHeader(String name, String value) { if(name != null && HEADER_CONTENT_LENGTH.equalsIgnoreCase(name.trim())) { return; } super.addHeader(name, value); } @Override public void addDateHeader(String name, long date) { if(name != null && HEADER_CONTENT_LENGTH.equalsIgnoreCase(name.trim())) { return; } super.addDateHeader(name, date); } public void finishResponse() { try { flushBuffer(); if (printWriter != null) { printWriter.close(); } if (gzipStream != null) { gzipStream.close(); } } catch (IOException e) { logger.error("close error",e); } } public ServletOutputStream getOutputStream() throws IOException { if (servletOutputStream == null) { servletOutputStream = createOutputStream(); } return servletOutputStream; } public PrintWriter getWriter() throws IOException { if (printWriter == null) { printWriter = new PrintWriter(new OutputStreamWriter( getOutputStream(), getCharacterEncoding())) { // This is // important // for // I18N // Workaround for Tomcat bug where flush is NOT called when // JSP output finished public void write(char[] cb, int off, int len) { super.write(cb, off, len); super.flush(); } }; } return printWriter; } private ServletOutputStream createOutputStream() throws IOException { ServletResponse resp = this.getResponse(); gzipStream = new GZIPOutputStream(resp.getOutputStream()); addHeader("Content-Encoding", "gzip"); addHeader("Vary", "Accept-Encoding"); return new ServletOutputStream() { /* The first three methods must be overwritten */ @Override public void write(int b) throws IOException { gzipStream.write(b); } @Override public void flush() throws IOException { gzipStream.flush(); } @Override public void close() throws IOException { gzipStream.close(); } /* * These two are not absolutely needed. They are here simply * because they were overriden by GZIPOutputStream. */ @Override public void write(byte[] b) throws IOException { gzipStream.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { gzipStream.write(b, off, len); } @Override public boolean isReady() { // TODO Auto-generated method stub return false; } public void setWriteListener(WriteListener writeListener) { } }; } } }