javaspring-bootmicroservicesmultipart

Cannot read request body from HttpServletRequest when Content-Type is multipart/mixed


Below code handles the incoming API calls:

@RequestMapping(value = "**")
void process(HttpServletRequest request, HttpServletResponse response) throws IOException {
    if (request.getInputStream().available() > 0) {
        System.out.println("Input Stream data present");
    }
}

I run my API call from Postman like below:

curl --location --request POST 'http://localhost:8084/api/v1/inv/$batch' \
--header 'Content-Type: multipart/mixed;boundary=abc123;' \
--data-raw '--abc123
Content-Type: application/http
Content-Transfer-Encoding: binary

GET http://localhost:8084/api/v1/inv/Port_Type HTTP/1.1

--abc123
Content-Type: application/http
Content-Transfer-Encoding: binary

GET http://localhost:8084/api/v1/inv/Device_Type HTTP/1.1

--abc123--
'

request.getInputStream().available() always returns 0 but it returns a non-zero value when the Content-Type is not multipart/mixed.

One interesting thing I noticed is that when I modify the code to read the request body using a BufferedReader,
I get an exception saying that getInputStream() has already been called for this request

public void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    BufferedReader reader = request.getReader();
}

Looks like getInputStream() is being invoked even before reaching the controller.


Solution

  • You need to get the part and then read its input stream. Try the following:

    public void process(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for (Part part : request.getParts()) {
            if (part.getInputStream().available() > 0) {
                System.out.println("Input Stream data present");
            }
        }
    }
    

    And following changes are needed in the curl command:

    So the curl command will look like:

    curl --location --request POST 'http://localhost:8084/api/v1/inv/$batch' \
    --header 'Content-Type: multipart/mixed;boundary=abc123;' \
    --data-raw $'--abc123\r\nContent-Type: application/http\r\nContent-Disposition: form-data; name="part1"\r\nContent-Transfer-Encoding: binary\r\n\r\nGET http://localhost:8084/api/v1/inv/Port_Type HTTP/1.1\r\n\r\n--abc123\r\nContent-Type: application/http\r\nContent-Disposition: form-data; name="part2"\r\nContent-Transfer-Encoding: binary\r\n\r\nGET http://localhost:8084/api/v1/inv/Device_Type HTTP/1.1\r\n\r\n--abc123--\r\n'