From d02e262a4c73811bbba3ba770f704c667c448070 Mon Sep 17 00:00:00 2001 From: Manuel Date: Sun, 28 Feb 2021 14:24:44 +0100 Subject: [PATCH] Fix NPE when proxy exchange is not configured Fixes gh-2075 Fixes gh-2163 --- .../config/ProxyExchangeArgumentResolver.java | 30 +++-- .../ProxyExchangeArgumentResolverTest.java | 119 ++++++++++++++++++ 2 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolverTest.java diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java index f07987ac..2f767e0a 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java @@ -41,7 +41,7 @@ import static java.util.stream.Collectors.toSet; */ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResolver { - private RestTemplate rest; + private final RestTemplate rest; private HttpHeaders headers; @@ -77,13 +77,9 @@ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResol WebDataBinderFactory binderFactory) throws Exception { ProxyExchange proxy = new ProxyExchange<>(rest, webRequest, mavContainer, binderFactory, type(parameter)); - proxy.headers(headers); - if (this.autoForwardedHeaders.size() > 0) { - proxy.headers(extractAutoForwardedHeaders(webRequest)); - } - if (sensitive != null) { - proxy.sensitive(sensitive.toArray(new String[0])); - } + configureHeaders(proxy); + configureAutoForwardedHeaders(proxy, webRequest); + configureSensitive(proxy); return proxy; } @@ -111,4 +107,22 @@ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResol return headers; } + private void configureHeaders(final ProxyExchange proxy) { + if (headers != null) { + proxy.headers(headers); + } + } + + private void configureAutoForwardedHeaders(final ProxyExchange proxy, final NativeWebRequest webRequest) { + if ((autoForwardedHeaders != null) && (autoForwardedHeaders.size() > 0)) { + proxy.headers(extractAutoForwardedHeaders(webRequest)); + } + } + + private void configureSensitive(final ProxyExchange proxy) { + if (sensitive != null) { + proxy.sensitive(sensitive.toArray(new String[0])); + } + } + } diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolverTest.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolverTest.java new file mode 100644 index 00000000..9cf70aab --- /dev/null +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolverTest.java @@ -0,0 +1,119 @@ +/* + * Copyright 2016-2019 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.mvc.config; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.gateway.mvc.ProxyExchange; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.DefaultResponseErrorHandler; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ContextConfiguration(classes = ProxyExchangeArgumentResolverTest.ProxyExchangeArgumentResolverTestApplication.class) +public class ProxyExchangeArgumentResolverTest { + + @Autowired + private TestRestTemplate rest; + + @Autowired + private ProxyExchangeArgumentResolverTestApplication application; + + @LocalServerPort + private int port; + + @Before + public void setUp() throws Exception { + application.setHome(new URI("http://localhost:" + port)); + } + + @Test + public void shouldProxyRequestWhenProxyExchangeArgumentResolverIsNotConfigured() { + final ResponseEntity response = rest.getForEntity("/proxy", String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).contains("Hello World"); + } + + @SpringBootApplication + static class ProxyExchangeArgumentResolverTestApplication { + + @Autowired + private ProxyController controller; + + @Bean + public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver() { + RestTemplateBuilder builder = new RestTemplateBuilder(); + builder.errorHandler(new DefaultResponseErrorHandler()); + builder.messageConverters(new ByteArrayHttpMessageConverter()); + return new ProxyExchangeArgumentResolver(builder.build()); + } + + public void setHome(final URI home) { + controller.setHome(home); + } + + @RestController + static class ProxyController { + + private URI home; + + public void setHome(URI home) { + this.home = home; + } + + @GetMapping("/proxy") + public ResponseEntity proxyFoo(ProxyExchange proxy) { + return proxy.uri(home.toString() + "/foo").get(); + } + + } + + @RestController + static class TestController { + + @GetMapping("/foo") + public List foo() { + return Collections.singletonList("Hello World"); + } + + } + + } + +}