What's wrong with Spring's @RequestBody byte[] (length bigger than expected)?
In Spring's ByteArrayHttpMessageConverter
, you can find the method readInternal
which converts the contents of a request into the desired format (in this case byte[]
).
The code (Spring 4.0.0.RELEASE):
long contentLength = inputMessage.getHeaders().getContentLength();
ByteArrayOutputStream bos = new ByteArrayOutputStream(contentLength >= 0 ? (int) contentLength : StreamUtils.BUFFER_SIZE);
StreamUtils.copy(inputMessage.getBody(), bos);
return bos.toByteArray();
The second line says: *If the request payload isn't empty take it's content length, and set the capacity of the ByteArrayOutputStream
with that. Else if the content length is < 0, then set it to StreamUtils.BUFFER_SIZE (= 4096).*
Im not really sure why it is implemented this way, but that's how it actually works.
Benjamin M
Updated on June 07, 2022Comments
-
Benjamin M almost 2 years
I tried to use
@RequestBody byte[] data
as automatic Base64 decoder, in order to receive some RSA encrypted data and afterwards decrypt it in my service:Controller:
@RequestMapping void doIt(@RequestBody byte[] data) { service.doIt(data); }
Service:
void doIt(byte[] encryptedData) { String testDataString = "hgLGtzF4D8tlJbVivQgaXXwfI9TbQ//PrYHEez5k93sqJSi17eLCa+r/cGNGvoxDRaPYONvP4yxW0ajKDFrusQ4V4owfhkijS9KzBOTjBeAVmA+5jBsZCdoxwCA65DiP5lJ+GRbn8CjcjCr4DaEWFbWHsyvY4NGGAQLuYv+PyZipfU9pXTEDsBb15NwaHlD5m7Z4CHWdWTt1ARvRaQs56Bp63/IEmGR7w4brA1+iuKPv83FLh0rsxyoJ+F8TeqtuPhm2fHTh1FiHn0Bpaqqoyd/cBl0/utSzu4qoZhB3AiVgLjnT6Iy9p5nVoAozxQo/Es59LrpGZfjYJer073jNIg=="; byte[] testDataBytes = Base64.decodeBase64(testDataString); System.out.println(encryptedData.length); System.out.println(testDataBytes.length); System.out.println(new String(encryptedData).length()); System.out.println(Base64.encodeBase64String(testDataBytes).length()); System.out.println(new String(encryptedData).equals(Base64.encodeBase64String(testDataBytes))); }
Request:
Content-Type: application/octet-stream Request Payload: hgLGtzF4D8tlJbVivQgaXXwfI9TbQ//PrYHEez5k93sqJSi17eLCa+r/cGNGvoxDRaPYONvP4yxW0ajKDFrusQ4V4owfhkijS9KzBOTjBeAVmA+5jBsZCdoxwCA65DiP5lJ+GRbn8CjcjCr4DaEWFbWHsyvY4NGGAQLuYv+PyZipfU9pXTEDsBb15NwaHlD5m7Z4CHWdWTt1ARvRaQs56Bp63/IEmGR7w4brA1+iuKPv83FLh0rsxyoJ+F8TeqtuPhm2fHTh1FiHn0Bpaqqoyd/cBl0/utSzu4qoZhB3AiVgLjnT6Iy9p5nVoAozxQo/Es59LrpGZfjYJer073jNIg==
The Output:
(Spring) Byte length: 344 (test) Byte length: 256 (Spring) Base64 String length: 344 (test) Base64 String length: 344 Base64 String equals: true
As you can see:
The request contains exactly the same data as the test data I put into the source code.
After doing Base64 encoding both have the same length and are `equal``
BUT: The length of the byte arrays are different.
Question:
Why is the
byte[]
that was generated by Spring bigger? (It's useless when trying to decode it using some RSA private key, because RSA expects a length of 256.)Workaround:
Controller:
@RequestMapping void doIt(@RequestBody String data) { service.doIt(Base64.decodeBase64(data)); }
-
mvmn about 7 yearsThat has nothing to do with it. The problem author has is that he somehow assumes Spring will decode his 344 characters long BASE64 encoded string, but Spring doesn't do that, it just creates a byte array with 1 byte for each character.
-
user2914191 over 5 yearsits implemented that way because without content type header it doesnt know how much memory to allocate, so it allocates 4K. if you know the size, specify the content length