Skip to content

Commit 1ff8da3

Browse files
committed
StandardServletMultipartResolver provides strict Servlet compliance option
Closes gh-26826
1 parent ed27ea7 commit 1ff8da3

File tree

3 files changed

+155
-8
lines changed

3 files changed

+155
-8
lines changed

spring-web/src/main/java/org/springframework/web/multipart/support/StandardServletMultipartResolver.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121

2222
import org.apache.commons.logging.LogFactory;
2323

24+
import org.springframework.http.MediaType;
2425
import org.springframework.util.StringUtils;
2526
import org.springframework.web.multipart.MultipartException;
2627
import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -32,6 +33,15 @@
3233
* To be added as "multipartResolver" bean to a Spring DispatcherServlet context,
3334
* without any extra configuration at the bean level (see below).
3435
*
36+
* <p>This resolver variant uses your Servlet container's multipart parser as-is,
37+
* potentially exposing the application to container implementation differences.
38+
* See {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}
39+
* for an alternative implementation using a local Commons FileUpload library
40+
* within the application, providing maximum portability across Servlet containers.
41+
* Also, see this resolver's configuration option for
42+
* {@link #setStrictServletCompliance strict Servlet compliance}, narrowing the
43+
* applicability of Spring's {@link MultipartHttpServletRequest} to form data only.
44+
*
3545
* <p><b>Note:</b> In order to use Servlet 3.0 based multipart parsing,
3646
* you need to mark the affected servlet with a "multipart-config" section in
3747
* {@code web.xml}, or with a {@link javax.servlet.MultipartConfigElement}
@@ -55,13 +65,16 @@
5565
* @author Juergen Hoeller
5666
* @since 3.1
5767
* @see #setResolveLazily
68+
* @see #setStrictServletCompliance
5869
* @see HttpServletRequest#getParts()
5970
* @see org.springframework.web.multipart.commons.CommonsMultipartResolver
6071
*/
6172
public class StandardServletMultipartResolver implements MultipartResolver {
6273

6374
private boolean resolveLazily = false;
6475

76+
private boolean strictServletCompliance = false;
77+
6578

6679
/**
6780
* Set whether to resolve the multipart request lazily at the time of
@@ -76,10 +89,32 @@ public void setResolveLazily(boolean resolveLazily) {
7689
this.resolveLazily = resolveLazily;
7790
}
7891

92+
/**
93+
* Specify whether this resolver should strictly comply with the Servlet
94+
* specification, only kicking in for "multipart/form-data" requests.
95+
* <p>Default is "false", trying to process any request with a "multipart/"
96+
* content type as far as the underlying Servlet container supports it
97+
* (which works on e.g. Tomcat but not on Jetty). For consistent portability
98+
* and in particular for consistent custom handling of non-form multipart
99+
* request types outside of Spring's {@link MultipartResolver} mechanism,
100+
* switch this flag to "true": Only "multipart/form-data" requests will be
101+
* wrapped with a {@link MultipartHttpServletRequest} then; other kinds of
102+
* requests will be left as-is, allowing for custom processing in user code.
103+
* <p>Note that Commons FileUpload and therefore
104+
* {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}
105+
* supports any "multipart/" request type. However, it restricts processing
106+
* to POST requests which standard Servlet multipart parsers might not do.
107+
* @since 5.3.9
108+
*/
109+
public void setStrictServletCompliance(boolean strictServletCompliance) {
110+
this.strictServletCompliance = strictServletCompliance;
111+
}
112+
79113

80114
@Override
81115
public boolean isMultipart(HttpServletRequest request) {
82-
return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
116+
return StringUtils.startsWithIgnoreCase(request.getContentType(),
117+
(this.strictServletCompliance ? MediaType.MULTIPART_FORM_DATA_VALUE : "multipart/"));
83118
}
84119

85120
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.multipart.support;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.http.MediaType;
22+
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
26+
/**
27+
* @author Juergen Hoeller
28+
*/
29+
public class StandardServletMultipartResolverTests {
30+
31+
@Test
32+
public void isMultipartWithDefaultSetting() {
33+
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
34+
35+
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
36+
assertThat(resolver.isMultipart(request)).isFalse();
37+
38+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
39+
assertThat(resolver.isMultipart(request)).isTrue();
40+
41+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
42+
assertThat(resolver.isMultipart(request)).isTrue();
43+
44+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
45+
assertThat(resolver.isMultipart(request)).isTrue();
46+
47+
request = new MockHttpServletRequest("PUT", "/");
48+
assertThat(resolver.isMultipart(request)).isFalse();
49+
50+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
51+
assertThat(resolver.isMultipart(request)).isTrue();
52+
53+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
54+
assertThat(resolver.isMultipart(request)).isTrue();
55+
56+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
57+
assertThat(resolver.isMultipart(request)).isTrue();
58+
}
59+
60+
@Test
61+
public void isMultipartWithStrictSetting() {
62+
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
63+
resolver.setStrictServletCompliance(true);
64+
65+
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
66+
assertThat(resolver.isMultipart(request)).isFalse();
67+
68+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
69+
assertThat(resolver.isMultipart(request)).isTrue();
70+
71+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
72+
assertThat(resolver.isMultipart(request)).isFalse();
73+
74+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
75+
assertThat(resolver.isMultipart(request)).isFalse();
76+
77+
request = new MockHttpServletRequest("PUT", "/");
78+
assertThat(resolver.isMultipart(request)).isFalse();
79+
80+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
81+
assertThat(resolver.isMultipart(request)).isTrue();
82+
83+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
84+
assertThat(resolver.isMultipart(request)).isFalse();
85+
86+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
87+
assertThat(resolver.isMultipart(request)).isFalse();
88+
}
89+
90+
}

src/docs/asciidoc/web/webmvc.adoc

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,18 +1140,30 @@ another based on Servlet 3.0 multipart request parsing.
11401140

11411141
To enable multipart handling, you need to declare a `MultipartResolver` bean in your
11421142
`DispatcherServlet` Spring configuration with a name of `multipartResolver`.
1143-
The `DispatcherServlet` detects it and applies it to the incoming request. When a POST with
1144-
content-type of `multipart/form-data` is received, the resolver parses the content and
1145-
wraps the current `HttpServletRequest` as `MultipartHttpServletRequest` to
1146-
provide access to resolved parts in addition to exposing them as request parameters.
1143+
The `DispatcherServlet` detects it and applies it to the incoming request. When a POST
1144+
with a content type of `multipart/form-data` is received, the resolver parses the
1145+
content wraps the current `HttpServletRequest` as a `MultipartHttpServletRequest` to
1146+
provide access to resolved files in addition to exposing parts as request parameters.
11471147

11481148

11491149
[[mvc-multipart-resolver-commons]]
11501150
==== Apache Commons `FileUpload`
11511151

11521152
To use Apache Commons `FileUpload`, you can configure a bean of type
1153-
`CommonsMultipartResolver` with a name of `multipartResolver`. You also need to
1154-
have `commons-fileupload` as a dependency on your classpath.
1153+
`CommonsMultipartResolver` with a name of `multipartResolver`. You also need to have
1154+
the `commons-fileupload` jar as a dependency on your classpath.
1155+
1156+
This resolver variant delegates to a local library within the application, providing
1157+
maximum portability across Servlet containers. As an alternative, consider standard
1158+
Servlet multipart resolution through the container's own parser as discussed below.
1159+
1160+
[NOTE]
1161+
====
1162+
Commons FileUpload traditionally applies to POST requests only but accepts any
1163+
`multipart/` content type. See the
1164+
{api-spring-framework}/web/multipart/commons/CommonsMultipartResolver.html[`CommonsMultipartResolver`]
1165+
javadoc for details and configuration options.
1166+
====
11551167

11561168

11571169
[[mvc-multipart-resolver-standard]]
@@ -1200,6 +1212,16 @@ The following example shows how to set a `MultipartConfigElement` on the Servlet
12001212
Once the Servlet 3.0 configuration is in place, you can add a bean of type
12011213
`StandardServletMultipartResolver` with a name of `multipartResolver`.
12021214

1215+
[NOTE]
1216+
====
1217+
This resolver variant uses your Servlet container's multipart parser as-is,
1218+
potentially exposing the application to container implementation differences.
1219+
By default, it will try to parse any `multipart/` content type with any HTTP
1220+
method but this may not be supported across all Servlet containers. See the
1221+
{api-spring-framework}/web/multipart/support/StandardServletMultipartResolver.html[`StandardServletMultipartResolver`]
1222+
javadoc for details and configuration options.
1223+
====
1224+
12031225

12041226

12051227
[[mvc-logging]]

0 commit comments

Comments
 (0)