From 390bb871d85f56aaeed98aeb45d688fcf35af8e7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 20 Jul 2018 18:11:05 +0200 Subject: [PATCH] Switch order of multipart Content-Type directives Since SPR-15205, the `FormHttpMessageConverter` is adding a `charset` directive to the `Content-Type` request header in order to help servers understand which charset is being used to encode headers of each part. As reported in SPR-17030 and others, some servers are not parsing properly such header values and assume that `boundary` is the last directive in the `Content-Type` header. This commit reorders the charset information right before the boundary declaration to get around those issues. Issue: SPR-17030 --- .../http/converter/FormHttpMessageConverter.java | 6 +++--- .../http/converter/FormHttpMessageConverterTests.java | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java index 1570b934d01..eb4909015ff 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java @@ -25,7 +25,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.mail.internet.MimeUtility; @@ -351,11 +351,11 @@ public class FormHttpMessageConverter implements HttpMessageConverter parameters = new HashMap<>(2); - parameters.put("boundary", new String(boundary, "US-ASCII")); + Map parameters = new LinkedHashMap<>(2); if (!isFilenameCharsetSet()) { parameters.put("charset", this.charset.name()); } + parameters.put("boundary", new String(boundary, "US-ASCII")); MediaType contentType = new MediaType(MediaType.MULTIPART_FORM_DATA, parameters); HttpHeaders headers = outputMessage.getHeaders(); diff --git a/spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java index 5142eac379e..ceaf639cb5c 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java @@ -30,6 +30,8 @@ import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.RequestContext; import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; import org.junit.Test; import org.springframework.core.io.ClassPathResource; @@ -148,7 +150,8 @@ public class FormHttpMessageConverterTests { this.converter.write(parts, new MediaType("multipart", "form-data", StandardCharsets.UTF_8), outputMessage); final MediaType contentType = outputMessage.getHeaders().getContentType(); - assertNotNull("No boundary found", contentType.getParameter("boundary")); + // SPR-17030 + assertThat(contentType.getParameters().keySet(), Matchers.contains("charset", "boundary")); // see if Commons FileUpload can read what we wrote FileItemFactory fileItemFactory = new DiskFileItemFactory();