users@jersey.java.net

Re: [Jersey] [jersey 1.0.3] 'Unexpected end of ZLIB input stream' error with GZIPContentEncodingFilter

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Wed, 22 Apr 2009 18:09:14 +0200

Hi Sergey,

The config looks good. The error is occurring when the server side is
reading the GZIP-encoded request entity sent by the client implying
some sort of flushing issue.

Having a look more closely the client does not call
GZIPOutputStream.finish. So i think i need to fix the client side
adapting to support finishing.

Could you try with the client filter at the end of this email and see
if that works for you.

Paul.

public class GZIPContentEncodingFilter extends ClientFilter {

     private static class FinishingOutputStream extends OutputStream {
         private final GZIPOutputStream out;

         FinishingOutputStream(GZIPOutputStream out) {
             this.out = out;
         }

         @Override
         public void write(int b) throws IOException {
             out.write(b);
         }

         @Override
         public void write(byte[] b) throws IOException {
             out.write(b);
         }

         @Override
         public void write(byte[] b, int off, int len) throws
IOException {
             out.write(b, off, len);
         }

         @Override
         public void flush() throws IOException {
             out.flush();
         }

         @Override
         public void close() throws IOException {
             out.finish();
             out.close();
         }
     }

     private static final class Adapter extends
AbstractClientRequestAdapter {

         Adapter(ClientRequestAdapter cra) {
             super(cra);
         }

         public OutputStream adapt(ClientRequest request, OutputStream
out) throws IOException {
             return new FinishingOutputStream(
                     new GZIPOutputStream(getAdapter().adapt(request,
out)));
         }
     }

     private final boolean compressRequestEntity;

     /**
      * Create a GZIP Content-Encoding filter that compresses the
request
      * entity.
      */
     public GZIPContentEncodingFilter() {
         this(true);
     }

     /**
      * Create a GZIP Content-Encoding filter.
      *
      * @param compressRequestEntity if true the request entity (if any)
      * is always compressed, otherwise the request entity is
compressed
      * only if there exists a Content-Encoding header whose
      * value is "gzip".
      */
     public GZIPContentEncodingFilter(boolean compressRequestEntity) {
         this.compressRequestEntity = compressRequestEntity;
     }

     @Override
     public ClientResponse handle(ClientRequest request) throws
ClientHandlerException {
         if (!
request.getMetadata().containsKey(HttpHeaders.ACCEPT_ENCODING)) {
             request.getMetadata().add(HttpHeaders.ACCEPT_ENCODING,
"gzip");
         }

         if (request.getEntity() != null) {
             Object o =
request.getMetadata().getFirst(HttpHeaders.CONTENT_ENCODING);
             if (o != null && o.equals("gzip")) {
                 request.setAdapter(new Adapter(request.getAdapter()));
             } else if (compressRequestEntity) {
                  
request.getMetadata().add(HttpHeaders.CONTENT_ENCODING, "gzip");
                 request.setAdapter(new Adapter(request.getAdapter()));
             }
         }

         ClientResponse response = getNext().handle(request);

         if (response.hasEntity() &&
                  
response.getMetadata().containsKey(HttpHeaders.CONTENT_ENCODING)) {
             String encodings =
response.getMetadata().getFirst(HttpHeaders.CONTENT_ENCODING);

             if (encodings.equals("gzip")) {
                  
response.getMetadata().remove(HttpHeaders.CONTENT_ENCODING);
                 try {
                     response.setEntityInputStream(new
GZIPInputStream(response.getEntityInputStream()));
                 } catch (IOException ex) {
                     throw new ClientHandlerException(ex);
                 }
             }
         }

         return response;
     }
}

On Apr 22, 2009, at 5:29 PM, Privalov, Sergey wrote:

> Hello,
>
> I have the “com.sun.jersey.api.container.MappableContainerException:
> java.io.EOFException: Unexpected end of ZLIB input stream” error
> when using client/serverGZIPContentEncodingFilter. And everything is
> working fine when these filters are removed from the configuration.
>
> Here is my part of the server web.xml:
>
> <servlet>
> <servlet-name>esWebServices</servlet-name>
> <servlet-
> class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</
> servlet-class>
> <init-param>
> <param-
> name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
> <param-
> value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</
> param-value>
> </init-param>
> <init-param>
> <param-
> name>com.sun.jersey.spi.container.ContainerResponseFilters</param-
> name>
> <param-
> value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</
> param-value>
> </init-param>
> <init-param>
> <param-name>com.sun.jersey.config.feature.Redirect</
> param-name>
> <param-value>true</param-value>
> </init-param>
> <init-param>
> <param-
> name>com.sun.jersey.config.feature.ImplicitViewables</param-name>
> <param-value>true</param-value>
> </init-param>
> <load-on-startup>1</load-on-startup>
> </servlet>
>
> My client config:
>
> private Client initClient() {
> ClientConfig clientConfig = new
> DefaultApacheHttpClientConfig();
>
>
> clientConfig
> .getProperties
> ().put(ApacheHttpClientConfig.PROPERTY_PREEMPTIVE_AUTHENTICATION,
> false);
>
> clientConfig
> .getProperties
> ().put(ApacheHttpClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 0);
>
> clientConfig
> .getProperties
> ().put(ApacheHttpClientConfig.PROPERTY_CREDENTIALS_PROVIDER,
> new
> DefaultCredentialsProvider(realm));
>
> clientConfig
> .getProperties().put(ApacheHttpClientConfig.PROPERTY_INTERACTIVE,
> false);
> int readTimeOut =
> GeneralPreferences.getInstance().getServerReadTimeout();
> if (readTimeOut > 0) {
>
> clientConfig
> .getProperties().put(ApacheHttpClientConfig.PROPERTY_READ_TIMEOUT,
> readTimeOut);
> }
>
> int connectTimeOut =
> GeneralPreferences.getInstance().getServerConnectionTimeout();
>
> if (connectTimeOut > 0) {
>
> clientConfig
> .getProperties
> ().put(ApacheHttpClientConfig.PROPERTY_CONNECT_TIMEOUT,
> connectTimeOut);
> }
>
> httpState = new HttpState();
>
> clientConfig
> .getProperties().put(ApacheHttpClientConfig.PROPERTY_HTTP_STATE,
> new
> ApacheHttpClientState(httpState));
>
> clientConfig
> .getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES,
> true);
>
> Protocol easyHttps = new Protocol(HTTPS_SCHEMA,
> (ProtocolSocketFactory) new EasySSLProtocolSocketFactory(),
> defaultSslPort);
>
> Protocol.registerProtocol(HTTPS_SCHEMA, easyHttps);
>
> ApacheHttpClient apaheClient =
> ApacheHttpClient.create(clientConfig);
> apaheClient.addFilter(new GZIPContentEncodingFilter());
> return apaheClient;
> }
>
> And client code which makes call to the server:
>
> UserAuthenticationDto usrAuth = new UserAuthenticationDto();
> usrAuth.setUser("Test User");
> return webResource.path("helloto.ws").accept("application/
> json").put(String.class, usrAuth);
>
> Is it jersey bug? Or maybe something wrong with my config?
>
>
> Best Regards,
> Sergey