JBoss.org Community Documentation

- Prev
- Next

## Chapter 32. Content encoding

## 32.1. GZIP Compression/Decompression

RESTEasy supports (though not by default - see below) GZIP decompression. If properly configured, the client framework or a JAX-RS service, upon receiving a message body with a Content-Encoding of "gzip", will automatically decompress it. The client framework can (though not by default - see below) automatically set the Accept-Encoding header to be "gzip, deflate" so you do not have to set this header yourself.

RESTEasy also supports (though not by default - see below) automatic compression. If the client framework is sending a request or the server is sending a response with the Content-Encoding header set to "gzip", RESTEasy will (if properly configured) do the compression. So that you do not have to set the Content-Encoding header directly, you can use the @org.jboss.resteasy.annotation.GZIP annotation.

    @Path("/")
    public interface MyProxy {

       @Consumes("application/xml")
       @PUT
       public void put(@GZIP Order order);
    }

In the above example, we tag the outgoing message body, order, to be gzip compressed. You can use the same annotation to tag server responses

    @Path("/")
    public class MyService {

       @GET
       @Produces("application/xml")
       @GZIP
       public String getData() {...}
    }

### 32.1.1. Configuring GZIP compression / decompression

Note. Decompression carries a risk of attack from a bad actor that can package an entity that will expand greatly. Consequently, RESTEasy disables GZIP compression / decompression by default.

There are three interceptors that are relevant to GZIP compression / decompression:

1. org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor: If the Content-Encoding header is present and has the value "gzip", `GZIPDecodingInterceptor` will install an `InputStream` that decompresses the message body.
2. org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor: If the Content-Encoding header is present and has the value "gzip", `GZIPEncodingInterceptor` will install an `OutputStream` that compresses the message body.
3. org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter: If the Accept-Encoding header does not exist, `AcceptEncodingGZIPFilter` will add Accept-Encoding with the value "gzip, deflate". If the Accept-Encoding header exists but does not contain "gzip", `AcceptEncodingGZIPFilter` will append ", gzip". Note that enabling GZIP compression / decompression does not depend on the presence of this interceptor.

If GZIP decompression is enabled, an upper limit is imposed on the number of bytes `GZIPDecodingInterceptor` will extract from a compressed message body. The default limit is 10,000,000, but a different value can be configured. See below.

#### 32.1.1.1. Server side configuration

The interceptors may be enabled by including their classnames in a META-INF/services/javax.ws.rs.ext.Providers file on the classpath. The upper limit on deflated files may be configured by setting the parameter "resteasy.gzip.max.input". [See Section 3.4, “Configuration” for more information about application configuration.] If the limit is exceeded on the server side, GZIPDecodingInterceptor will return a `Response` with status 413 ("Request Entity Too Large") and a message specifying the upper limit.

Note. As of release 3.1.0.Final, the GZIP interceptors have moved from package `org.jboss.resteasy.plugins.interceptors.encoding` to `org.jboss.resteasy.plugins.interceptors`. and they should be named accordingly in javax.ws.rs.ext.Providers.

#### 32.1.1.2. Client side configuration

The interceptors may be enabled by registering them with, for example, a `Client` or `WebTarget`. For example,

    Client client = ClientBuilder.newBuilder() // Activate gzip compression on client:
                        .register(AcceptEncodingGZIPFilter.class)
                        .register(GZIPDecodingInterceptor.class)
                        .register(GZIPEncodingInterceptor.class)
                        .build();

The upper limit on deflated files may configured by creating an instance of `GZIPDecodingInterceptor` with a specific value:

    Client client = ClientBuilder.newBuilder() // Activate gzip compression on client:
                        .register(AcceptEncodingGZIPFilter.class)
                        .register(new GZIPDecodingInterceptor(256))
                        .register(GZIPEncodingInterceptor.class)
                        .build();

If the limit is exceeded on the client side, GZIPDecodingInterceptor will throw a `ProcessingException` with a message specifying the upper limit.

## 32.2. General content encoding

The designation of a compressible entity by the use of the `@GZIP` annotation is a built in, specific instance of a more general facility supported by RESTEasy. There are three components to this facility.

1. The annotation `org.jboss.resteasy.annotations.ContentEncoding` is a "meta-annotation" used on other annotations to indicate that they represent a Content-Encoding. For example, `@GZIP` is defined

       @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
       @Retention(RetentionPolicy.RUNTIME)
       @ContentEncoding("gzip")
       public @interface GZIP
       {
       }

   The value of `@ContentEncoding` indicates the represented Content-Encoding. For `@GZIP` it is "gzip".
2. `ClientContentEncodingAnnotationFeature` and `ServerContentEncodingAnnotationFeature`, two `DynamicFeature`s in package `org.jboss.resteasy.plugins.interceptors`, examine resource methods for annotations decorated with `@ContentEncoding`.
3. For each value found in a `@ContentEncoding` decorated annotation on a resource method, an instance of `ClientContentEncodingAnnotationFilter` or `ServerContentEncodingAnnotationFilter`, `javax.ws.rs.ext.WriterInterceptor`s in package `org.jboss.resteasy.plugins.interceptors`, is registered. They are responsible for adding an appropriate Content-Encoding header. For example, `ClientContentEncodingAnnotationFilter` is defined

       @ConstrainedTo(RuntimeType.CLIENT)
       @Priority(Priorities.HEADER_DECORATOR)
       public class ClientContentEncodingAnnotationFilter implements WriterInterceptor
       {
          protected String encoding;

          public ClientContentEncodingAnnotationFilter(String encoding)
          {
             this.encoding = encoding;
          }

          @Override
          public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException
          {
             context.getHeaders().putSingle(HttpHeaders.CONTENT_ENCODING, encoding);
             context.proceed();
          }
       }

   When it is created, `ClientContentEncodingAnnotationFeature` passes in the value to be used for Content-Encoding headers.

The annotation `@GZIP` is built into RESTEasy, but `ClientContentEncodingAnnotationFeature` and `ServerContentEncodingAnnotationFeature` will also recognize application defined annotations. For example,

       @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
       @Retention(RetentionPolicy.RUNTIME)
       @ContentEncoding("compress")
       public @interface Compress
       {
       }

       @Path("")
       public static class TestResource {

          @GET
          @Path("a")
          @Compress
          public String a() {
             return "a";
          }
       }

If `TestResource.a()` is invoked as follows

       @Test
       public void testCompress() throws Exception
       {
          Client client = ClientBuilder.newClient();
          Invocation.Builder request = client.target("http://localhost:8081/a").request();
          request.acceptEncoding("gzip,compress");
          Response response = request.get();
          System.out.println("content-encoding: "+ response.getHeaderString("Content-Encoding"));
          client.close();
       }

the output will be

    content-encoding: compress

- PrevChapter 31. Configuring Individual JAX-RS Resourc...
- Top of page
- Front page
- NextChapter 33. CORS