Commit d46de7ab authored by Brian Clozel's avatar Brian Clozel

Polish "Set UTF-8 charset for whitelabel HTML error pages"

Closes gh-16611
parent 64a83269
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.web.reactive.error; package org.springframework.boot.autoconfigure.web.reactive.error;
import java.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
...@@ -73,6 +74,9 @@ import static org.springframework.web.reactive.function.server.RouterFunctions.r ...@@ -73,6 +74,9 @@ import static org.springframework.web.reactive.function.server.RouterFunctions.r
*/ */
public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html",
StandardCharsets.UTF_8);
private static final Map<HttpStatus.Series, String> SERIES_VIEWS; private static final Map<HttpStatus.Series, String> SERIES_VIEWS;
static { static {
...@@ -105,8 +109,6 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa ...@@ -105,8 +109,6 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
this::renderErrorResponse); this::renderErrorResponse);
} }
private static final MediaType HTML_CONTENT_TYPE = MediaType.valueOf(MediaType.TEXT_HTML_VALUE+";charset=UTF-8");
/** /**
* Render the error information as an HTML view. * Render the error information as an HTML view.
* @param request the current request * @param request the current request
...@@ -117,7 +119,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa ...@@ -117,7 +119,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
Map<String, Object> error = getErrorAttributes(request, includeStackTrace); Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
HttpStatus errorStatus = getHttpStatus(error); HttpStatus errorStatus = getHttpStatus(error);
ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus) ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus)
.contentType(HTML_CONTENT_TYPE); .contentType(TEXT_HTML_UTF8);
return Flux return Flux
.just("error/" + errorStatus.value(), .just("error/" + errorStatus.value(),
"error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error") "error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error")
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.web.servlet.error; package org.springframework.boot.autoconfigure.web.servlet.error;
import java.nio.charset.StandardCharsets;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -66,6 +67,7 @@ import org.springframework.context.annotation.Conditional; ...@@ -66,6 +67,7 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View; import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.BeanNameViewResolver; import org.springframework.web.servlet.view.BeanNameViewResolver;
...@@ -202,6 +204,9 @@ public class ErrorMvcAutoConfiguration { ...@@ -202,6 +204,9 @@ public class ErrorMvcAutoConfiguration {
*/ */
private static class StaticView implements View { private static class StaticView implements View {
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html",
StandardCharsets.UTF_8);
private static final Log logger = LogFactory.getLog(StaticView.class); private static final Log logger = LogFactory.getLog(StaticView.class);
@Override @Override
...@@ -212,6 +217,7 @@ public class ErrorMvcAutoConfiguration { ...@@ -212,6 +217,7 @@ public class ErrorMvcAutoConfiguration {
logger.error(message); logger.error(message);
return; return;
} }
response.setContentType(TEXT_HTML_UTF8.toString());
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
Date timestamp = (Date) model.get("timestamp"); Date timestamp = (Date) model.get("timestamp");
Object message = model.get("message"); Object message = model.get("message");
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.web.reactive.error; package org.springframework.boot.autoconfigure.web.reactive.error;
import java.nio.charset.StandardCharsets;
import javax.validation.Valid; import javax.validation.Valid;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
...@@ -55,6 +57,9 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ...@@ -55,6 +57,9 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/ */
public class DefaultErrorWebExceptionHandlerIntegrationTests { public class DefaultErrorWebExceptionHandlerIntegrationTests {
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html",
StandardCharsets.UTF_8);
private final LogIdFilter logIdFilter = new LogIdFilter(); private final LogIdFilter logIdFilter = new LogIdFilter();
@RegisterExtension @RegisterExtension
...@@ -106,8 +111,8 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -106,8 +111,8 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
WebTestClient client = getWebClient(context); WebTestClient client = getWebClient(context);
String body = client.get().uri("/").accept(MediaType.TEXT_HTML).exchange() String body = client.get().uri("/").accept(MediaType.TEXT_HTML).exchange()
.expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR) .expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
.expectHeader().contentType(MediaType.TEXT_HTML) .expectHeader().contentType(TEXT_HTML_UTF8).expectBody(String.class)
.expectBody(String.class).returnResult().getResponseBody(); .returnResult().getResponseBody();
assertThat(body).contains("status: 500").contains("message: Expected!"); assertThat(body).contains("status: 500").contains("message: Expected!");
}); });
} }
...@@ -201,7 +206,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -201,7 +206,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
String body = client.get().uri("/").accept(MediaType.TEXT_HTML) String body = client.get().uri("/").accept(MediaType.TEXT_HTML)
.exchange().expectStatus() .exchange().expectStatus()
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader() .isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader()
.contentType(MediaType.TEXT_HTML).expectBody(String.class) .contentType(TEXT_HTML_UTF8).expectBody(String.class)
.returnResult().getResponseBody(); .returnResult().getResponseBody();
assertThat(body).contains("Whitelabel Error Page") assertThat(body).contains("Whitelabel Error Page")
.contains(this.logIdFilter.getLogId()) .contains(this.logIdFilter.getLogId())
...@@ -219,7 +224,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -219,7 +224,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
String body = client.get().uri("/html").accept(MediaType.TEXT_HTML) String body = client.get().uri("/html").accept(MediaType.TEXT_HTML)
.exchange().expectStatus() .exchange().expectStatus()
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader() .isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader()
.contentType(MediaType.TEXT_HTML).expectBody(String.class) .contentType(TEXT_HTML_UTF8).expectBody(String.class)
.returnResult().getResponseBody(); .returnResult().getResponseBody();
assertThat(body).contains("Whitelabel Error Page") assertThat(body).contains("Whitelabel Error Page")
.contains(this.logIdFilter.getLogId()) .contains(this.logIdFilter.getLogId())
...@@ -235,7 +240,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -235,7 +240,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
WebTestClient client = getWebClient(context); WebTestClient client = getWebClient(context);
String body = client.get().uri("/notfound") String body = client.get().uri("/notfound")
.accept(MediaType.TEXT_HTML).exchange().expectStatus() .accept(MediaType.TEXT_HTML).exchange().expectStatus()
.isNotFound().expectHeader().contentType(MediaType.TEXT_HTML) .isNotFound().expectHeader().contentType(TEXT_HTML_UTF8)
.expectBody(String.class).returnResult().getResponseBody(); .expectBody(String.class).returnResult().getResponseBody();
assertThat(body).contains("Whitelabel Error Page") assertThat(body).contains("Whitelabel Error Page")
.contains(this.logIdFilter.getLogId()) .contains(this.logIdFilter.getLogId())
......
...@@ -56,6 +56,8 @@ public class ErrorMvcAutoConfigurationTests { ...@@ -56,6 +56,8 @@ public class ErrorMvcAutoConfigurationTests {
new IllegalStateException("Exception message"), false); new IllegalStateException("Exception message"), false);
errorView.render(errorAttributes.getErrorAttributes(webRequest, true), errorView.render(errorAttributes.getErrorAttributes(webRequest, true),
webRequest.getRequest(), webRequest.getResponse()); webRequest.getRequest(), webRequest.getResponse());
assertThat(webRequest.getResponse().getContentType())
.isEqualTo("text/html;charset=UTF-8");
String responseString = ((MockHttpServletResponse) webRequest.getResponse()) String responseString = ((MockHttpServletResponse) webRequest.getResponse())
.getContentAsString(); .getContentAsString();
assertThat(responseString).contains( assertThat(responseString).contains(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment