Skip to content

Commons FileUpload failed after Spring framework upgrade [SPR-13014] #17605

Closed
@spring-projects-issues

Description

@spring-projects-issues

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:

Referenced from: commits a899e06

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions