From e2e7adabe43be4af55abea8ed5d051fccbc94835 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 17 Jul 2017 13:59:46 +0100 Subject: [PATCH] Update some deps and remove gateway (moved to separate project) --- pom.xml | 7 +- spring-cloud-function-gateway/.jdk8 | 0 spring-cloud-function-gateway/pom.xml | 33 - .../cloud/function/gateway/ProxyExchange.java | 644 ------------------ .../config/ProxyExchangeArgumentResolver.java | 83 --- .../gateway/config/ProxyProperties.java | 70 -- .../ProxyResponseAutoConfiguration.java | 89 --- .../main/resources/META-INF/spring.factories | 5 - .../gateway/ProductionConfigurationTests.java | 445 ------------ .../src/test/resources/static/test.html | 4 - 10 files changed, 3 insertions(+), 1377 deletions(-) delete mode 100644 spring-cloud-function-gateway/.jdk8 delete mode 100644 spring-cloud-function-gateway/pom.xml delete mode 100644 spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/ProxyExchange.java delete mode 100644 spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyExchangeArgumentResolver.java delete mode 100644 spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyProperties.java delete mode 100644 spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyResponseAutoConfiguration.java delete mode 100644 spring-cloud-function-gateway/src/main/resources/META-INF/spring.factories delete mode 100644 spring-cloud-function-gateway/src/test/java/org/springframework/cloud/function/web/gateway/ProductionConfigurationTests.java delete mode 100644 spring-cloud-function-gateway/src/test/resources/static/test.html diff --git a/pom.xml b/pom.xml index 183ca6f34..ca504c914 100644 --- a/pom.xml +++ b/pom.xml @@ -10,16 +10,16 @@ org.springframework.cloud spring-cloud-build - 1.3.0.BUILD-SNAPSHOT + 1.3.3.RELEASE 1.8 - Aluminium-BUILD-SNAPSHOT + Aluminium-SR3 Chelsea.SR1 1.0.5.RELEASE - 1.5.2.RELEASE + 1.5.4.RELEASE @@ -52,7 +52,6 @@ spring-cloud-function-compiler spring-cloud-function-core spring-cloud-function-context - spring-cloud-function-gateway spring-cloud-function-stream spring-cloud-function-task spring-cloud-function-web diff --git a/spring-cloud-function-gateway/.jdk8 b/spring-cloud-function-gateway/.jdk8 deleted file mode 100644 index e69de29bb..000000000 diff --git a/spring-cloud-function-gateway/pom.xml b/spring-cloud-function-gateway/pom.xml deleted file mode 100644 index c412ec863..000000000 --- a/spring-cloud-function-gateway/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - 4.0.0 - - spring-cloud-function-gateway - jar - spring-cloud-function-gateway - Spring Cloud Function Gateway Support - - - org.springframework.cloud - spring-cloud-function-parent - 1.0.0.BUILD-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-configuration-processor - true - - - diff --git a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/ProxyExchange.java b/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/ProxyExchange.java deleted file mode 100644 index a8764f7e9..000000000 --- a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/ProxyExchange.java +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Copyright 2016-2017 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 - * - * http://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.function.gateway; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.Vector; -import java.util.function.Function; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.springframework.core.Conventions; -import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpHeaders; -import org.springframework.http.RequestEntity; -import org.springframework.http.RequestEntity.BodyBuilder; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.HttpMessageNotWritableException; -import org.springframework.util.ClassUtils; -import org.springframework.validation.BindingResult; -import org.springframework.web.HttpMediaTypeNotAcceptableException; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.client.RequestCallback; -import org.springframework.web.client.ResponseExtractor; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; -import org.springframework.web.util.AbstractUriTemplateHandler; - -/** - * A @RequestMapping argument type that can proxy the request to a backend. - * Spring will inject one of these into your MVC handler method, and you get return a - * ResponseEntity that you get from one of the HTTP methods {@link #get()}, - * {@link #post()}, {@link #put()}, {@link #patch()}, {@link #delete()} etc. Example: - * - *
- * @GetMapping("/proxy/{id}")
- * public ResponseEntity<?> proxy(@PathVariable Integer id, ProxyExchange<?> proxy)
- * 		throws Exception {
- * 	return proxy.uri("http://localhost:9000/foos/" + id).get();
- * }
- * 
- * - *

