2 Replies Latest reply: May 9, 2013 8:58 PM by 1008130 RSS

    Servlet request input decompression filter

    1008130
      I would like to find/write a http servlet filter to decompress gziped input from a client.
      If the client makes a request with the header *"Content-Encoding"* set to *"gzip"* then I would like the input to be decompressed by the filter.

      I have been able to write a filter that wraps the request if the content type is gzip.
      The wrapper overrides the getInputStream() and getReader() methods and returns a GZIPInputStream of the input stream instead.

      This method works for any servlet that calls getInputStream() or getReader().
      The input stream returned to the servlet can be read and the unziped content retrieved.

      The problem occurs when the content type is "multipart/form-data".
      I would like to be able to call the getPart() and getParts() methods inside my servlet to get the content of the multipart message.

      When my servlet invokes getParts() on my request wrapper
      this invokes getParts() on RequestFacade
      which invokes getParts() on its internal Request object *(not my request wrapper)*
      which eventually invokes getInputStream() on the internal Request object *(not my wrapped request)*

      This means that when getParts() is called, it tries to read the multipart message out of the compressed input stream, not my wrappers decompressed input stream.
      This results in no parts being read.

      In the Glassfish source, the offending line is here:
      [http://grepcode.com/file/repo1.maven.org/maven2/org.glassfish.web/web-core/3.0/org/apache/catalina/connector/RequestFacade.java#1115]
      Tomcat also has the same problem.

      I would greatly appreciate it if someone could provide some insight on this problem or suggest an alternative method for decompressing the input before getting parts from a multipart request.

      I have included the source for my servlet filter below in case it is of use.
      The code below is only for testing and is not robust against invalid requests.
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      import java.util.zip.GZIPInputStream;
      import javax.servlet.Filter;
      import javax.servlet.FilterChain;
      import javax.servlet.FilterConfig;
      import javax.servlet.ServletException;
      import javax.servlet.ServletInputStream;
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletRequestWrapper;
      import javax.servlet.http.HttpServletResponse;
      
      public class CompressionFilter implements Filter {
      
          @Override
          public void init(FilterConfig fc) throws ServletException {
          }
      
          @Override
          public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
              HttpServletRequest httpReq = (HttpServletRequest) req;
              HttpServletResponse httpRes = (HttpServletResponse) res;
      
              String encoding = httpReq.getHeader("Content-Encoding");
              if(encoding != null){
                  if(encoding.equalsIgnoreCase("gzip")){
                      req = new GZIPServletRequestWrapper(httpReq);
                  }
              }
              
              fc.doFilter(req, res);
          }
      
          @Override
          public void destroy() {
          }
          
          private class GZIPServletRequestWrapper extends HttpServletRequestWrapper{
      
              public GZIPServletRequestWrapper(HttpServletRequest request) {
                  super(request);
              }
      
              @Override
              public ServletInputStream getInputStream() throws IOException {
                  return new GZIPServletInputStream(super.getInputStream());
              }
      
              @Override
              public BufferedReader getReader() throws IOException {
                  return new BufferedReader(new InputStreamReader(new GZIPServletInputStream(super.getInputStream())));
              }
          }
      
          private class GZIPServletInputStream extends ServletInputStream{
              private InputStream input;
      
              public GZIPServletInputStream(InputStream input) throws IOException {
                  this.input = new GZIPInputStream(input);
              }
      
              @Override
              public int read() throws IOException {
                  return input.read();
              }
          }
      }
        • 1. Re: Servlet request input decompression filter
          EJP
          You don't need one. The servlet container should do that for you.
          • 2. Re: Servlet request input decompression filter
            1008130
            I am using "Oracle GlassFish Server 3.1.2 (build 23)"
            As far as I was aware, client side compression was not supported by default in either glassfish or tomcat.

            I have tested receiving an encoded request, however getParts() returns zero parts when the request is gziped and has the header "Content-Encoding: gzip"
            If the request is not gziped by the client, getParts() returns the content correctly.

            If decoding gziped requests automatically is an available feature of the server, I would greatly like to know how to enable it.

            Thanks