Skip to content

Commit

Permalink
CommonsMultipartResolver supports configurable HTTP methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoeller authored and XIACYBING committed Jan 27, 2023
1 parent 6110925 commit b2cac38
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,10 @@

package org.springframework.web.multipart.commons;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -27,7 +30,9 @@
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

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

private boolean resolveLazily = false;

@Nullable
private Set<String> supportedMethods;


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

/**
* Specify supported methods as an array of HTTP method names.
* The traditional Commons FileUpload default is "POST" only.
* <p>When configured as a Spring property value,
* this can be a comma-separated String: e.g. "POST,PUT".
* @since 5.3.9
*/
public void setSupportedMethods(String... supportedMethods) {
this.supportedMethods = new HashSet<>(Arrays.asList(supportedMethods));
}

/**
* Initialize the underlying {@code org.apache.commons.fileupload.servlet.ServletFileUpload}
* instance. Can be overridden to use a custom subclass, e.g. for testing purposes.
Expand All @@ -122,7 +152,10 @@ public void setServletContext(ServletContext servletContext) {

@Override
public boolean isMultipart(HttpServletRequest request) {
return ServletFileUpload.isMultipartContent(request);
return (this.supportedMethods != null ?
this.supportedMethods.contains(request.getMethod()) &&
FileUploadBase.isMultipartContent(new ServletRequestContext(request)) :
ServletFileUpload.isMultipartContent(request));
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,6 +46,7 @@
import org.junit.jupiter.api.Test;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.WebApplicationContext;
Expand All @@ -71,6 +72,65 @@
*/
public class CommonsMultipartResolverTests {

@Test
public void isMultipartWithDefaultSetting() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();

MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request = new MockHttpServletRequest("PUT", "/");
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
assertThat(resolver.isMultipart(request)).isFalse();
}

@Test
public void isMultipartWithSupportedMethods() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setSupportedMethods("POST", "PUT");

MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request = new MockHttpServletRequest("PUT", "/");
assertThat(resolver.isMultipart(request)).isFalse();

request.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_MIXED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();

request.setContentType(MediaType.MULTIPART_RELATED_VALUE);
assertThat(resolver.isMultipart(request)).isTrue();
}

@Test
public void withApplicationContext() throws Exception {
doTestWithApplicationContext(false);
Expand Down

0 comments on commit b2cac38

Please sign in to comment.