JBoss.orgCommunity Documentation
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() {...} }
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:
GZIPDecodingInterceptor
will install an InputStream
that decompresses the message body.
GZIPEncodingInterceptor
will install an OutputStream
that compresses the message body.
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.
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 web application context parameter "resteasy.gzip.max.input".
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. However, they continue to exist in
org.jboss.resteasy.plugins.interceptors.encoding
in module
resteasy-legacy, so, if resteasy-legacy is available, the original names can be used.
See Chapter Migration to RESTEasy 3.1 for more
information.
The interceptors may be enabled by registering them with, for example, a
Client
or WebTarget
. For example,
Client client = new ResteasyClientBuilder() // 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 = new ResteasyClientBuilder() // 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.
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.
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".
ClientContentEncodingAnnotationFeature
and
ServerContentEncodingAnnotationFeature
,
two DynamicFeature
s
in package org.jboss.resteasy.plugins.interceptors
,
examine resource methods for annotations decorated with @ContentEncoding
.
@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 { ResteasyClient client = new ResteasyClientBuilder().build(); 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