I'm using the new java.net.http
classes to handle asynchronous HTTP request+response exchanges, and I'm trying to find a way to have the BodySubscriber handle different encoding types such as gzip.
However, mapping a BodySubsriber<InputStream>
so that the underlying stream is wrapped by a GZIPInputStream
(when "Content-Encoding: gzip" is found in the response header) leads to a hang. No exceptions, just a total cessation of activity.
The code which maps the BodySubscriber
looks like this:
private HttpResponse.BodySubscriber<InputStream> gzippedBodySubscriber(
HttpResponse.ResponseInfo responseInfo) {
return HttpResponse.BodySubscribers.mapping(
HttpResponse.BodySubscribers.ofInputStream(),
this::decodeGzipStream);
}
private InputStream decodeGzipStream(InputStream gzippedStream) {
System.out.println("Entered decodeGzipStream method.");
try {
InputStream decodedStream = new GZIPInputStream(gzippedStream);
System.out.println(
"Created GZIPInputStream to handle response body stream.");
return decodedStream;
} catch (IOException ex) {
System.out.println("IOException occurred while trying to create GZIPInputStream.");
throw new UncheckedIOException(ex);
}
}
Receiving an HTTP response which has "gzip" encoding leads to the console showing just this:
Entered EncodedBodyHandler.apply method.
Entered decodeGzipStream method.
Nothing more is seen, so the line after the call to the GZIPInputStream
constructor is never executed.
Does anyone know why this attempt to wrap the InputStream
from a BodySubscriber<InputStream>
in a GZIPInputStream
is hanging?
Note: the equivalent method for unencoded (raw text) HTTP response bodies contains simply a call to BodySubscribers.ofInputStream()
with no mapping, and this allows the response to be received and displayed without problem.
EDIT: JDK-8217264 is fixed since JDK13
This is indeed a bug. I have logged JDK-8217264. I can suggest two work-arounds:
Workaround one
Do not use
BodySubscribers.mapping
- but transform theInputStream
into aGZIPInputStream
after getting the HttpResponse's body:Workaround two
Have the mapping function return a
Supplier<InputStream>
instead, taking care not to create theGZIPInputStream
untilSupplier::get
is called