mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Add property to control 'path' field inclusion in error responses
By default it is included. Closes gh-38619
This commit is contained in:
parent
c4be302fdb
commit
2cce123bb5
@ -36,6 +36,7 @@ import org.springframework.web.context.request.ServletWebRequest;
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Controller
|
||||
@ -72,6 +73,7 @@ public class ManagementErrorEndpoint {
|
||||
if (includeBindingErrors(request)) {
|
||||
options = options.including(Include.BINDING_ERRORS);
|
||||
}
|
||||
options = includePath(request) ? options.including(Include.PATH) : options.excluding(Include.PATH);
|
||||
return options;
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ public class ManagementErrorEndpoint {
|
||||
return switch (this.errorProperties.getIncludeStacktrace()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getBooleanParameter(request, "trace");
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -87,7 +89,7 @@ public class ManagementErrorEndpoint {
|
||||
return switch (this.errorProperties.getIncludeMessage()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getBooleanParameter(request, "message");
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -95,7 +97,15 @@ public class ManagementErrorEndpoint {
|
||||
return switch (this.errorProperties.getIncludeBindingErrors()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getBooleanParameter(request, "errors");
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean includePath(ServletWebRequest request) {
|
||||
return switch (this.errorProperties.getIncludePath()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getBooleanParameter(request, "path");
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,11 @@ public class ErrorProperties {
|
||||
*/
|
||||
private IncludeAttribute includeBindingErrors = IncludeAttribute.NEVER;
|
||||
|
||||
/**
|
||||
* When to include "path" attribute.
|
||||
*/
|
||||
private IncludeAttribute includePath = IncludeAttribute.ALWAYS;
|
||||
|
||||
private final Whitelabel whitelabel = new Whitelabel();
|
||||
|
||||
public String getPath() {
|
||||
@ -97,6 +102,14 @@ public class ErrorProperties {
|
||||
this.includeBindingErrors = includeBindingErrors;
|
||||
}
|
||||
|
||||
public IncludeAttribute getIncludePath() {
|
||||
return this.includePath;
|
||||
}
|
||||
|
||||
public void setIncludePath(IncludeAttribute includePath) {
|
||||
this.includePath = includePath;
|
||||
}
|
||||
|
||||
public Whitelabel getWhitelabel() {
|
||||
return this.whitelabel;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ import org.springframework.web.util.HtmlUtils;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.0.0
|
||||
* @see ErrorAttributes
|
||||
*/
|
||||
@ -168,6 +169,17 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
||||
return getBooleanParameter(request, "errors");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the path attribute has been set on the given request.
|
||||
* @param request the source request
|
||||
* @return {@code true} if the path attribute has been requested, {@code false}
|
||||
* otherwise
|
||||
* @since 3.3.0
|
||||
*/
|
||||
protected boolean isPathEnabled(ServerRequest request) {
|
||||
return getBooleanParameter(request, "path");
|
||||
}
|
||||
|
||||
private boolean getBooleanParameter(ServerRequest request, String parameterName) {
|
||||
String parameter = request.queryParam(parameterName).orElse("false");
|
||||
return !"false".equalsIgnoreCase(parameter);
|
||||
|
@ -75,6 +75,7 @@ import static org.springframework.web.reactive.function.server.RouterFunctions.r
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
|
||||
@ -164,6 +165,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
if (isIncludeBindingErrors(request, mediaType)) {
|
||||
options = options.including(Include.BINDING_ERRORS);
|
||||
}
|
||||
options = isIncludePath(request, mediaType) ? options.including(Include.PATH) : options.excluding(Include.PATH);
|
||||
return options;
|
||||
}
|
||||
|
||||
@ -177,7 +179,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
return switch (this.errorProperties.getIncludeStacktrace()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> isTraceEnabled(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -191,7 +193,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
return switch (this.errorProperties.getIncludeMessage()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> isMessageEnabled(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -205,7 +207,22 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
||||
return switch (this.errorProperties.getIncludeBindingErrors()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> isBindingErrorsEnabled(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the path attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the path attribute should be included
|
||||
* @since 3.3.0
|
||||
*/
|
||||
protected boolean isIncludePath(ServerRequest request, MediaType produces) {
|
||||
return switch (this.errorProperties.getIncludePath()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> isPathEnabled(request);
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 1.3.0
|
||||
* @see ErrorAttributes
|
||||
*/
|
||||
@ -74,18 +75,43 @@ public abstract class AbstractErrorController implements ErrorController {
|
||||
return this.errorAttributes.getErrorAttributes(webRequest, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the trace parameter is set.
|
||||
* @param request the request
|
||||
* @return whether the trace parameter is set
|
||||
*/
|
||||
protected boolean getTraceParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "trace");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the message parameter is set.
|
||||
* @param request the request
|
||||
* @return whether the message parameter is set
|
||||
*/
|
||||
protected boolean getMessageParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the errors parameter is set.
|
||||
* @param request the request
|
||||
* @return whether the errors parameter is set
|
||||
*/
|
||||
protected boolean getErrorsParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "errors");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the path parameter is set.
|
||||
* @param request the request
|
||||
* @return whether the path parameter is set
|
||||
* @since 3.3.0
|
||||
*/
|
||||
protected boolean getPathParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "path");
|
||||
}
|
||||
|
||||
protected boolean getBooleanParameter(HttpServletRequest request, String parameterName) {
|
||||
String parameter = request.getParameter(parameterName);
|
||||
if (parameter == null) {
|
||||
|
@ -49,6 +49,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
* @author Michael Stummvoll
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 1.0.0
|
||||
* @see ErrorAttributes
|
||||
* @see ErrorProperties
|
||||
@ -121,6 +122,7 @@ public class BasicErrorController extends AbstractErrorController {
|
||||
if (isIncludeBindingErrors(request, mediaType)) {
|
||||
options = options.including(Include.BINDING_ERRORS);
|
||||
}
|
||||
options = isIncludePath(request, mediaType) ? options.including(Include.PATH) : options.excluding(Include.PATH);
|
||||
return options;
|
||||
}
|
||||
|
||||
@ -134,7 +136,7 @@ public class BasicErrorController extends AbstractErrorController {
|
||||
return switch (getErrorProperties().getIncludeStacktrace()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getTraceParameter(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -148,7 +150,7 @@ public class BasicErrorController extends AbstractErrorController {
|
||||
return switch (getErrorProperties().getIncludeMessage()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getMessageParameter(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -162,7 +164,22 @@ public class BasicErrorController extends AbstractErrorController {
|
||||
return switch (getErrorProperties().getIncludeBindingErrors()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getErrorsParameter(request);
|
||||
default -> false;
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the path attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the path attribute should be included
|
||||
* @since 3.3.0
|
||||
*/
|
||||
protected boolean isIncludePath(HttpServletRequest request, MediaType produces) {
|
||||
return switch (getErrorProperties().getIncludePath()) {
|
||||
case ALWAYS -> true;
|
||||
case ON_PARAM -> getPathParameter(request);
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,7 @@ class ErrorMvcAutoConfigurationTests {
|
||||
}
|
||||
|
||||
private ErrorAttributeOptions withAllOptions() {
|
||||
return ErrorAttributeOptions.of(Include.EXCEPTION, Include.STACK_TRACE, Include.MESSAGE,
|
||||
Include.BINDING_ERRORS);
|
||||
return ErrorAttributeOptions.of(Include.values());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public final class ErrorAttributeOptions {
|
||||
* @return an {@code ErrorAttributeOptions}
|
||||
*/
|
||||
public static ErrorAttributeOptions defaults() {
|
||||
return of();
|
||||
return of(Include.PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +135,13 @@ public final class ErrorAttributeOptions {
|
||||
/**
|
||||
* Include the binding errors attribute.
|
||||
*/
|
||||
BINDING_ERRORS
|
||||
BINDING_ERRORS,
|
||||
|
||||
/**
|
||||
* Include the request path.
|
||||
* @since 3.3.0
|
||||
*/
|
||||
PATH
|
||||
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @author Stephane Nicoll
|
||||
* @author Michele Mancioppi
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.0.0
|
||||
* @see ErrorAttributes
|
||||
*/
|
||||
@ -79,6 +80,9 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
||||
if (!options.isIncluded(Include.BINDING_ERRORS)) {
|
||||
errorAttributes.remove("errors");
|
||||
}
|
||||
if (!options.isIncluded(Include.PATH)) {
|
||||
errorAttributes.remove("path");
|
||||
}
|
||||
return errorAttributes;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
* @since 2.0.0
|
||||
* @see ErrorAttributes
|
||||
*/
|
||||
@ -100,6 +101,9 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
if (!options.isIncluded(Include.BINDING_ERRORS)) {
|
||||
errorAttributes.remove("errors");
|
||||
}
|
||||
if (!options.isIncluded(Include.PATH)) {
|
||||
errorAttributes.remove("path");
|
||||
}
|
||||
return errorAttributes;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -50,6 +50,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class DefaultErrorAttributesTests {
|
||||
|
||||
@ -212,6 +213,14 @@ class DefaultErrorAttributesTests {
|
||||
assertThat(attributes.get("trace").toString()).startsWith("java.lang");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includePathByDefault() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, NOT_FOUND),
|
||||
ErrorAttributeOptions.defaults());
|
||||
assertThat(attributes).containsEntry("path", "/test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includePath() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
@ -220,6 +229,14 @@ class DefaultErrorAttributesTests {
|
||||
assertThat(attributes).containsEntry("path", "/test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void excludePath() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, NOT_FOUND),
|
||||
ErrorAttributeOptions.of());
|
||||
assertThat(attributes).doesNotContainEntry("path", "/test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includeLogPrefix() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
|
@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Phillip Webb
|
||||
* @author Vedran Pavic
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class DefaultErrorAttributesTests {
|
||||
|
||||
@ -249,13 +250,29 @@ class DefaultErrorAttributesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void path() {
|
||||
void shouldIncludePathByDefault() {
|
||||
this.request.setAttribute("jakarta.servlet.error.request_uri", "path");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,
|
||||
ErrorAttributeOptions.defaults());
|
||||
assertThat(attributes).containsEntry("path", "path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIncludePath() {
|
||||
this.request.setAttribute("jakarta.servlet.error.request_uri", "path");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,
|
||||
ErrorAttributeOptions.of(Include.PATH));
|
||||
assertThat(attributes).containsEntry("path", "path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExcludePath() {
|
||||
this.request.setAttribute("jakarta.servlet.error.request_uri", "path");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,
|
||||
ErrorAttributeOptions.of());
|
||||
assertThat(attributes).doesNotContainEntry("path", "path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenGetMessageIsOverriddenThenMessageAttributeContainsValueReturnedFromIt() {
|
||||
Map<String, Object> attributes = new DefaultErrorAttributes() {
|
||||
|
Loading…
Reference in New Issue
Block a user