- * By default the incoming request body and headers are sent intact to the downstream - * service (with the exception of "sensitive" headers). To manipulate the downstream - * request there are "builder" style methods in {@link ProxyExchange}, but only the - * {@link #uri(String)} is mandatory. You can change the sensitive headers by calling the - * {@link #sensitive(String...)} method (Authorization and Cookie are sensitive by - * default). - *

- *

- * The type parameter T in ProxyExchange<T> is the type of - * the response body, so it comes out in the {@link ResponseEntity} that you return from - * your @RequestMapping. If you don't care about the type of the request and - * response body (e.g. if it's just a passthru) then use a wildcard, or - * byte[] or Object. Use a concrete type if you want to - * transform or manipulate the response, or if you want to assert that it is convertible - * to the type you declare. - *

- *

- * To manipulate the response use the overloaded HTTP methods with a Function - * argument and pass in code to transform the response. E.g. - * - *

- * @PostMapping("/proxy")
- * public ResponseEntity<Foo> proxy(ProxyExchange<Foo> proxy) throws Exception {
- * 	return proxy.uri("http://localhost:9000/foos/") //
- * 			.post(response -> ResponseEntity.status(response.getStatusCode()) //
- * 					.headers(response.getHeaders()) //
- * 					.header("X-Custom", "MyCustomHeader") //
- * 					.body(response.getBody()) //
- * 	);
- * }
- * 
- * 
- * - *

- *

- * The full machinery of Spring {@link HttpMessageConverter message converters} is applied - * to the incoming request and response and also to the backend request. If you need - * additional converters then they need to be added upstream in the MVC configuration and - * also to the {@link RestTemplate} that is used in the backend calls (see the - * {@link ProxyExchange#ProxyExchange(RestTemplate, NativeWebRequest, ModelAndViewContainer, WebDataBinderFactory, Type) - * constructor} for details). - *

- *

- * As well as the HTTP methods for a backend call you can also use - * {@link #forward(String)} for a local in-container dispatch. - *

- * - * @author Dave Syer - * - */ -public class ProxyExchange { - - public static Set DEFAULT_SENSITIVE = new HashSet<>( - Arrays.asList("cookie", "authorization")); - - private URI uri; - - private NestedTemplate rest; - - private Object body; - - private RequestResponseBodyMethodProcessor delegate; - - private NativeWebRequest webRequest; - - private ModelAndViewContainer mavContainer; - - private WebDataBinderFactory binderFactory; - - private Set sensitive; - - private HttpHeaders headers = new HttpHeaders(); - - private Type responseType; - - public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest, - ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory, - Type type) { - this.responseType = type; - this.rest = createTemplate(rest); - this.webRequest = webRequest; - this.mavContainer = mavContainer; - this.binderFactory = binderFactory; - this.delegate = new RequestResponseBodyMethodProcessor( - rest.getMessageConverters()); - } - - /** - * Sets the body for the downstream request (if using {@link #post()}, {@link #put()} - * or {@link #patch()}). The body can be omitted if you just want to pass the incoming - * request downstream without changing it. If you want to transform the incoming - * request you can declare it as a @RequestBody in your - * @RequestMapping in the usual Spring MVC way. - * - * @param body the request body to send downstream - * @return this for convenience - */ - public ProxyExchange body(Object body) { - this.body = body; - return this; - } - - /** - * Sets a header for the downstream call. - * - * @param name - * @param value - * @return this for convenience - */ - public ProxyExchange header(String name, String... value) { - this.headers.put(name, Arrays.asList(value)); - return this; - } - - /** - * Additional headers, or overrides of the incoming ones, to be used in the downstream - * call. - * - * @param headers the http headers to use in the downstream call - * @return this for convenience - */ - public ProxyExchange headers(HttpHeaders headers) { - this.headers.putAll(headers); - return this; - } - - /** - * Sets the names of sensitive headers that are not passed downstream to the backend - * service. - * - * @param names the names of sensitive headers - * @return this for convenience - */ - public ProxyExchange sensitive(String... names) { - if (this.sensitive == null) { - this.sensitive = new HashSet<>(); - } - for (String name : names) { - this.sensitive.add(name.toLowerCase()); - } - return this; - } - - /** - * Sets the uri for the backend call when triggered by the HTTP methods. - * - * @param uri the backend uri to send the request to - * @return this for convenience - */ - public ProxyExchange uri(String uri) { - try { - this.uri = new URI(uri); - } - catch (URISyntaxException e) { - throw new IllegalStateException("Cannot create URI", e); - } - return this; - } - - public String path() { - return (String) this.webRequest.getAttribute( - HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, - WebRequest.SCOPE_REQUEST); - } - - public String path(String prefix) { - String path = path(); - if (!path.startsWith(prefix)) { - throw new IllegalArgumentException( - "Path does not start with prefix (" + prefix + "): " + path); - } - return path.substring(prefix.length()); - } - - public void forward(String path) { - HttpServletRequest request = this.webRequest - .getNativeRequest(HttpServletRequest.class); - HttpServletResponse response = this.webRequest - .getNativeResponse(HttpServletResponse.class); - try { - request.getRequestDispatcher(path).forward( - new BodyForwardingHttpServletRequest(request, response), response); - } - catch (Exception e) { - throw new IllegalStateException("Cannot forward request", e); - } - } - - public ResponseEntity get() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.get(uri)) - .build(); - return exchange(requestEntity); - } - - public ResponseEntity get( - Function, ResponseEntity> converter) { - return converter.apply(get()); - } - - public ResponseEntity head() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.head(uri)) - .build(); - return exchange(requestEntity); - } - - public ResponseEntity head( - Function, ResponseEntity> converter) { - return converter.apply(head()); - } - - public ResponseEntity options() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.options(uri)) - .build(); - return exchange(requestEntity); - } - - public ResponseEntity options( - Function, ResponseEntity> converter) { - return converter.apply(options()); - } - - public ResponseEntity post() { - RequestEntity requestEntity = headers(RequestEntity.post(uri)) - .body(body()); - return exchange(requestEntity); - } - - public ResponseEntity post( - Function, ResponseEntity> converter) { - return converter.apply(post()); - } - - public ResponseEntity delete() { - RequestEntity requestEntity = headers( - (BodyBuilder) RequestEntity.delete(uri)).build(); - return exchange(requestEntity); - } - - public ResponseEntity delete( - Function, ResponseEntity> converter) { - return converter.apply(delete()); - } - - public ResponseEntity put() { - RequestEntity requestEntity = headers(RequestEntity.put(uri)) - .body(body()); - return exchange(requestEntity); - } - - public ResponseEntity put( - Function, ResponseEntity> converter) { - return converter.apply(put()); - } - - public ResponseEntity patch() { - RequestEntity requestEntity = headers(RequestEntity.patch(uri)) - .body(body()); - return exchange(requestEntity); - } - - public ResponseEntity patch( - Function, ResponseEntity> converter) { - return converter.apply(patch()); - } - - private ResponseEntity exchange(RequestEntity requestEntity) { - Type type = this.responseType; - if (type instanceof TypeVariable || type instanceof WildcardType) { - type = Object.class; - } - RequestCallback requestCallback = rest.httpEntityCallback((Object) requestEntity, - type); - ResponseExtractor> responseExtractor = rest - .responseEntityExtractor(type); - return rest.execute(requestEntity.getUrl(), requestEntity.getMethod(), - requestCallback, responseExtractor); - } - - private BodyBuilder headers(BodyBuilder builder) { - Set sensitive = this.sensitive; - if (sensitive == null) { - sensitive = DEFAULT_SENSITIVE; - } - proxy(); - for (String name : headers.keySet()) { - if (sensitive.contains(name.toLowerCase())) { - continue; - } - builder.header(name, headers.get(name).toArray(new String[0])); - } - return builder; - } - - private void proxy() { - try { - URI uri = new URI(webRequest.getNativeRequest(HttpServletRequest.class) - .getRequestURL().toString()); - appendForwarded(uri); - appendXForwarded(uri); - } - catch (URISyntaxException e) { - throw new IllegalStateException("Cannot create URI for request: " + webRequest - .getNativeRequest(HttpServletRequest.class).getRequestURL()); - } - } - - private void appendXForwarded(URI uri) { - // Append the legacy headers if they were already added upstream - String host = headers.getFirst("x-forwarded-host"); - if (host == null) { - return; - } - host = host + "," + uri.getHost(); - headers.set("x-forwarded-host", host); - String proto = headers.getFirst("x-forwarded-proto"); - if (proto == null) { - return; - } - proto = proto + "," + uri.getScheme(); - headers.set("x-forwarded-proto", proto); - } - - private void appendForwarded(URI uri) { - String forwarded = headers.getFirst("forwarded"); - if (forwarded != null) { - forwarded = forwarded + ","; - } else { - forwarded = ""; - } - forwarded = forwarded + forwarded(uri); - headers.set("forwarded", forwarded); - } - - private String forwarded(URI uri) { - if ("http".equals(uri.getScheme())) { - return "host=" + uri.getHost(); - } - return String.format("host=%s;proto=%s", uri.getHost(), uri.getScheme()); - } - - private Object body() { - if (body != null) { - return body; - } - body = getRequestBody(); - return body; - } - - /** - * Search for the request body if it was already deserialized using - * @RequestBody. If it is not found then deserialize it in the same way - * that it would have been for a @RequestBody. - * - * @return the request body - */ - private Object getRequestBody() { - for (String key : mavContainer.getModel().keySet()) { - if (key.startsWith(BindingResult.MODEL_KEY_PREFIX)) { - BindingResult result = (BindingResult) mavContainer.getModel().get(key); - return result.getTarget(); - } - } - MethodParameter input = new MethodParameter( - ClassUtils.getMethod(BodyGrabber.class, "body", Object.class), 0); - try { - delegate.resolveArgument(input, mavContainer, webRequest, binderFactory); - } - catch (Exception e) { - throw new IllegalStateException("Cannot resolve body", e); - } - String name = Conventions.getVariableNameForParameter(input); - BindingResult result = (BindingResult) mavContainer.getModel() - .get(BindingResult.MODEL_KEY_PREFIX + name); - return result.getTarget(); - } - - private NestedTemplate createTemplate(RestTemplate input) { - NestedTemplate rest = new NestedTemplate(); - rest.setMessageConverters(input.getMessageConverters()); - rest.setErrorHandler(input.getErrorHandler()); - rest.setDefaultUriVariables( - ((AbstractUriTemplateHandler) input.getUriTemplateHandler()) - .getDefaultUriVariables()); - rest.setRequestFactory(input.getRequestFactory()); - rest.setInterceptors(input.getInterceptors()); - return rest; - } - - /** - * A special {@link RestTemplate} that knows about the {@link Type} of its response - * body explicitly (rather than through a {@link ParameterizedTypeReference}, which is - * the only way to access this feature in a regular template). - * - */ - class NestedTemplate extends RestTemplate { - @Override - protected RequestCallback httpEntityCallback(Object requestBody, - Type responseType) { - return super.httpEntityCallback(requestBody, responseType); - } - - @Override - protected ResponseExtractor> responseEntityExtractor( - Type responseType) { - return super.responseEntityExtractor(responseType); - } - } - - /** - * A servlet request wrapper that can be safely passed downstream to an internal - * forward dispatch, caching its body, and making it available in converted form using - * Spring message converters. - * - */ - class BodyForwardingHttpServletRequest extends HttpServletRequestWrapper { - private HttpServletRequest request; - private HttpServletResponse response; - - BodyForwardingHttpServletRequest(HttpServletRequest request, - HttpServletResponse response) { - super(request); - this.request = request; - this.response = response; - } - - private List header(String name) { - List list = headers.get(name); - return list; - } - - @Override - public ServletInputStream getInputStream() throws IOException { - Object body = body(); - MethodParameter output = new MethodParameter( - ClassUtils.getMethod(BodySender.class, "body"), -1); - ServletOutputToInputConverter response = new ServletOutputToInputConverter( - this.response); - ServletWebRequest webRequest = new ServletWebRequest(this.request, response); - try { - delegate.handleReturnValue(body, output, mavContainer, webRequest); - } - catch (HttpMessageNotWritableException - | HttpMediaTypeNotAcceptableException e) { - throw new IllegalStateException("Cannot convert body", e); - } - return response.getInputStream(); - } - - @Override - public Enumeration getHeaderNames() { - Set names = headers.keySet(); - if (names.isEmpty()) { - return super.getHeaderNames(); - } - Set result = new LinkedHashSet<>(names); - result.addAll(Collections.list(super.getHeaderNames())); - return new Vector(result).elements(); - } - - @Override - public Enumeration getHeaders(String name) { - List list = header(name); - if (list != null) { - return new Vector(list).elements(); - } - return super.getHeaders(name); - } - - @Override - public String getHeader(String name) { - List list = header(name); - if (list != null && !list.isEmpty()) { - return list.iterator().next(); - } - return super.getHeader(name); - } - } - - protected static class BodyGrabber { - public Object body(@RequestBody Object body) { - return body; - } - } - - protected static class BodySender { - @ResponseBody - public Object body() { - return null; - } - } - -} - -/** - * Convenience class that converts an incoming request input stream into a form that can - * be easily deserialized to a Java object using Spring message converters. It is only - * used in a local forward dispatch, in which case there is a danger that the request body - * will need to be read and analysed more than once. Apart from using the message - * converters the other main feature of this class is that the request body is cached and - * can be read repeatedly as necessary. - * - * @author Dave Syer - * - */ -class ServletOutputToInputConverter extends HttpServletResponseWrapper { - - private StringBuilder builder = new StringBuilder(); - - public ServletOutputToInputConverter(HttpServletResponse response) { - super(response); - } - - @Override - public ServletOutputStream getOutputStream() throws IOException { - return new ServletOutputStream() { - - @Override - public void write(int b) throws IOException { - builder.append(new Character((char) b)); - } - - @Override - public void setWriteListener(WriteListener listener) { - } - - @Override - public boolean isReady() { - return true; - } - }; - } - - public ServletInputStream getInputStream() { - ByteArrayInputStream body = new ByteArrayInputStream( - builder.toString().getBytes()); - return new ServletInputStream() { - - @Override - public int read() throws IOException { - return body.read(); - } - - @Override - public void setReadListener(ReadListener listener) { - } - - @Override - public boolean isReady() { - return true; - } - - @Override - public boolean isFinished() { - return body.available() <= 0; - } - }; - } - -} diff --git a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyExchangeArgumentResolver.java b/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyExchangeArgumentResolver.java deleted file mode 100644 index bc9e143be..000000000 --- a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyExchangeArgumentResolver.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2016-2017 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 - * - * http://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.function.gateway.config; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Set; - -import org.springframework.cloud.function.gateway.ProxyExchange; -import org.springframework.core.MethodParameter; -import org.springframework.http.HttpHeaders; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * @author Dave Syer - * - */ -public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResolver { - - private RestTemplate rest; - - private HttpHeaders headers; - - private Set sensitive; - - public ProxyExchangeArgumentResolver(RestTemplate builder) { - this.rest = builder; - } - - public void setHeaders(HttpHeaders headers) { - this.headers = headers; - } - - public void setSensitive(Set sensitive) { - this.sensitive = sensitive; - } - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return ProxyExchange.class.isAssignableFrom(parameter.getParameterType()); - } - - @Override - public Object resolveArgument(MethodParameter parameter, - ModelAndViewContainer mavContainer, NativeWebRequest webRequest, - WebDataBinderFactory binderFactory) throws Exception { - ProxyExchange proxy = new ProxyExchange<>(rest, webRequest, mavContainer, - binderFactory, type(parameter)); - proxy.headers(headers); - if (sensitive != null) { - proxy.sensitive(sensitive.toArray(new String[0])); - } - return proxy; - } - - private Type type(MethodParameter parameter) { - Type type = parameter.getGenericParameterType(); - if (type instanceof ParameterizedType) { - ParameterizedType param = (ParameterizedType) type; - type = param.getActualTypeArguments()[0]; - } - return type; - } - -} diff --git a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyProperties.java b/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyProperties.java deleted file mode 100644 index 01419f35d..000000000 --- a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyProperties.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2016-2017 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 - * - * http://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.function.gateway.config; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.function.gateway.ProxyExchange; -import org.springframework.http.HttpHeaders; - -/** - * Configuration properties for the {@link ProxyExchange} argument handler in - * @RequestMapping methods. - * @author Dave Syer - * - */ -@ConfigurationProperties("spring.cloud.gateway.proxy") -public class ProxyProperties { - - /** - * Fixed header values that will be added to all downstream requests. - */ - private Map headers = new LinkedHashMap<>(); - - /** - * A set of sensitive header names that will not be sent downstream by default. - */ - private Set sensitive = null; - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public Set getSensitive() { - return sensitive; - } - - public void setSensitive(Set sensitive) { - this.sensitive = sensitive; - } - - public HttpHeaders convertHeaders() { - HttpHeaders headers = new HttpHeaders(); - for (String key : this.headers.keySet()) { - headers.set(key, this.headers.get(key)); - } - return headers; - } - -} diff --git a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyResponseAutoConfiguration.java b/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyResponseAutoConfiguration.java deleted file mode 100644 index ddfd07676..000000000 --- a/spring-cloud-function-gateway/src/main/java/org/springframework/cloud/function/gateway/config/ProxyResponseAutoConfiguration.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2016-2017 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 - * - * http://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.function.gateway.config; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.function.gateway.ProxyExchange; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.http.converter.ByteArrayHttpMessageConverter; -import org.springframework.web.client.DefaultResponseErrorHandler; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -/** - * Autoconfiguration for the {@link ProxyExchange} argument handler in Spring MVC - * @RequestMapping methods. - * - * @author Dave Syer - */ -@Configuration -@ConditionalOnWebApplication -@ConditionalOnClass({ HandlerMethodReturnValueHandler.class }) -@EnableConfigurationProperties(ProxyProperties.class) -public class ProxyResponseAutoConfiguration extends WebMvcConfigurerAdapter { - - @Autowired - private ApplicationContext context; - - @Bean - @ConditionalOnMissingBean - public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver( - Optional optional, ProxyProperties proxy) { - RestTemplateBuilder builder = optional.orElse(new RestTemplateBuilder()); - RestTemplate template = builder.build(); - template.setErrorHandler(new NoOpResponseErrorHandler()); - template.getMessageConverters().add(new ByteArrayHttpMessageConverter() { - @Override - public boolean supports(Class clazz) { - return true; - } - }); - ProxyExchangeArgumentResolver resolver = new ProxyExchangeArgumentResolver( - template); - resolver.setHeaders(proxy.convertHeaders()); - resolver.setSensitive(proxy.getSensitive()); // can be null - return resolver; - } - - @Override - public void addArgumentResolvers( - List argumentResolvers) { - argumentResolvers.add(context.getBean(ProxyExchangeArgumentResolver.class)); - } - - private static class NoOpResponseErrorHandler extends DefaultResponseErrorHandler { - - @Override - public void handleError(ClientHttpResponse response) throws IOException { - } - - } -} diff --git a/spring-cloud-function-gateway/src/main/resources/META-INF/spring.factories b/spring-cloud-function-gateway/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 8a98f9330..000000000 --- a/spring-cloud-function-gateway/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,5 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.springframework.cloud.function.gateway.config.ProxyResponseAutoConfiguration - -org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc=\ -org.springframework.cloud.function.gateway.config.ProxyResponseAutoConfiguration diff --git a/spring-cloud-function-gateway/src/test/java/org/springframework/cloud/function/web/gateway/ProductionConfigurationTests.java b/spring-cloud-function-gateway/src/test/java/org/springframework/cloud/function/web/gateway/ProductionConfigurationTests.java deleted file mode 100644 index ec2772920..000000000 --- a/spring-cloud-function-gateway/src/test/java/org/springframework/cloud/function/web/gateway/ProductionConfigurationTests.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright 2016-2017 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 - * - * http://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.function.web.gateway; - -import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -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.context.embedded.LocalServerPort; -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.cloud.function.gateway.ProxyExchange; -import org.springframework.cloud.function.web.gateway.ProductionConfigurationTests.TestApplication; -import org.springframework.cloud.function.web.gateway.ProductionConfigurationTests.TestApplication.Bar; -import org.springframework.cloud.function.web.gateway.ProductionConfigurationTests.TestApplication.Foo; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; -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.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ContextConfiguration(classes = TestApplication.class) -public class ProductionConfigurationTests { - - @Autowired - private TestRestTemplate rest; - - @Autowired - private TestApplication application; - - @LocalServerPort - private int port; - - @Before - public void init() throws Exception { - application.setHome(new URI("http://localhost:" + port)); - } - - @Test - public void get() throws Exception { - assertThat(rest.getForObject("/proxy/0", Foo.class).getName()).isEqualTo("bye"); - } - - @Test - public void path() throws Exception { - assertThat(rest.getForObject("/proxy/path/1", Foo.class).getName()) - .isEqualTo("foo"); - } - - @Test - public void resource() throws Exception { - assertThat(rest.getForObject("/proxy/html/test.html", String.class)) - .contains("Test"); - } - - @Test - public void resourceWithNoType() throws Exception { - assertThat(rest.getForObject("/proxy/typeless/test.html", String.class)) - .contains("Test"); - } - - @Test - public void missing() throws Exception { - assertThat(rest.getForEntity("/proxy/missing/0", Foo.class).getStatusCode()) - .isEqualTo(HttpStatus.NOT_FOUND); - } - - @Test - public void uri() throws Exception { - assertThat(rest.getForObject("/proxy/0", Foo.class).getName()).isEqualTo("bye"); - } - - @Test - public void post() throws Exception { - assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); - } - - @Test - public void forward() throws Exception { - assertThat(rest.getForObject("/forward/foos/0", Foo.class).getName()) - .isEqualTo("bye"); - } - - @Test - public void forwardHeader() throws Exception { - ResponseEntity result = rest.getForEntity("/forward/special/foos/0", - Foo.class); - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody().getName()).isEqualTo("FOO"); - } - - @Test - public void postForwardHeader() throws Exception { - ResponseEntity> result = rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler().expand( - "/forward/special/bars")) - .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), - new ParameterizedTypeReference>() { - }); - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody().iterator().next().getName()).isEqualTo("FOOfoo"); - } - - @Test - public void postForwardBody() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler().expand( - "/forward/body/bars")) - .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), - String.class); - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody()).contains("foo"); - } - - @Test - public void postForwardForgetBody() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler().expand( - "/forward/forget/bars")) - .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), - String.class); - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody()).contains("foo"); - } - - @Test - public void postForwardBodyFoo() throws Exception { - ResponseEntity> result = rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler().expand( - "/forward/body/bars")) - .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), - new ParameterizedTypeReference>() { - }); - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody().iterator().next().getName()).isEqualTo("foo"); - } - - @Test - public void list() throws Exception { - assertThat(rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler().expand( - "/proxy")) - .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), - new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); - } - - @Test - public void bodyless() throws Exception { - assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), - Bar.class).getName()).isEqualTo("host=localhost;foo"); - } - - @Test - public void entity() throws Exception { - assertThat(rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler() - .expand("/proxy/entity")) - .body(Collections.singletonMap("name", "foo")), - new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); - } - - @Test - public void entityWithType() throws Exception { - assertThat(rest.exchange( - RequestEntity - .post(rest.getRestTemplate().getUriTemplateHandler() - .expand("/proxy/type")) - .body(Collections.singletonMap("name", "foo")), - new ParameterizedTypeReference>() { - }).getBody().iterator().next().getName()).isEqualTo("host=localhost;foo"); - } - - @Test - public void single() throws Exception { - assertThat(rest.postForObject("/proxy/single", - Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); - } - - @Test - public void converter() throws Exception { - assertThat(rest.postForObject("/proxy/converter", - Collections.singletonMap("name", "foobar"), Bar.class).getName()) - .isEqualTo("host=localhost;foobar"); - } - - @SpringBootApplication - static class TestApplication { - - @RestController - static class ProxyController { - - private URI home; - - public void setHome(URI home) { - this.home = home; - } - - @GetMapping("/proxy/{id}") - public ResponseEntity proxyFoos(@PathVariable Integer id, - ProxyExchange proxy) throws Exception { - return proxy.uri(home.toString() + "/foos/" + id).get(); - } - - @GetMapping("/proxy/path/**") - public ResponseEntity proxyPath(ProxyExchange proxy, - UriComponentsBuilder uri) throws Exception { - String path = proxy.path("/proxy/path/"); - return proxy.uri(home.toString() + "/foos/" + path).get(); - } - - @GetMapping("/proxy/html/**") - public ResponseEntity proxyHtml(ProxyExchange proxy, - UriComponentsBuilder uri) throws Exception { - String path = proxy.path("/proxy/html"); - return proxy.uri(home.toString() + path).get(); - } - - @GetMapping("/proxy/typeless/**") - public ResponseEntity proxyTypeless(ProxyExchange proxy, - UriComponentsBuilder uri) throws Exception { - String path = proxy.path("/proxy/typeless"); - return proxy.uri(home.toString() + path).get(); - } - - @GetMapping("/proxy/missing/{id}") - public ResponseEntity proxyMissing(@PathVariable Integer id, - ProxyExchange proxy) throws Exception { - return proxy.uri(home.toString() + "/missing/" + id).get(); - } - - @GetMapping("/proxy") - public ResponseEntity proxyUri(ProxyExchange proxy) throws Exception { - return proxy.uri(home.toString() + "/foos").get(); - } - - @PostMapping("/proxy/{id}") - public ResponseEntity proxyBars(@PathVariable Integer id, - @RequestBody Map body, - ProxyExchange> proxy) throws Exception { - body.put("id", id); - return proxy.uri(home.toString() + "/bars").body(Arrays.asList(body)) - .post(this::first); - } - - @PostMapping("/proxy") - public ResponseEntity barsWithNoBody(ProxyExchange proxy) - throws Exception { - return proxy.uri(home.toString() + "/bars").post(); - } - - @PostMapping("/proxy/entity") - public ResponseEntity explicitEntity(@RequestBody Foo foo, - ProxyExchange proxy) throws Exception { - return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)) - .post(); - } - - @PostMapping("/proxy/type") - public ResponseEntity> explicitEntityWithType(@RequestBody Foo foo, - ProxyExchange> proxy) throws Exception { - return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)) - .post(); - } - - @PostMapping("/proxy/single") - public ResponseEntity implicitEntity(@RequestBody Foo foo, - ProxyExchange> proxy) throws Exception { - return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)) - .post(this::first); - } - - @PostMapping("/proxy/converter") - public ResponseEntity implicitEntityWithConverter(@RequestBody Foo foo, - ProxyExchange> proxy) throws Exception { - return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)) - .post(response -> ResponseEntity.status(response.getStatusCode()) - .headers(response.getHeaders()) - .body(response.getBody().iterator().next())); - } - - @GetMapping("/forward/**") - public void forward(ProxyExchange proxy) throws Exception { - String path = proxy.path("/forward"); - if (path.startsWith("/special")) { - proxy.header("X-Custom", "FOO"); - path = proxy.path("/forward/special"); - } - proxy.forward(path); - } - - @PostMapping("/forward/**") - public void postForward(ProxyExchange proxy) throws Exception { - String path = proxy.path("/forward"); - if (path.startsWith("/special")) { - proxy.header("X-Custom", "FOO"); - path = proxy.path("/forward/special"); - } - proxy.forward(path); - } - - @PostMapping("/forward/body/**") - public void postForwardBody(@RequestBody byte[] body, ProxyExchange proxy) - throws Exception { - String path = proxy.path("/forward/body"); - proxy.body(body).forward(path); - } - - @PostMapping("/forward/forget/**") - public void postForwardForgetBody(@RequestBody byte[] body, - ProxyExchange proxy) throws Exception { - String path = proxy.path("/forward/forget"); - proxy.forward(path); - } - - private ResponseEntity first(ResponseEntity> response) { - return ResponseEntity.status(response.getStatusCode()) - .headers(response.getHeaders()) - .body(response.getBody().iterator().next()); - } - - } - - @Autowired - private ProxyController controller; - - public void setHome(URI home) { - controller.setHome(home); - } - - @RestController - static class TestController { - - @GetMapping("/foos") - public List foos() { - return Arrays.asList(new Foo("hello")); - } - - @GetMapping("/foos/{id}") - public Foo foo(@PathVariable Integer id, @RequestHeader HttpHeaders headers) { - String custom = headers.getFirst("X-Custom"); - return new Foo(id == 1 ? "foo" : custom != null ? custom : "bye"); - } - - @PostMapping("/bars") - public List bars(@RequestBody List foos, - @RequestHeader HttpHeaders headers) { - String custom = headers.getFirst("X-Custom"); - custom = custom == null ? "" : custom; - custom = headers.getFirst("forwarded")==null ? custom : headers.getFirst("forwarded") + ";" + custom; - return Arrays.asList(new Bar(custom + foos.iterator().next().getName())); - } - - } - - @JsonIgnoreProperties(ignoreUnknown = true) - static class Foo { - private String name; - - public Foo() { - } - - public Foo(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - - @JsonIgnoreProperties(ignoreUnknown = true) - static class Bar { - private String name; - - public Bar() { - } - - public Bar(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - - } - -} \ No newline at end of file diff --git a/spring-cloud-function-gateway/src/test/resources/static/test.html b/spring-cloud-function-gateway/src/test/resources/static/test.html deleted file mode 100644 index 0cfed139f..000000000 --- a/spring-cloud-function-gateway/src/test/resources/static/test.html +++ /dev/null @@ -1,4 +0,0 @@ - -Test - - \ No newline at end of file