Skip to content

ByteArrayHttpMessageConverter truncation when content is compressed #36064

@deathy

Description

@deathy

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:

Image

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?)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions