Browse Source

ResourceWebHandler signals error for missing resources

Prior to this commit, the `ResourceWebHandler` would itself handle the
response with an HTTP 404 in many cases, including a missing static
resource.

This does not give a chance to `WebExceptionHandler` instances to handle
that error and, for example, display an error page.

See spring-projects/spring-boot#8625

Issue: SPR-16023
pull/1553/head
Brian Clozel 9 years ago
parent
commit
3febec3df6
  1. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java
  2. 31
      spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java

8
spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java

@ -50,6 +50,7 @@ import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.server.MethodNotAllowedException; import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler; import org.springframework.web.server.WebHandler;
@ -86,8 +87,10 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
/** Set of supported HTTP methods */ /** Set of supported HTTP methods */
private static final Set<HttpMethod> SUPPORTED_METHODS = EnumSet.of(HttpMethod.GET, HttpMethod.HEAD); private static final Set<HttpMethod> SUPPORTED_METHODS = EnumSet.of(HttpMethod.GET, HttpMethod.HEAD);
private static final Log logger = LogFactory.getLog(ResourceWebHandler.class); private static final ResponseStatusException NOT_FOUND_EXCEPTION =
new ResponseStatusException(HttpStatus.NOT_FOUND);
private static final Log logger = LogFactory.getLog(ResourceWebHandler.class);
private final List<Resource> locations = new ArrayList<>(4); private final List<Resource> locations = new ArrayList<>(4);
@ -245,8 +248,7 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
return getResource(exchange) return getResource(exchange)
.switchIfEmpty(Mono.defer(() -> { .switchIfEmpty(Mono.defer(() -> {
logger.trace("No matching resource found - returning 404"); logger.trace("No matching resource found - returning 404");
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND); return Mono.error(NOT_FOUND_EXCEPTION);
return Mono.empty();
})) }))
.flatMap(resource -> { .flatMap(resource -> {
try { try {

31
spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java

@ -51,11 +51,14 @@ import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.server.MethodNotAllowedException; import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -273,11 +276,14 @@ public class ResourceWebHandlerTests {
MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build(); MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();
ServerWebExchange exchange = MockServerWebExchange.from(request); ServerWebExchange exchange = MockServerWebExchange.from(request);
setPathWithinHandlerMapping(exchange, requestPath); setPathWithinHandlerMapping(exchange, requestPath);
this.handler.handle(exchange).block(TIMEOUT); StepVerifier.create(this.handler.handle(exchange))
.expectErrorSatisfies(err -> {
assertThat(err, instanceOf(ResponseStatusException.class));
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
}).verify(TIMEOUT);
if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) { if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {
fail(requestPath + " doesn't actually exist as a relative path"); fail(requestPath + " doesn't actually exist as a relative path");
} }
assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());
} }
@Test @Test
@ -363,8 +369,11 @@ public class ResourceWebHandlerTests {
public void directory() throws Exception { public void directory() throws Exception {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build()); MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());
setPathWithinHandlerMapping(exchange, "js/"); setPathWithinHandlerMapping(exchange, "js/");
this.handler.handle(exchange).block(TIMEOUT); StepVerifier.create(this.handler.handle(exchange))
assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode()); .expectErrorSatisfies(err -> {
assertThat(err, instanceOf(ResponseStatusException.class));
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
}).verify(TIMEOUT);
} }
@Test @Test
@ -381,8 +390,11 @@ public class ResourceWebHandlerTests {
public void missingResourcePath() throws Exception { public void missingResourcePath() throws Exception {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build()); MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());
setPathWithinHandlerMapping(exchange, ""); setPathWithinHandlerMapping(exchange, "");
this.handler.handle(exchange).block(TIMEOUT); StepVerifier.create(this.handler.handle(exchange))
assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode()); .expectErrorSatisfies(err -> {
assertThat(err, instanceOf(ResponseStatusException.class));
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
}).verify(TIMEOUT);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
@ -409,8 +421,11 @@ public class ResourceWebHandlerTests {
MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build(); MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();
MockServerWebExchange exchange = MockServerWebExchange.from(request); MockServerWebExchange exchange = MockServerWebExchange.from(request);
setPathWithinHandlerMapping(exchange, "not-there.css"); setPathWithinHandlerMapping(exchange, "not-there.css");
this.handler.handle(exchange).block(TIMEOUT); StepVerifier.create(this.handler.handle(exchange))
assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode()); .expectErrorSatisfies(err -> {
assertThat(err, instanceOf(ResponseStatusException.class));
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) err).getStatus());
}).verify(TIMEOUT);
} }
@Test @Test

Loading…
Cancel
Save