@ -19,9 +19,9 @@ package org.springframework.web.servlet.mvc.method.annotation;
@@ -19,9 +19,9 @@ package org.springframework.web.servlet.mvc.method.annotation;
import java.net.URI ;
import java.nio.charset.Charset ;
import java.util.ArrayList ;
import java.util.Array s ;
import java.util.Collection s ;
import java.util.List ;
import java.util.Map ;
import javax.servlet.MultipartConfigElement ;
import org.eclipse.jetty.server.Connector ;
@ -29,7 +29,6 @@ import org.eclipse.jetty.server.NetworkConnector;
@@ -29,7 +29,6 @@ import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server ;
import org.eclipse.jetty.servlet.ServletContextHandler ;
import org.eclipse.jetty.servlet.ServletHolder ;
import org.junit.AfterClass ;
import org.junit.Assert ;
import org.junit.Before ;
@ -43,6 +42,7 @@ import org.springframework.http.HttpEntity;
@@ -43,6 +42,7 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.MediaType ;
import org.springframework.http.RequestEntity ;
import org.springframework.http.ResponseEntity ;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory ;
import org.springframework.http.converter.ByteArrayHttpMessageConverter ;
@ -52,9 +52,9 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
@@ -52,9 +52,9 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter ;
import org.springframework.stereotype.Controller ;
import org.springframework.util.LinkedMultiValueMap ;
import org.springframework.util.MimeTypeUtils ;
import org.springframework.util.MultiValueMap ;
import org.springframework.web.bind.annotation.RequestMapping ;
import org.springframework.web.bind.annotation.RequestMethod ;
import org.springframework.web.bind.annotation.RequestPart ;
import org.springframework.web.client.RestTemplate ;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext ;
@ -66,7 +66,8 @@ import org.springframework.web.servlet.DispatcherServlet;
@@ -66,7 +66,8 @@ import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc ;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter ;
import static org.junit.Assert.* ;
import static org.junit.Assert.assertEquals ;
import static org.springframework.web.bind.annotation.RequestMethod.POST ;
/ * *
* Test access to parts of a multipart request with { @link RequestPart } .
@ -117,7 +118,7 @@ public class RequestPartIntegrationTests {
@@ -117,7 +118,7 @@ public class RequestPartIntegrationTests {
@Before
public void setUp ( ) {
ByteArrayHttpMessageConverter emptyBodyConverter = new ByteArrayHttpMessageConverter ( ) ;
emptyBodyConverter . setSupportedMediaTypes ( Arrays . as List( MediaType . APPLICATION_JSON ) ) ;
emptyBodyConverter . setSupportedMediaTypes ( Collections . singleton List( MediaType . APPLICATION_JSON ) ) ;
List < HttpMessageConverter < ? > > converters = new ArrayList < > ( 3 ) ;
converters . add ( emptyBodyConverter ) ;
@ -129,7 +130,7 @@ public class RequestPartIntegrationTests {
@@ -129,7 +130,7 @@ public class RequestPartIntegrationTests {
converter . setPartConverters ( converters ) ;
restTemplate = new RestTemplate ( new HttpComponentsClientHttpRequestFactory ( ) ) ;
restTemplate . setMessageConverters ( Arrays . < HttpMessageConverter < ? > > as List( converter ) ) ;
restTemplate . setMessageConverters ( Collections . singleton List( converter ) ) ;
}
@AfterClass
@ -150,6 +151,37 @@ public class RequestPartIntegrationTests {
@@ -150,6 +151,37 @@ public class RequestPartIntegrationTests {
testCreate ( baseUrl + "/standard-resolver/test" ) ;
}
// SPR-13319
@Test
public void standardMultipartResolverWithEncodedFileName ( ) throws Exception {
byte [ ] boundary = MimeTypeUtils . generateMultipartBoundary ( ) ;
String boundaryText = new String ( boundary , "US-ASCII" ) ;
Map < String , String > params = Collections . singletonMap ( "boundary" , boundaryText ) ;
String content =
"--" + boundaryText + "\n" +
"Content-Disposition: form-data; name=\"file\"; filename*=\"utf-8''%C3%A9l%C3%A8ve.txt\"\n" +
"Content-Type: text/plain\n" +
"Content-Length: 7\n" +
"\n" +
"content\n" +
"--" + boundaryText + "--" ;
RequestEntity < byte [ ] > requestEntity =
RequestEntity . post ( new URI ( baseUrl + "/standard-resolver/spr13319" ) )
. contentType ( new MediaType ( MediaType . MULTIPART_FORM_DATA , params ) )
. body ( content . getBytes ( Charset . forName ( "us-ascii" ) ) ) ;
ByteArrayHttpMessageConverter converter = new ByteArrayHttpMessageConverter ( ) ;
converter . setSupportedMediaTypes ( Collections . singletonList ( MediaType . MULTIPART_FORM_DATA ) ) ;
this . restTemplate . setMessageConverters ( Collections . singletonList ( converter ) ) ;
ResponseEntity < Void > responseEntity = restTemplate . exchange ( requestEntity , Void . class ) ;
assertEquals ( HttpStatus . OK , responseEntity . getStatusCode ( ) ) ;
}
private void testCreate ( String url ) {
MultiValueMap < String , Object > parts = new LinkedMultiValueMap < String , Object > ( ) ;
parts . add ( "json-data" , new HttpEntity < TestData > ( new TestData ( "Jason" ) ) ) ;
@ -176,6 +208,7 @@ public class RequestPartIntegrationTests {
@@ -176,6 +208,7 @@ public class RequestPartIntegrationTests {
}
@Configuration
@SuppressWarnings ( "unused" )
static class CommonsMultipartResolverTestConfig extends RequestPartTestConfig {
@Bean
@ -185,6 +218,7 @@ public class RequestPartIntegrationTests {
@@ -185,6 +218,7 @@ public class RequestPartIntegrationTests {
}
@Configuration
@SuppressWarnings ( "unused" )
static class StandardMultipartResolverTestConfig extends RequestPartTestConfig {
@Bean
@ -194,9 +228,10 @@ public class RequestPartIntegrationTests {
@@ -194,9 +228,10 @@ public class RequestPartIntegrationTests {
}
@Controller
@SuppressWarnings ( "unused" )
private static class RequestPartTestController {
@RequestMapping ( value = "/test" , method = RequestMethod . POST , consumes = { "multipart/mixed" , "multipart/form-data" } )
@RequestMapping ( value = "/test" , method = POST , consumes = { "multipart/mixed" , "multipart/form-data" } )
public ResponseEntity < Object > create ( @RequestPart ( name = "json-data" ) TestData testData ,
@RequestPart ( "file-data" ) MultipartFile file ,
@RequestPart ( name = "empty-data" , required = false ) TestData emptyData ,
@ -209,6 +244,12 @@ public class RequestPartIntegrationTests {
@@ -209,6 +244,12 @@ public class RequestPartIntegrationTests {
headers . setLocation ( URI . create ( url ) ) ;
return new ResponseEntity < Object > ( headers , HttpStatus . CREATED ) ;
}
@RequestMapping ( value = "/spr13319" , method = POST , consumes = "multipart/form-data" )
public ResponseEntity < Void > create ( @RequestPart ( "file" ) MultipartFile multipartFile ) {
assertEquals ( "%C3%A9l%C3%A8ve.txt" , multipartFile . getOriginalFilename ( ) ) ;
return ResponseEntity . ok ( ) . build ( ) ;
}
}
@SuppressWarnings ( "unused" )