From df1f8139ccac06c2a5b9122ecb1b3968eb95cdef Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Tue, 21 Feb 2023 20:19:52 -0800 Subject: [PATCH] Use Content-Length for optimal read to byte[] If content-length is available, pass it to readNBytes in ByteArrayHttpMessageConverter. When the content length is less than the internal buffer size in InputStream (8192), this avoids a copy, as readNBytes will return the buffer directly. When the content length is greater than the buffer size used in InputStream, passing the content-length at least avoids over-allocating the final buffer (e.g., if the content length were 8193 bytes, 1 byte more than the default buffer size). If the content length isn't present or is too large to represent as an integer, fall back to the default behavior of readAllBytes by passing in Integer.MAX_VALUE. See gh-30010 --- .../http/converter/ByteArrayHttpMessageConverter.java | 10 +++++++++- .../converter/ByteArrayHttpMessageConverterTests.java | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java index 3a7025acbf1..31de40f3a9b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java @@ -52,7 +52,15 @@ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter< @Override public byte[] readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException { - return inputMessage.getBody().readAllBytes(); + long contentLength = inputMessage.getHeaders().getContentLength(); + final int len; + if (contentLength >= 0 && contentLength <= Integer.MAX_VALUE) { + len = (int) contentLength; + } + else { + len = Integer.MAX_VALUE; + } + return inputMessage.getBody().readNBytes(len); } @Override diff --git a/spring-web/src/test/java/org/springframework/http/converter/ByteArrayHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/ByteArrayHttpMessageConverterTests.java index 612ec0ce4cd..5a00d76582f 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/ByteArrayHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/ByteArrayHttpMessageConverterTests.java @@ -57,6 +57,16 @@ public class ByteArrayHttpMessageConverterTests { assertThat(result).as("Invalid result").isEqualTo(body); } + @Test + public void readWithContentLengthHeaderSet() throws IOException { + byte[] body = new byte[]{0x1, 0x2, 0x3, 0x4, 0x5}; + MockHttpInputMessage inputMessage = new MockHttpInputMessage(body); + inputMessage.getHeaders().setContentType(new MediaType("application", "octet-stream")); + inputMessage.getHeaders().setContentLength(body.length); + byte[] result = converter.read(byte[].class, inputMessage); + assertThat(result).as("Invalid result").isEqualTo(body); + } + @Test public void write() throws IOException { MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();