Always specify charset for form data requests
Issue: SPR-16613
This commit is contained in:
parent
e00384a6fd
commit
5861e9685b
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -61,12 +61,15 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St
|
||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
private static final ResolvableType MULTIVALUE_TYPE =
|
private static final MediaType DEFAULT_FORM_DATA_MEDIA_TYPE =
|
||||||
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class);
|
new MediaType(MediaType.APPLICATION_FORM_URLENCODED, DEFAULT_CHARSET);
|
||||||
|
|
||||||
private static final List<MediaType> MEDIA_TYPES =
|
private static final List<MediaType> MEDIA_TYPES =
|
||||||
Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED);
|
Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
|
||||||
|
private static final ResolvableType MULTIVALUE_TYPE =
|
||||||
|
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class);
|
||||||
|
|
||||||
|
|
||||||
private Charset defaultCharset = DEFAULT_CHARSET;
|
private Charset defaultCharset = DEFAULT_CHARSET;
|
||||||
|
|
||||||
|
@ -117,13 +120,16 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St
|
||||||
ResolvableType elementType, @Nullable MediaType mediaType, ReactiveHttpOutputMessage message,
|
ResolvableType elementType, @Nullable MediaType mediaType, ReactiveHttpOutputMessage message,
|
||||||
Map<String, Object> hints) {
|
Map<String, Object> hints) {
|
||||||
|
|
||||||
MediaType contentType = message.getHeaders().getContentType();
|
mediaType = (mediaType != null ? mediaType : DEFAULT_FORM_DATA_MEDIA_TYPE);
|
||||||
if (contentType == null) {
|
Charset charset;
|
||||||
contentType = MediaType.APPLICATION_FORM_URLENCODED;
|
if (mediaType.getCharset() == null) {
|
||||||
message.getHeaders().setContentType(contentType);
|
charset = getDefaultCharset();
|
||||||
|
mediaType = new MediaType(mediaType, charset);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
Charset charset = getMediaTypeCharset(contentType);
|
charset = mediaType.getCharset();
|
||||||
|
}
|
||||||
|
message.getHeaders().setContentType(mediaType);
|
||||||
|
|
||||||
return Mono.from(inputStream).flatMap(form -> {
|
return Mono.from(inputStream).flatMap(form -> {
|
||||||
String value = serializeForm(form, charset);
|
String value = serializeForm(form, charset);
|
||||||
|
|
|
@ -96,6 +96,9 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
private static final MediaType DEFAULT_FORM_DATA_MEDIA_TYPE =
|
||||||
|
new MediaType(MediaType.APPLICATION_FORM_URLENCODED, DEFAULT_CHARSET);
|
||||||
|
|
||||||
|
|
||||||
private List<MediaType> supportedMediaTypes = new ArrayList<>();
|
private List<MediaType> supportedMediaTypes = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -290,15 +293,14 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
private void writeForm(MultiValueMap<String, String> form, @Nullable MediaType contentType,
|
private void writeForm(MultiValueMap<String, String> form, @Nullable MediaType contentType,
|
||||||
HttpOutputMessage outputMessage) throws IOException {
|
HttpOutputMessage outputMessage) throws IOException {
|
||||||
|
|
||||||
Charset charset;
|
contentType = (contentType != null ? contentType : DEFAULT_FORM_DATA_MEDIA_TYPE);
|
||||||
if (contentType != null) {
|
Charset charset = contentType.getCharset();
|
||||||
outputMessage.getHeaders().setContentType(contentType);
|
if (charset == null) {
|
||||||
charset = (contentType.getCharset() != null ? contentType.getCharset() : this.charset);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
outputMessage.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
||||||
charset = this.charset;
|
charset = this.charset;
|
||||||
|
contentType = new MediaType(contentType, charset);
|
||||||
}
|
}
|
||||||
|
outputMessage.getHeaders().setContentType(contentType);
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (Iterator<String> nameIterator = form.keySet().iterator(); nameIterator.hasNext();) {
|
for (Iterator<String> nameIterator = form.keySet().iterator(); nameIterator.hasNext();) {
|
||||||
String name = nameIterator.next();
|
String name = nameIterator.next();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -22,6 +22,7 @@ import org.junit.Test;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
|
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
@ -79,8 +80,9 @@ public class FormHttpMessageWriterTests {
|
||||||
|
|
||||||
String responseBody = response.getBodyAsString().block();
|
String responseBody = response.getBodyAsString().block();
|
||||||
assertEquals("name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3", responseBody);
|
assertEquals("name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3", responseBody);
|
||||||
assertEquals(MediaType.APPLICATION_FORM_URLENCODED, response.getHeaders().getContentType());
|
HttpHeaders headers = response.getHeaders();
|
||||||
assertEquals(responseBody.getBytes().length, response.getHeaders().getContentLength());
|
assertEquals("application/x-www-form-urlencoded;charset=UTF-8", headers.getContentType().toString());
|
||||||
|
assertEquals(responseBody.getBytes().length, headers.getContentLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -112,8 +112,8 @@ public class FormHttpMessageConverterTests {
|
||||||
|
|
||||||
assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
|
assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
|
||||||
outputMessage.getBodyAsString(StandardCharsets.UTF_8));
|
outputMessage.getBodyAsString(StandardCharsets.UTF_8));
|
||||||
assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),
|
assertEquals("Invalid content-type", "application/x-www-form-urlencoded;charset=UTF-8",
|
||||||
outputMessage.getHeaders().getContentType());
|
outputMessage.getHeaders().getContentType().toString());
|
||||||
assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
|
assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
|
||||||
outputMessage.getHeaders().getContentLength());
|
outputMessage.getHeaders().getContentLength());
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class AbstractMockWebServerTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MockResponse formRequest(RecordedRequest request) {
|
private MockResponse formRequest(RecordedRequest request) {
|
||||||
assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type"));
|
assertEquals("application/x-www-form-urlencoded;charset=UTF-8", request.getHeader("Content-Type"));
|
||||||
String body = request.getBody().readUtf8();
|
String body = request.getBody().readUtf8();
|
||||||
assertThat(body, Matchers.containsString("name+1=value+1"));
|
assertThat(body, Matchers.containsString("name+1=value+1"));
|
||||||
assertThat(body, Matchers.containsString("name+2=value+2%2B1"));
|
assertThat(body, Matchers.containsString("name+2=value+2%2B1"));
|
||||||
|
|
Loading…
Reference in New Issue