diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java index 46e9d032..60018148 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java @@ -16,6 +16,7 @@ package org.springframework.cloud.gateway.server.mvc.handler; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -69,9 +70,15 @@ public class RestClientProxyExchange extends AbstractProxyExchange { } private ServerResponse doExchange(Request request, ClientHttpResponse clientResponse) throws IOException { - InputStream body = clientResponse.getBody(); - // put the body input stream in a request attribute so filters can read it. - MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, body); + try { + InputStream body = clientResponse.getBody(); + // put the body input stream in a request attribute so filters can read it. + MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, body); + } + catch (FileNotFoundException e) { + // if using SimpleClientHttpRequestFactory + return ServerResponse.notFound().build(); + } ServerResponse serverResponse = GatewayServerResponse.status(clientResponse.getStatusCode()) .build((req, httpServletResponse) -> { try (clientResponse) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index d9a7dc7b..6ceffe35 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -275,12 +275,12 @@ public class ServerMvcIntegrationTests { public void setStatusGatewayRouterFunctionWorks() { restClient.get() .uri("/status/201") + .header("Host", "www.setstatus.org") .exchange() .expectStatus() .isEqualTo(HttpStatus.TOO_MANY_REQUESTS) .expectHeader() - .valueEquals("x-status", "201"); // .expectBody(String.class).isEqualTo("Failed - // with 201"); + .valueEquals("x-status", "201"); } @Test @@ -981,6 +981,11 @@ public class ServerMvcIntegrationTests { }); } + @Test + public void notFoundWorks() { + restClient.get().uri("/status/404").header("Host", "www.notfound.org").exchange().expectStatus().isNotFound(); + } + @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) @@ -1032,7 +1037,7 @@ public class ServerMvcIntegrationTests { public RouterFunction gatewayRouterFunctionsSetStatusAndAddRespHeader() { // @formatter:off return route("testsetstatus") - .GET("/status/{status}", http()) + .GET("/status/{status}", host("**.setstatus.org"), http()) .before(new HttpbinUriResolver()) .after(setStatus(HttpStatus.TOO_MANY_REQUESTS)) .after(addResponseHeader("X-Status", "{status}")) @@ -1600,6 +1605,16 @@ public class ServerMvcIntegrationTests { // @formatter:on } + @Bean + public RouterFunction gatewayRouterFunctions404() { + // @formatter:off + return route("testnotfound") + .GET("/status/404", host("**.notfound.org"), http()) + .before(new HttpbinUriResolver()) + .build(); + // @formatter:on + } + @Bean public FilterRegistrationBean myFilter() { FilterRegistrationBean reg = new FilterRegistrationBean<>(new MyFilter()); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/SimpleHttpClientIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/SimpleHttpClientIntegrationTests.java new file mode 100644 index 00000000..bd42c04e --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/SimpleHttpClientIntegrationTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2013-2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; +import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = { "spring.cloud.gateway.mvc.http-client.type=autodetect" }, + webEnvironment = WebEnvironment.RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +public class SimpleHttpClientIntegrationTests { + + static { + // if set type to autodetect above + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + } + + @LocalServerPort + int port; + + @Autowired + TestRestClient restClient; + + @Test + public void simpleHttpClientNotFoundWorks() { + restClient.get().uri("/status/404").header("Host", "www.notfound.org").exchange().expectStatus().isNotFound(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + protected static class TestConfiguration { + + @Bean + public RouterFunction gatewayRouterFunctions404() { + // @formatter:off + return route("testnotfound") + .GET("/status/404", host("**.notfound.org"), http()) + .before(new HttpbinUriResolver()) + .build(); + // @formatter:on + } + + } + +}