Description
william zhou opened SPR-13014 and commented
We recently upgraded from Spring framework 3.2.2 to 4.1.6 for our RESTful Services. We have a custom HTTP message reader for multipart request parsing using Apache Commons FileUpload. The code is like this:
@Override
public T read(Class<T> clazz, HttpInputMessage inputMessage)
throws HttpMessageNotReadableException, IOException {
if (inputMessage instanceof ServletServerHttpRequest
&& ServletFileUpload.isMultipartContent(
((ServletServerHttpRequest) inputMessage).getServletRequest())) {
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iterator = upload
.getItemIterator(
((ServletServerHttpRequest)inputMessage).getServletRequest());
T po = null;
if (iterator.hasNext()) {
po = parseDocument(iterator.next(), clazz);
...
}
It works fine while we were using Spring framework 3.2.2. However, after we upgraded to the Spring framework 4.1.6, the multipart request failed as the 1st part was dropped.
After debugging into the Spring code, we found that org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor has been changed that, in Spring 3.2.2, it wraps the servlet request's inputstream as a PushbackInputStream only when @RequestBody
is not required.
RequestBody annot = methodParam.getParameterAnnotation(RequestBody.class);
if (!annot.required()) {
...
inputMessage = new ServletServerHttpRequest(servletRequest) {
@Override
public InputStream getBody() throws IOException {
// Form POST should not get here
return pushbackInputStream;
}
};
And in Spring 4.1.6, it always wraps the inputstream. This makes our code failed because Commons FileUpload takes the HttpServletRequest as the input parameter, and the wrapped inputstream is just ignored.
To make it work, we have to workaround our code, like below:
final InputStream bodyWrapper = inputMessage.getBody();
HttpServletRequest requestWrapper = new HttpServletRequestWrapper(((ServletServerHttpRequest) inputMessage)
.getServletRequest()) {
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(bodyWrapper);
}
};
FileItemIterator iterator = upload.getItemIterator(requestWrapper);
However, this should really be fixed by Spring code.
Affects: 4.1.6
Issue Links:
- Re-allow handling empty request body [SPR-12778] #17376 Re-allow handling empty request body
Referenced from: commits a899e06