-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Seems that ByteArrayHttpMessageConverter may truncate response body when the response is compressed (via gzip,deflate,etc.)
Context:
- Spring Boot 4.0.1
- HttpComponents 5.6
- which as per https://hc.apache.org/news.html 5.6 introduced "Support for pluggable content codecs via Commons-Compress in the classic transport. (optional)." and "Support for transparent content decompression and content compression with deflate, gzip, zstd (optional), and brotli (optional) codecs in the async transport. "
- RestClient reading external URL that is served with gzip compression
- .retrieve().body(byte[].class) only returns size of compressed content not entire decompressed content
From debugging session:
Response headers:
- Content-Length: 9075
- Content-Encoding: gzip
From ByteArrayHttpMessageConverter:
@Override
public byte[] readInternal(Class<? extends byte[]> clazz, HttpInputMessage message) throws IOException {
long length = message.getHeaders().getContentLength();
return (length >= 0 && length < Integer.MAX_VALUE ?
message.getBody().readNBytes((int) length) : message.getBody().readAllBytes());
}So in case of existing Content-Length header is only reads that many bytes giving back 9075 bytes of decompressed content.
But message.getBody().readAllBytes()) returns proper byte array of length 56815 bytes.
The check there seems to assume plain not-compressed content, since Content-Length is only about the representation (number of gzipped bytes) not actual response body bytes after any decompression.
There's the edge-cases of content-length header not being present meaning -1 or larger than Integer.MAX_VALUE but in both those cases readAllBytes() will be called. Why not always call readAllBytes() ? (range request?)