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();
}
}
}