Why does the following example swallow my HTTP-Header for "Content-Encoding" in the request. I am writing an application where I need to decode a custom encoding format. However, I can never get hold of the "Content-Encoding" header from the request. Neither in the actual resource nor in an ReaderInterceptor. In the response, this encoding header is not swallowed.
This behavior can be easily observed in the following (runnable) example:
public class Demo extends JerseyTest {
@Override
protected Application configure() {
enable(TestProperties.DUMP_ENTITY);
enable(TestProperties.LOG_TRAFFIC);
return new ResourceConfig(MyResource.class, MyInterceptor.class);
}
public static final String PATH = "path";
public static final String ENCODING = "my-encoding";
public static final String CUSTOM_HEADER = "X-Content-Encoding";
public static final String QUESTION = "question", ANSWER = "answer";
@Path(PATH)
public static class MyResource {
@POST
public Response handle(String value, @Context HttpHeaders httpHeaders) {
assertEquals(ENCODING, httpHeaders.getHeaderString(CUSTOM_HEADER));
// Here, the "Content-Encoding" header mysteriously disappeared.
assertEquals(ENCODING, httpHeaders.getHeaderString(HttpHeaders.CONTENT_ENCODING));
return Response
.ok(ANSWER)
.header(CUSTOM_HEADER, ENCODING)
.header(HttpHeaders.CONTENT_ENCODING, ENCODING)
.build();
}
}
public static class MyInterceptor implements ReaderInterceptor, WriterInterceptor {
@Override
public Object aroundReadFrom(ReaderInterceptorContext context)
throws IOException, WebApplicationException {
assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header mysteriously disappeared.
assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
return context.proceed();
}
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header can be found.
assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
context.proceed();
}
}
@Test
public void test() throws Exception {
Response response = target(PATH)
.request()
.header(CUSTOM_HEADER, ENCODING)
.header(HttpHeaders.CONTENT_ENCODING, ENCODING)
.post(Entity.text(QUESTION));
assertEquals(200, response.getStatus());
assertEquals(ENCODING, response.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header can be found.
assertEquals(ENCODING, response.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
}
}
Is there some magic happening behind the curtains where Jersey tries to fix up my content encoding? (What it cannot since its a closed-source encoding which I must as a matter of fact resolve by querying another application on another server in the network.) I cannot even discover the "Content-Encoding" header in the request dump which is why I suspect Jersey to not send the header at all.
I could of course use some "X-Content-Encoding" header, this works as demonstrated in the example. But this solution is just dumb. I already searched the various CommonProperties
, ServerProperties
, ClientProperties
constant pools but I did not find a configuration option.
The Content-Encoding representation header lists any encodings that have been applied to the representation (message payload), and in what order. This lets the recipient know how to decode the representation in order to obtain the original payload format.
All the HTTP client used to tell the server which encoding or encoding it supports. Then the server will respond in any of the supporting encoding formats. The server selects any one of the proposals, uses it and informs the client of its choice with the Content-Encoding response header.
The Accept-Encoding request HTTP header indicates the content encoding (usually a compression algorithm) that the client can understand. The server uses content negotiation to select one of the proposals and informs the client of that choice with the Content-Encoding response header.
The problem you see is because you are effectively overwriting the Content-Encoding header with the
.post(Entity.text(QUESTION));
call. The Entity.text(...)
method produces entity with the content data Variant
fields set to:
media type = "text/plain";
content language = null;
content encoding = null;
These null
values of content encoding and language in turn erase any previously set Content-Encoding
or Content-Language
headers. To fix this, you need to specify the content encoding as part of your entity:
Response response = target(PATH)
.request()
.post(Entity.entity(QUESTION,
new Variant(MediaType.TEXT_PLAIN_TYPE, (String) null, "my-encoding")));
(I agree this behavior is somewhat confusing as it is not obvious. Perhaps we should fix Jersey to not override headers with null
variant field values if set...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With