This discussion is archived
2 Replies Latest reply: May 9, 2013 6:58 PM by 1008130 RSS

Servlet request input decompression filter

1008130 Newbie
Currently Being Moderated
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 Guru
    Currently Being Moderated
    You don't need one. The servlet container should do that for you.
  • 2. Re: Servlet request input decompression filter
    1008130 Newbie
    Currently Being Moderated
    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

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points