Skip to content

StandardServletMultipartResolver#resolveLazily does not consistently convert parsing exceptions to MultipartException [SPR-11811] #16431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 20, 2014 · 2 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented May 20, 2014

Kazuki Shimizu opened SPR-11811 and commented

After the resolveLazily set true, i was sent a request that exceeds the max-file-size.
But occurred exception is not wrapped to the MultipartException.

Probably, should call the initializeMultipart method via getParameter, getParameterValues in StandardMultipartHttpServletRequest.

[WebLogic]
(not occurred the MultipartException)

date:2014-05-21 05:09:51	thread:[ACTIVE] ExecuteThread: '11' for queue: 'weblogic.kernel.Default (self-tuning)'	X-Track:cb70d65d1ef546b3aed89f78162fdc6e	level:DEBUG	logger:o.t.gfw.web.exception.SystemExceptionResolver   	message:Exposing Exception as model attribute 'exception'
date:2014-05-21 05:09:51	thread:[ACTIVE] ExecuteThread: '11' for queue: 'weblogic.kernel.Default (self-tuning)'	X-Track:cb70d65d1ef546b3aed89f78162fdc6e	level:ERROR	logger:o.t.gfw.common.exception.ExceptionLogger        	message:[e.xx.fw.9001] weblogic.servlet.utils.fileupload.SizeException: The field file exceeds its maximum permitted  size of 10240 characters.
java.lang.IllegalStateException: weblogic.servlet.utils.fileupload.SizeException: The field file exceeds its maximum permitted  size of 10240 characters.
	at weblogic.servlet.utils.fileupload.Multipart.initParts(Multipart.java:143) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.utils.fileupload.Multipart.getPart(Multipart.java:168) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.internal.ServletRequestImpl.getPart(ServletRequestImpl.java:3332) [weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.internal.ServletRequestImpl$RequestParameters.getPartParam(ServletRequestImpl.java:2235) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.internal.ServletRequestImpl$RequestParameters.getParameter(ServletRequestImpl.java:2228) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.internal.ServletRequestImpl$RequestParameters.access$800(ServletRequestImpl.java:2002) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at weblogic.servlet.internal.ServletRequestImpl.getParameter(ServletRequestImpl.java:881) [weblogic.server.merged.jar:12.1.2.0.0]
	at javax.servlet.ServletRequestWrapper.getParameter(ServletRequestWrapper.java:180) ~[weblogic.server.merged.jar:12.1.2.0.0]
	at org.springframework.web.util.WebUtils.hasSubmitParameter(WebUtils.java:554) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.ParamsRequestCondition$ParamExpression.matchName(ParamsRequestCondition.java:138) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression.match(AbstractNameValueExpression.java:72) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.getMatchingCondition(ParamsRequestCondition.java:99) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfo.getMatchingCondition(RequestMappingInfo.java:170) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:73) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:55) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.addMatchingMappings(AbstractHandlerMethodMapping.java:290) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:256) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:231) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:56) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:297) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1085) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1070) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:891) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:851) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:855) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:751) [weblogic.server.merged.jar:12.1.2.0.0]
	... (omitted)

[Resin]
(not occurred the MultipartException)

date:2014-05-21 05:41:29	thread:resin-port-18080-42	X-Track:6912aa3b9ecb4ccc961495e2a2061713	level:ERROR	logger:o.t.gfw.common.exception.ExceptionLogger        	message:[e.xx.fw.9001] multipart form data part 'file':'17806' is greater then the accepted value of '10240'
java.lang.IllegalStateException: multipart form data part 'file':'17806' is greater then the accepted value of '10240'
	at com.caucho.server.http.MultipartFormParser.parsePostData(MultipartFormParser.java:137) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.parsePostQueryImpl(AbstractCauchoRequest.java:449) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.parseQueryImpl(AbstractCauchoRequest.java:283) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.getParameterValuesImpl(AbstractCauchoRequest.java:188) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.getParameterValues(AbstractCauchoRequest.java:182) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.getParameterImpl(AbstractCauchoRequest.java:204) ~[resin.jar:4.0.37]
	at com.caucho.server.http.AbstractCauchoRequest.getParameter(AbstractCauchoRequest.java:199) ~[resin.jar:4.0.37]
	at javax.servlet.ServletRequestWrapper.getParameter(ServletRequestWrapper.java:174) ~[javaee-16.jar:na]
	at org.springframework.web.util.WebUtils.hasSubmitParameter(WebUtils.java:554) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.ParamsRequestCondition$ParamExpression.matchName(ParamsRequestCondition.java:138) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression.match(AbstractNameValueExpression.java:72) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.getMatchingCondition(ParamsRequestCondition.java:99) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfo.getMatchingCondition(RequestMappingInfo.java:170) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:73) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:55) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.addMatchingMappings(AbstractHandlerMethodMapping.java:290) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:256) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:231) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:56) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:297) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1085) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1070) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:891) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:851) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:855) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:159) [javaee-16.jar:na]
	(omitted)

[Tomcat]
(occurred the MultipartException)

date:2014-05-21 05:21:52	thread:http-bio-9080-exec-8	X-Track:641ff486cbe34bfe92d24410d4ef886a	level:ERROR	logger:o.t.gfw.common.exception.ExceptionLogger        	message:[e.xx.fw.9001] Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 10240 bytes.
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 10240 bytes.
	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:99) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.initializeMultipart(StandardMultipartHttpServletRequest.java:131) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.getParameterNames(StandardMultipartHttpServletRequest.java:137) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.util.WebUtils.getParametersStartingWith(WebUtils.java:644) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.bind.ServletRequestParameterPropertyValues.<init>(ServletRequestParameterPropertyValues.java:77) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.bind.ServletRequestParameterPropertyValues.<init>(ServletRequestParameterPropertyValues.java:52) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:106) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:153) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:106) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:685) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) ~[spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:919) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:851) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:855) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) [servlet-api.jar:na]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829) [spring-webmvc-3.2.9.RELEASE.jar:3.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api.jar:na]
	(omitted)

Affects: 3.2.9, 4.0.5

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

On deeper review, the stacktraces reveal an interesting detail: Multipart parsing fails at different times there...

  • Tomcat: Fails on data binding in the handler adapter phase, i.e. late in the game. Individual getParameter calls for your params-based request mapping have passed properly, retrieving the specific parameter value without evaluating further fields and files in the request body at that point. The eventual exception in the handler adapter phase, when we actually access all parameters, can be handled in a HandlerInterceptor as expected.

  • Resin & WebLogic: Fails on evaluation of the params-based request mapping, not even getting to the handler adapter phase since no handler could be determined. Individual getParameter calls fail immediately on those servers, so you'd only get to next stage in case of no params-based request mapping condition. An exception raised that early cannot be handled in a HandlerInterceptor, independent from the type of exception thrown.

So effectively, Tomcat has an optimized implementation which handles individual parameter retrieval without parsing the entire multipart request, or at least without evaluating the size constraints against file content in the request body at that point. Resin and WebLogic, on the other hand, don't proceed as subtly and rather fail immediately even for a single getParameter call that is only meant for mapping purposes. Unfortunately, we cannot just enforce our initializeMultipart step on getParameter and getParameterValues, since we'd lose Tomcat's arguably beneficial late-parsing feature - a reason why we support a "resolveLazily" mode in the first place.

As an alternative, we could catch IllegalStateExceptions from getParameter/getParameterValues and manually convert them to MultipartException (without triggering our initializeMultipart step). However, those IllegalStateExceptions aren't defined anywhere in the Servlet spec and could be thrown for other reasons as well - which we shouldn't turn into MultipartExceptions unless we clearly know that they actually have a multipart parsing cause. Also, as indicated above, exceptions raised at that early point cannot be handled in a HandlerInterceptor in any case, so a common MultipartException wouldn't be as beneficial for common handling code there.

Based on the reasoning above, I'd suggest to leave it at early multipart resolution if you absolutely require consistent exception handling across those servers and processing stages, and to only set resolveLazily=true if you know that the resulting exception behavior works for you on the specific servers that you deploy to.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Kazuki Shimizu commented

Thanks for detail comment.
I agree your comment.

I confirmed the API specification of getParameter and getParameterValues, these method specification did not written about java.lang.IllegalStateException.
In other word, WebLogic and Resin might be violates API specification of servlet 3.

If possible, I hope that are written the last sentence of your comment in Javadoc.
(As a side note of useing resolveLazily=true)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants