Skip to Main Content

Java EE (Java Enterprise Edition) General Discussion

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Servlet request input decompression filter

1008130May 9 2013 — edited May 9 2013
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();
        }
    }
}

Comments

Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Jun 6 2013
Added on May 9 2013
2 comments
5,581 views