Commit 0162978c authored by Brian Clozel's avatar Brian Clozel

Support server.error.whitelabel.enabled in WebFlux

This commit disables the default HTML view in the WebFlux error handling
support when `server.error.whitelabel.enabled=false`.
In this case, the original exception will be forwarded down the stream
and handled by the default `WebExceptionHandler` provided by Spring
WebFlux (likely to respond a blank page and an error HTTP response
status).

Closes gh-12520
parent 161ecc05
...@@ -121,12 +121,18 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa ...@@ -121,12 +121,18 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
HttpStatus errorStatus = getHttpStatus(error); HttpStatus errorStatus = getHttpStatus(error);
ServerResponse.BodyBuilder response = ServerResponse.status(errorStatus) ServerResponse.BodyBuilder response = ServerResponse.status(errorStatus)
.contentType(MediaType.TEXT_HTML); .contentType(MediaType.TEXT_HTML);
return Flux Flux<ServerResponse> result = Flux
.just("error/" + errorStatus.toString(), .just("error/" + errorStatus.toString(),
"error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error") "error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error")
.flatMap((viewName) -> renderErrorView(viewName, response, error)) .flatMap((viewName) -> renderErrorView(viewName, response, error));
.switchIfEmpty(renderDefaultErrorView(response, error)).next() if (this.errorProperties.getWhitelabel().isEnabled()) {
.doOnNext((resp) -> logError(request, errorStatus)); result = result.switchIfEmpty(renderDefaultErrorView(response, error));
}
else {
Throwable ex = getError(request);
result = result.switchIfEmpty(Mono.error(ex));
}
return result.next().doOnNext((resp) -> logError(request, errorStatus));
} }
/** /**
......
...@@ -74,7 +74,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -74,7 +74,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
public OutputCapture output = new OutputCapture(); public OutputCapture output = new OutputCapture();
@Test @Test
public void jsonError() throws Exception { public void jsonError() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
...@@ -91,12 +91,13 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -91,12 +91,13 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void notFound() throws Exception { public void notFound() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
client.get().uri("/notFound").exchange().expectStatus() client.get().uri("/notFound").exchange()
.isEqualTo(HttpStatus.NOT_FOUND).expectBody().jsonPath("status") .expectStatus().isNotFound()
.expectBody().jsonPath("status")
.isEqualTo("404").jsonPath("error") .isEqualTo("404").jsonPath("error")
.isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase()).jsonPath("path") .isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase()).jsonPath("path")
.isEqualTo(("/notFound")).jsonPath("exception").doesNotExist(); .isEqualTo(("/notFound")).jsonPath("exception").doesNotExist();
...@@ -104,7 +105,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -104,7 +105,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void htmlError() throws Exception { public void htmlError() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
...@@ -119,13 +120,14 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -119,13 +120,14 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void bindingResultError() throws Exception { public void bindingResultError() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
client.post().uri("/bind").contentType(MediaType.APPLICATION_JSON) client.post().uri("/bind").contentType(MediaType.APPLICATION_JSON)
.syncBody("{}").exchange().expectStatus() .syncBody("{}").exchange()
.isEqualTo(HttpStatus.BAD_REQUEST).expectBody().jsonPath("status") .expectStatus().isBadRequest()
.expectBody().jsonPath("status")
.isEqualTo("400").jsonPath("error") .isEqualTo("400").jsonPath("error")
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("path") .isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("path")
.isEqualTo(("/bind")).jsonPath("exception").doesNotExist() .isEqualTo(("/bind")).jsonPath("exception").doesNotExist()
...@@ -137,7 +139,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -137,7 +139,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void includeStackTraceOnParam() throws Exception { public void includeStackTraceOnParam() {
this.contextRunner this.contextRunner
.withPropertyValues("server.error.include-exception=true", .withPropertyValues("server.error.include-exception=true",
"server.error.include-stacktrace=on-trace-param") "server.error.include-stacktrace=on-trace-param")
...@@ -171,7 +173,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -171,7 +173,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void neverIncludeStackTrace() throws Exception { public void neverIncludeStackTrace() {
this.contextRunner.withPropertyValues("server.error.include-exception=true", this.contextRunner.withPropertyValues("server.error.include-exception=true",
"server.error.include-stacktrace=never").run((context) -> { "server.error.include-stacktrace=never").run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
...@@ -188,14 +190,15 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -188,14 +190,15 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void statusException() throws Exception { public void statusException() {
this.contextRunner.withPropertyValues("server.error.include-exception=true") this.contextRunner.withPropertyValues("server.error.include-exception=true")
.run((context) -> { .run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
client.get().uri("/badRequest").exchange().expectStatus() client.get().uri("/badRequest").exchange()
.isEqualTo(HttpStatus.BAD_REQUEST).expectBody() .expectStatus().isBadRequest()
.jsonPath("status").isEqualTo("400").jsonPath("error") .expectBody().jsonPath("status").isEqualTo("400")
.jsonPath("error")
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()) .isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())
.jsonPath("exception") .jsonPath("exception")
.isEqualTo(ResponseStatusException.class.getName()); .isEqualTo(ResponseStatusException.class.getName());
...@@ -204,7 +207,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -204,7 +207,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void defaultErrorView() throws Exception { public void defaultErrorView() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/") .withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
.run((context) -> { .run((context) -> {
...@@ -224,7 +227,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -224,7 +227,7 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void escapeHtmlInDefaultErrorView() throws Exception { public void escapeHtmlInDefaultErrorView() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/") .withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
.run((context) -> { .run((context) -> {
...@@ -244,24 +247,24 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -244,24 +247,24 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
} }
@Test @Test
public void testExceptionWithNullMessage() throws Exception { public void testExceptionWithNullMessage() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/") .withPropertyValues("spring.mustache.prefix=classpath:/unknown/")
.run((context) -> { .run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
String body = client.get().uri("/notfound") String body = client.get().uri("/notfound")
.accept(MediaType.TEXT_HTML).exchange().expectStatus() .accept(MediaType.TEXT_HTML).exchange()
.isEqualTo(HttpStatus.NOT_FOUND).expectHeader() .expectStatus().isNotFound()
.contentType(MediaType.TEXT_HTML).expectBody(String.class) .expectHeader().contentType(MediaType.TEXT_HTML)
.returnResult().getResponseBody(); .expectBody(String.class).returnResult().getResponseBody();
assertThat(body).contains("Whitelabel Error Page") assertThat(body).contains("Whitelabel Error Page")
.contains("type=Not Found, status=404"); .contains("type=Not Found, status=404");
}); });
} }
@Test @Test
public void responseCommitted() throws Exception { public void responseCommitted() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context) WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build(); .build();
...@@ -271,6 +274,21 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { ...@@ -271,6 +274,21 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests {
}); });
} }
@Test
public void whilelabelDisabled() {
this.contextRunner
.withPropertyValues("server.error.whitelabel.enabled=false",
"spring.mustache.prefix=classpath:/unknown/")
.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context)
.build();
client.get().uri("/notfound")
.accept(MediaType.TEXT_HTML).exchange()
.expectStatus().isNotFound()
.expectBody().isEmpty();
});
}
@Configuration @Configuration
public static class Application { public static class Application {
......
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