Skip to content

Commit e1c0f3b

Browse files
committed
CommonsMultipartResolver supports configurable HTTP methods
Closes gh-27161
1 parent 1ff8da3 commit e1c0f3b

File tree

2 files changed

+97
-4
lines changed

2 files changed

+97
-4
lines changed

spring-web/src/main/java/org/springframework/web/multipart/commons/CommonsMultipartResolver.java

Lines changed: 36 additions & 3 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.
@@ -16,7 +16,10 @@
1616

1717
package org.springframework.web.multipart.commons;
1818

19+
import java.util.Arrays;
20+
import java.util.HashSet;
1921
import java.util.List;
22+
import java.util.Set;
2023

2124
import javax.servlet.ServletContext;
2225
import javax.servlet.http.HttpServletRequest;
@@ -27,7 +30,9 @@
2730
import org.apache.commons.fileupload.FileUploadBase;
2831
import org.apache.commons.fileupload.FileUploadException;
2932
import org.apache.commons.fileupload.servlet.ServletFileUpload;
33+
import org.apache.commons.fileupload.servlet.ServletRequestContext;
3034

35+
import org.springframework.lang.Nullable;
3136
import org.springframework.util.Assert;
3237
import org.springframework.web.context.ServletContextAware;
3338
import org.springframework.web.multipart.MaxUploadSizeExceededException;
@@ -41,7 +46,11 @@
4146
/**
4247
* Servlet-based {@link MultipartResolver} implementation for
4348
* <a href="https://commons.apache.org/proper/commons-fileupload">Apache Commons FileUpload</a>
44-
* 1.2 or above.
49+
* 1.2 or above. This resolver variant delegates to a local FileUpload library
50+
* within the application, providing maximum portability across Servlet containers.
51+
*
52+
* <p>Commons FileUpload traditionally parses POST requests with any "multipart/" type.
53+
* Supported HTTP methods may be customized through {@link #setSupportedMethods}.
4554
*
4655
* <p>Provides "maxUploadSize", "maxInMemorySize" and "defaultEncoding" settings as
4756
* bean properties (inherited from {@link CommonsFileUploadSupport}). See corresponding
@@ -52,19 +61,29 @@
5261
* Needs to be initialized <i>either</i> by an application context <i>or</i>
5362
* via the constructor that takes a ServletContext (for standalone usage).
5463
*
64+
* <p>Note: The common alternative is
65+
* {@link org.springframework.web.multipart.support.StandardServletMultipartResolver},
66+
* delegating to the Servlet container's own multipart parser, with configuration to
67+
* happen at the container level and potentially with container-specific limitations.
68+
*
5569
* @author Trevor D. Cook
5670
* @author Juergen Hoeller
5771
* @since 29.09.2003
5872
* @see #CommonsMultipartResolver(ServletContext)
5973
* @see #setResolveLazily
74+
* @see #setSupportedMethods
6075
* @see org.apache.commons.fileupload.servlet.ServletFileUpload
6176
* @see org.apache.commons.fileupload.disk.DiskFileItemFactory
77+
* @see org.springframework.web.multipart.support.StandardServletMultipartResolver
6278
*/
6379
public class CommonsMultipartResolver extends CommonsFileUploadSupport
6480
implements MultipartResolver, ServletContextAware {
6581

6682
private boolean resolveLazily = false;
6783

84+
@Nullable
85+
private Set<String> supportedMethods;
86+
6887

6988
/**
7089
* Constructor for use as bean. Determines the servlet container's
@@ -101,6 +120,17 @@ public void setResolveLazily(boolean resolveLazily) {
101120
this.resolveLazily = resolveLazily;
102121
}
103122

123+
/**
124+
* Specify supported methods as an array of HTTP method names.
125+
* The traditional Commons FileUpload default is "POST" only.
126+
* <p>When configured as a Spring property value,
127+
* this can be a comma-separated String: e.g. "POST,PUT".
128+
* @since 5.3.9
129+
*/
130+
public void setSupportedMethods(String... supportedMethods) {
131+
this.supportedMethods = new HashSet<>(Arrays.asList(supportedMethods));
132+
}
133+
104134
/**
105135
* Initialize the underlying {@code org.apache.commons.fileupload.servlet.ServletFileUpload}
106136
* instance. Can be overridden to use a custom subclass, e.g. for testing purposes.
@@ -122,7 +152,10 @@ public void setServletContext(ServletContext servletContext) {
122152

123153
@Override
124154
public boolean isMultipart(HttpServletRequest request) {
125-
return ServletFileUpload.isMultipartContent(request);
155+
return (this.supportedMethods != null ?
156+
this.supportedMethods.contains(request.getMethod()) &&
157+
FileUploadBase.isMultipartContent(new ServletRequestContext(request)) :
158+
ServletFileUpload.isMultipartContent(request));
126159
}
127160

128161
@Override

spring-web/src/test/java/org/springframework/web/multipart/commons/CommonsMultipartResolverTests.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 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.
@@ -46,6 +46,7 @@
4646
import org.junit.jupiter.api.Test;
4747

4848
import org.springframework.beans.MutablePropertyValues;
49+
import org.springframework.http.MediaType;
4950
import org.springframework.util.MultiValueMap;
5051
import org.springframework.web.bind.ServletRequestDataBinder;
5152
import org.springframework.web.context.WebApplicationContext;
@@ -71,6 +72,65 @@
7172
*/
7273
public class CommonsMultipartResolverTests {
7374

75+
@Test
76+
public void isMultipartWithDefaultSetting() {
77+
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
78+
79+
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
80+
assertThat(resolver.isMultipart(request)).isFalse();
81+
82+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
83+
assertThat(resolver.isMultipart(request)).isTrue();
84+
85+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
86+
assertThat(resolver.isMultipart(request)).isTrue();
87+
88+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
89+
assertThat(resolver.isMultipart(request)).isTrue();
90+
91+
request = new MockHttpServletRequest("PUT", "/");
92+
assertThat(resolver.isMultipart(request)).isFalse();
93+
94+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
95+
assertThat(resolver.isMultipart(request)).isFalse();
96+
97+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
98+
assertThat(resolver.isMultipart(request)).isFalse();
99+
100+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
101+
assertThat(resolver.isMultipart(request)).isFalse();
102+
}
103+
104+
@Test
105+
public void isMultipartWithSupportedMethods() {
106+
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
107+
resolver.setSupportedMethods("POST", "PUT");
108+
109+
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
110+
assertThat(resolver.isMultipart(request)).isFalse();
111+
112+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
113+
assertThat(resolver.isMultipart(request)).isTrue();
114+
115+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
116+
assertThat(resolver.isMultipart(request)).isTrue();
117+
118+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
119+
assertThat(resolver.isMultipart(request)).isTrue();
120+
121+
request = new MockHttpServletRequest("PUT", "/");
122+
assertThat(resolver.isMultipart(request)).isFalse();
123+
124+
request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
125+
assertThat(resolver.isMultipart(request)).isTrue();
126+
127+
request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
128+
assertThat(resolver.isMultipart(request)).isTrue();
129+
130+
request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
131+
assertThat(resolver.isMultipart(request)).isTrue();
132+
}
133+
74134
@Test
75135
public void withApplicationContext() throws Exception {
76136
doTestWithApplicationContext(false);

0 commit comments

Comments
 (0)