What's wrong with Spring's @RequestBody byte[] (length bigger than expected)?

11,512

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.

Share:
11,512
Benjamin M
Author by

Benjamin M

Updated on June 07, 2022

Comments

  • Benjamin M
    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
    mvmn about 7 years
    That 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
    user2914191 over 5 years
    its 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