Merge branch 'disable-builtin-filters-predicates' into 2.2.x

This commit is contained in:
spencergibb
2020-09-25 20:49:38 -04:00
34 changed files with 1871 additions and 164 deletions

View File

@@ -53,6 +53,9 @@ import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint;
import org.springframework.cloud.gateway.actuate.GatewayLegacyControllerEndpoint;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledFilter;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledGlobalFilter;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledPredicate;
import org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter;
import org.springframework.cloud.gateway.filter.ForwardPathFilter;
import org.springframework.cloud.gateway.filter.ForwardRoutingFilter;
@@ -118,7 +121,7 @@ import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFac
import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactory;
@@ -294,27 +297,32 @@ public class GatewayAutoConfiguration {
// GlobalFilter beans
@Bean
@ConditionalOnEnabledGlobalFilter
public AdaptCachedBodyGlobalFilter adaptCachedBodyGlobalFilter() {
return new AdaptCachedBodyGlobalFilter();
}
@Bean
@ConditionalOnEnabledGlobalFilter
public RemoveCachedBodyFilter removeCachedBodyFilter() {
return new RemoveCachedBodyFilter();
}
@Bean
@ConditionalOnEnabledGlobalFilter
public RouteToRequestUrlFilter routeToRequestUrlFilter() {
return new RouteToRequestUrlFilter();
}
@Bean
@ConditionalOnEnabledGlobalFilter
public ForwardRoutingFilter forwardRoutingFilter(
ObjectProvider<DispatcherHandler> dispatcherHandler) {
return new ForwardRoutingFilter(dispatcherHandler);
}
@Bean
@ConditionalOnEnabledGlobalFilter
public ForwardPathFilter forwardPathFilter() {
return new ForwardPathFilter();
}
@@ -326,6 +334,7 @@ public class GatewayAutoConfiguration {
}
@Bean
@ConditionalOnEnabledGlobalFilter
public WebsocketRoutingFilter websocketRoutingFilter(WebSocketClient webSocketClient,
WebSocketService webSocketService,
ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
@@ -352,68 +361,81 @@ public class GatewayAutoConfiguration {
// Predicate Factory beans
@Bean
@ConditionalOnEnabledPredicate
public AfterRoutePredicateFactory afterRoutePredicateFactory() {
return new AfterRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public BeforeRoutePredicateFactory beforeRoutePredicateFactory() {
return new BeforeRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public BetweenRoutePredicateFactory betweenRoutePredicateFactory() {
return new BetweenRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public CookieRoutePredicateFactory cookieRoutePredicateFactory() {
return new CookieRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public HeaderRoutePredicateFactory headerRoutePredicateFactory() {
return new HeaderRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public HostRoutePredicateFactory hostRoutePredicateFactory() {
return new HostRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public MethodRoutePredicateFactory methodRoutePredicateFactory() {
return new MethodRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public PathRoutePredicateFactory pathRoutePredicateFactory() {
return new PathRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public QueryRoutePredicateFactory queryRoutePredicateFactory() {
return new QueryRoutePredicateFactory();
}
@Bean
public ReadBodyPredicateFactory readBodyPredicateFactory(
@ConditionalOnEnabledPredicate
public ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory(
ServerCodecConfigurer codecConfigurer) {
return new ReadBodyPredicateFactory(codecConfigurer.getReaders());
return new ReadBodyRoutePredicateFactory(codecConfigurer.getReaders());
}
@Bean
@ConditionalOnEnabledPredicate
public RemoteAddrRoutePredicateFactory remoteAddrRoutePredicateFactory() {
return new RemoteAddrRoutePredicateFactory();
}
@Bean
@DependsOn("weightCalculatorWebFilter")
@ConditionalOnEnabledPredicate
public WeightRoutePredicateFactory weightRoutePredicateFactory() {
return new WeightRoutePredicateFactory();
}
@Bean
@ConditionalOnEnabledPredicate
public CloudFoundryRouteServiceRoutePredicateFactory cloudFoundryRouteServiceRoutePredicateFactory() {
return new CloudFoundryRouteServiceRoutePredicateFactory();
}
@@ -421,37 +443,44 @@ public class GatewayAutoConfiguration {
// GatewayFilter Factory beans
@Bean
@ConditionalOnEnabledFilter
public AddRequestHeaderGatewayFilterFactory addRequestHeaderGatewayFilterFactory() {
return new AddRequestHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public MapRequestHeaderGatewayFilterFactory mapRequestHeaderGatewayFilterFactory() {
return new MapRequestHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public AddRequestParameterGatewayFilterFactory addRequestParameterGatewayFilterFactory() {
return new AddRequestParameterGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public AddResponseHeaderGatewayFilterFactory addResponseHeaderGatewayFilterFactory() {
return new AddResponseHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public ModifyRequestBodyGatewayFilterFactory modifyRequestBodyGatewayFilterFactory(
ServerCodecConfigurer codecConfigurer) {
return new ModifyRequestBodyGatewayFilterFactory(codecConfigurer.getReaders());
}
@Bean
@ConditionalOnEnabledFilter
public DedupeResponseHeaderGatewayFilterFactory dedupeResponseHeaderGatewayFilterFactory() {
return new DedupeResponseHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public ModifyResponseBodyGatewayFilterFactory modifyResponseBodyGatewayFilterFactory(
ServerCodecConfigurer codecConfigurer, Set<MessageBodyDecoder> bodyDecoders,
Set<MessageBodyEncoder> bodyEncoders) {
@@ -460,31 +489,37 @@ public class GatewayAutoConfiguration {
}
@Bean
@ConditionalOnEnabledFilter
public PrefixPathGatewayFilterFactory prefixPathGatewayFilterFactory() {
return new PrefixPathGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public PreserveHostHeaderGatewayFilterFactory preserveHostHeaderGatewayFilterFactory() {
return new PreserveHostHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RedirectToGatewayFilterFactory redirectToGatewayFilterFactory() {
return new RedirectToGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RemoveRequestHeaderGatewayFilterFactory removeRequestHeaderGatewayFilterFactory() {
return new RemoveRequestHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RemoveRequestParameterGatewayFilterFactory removeRequestParameterGatewayFilterFactory() {
return new RemoveRequestParameterGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RemoveResponseHeaderGatewayFilterFactory removeResponseHeaderGatewayFilterFactory() {
return new RemoveResponseHeaderGatewayFilterFactory();
}
@@ -498,83 +533,99 @@ public class GatewayAutoConfiguration {
@Bean
@ConditionalOnBean({ RateLimiter.class, KeyResolver.class })
@ConditionalOnEnabledFilter
public RequestRateLimiterGatewayFilterFactory requestRateLimiterGatewayFilterFactory(
RateLimiter rateLimiter, KeyResolver resolver) {
return new RequestRateLimiterGatewayFilterFactory(rateLimiter, resolver);
}
@Bean
@ConditionalOnEnabledFilter
public RewritePathGatewayFilterFactory rewritePathGatewayFilterFactory() {
return new RewritePathGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RetryGatewayFilterFactory retryGatewayFilterFactory() {
return new RetryGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SetPathGatewayFilterFactory setPathGatewayFilterFactory() {
return new SetPathGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SecureHeadersGatewayFilterFactory secureHeadersGatewayFilterFactory(
SecureHeadersProperties properties) {
return new SecureHeadersGatewayFilterFactory(properties);
}
@Bean
@ConditionalOnEnabledFilter
public SetRequestHeaderGatewayFilterFactory setRequestHeaderGatewayFilterFactory() {
return new SetRequestHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SetRequestHostHeaderGatewayFilterFactory setRequestHostHeaderGatewayFilterFactory() {
return new SetRequestHostHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SetResponseHeaderGatewayFilterFactory setResponseHeaderGatewayFilterFactory() {
return new SetResponseHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RewriteResponseHeaderGatewayFilterFactory rewriteResponseHeaderGatewayFilterFactory() {
return new RewriteResponseHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RewriteLocationResponseHeaderGatewayFilterFactory rewriteLocationResponseHeaderGatewayFilterFactory() {
return new RewriteLocationResponseHeaderGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SetStatusGatewayFilterFactory setStatusGatewayFilterFactory() {
return new SetStatusGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public SaveSessionGatewayFilterFactory saveSessionGatewayFilterFactory() {
return new SaveSessionGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public StripPrefixGatewayFilterFactory stripPrefixGatewayFilterFactory() {
return new StripPrefixGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RequestHeaderToRequestUriGatewayFilterFactory requestHeaderToRequestUriGatewayFilterFactory() {
return new RequestHeaderToRequestUriGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RequestSizeGatewayFilterFactory requestSizeGatewayFilterFactory() {
return new RequestSizeGatewayFilterFactory();
}
@Bean
@ConditionalOnEnabledFilter
public RequestHeaderSizeGatewayFilterFactory requestHeaderSizeGatewayFilterFactory() {
return new RequestHeaderSizeGatewayFilterFactory();
}
@@ -726,6 +777,7 @@ public class GatewayAutoConfiguration {
}
@Bean
@ConditionalOnEnabledGlobalFilter
public NettyRoutingFilter routingFilter(HttpClient httpClient,
ObjectProvider<List<HttpHeadersFilter>> headersFilters,
HttpClientProperties properties) {
@@ -733,6 +785,7 @@ public class GatewayAutoConfiguration {
}
@Bean
@ConditionalOnEnabledGlobalFilter
public NettyWriteResponseFilter nettyWriteResponseFilter(
GatewayProperties properties) {
return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
@@ -772,6 +825,7 @@ public class GatewayAutoConfiguration {
protected static class HystrixConfiguration {
@Bean
@ConditionalOnEnabledFilter
public HystrixGatewayFilterFactory hystrixGatewayFilterFactory(
ObjectProvider<DispatcherHandler> dispatcherHandler) {
return new HystrixGatewayFilterFactory(dispatcherHandler);
@@ -779,6 +833,7 @@ public class GatewayAutoConfiguration {
@Bean
@ConditionalOnMissingBean(FallbackHeadersGatewayFilterFactory.class)
@ConditionalOnEnabledFilter
public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
return new FallbackHeadersGatewayFilterFactory();
}

View File

@@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledFilter;
import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerHystrixFilterFactory;
import org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerAutoConfiguration;
@@ -53,7 +54,8 @@ public class GatewayHystrixCircuitBreakerAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean(FallbackHeadersGatewayFilterFactory.class)
@ConditionalOnMissingBean
@ConditionalOnEnabledFilter
public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
return new FallbackHeadersGatewayFilterFactory();
}

View File

@@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledGlobalFilter;
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
@@ -46,6 +47,7 @@ public class GatewayLoadBalancerClientAutoConfiguration {
@ConditionalOnBean(LoadBalancerClient.class)
@ConditionalOnMissingBean({ LoadBalancerClientFilter.class,
ReactiveLoadBalancerClientFilter.class })
@ConditionalOnEnabledGlobalFilter
public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
LoadBalancerProperties properties) {
return new LoadBalancerClientFilter(client, properties);

View File

@@ -68,6 +68,7 @@ public class GatewayMetricsAutoConfiguration {
@ConditionalOnBean(MeterRegistry.class)
@ConditionalOnProperty(name = "spring.cloud.gateway.metrics.enabled",
matchIfMissing = true)
// @ConditionalOnEnabledGlobalFilter
public GatewayMetricsFilter gatewayMetricFilter(MeterRegistry meterRegistry,
List<GatewayTagsProvider> tagsProviders) {
return new GatewayMetricsFilter(meterRegistry, tagsProviders);

View File

@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledGlobalFilter;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
@@ -53,6 +54,7 @@ public class GatewayReactiveLoadBalancerClientAutoConfiguration {
@ConditionalOnBean(LoadBalancerClientFactory.class)
@ConditionalOnMissingBean(ReactiveLoadBalancerClientFilter.class)
@Conditional(OnNoRibbonDefaultCondition.class)
@ConditionalOnEnabledGlobalFilter
public ReactiveLoadBalancerClientFilter gatewayLoadBalancerClientFilter(
LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {
return new ReactiveLoadBalancerClientFilter(clientFactory, properties);

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JAutoConfiguration;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledFilter;
import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerResilience4JFilterFactory;
import org.springframework.context.annotation.Bean;
@@ -44,6 +45,7 @@ public class GatewayResilience4JCircuitBreakerAutoConfiguration {
@Bean
@ConditionalOnBean(ReactiveResilience4JCircuitBreakerFactory.class)
@ConditionalOnEnabledFilter
public SpringCloudCircuitBreakerResilience4JFilterFactory springCloudCircuitBreakerResilience4JFilterFactory(
ReactiveResilience4JCircuitBreakerFactory reactiveCircuitBreakerFactory,
ObjectProvider<DispatcherHandler> dispatcherHandler) {
@@ -52,7 +54,8 @@ public class GatewayResilience4JCircuitBreakerAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean(FallbackHeadersGatewayFilterFactory.class)
@ConditionalOnMissingBean
@ConditionalOnEnabledFilter
public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
return new FallbackHeadersGatewayFilterFactory();
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2013-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.config.conditional;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.context.annotation.Conditional;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnEnabledFilter.class)
public @interface ConditionalOnEnabledFilter {
/**
* The class component to check for.
* @return the class that must be enabled
*/
Class<? extends GatewayFilterFactory<?>> value() default OnEnabledFilter.DefaultValue.class;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2013-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.config.conditional;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Conditional;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnEnabledGlobalFilter.class)
public @interface ConditionalOnEnabledGlobalFilter {
/**
* The class component to check for.
* @return the class that must be enabled
*/
Class<? extends GlobalFilter> value() default OnEnabledGlobalFilter.DefaultValue.class;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2013-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.config.conditional;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.context.annotation.Conditional;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnEnabledPredicate.class)
public @interface ConditionalOnEnabledPredicate {
/**
* The class components to check for.
* @return the class that must be enabled
*/
Class<? extends RoutePredicateFactory<?>> value() default OnEnabledPredicate.DefaultValue.class;
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.Map;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import static org.springframework.boot.autoconfigure.condition.ConditionMessage.forCondition;
public abstract class OnEnabledComponent<T> extends SpringBootCondition
implements ConfigurationCondition {
private static final String PREFIX = "spring.cloud.gateway.";
private static final String SUFFIX = ".enabled";
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Class<? extends T> candidate = getEndpointType(annotationClass(), context,
metadata);
return determineOutcome(candidate, context.getEnvironment());
}
@SuppressWarnings("unchecked")
protected Class<? extends T> getEndpointType(Class<?> annotationClass,
ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata
.getAnnotationAttributes(annotationClass.getName());
if (attributes != null && attributes.containsKey("value")) {
Class<?> target = (Class<?>) attributes.get("value");
if (target != defaultValueClass()) {
return (Class<? extends T>) target;
}
}
Assert.state(
metadata instanceof MethodMetadata
&& metadata.isAnnotated(Bean.class.getName()),
getClass().getSimpleName()
+ " must be used on @Bean methods when the value is not specified");
MethodMetadata methodMetadata = (MethodMetadata) metadata;
try {
return (Class<? extends T>) ClassUtils.forName(
methodMetadata.getReturnTypeName(), context.getClassLoader());
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to extract endpoint id for "
+ methodMetadata.getDeclaringClassName() + "."
+ methodMetadata.getMethodName(), ex);
}
}
private ConditionOutcome determineOutcome(Class<? extends T> componentClass,
PropertyResolver resolver) {
String key = PREFIX + normalizeComponentName(componentClass) + SUFFIX;
ConditionMessage.Builder messageBuilder = forCondition(
annotationClass().getName(), componentClass.getName());
if ("false".equalsIgnoreCase(resolver.getProperty(key))) {
return ConditionOutcome
.noMatch(messageBuilder.because("bean is not available"));
}
return ConditionOutcome.match();
}
protected abstract String normalizeComponentName(Class<? extends T> componentClass);
protected abstract Class<?> annotationClass();
protected abstract Class<? extends T> defaultValueClass();
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2013-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.config.conditional;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory;
import org.springframework.cloud.gateway.support.NameUtils;
public class OnEnabledFilter extends OnEnabledComponent<GatewayFilterFactory<?>> {
@Override
protected String normalizeComponentName(
Class<? extends GatewayFilterFactory<?>> filterClass) {
if (SpringCloudCircuitBreakerFilterFactory.class.isAssignableFrom(filterClass)) {
return "filter." + NameUtils.normalizeToCanonicalPropertyFormat(
SpringCloudCircuitBreakerFilterFactory.NAME);
}
else {
return "filter."
+ NameUtils.normalizeFilterFactoryNameAsProperty(filterClass);
}
}
@Override
protected Class<?> annotationClass() {
return ConditionalOnEnabledFilter.class;
}
@Override
protected Class<? extends GatewayFilterFactory<?>> defaultValueClass() {
return DefaultValue.class;
}
static class DefaultValue implements GatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
throw new UnsupportedOperationException(
"class DefaultValue is never meant to be intantiated");
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2013-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.config.conditional;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.web.server.ServerWebExchange;
public class OnEnabledGlobalFilter extends OnEnabledComponent<GlobalFilter> {
@Override
protected String normalizeComponentName(Class<? extends GlobalFilter> filterClass) {
return "global-filter."
+ NameUtils.normalizeGlobalFilterNameAsProperty(filterClass);
}
@Override
protected Class<?> annotationClass() {
return ConditionalOnEnabledGlobalFilter.class;
}
@Override
protected Class<? extends GlobalFilter> defaultValueClass() {
return DefaultValue.class;
}
static class DefaultValue implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
throw new UnsupportedOperationException(
"class DefaultValue is never meant to be intantiated");
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.web.server.ServerWebExchange;
public class OnEnabledPredicate extends OnEnabledComponent<RoutePredicateFactory<?>> {
@Override
protected String normalizeComponentName(
Class<? extends RoutePredicateFactory<?>> predicateClass) {
return "predicate."
+ NameUtils.normalizeRoutePredicateNameAsProperty(predicateClass);
}
@Override
protected Class<?> annotationClass() {
return ConditionalOnEnabledPredicate.class;
}
@Override
protected Class<? extends RoutePredicateFactory<?>> defaultValueClass() {
return DefaultValue.class;
}
static class DefaultValue implements RoutePredicateFactory<Object> {
@Override
public Predicate<ServerWebExchange> apply(Consumer<Object> consumer) {
throw new UnsupportedOperationException(
"class DefaultValue is never meant to be intantiated");
}
@Override
public Predicate<ServerWebExchange> apply(Object config) {
throw new UnsupportedOperationException(
"class DefaultValue is never meant to be intantiated");
}
}
}

View File

@@ -28,7 +28,8 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.P
/**
* @author Spencer Gibb
*/
public class PreserveHostHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory {
public class PreserveHostHeaderGatewayFilterFactory
extends AbstractGatewayFilterFactory<Object> {
public GatewayFilter apply() {
return apply(o -> {

View File

@@ -35,7 +35,8 @@ import static org.springframework.cloud.gateway.support.GatewayToStringStyler.fi
*
* @author Greg Turnquist
*/
public class SaveSessionGatewayFilterFactory extends AbstractGatewayFilterFactory {
public class SaveSessionGatewayFilterFactory
extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {

View File

@@ -54,6 +54,9 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.r
public abstract class SpringCloudCircuitBreakerFilterFactory extends
AbstractGatewayFilterFactory<SpringCloudCircuitBreakerFilterFactory.Config> {
/** CircuitBreaker component name. */
public static final String NAME = "CircuitBreaker";
private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
private ReactiveCircuitBreaker cb;
@@ -148,7 +151,7 @@ public abstract class SpringCloudCircuitBreakerFilterFactory extends
@Override
public String name() {
return "CircuitBreaker";
return NAME;
}
public static class Config implements HasRouteId {

View File

@@ -17,145 +17,22 @@
package org.springframework.cloud.gateway.handler.predicate;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
/**
* Predicate that reads the body and applies a user provided predicate to run on the body.
* The body is cached in memory so that possible subsequent calls to the predicate do not
* need to deserialize again.
*/
public class ReadBodyPredicateFactory
extends AbstractRoutePredicateFactory<ReadBodyPredicateFactory.Config> {
protected static final Log log = LogFactory.getLog(ReadBodyPredicateFactory.class);
private static final String TEST_ATTRIBUTE = "read_body_predicate_test_attribute";
private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
private final List<HttpMessageReader<?>> messageReaders;
@Deprecated
public class ReadBodyPredicateFactory extends ReadBodyRoutePredicateFactory {
public ReadBodyPredicateFactory() {
super(Config.class);
this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
}
public ReadBodyPredicateFactory(List<HttpMessageReader<?>> messageReaders) {
super(Config.class);
this.messageReaders = messageReaders;
}
@Override
@SuppressWarnings("unchecked")
public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
return new AsyncPredicate<ServerWebExchange>() {
@Override
public Publisher<Boolean> apply(ServerWebExchange exchange) {
Class inClass = config.getInClass();
Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
Mono<?> modifiedBody;
// We can only read the body from the request once, once that happens if
// we try to read the body again an exception will be thrown. The below
// if/else caches the body object as a request attribute in the
// ServerWebExchange so if this filter is run more than once (due to more
// than one route using it) we do not try to read the request body
// multiple times
if (cachedBody != null) {
try {
boolean test = config.predicate.test(cachedBody);
exchange.getAttributes().put(TEST_ATTRIBUTE, test);
return Mono.just(test);
}
catch (ClassCastException e) {
if (log.isDebugEnabled()) {
log.debug("Predicate test failed because class in predicate "
+ "does not match the cached body object", e);
}
}
return Mono.just(false);
}
else {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
(serverHttpRequest) -> ServerRequest
.create(exchange.mutate().request(serverHttpRequest)
.build(), messageReaders)
.bodyToMono(inClass)
.doOnNext(objectValue -> exchange.getAttributes().put(
CACHE_REQUEST_BODY_OBJECT_KEY, objectValue))
.map(objectValue -> config.getPredicate()
.test(objectValue)));
}
}
@Override
public String toString() {
return String.format("ReadBody: %s", config.getInClass());
}
};
}
@Override
@SuppressWarnings("unchecked")
public Predicate<ServerWebExchange> apply(Config config) {
throw new UnsupportedOperationException(
"ReadBodyPredicateFactory is only async.");
}
public static class Config {
private Class inClass;
private Predicate predicate;
private Map<String, Object> hints;
public Class getInClass() {
return inClass;
}
public Config setInClass(Class inClass) {
this.inClass = inClass;
return this;
}
public Predicate getPredicate() {
return predicate;
}
public Config setPredicate(Predicate predicate) {
this.predicate = predicate;
return this;
}
public <T> Config setPredicate(Class<T> inClass, Predicate<T> predicate) {
setInClass(inClass);
this.predicate = predicate;
return this;
}
public Map<String, Object> getHints() {
return hints;
}
public Config setHints(Map<String, Object> hints) {
this.hints = hints;
return this;
}
super(messageReaders);
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright 2013-2020 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.handler.predicate;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
/**
* Predicate that reads the body and applies a user provided predicate to run on the body.
* The body is cached in memory so that possible subsequent calls to the predicate do not
* need to deserialize again.
*/
public class ReadBodyRoutePredicateFactory
extends AbstractRoutePredicateFactory<ReadBodyRoutePredicateFactory.Config> {
protected static final Log log = LogFactory
.getLog(ReadBodyRoutePredicateFactory.class);
private static final String TEST_ATTRIBUTE = "read_body_predicate_test_attribute";
private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
private final List<HttpMessageReader<?>> messageReaders;
public ReadBodyRoutePredicateFactory() {
super(Config.class);
this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
}
public ReadBodyRoutePredicateFactory(List<HttpMessageReader<?>> messageReaders) {
super(Config.class);
this.messageReaders = messageReaders;
}
@Override
@SuppressWarnings("unchecked")
public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
return new AsyncPredicate<ServerWebExchange>() {
@Override
public Publisher<Boolean> apply(ServerWebExchange exchange) {
Class inClass = config.getInClass();
Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
Mono<?> modifiedBody;
// We can only read the body from the request once, once that happens if
// we try to read the body again an exception will be thrown. The below
// if/else caches the body object as a request attribute in the
// ServerWebExchange so if this filter is run more than once (due to more
// than one route using it) we do not try to read the request body
// multiple times
if (cachedBody != null) {
try {
boolean test = config.predicate.test(cachedBody);
exchange.getAttributes().put(TEST_ATTRIBUTE, test);
return Mono.just(test);
}
catch (ClassCastException e) {
if (log.isDebugEnabled()) {
log.debug("Predicate test failed because class in predicate "
+ "does not match the cached body object", e);
}
}
return Mono.just(false);
}
else {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
(serverHttpRequest) -> ServerRequest
.create(exchange.mutate().request(serverHttpRequest)
.build(), messageReaders)
.bodyToMono(inClass)
.doOnNext(objectValue -> exchange.getAttributes().put(
CACHE_REQUEST_BODY_OBJECT_KEY, objectValue))
.map(objectValue -> config.getPredicate()
.test(objectValue)));
}
}
@Override
public String toString() {
return String.format("ReadBody: %s", config.getInClass());
}
};
}
@Override
@SuppressWarnings("unchecked")
public Predicate<ServerWebExchange> apply(Config config) {
throw new UnsupportedOperationException(
"ReadBodyPredicateFactory is only async.");
}
public static class Config {
private Class inClass;
private Predicate predicate;
private Map<String, Object> hints;
public Class getInClass() {
return inClass;
}
public Config setInClass(Class inClass) {
this.inClass = inClass;
return this;
}
public Predicate getPredicate() {
return predicate;
}
public Config setPredicate(Predicate predicate) {
this.predicate = predicate;
return this;
}
public <T> Config setPredicate(Class<T> inClass, Predicate<T> predicate) {
setInClass(inClass);
this.predicate = predicate;
return this;
}
public Map<String, Object> getHints() {
return hints;
}
public Config setHints(Map<String, Object> hints) {
this.hints = hints;
return this;
}
}
}

View File

@@ -75,7 +75,6 @@ import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataSize;
import org.springframework.web.server.ServerWebExchange;
@@ -386,7 +385,8 @@ public class GatewayFilterSpec extends UriSpec {
/**
* A filter that will set the Host header to
* {@param hostName} on the outgoing request
* {@param hostName} on the outgoing
* request.
* @param hostName the updated Host header value
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/

View File

@@ -33,7 +33,7 @@ import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFac
import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactory;
import org.springframework.cloud.gateway.route.Route;
@@ -72,7 +72,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate to check if a request was made after a specific {@link ZonedDateTime}
* A predicate to check if a request was made after a specific {@link ZonedDateTime}.
* @param datetime requests would only be routed after this {@link ZonedDateTime}
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -82,7 +82,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate to check if a request was made before a specific {@link ZonedDateTime}
* A predicate to check if a request was made before a specific {@link ZonedDateTime}.
* @param datetime requests will only be routed before this {@link ZonedDateTime}
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -92,7 +92,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate to check if a request was made between two {@link ZonedDateTime}s
* A predicate to check if a request was made between two {@link ZonedDateTime}s.
* @param datetime1 the request must have been made after this {@link ZonedDateTime}
* @param datetime2 the request must be made before this {@link ZonedDateTime}
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -103,7 +103,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if a cookie matches a given regular expression
* A predicate that checks if a cookie matches a given regular expression.
* @param name the name of the cookie
* @param regex the value of the cookies will be evaluated against this regular
* expression
@@ -115,7 +115,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if a given header is present on the request
* A predicate that checks if a given header is present on the request.
* @param header the header name to check
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -126,7 +126,7 @@ public class PredicateSpec extends UriSpec {
/**
* A predicate that checks if a given headers has a value which matches a regular
* expression
* expression.
* @param header the header name to check
* @param regex the regular expression to check against
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -137,7 +137,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the {@code host} header matches a given pattern
* A predicate that checks if the {@code host} header matches a given pattern.
* @param pattern the pattern to check against. The pattern is an Ant style pattern
* with {@code .} as a separator
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -148,7 +148,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the HTTP method matches
* A predicate that checks if the HTTP method matches.
* @param methods the name of the HTTP methods
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -161,7 +161,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the HTTP method matches
* A predicate that checks if the HTTP method matches.
* @param methods the HTTP methods
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -172,7 +172,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the path of the request matches the given pattern
* A predicate that checks if the path of the request matches the given pattern.
* @param patterns the pattern to check the path against. The pattern is a
* {@link org.springframework.util.PathMatcher} pattern
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -183,7 +183,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the path of the request matches the given pattern
* A predicate that checks if the path of the request matches the given pattern.
* @param pattern the pattern to check the path against. The pattern is a
* {@link org.springframework.util.PathMatcher} pattern
* @param matchOptionalTrailingSeparator set to false if you do not want this path to
@@ -198,7 +198,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if the path of the request matches the given pattern
* A predicate that checks if the path of the request matches the given pattern.
* @param patterns the pattern to check the path against. The pattern is a
* {@link org.springframework.util.PathMatcher} pattern
* @param matchOptionalTrailingSeparator set to false if you do not want this path to
@@ -220,12 +220,12 @@ public class PredicateSpec extends UriSpec {
* @return a {@link BooleanSpec} to be used to add logical operators
*/
public <T> BooleanSpec readBody(Class<T> inClass, Predicate<T> predicate) {
return asyncPredicate(getBean(ReadBodyPredicateFactory.class)
return asyncPredicate(getBean(ReadBodyRoutePredicateFactory.class)
.applyAsync(c -> c.setPredicate(inClass, predicate)));
}
/**
* A predicate that checks if a query parameter matches a regular expression
* A predicate that checks if a query parameter matches a regular expression.
* @param param the query parameter name
* @param regex the regular expression to evaluate the query parameter value against
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -236,7 +236,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate that checks if a given query parameter is present in the request URL
* A predicate that checks if a given query parameter is present in the request URL.
* @param param the query parameter name
* @return a {@link BooleanSpec} to be used to add logical operators
*/
@@ -286,7 +286,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate which will select a route based on its assigned weight. The
* A predicate which will select a route based on its assigned weight.
* @param group the group the route belongs to
* @param weight the weight for the route
* @return a {@link BooleanSpec} to be used to add logical operators
@@ -303,7 +303,7 @@ public class PredicateSpec extends UriSpec {
}
/**
* A predicate which is always true
* A predicate which is always true.
* @return a {@link BooleanSpec} to be used to add logical operators
*/
public BooleanSpec alwaysTrue() {

View File

@@ -28,7 +28,7 @@ import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Used to build a {@link RouteLocator}
* Used to build a {@link RouteLocator}.
*/
public class RouteLocatorBuilder {
@@ -39,15 +39,15 @@ public class RouteLocatorBuilder {
}
/**
* Creates a new {@link Builder}
* @return a new {@link Builder}
* Creates a new {@link Builder}.
* @return a new {@link Builder}.
*/
public Builder routes() {
return new Builder(context);
}
/**
* A class that can be used to construct routes and return a {@link RouteLocator}
* A class that can be used to construct routes and return a {@link RouteLocator}.
*/
public static class Builder {
@@ -60,7 +60,7 @@ public class RouteLocatorBuilder {
}
/**
* Creates a new {@link Route}
* Creates a new {@link Route}.
* @param id the unique id for the route
* @param fn a function which takes in a {@link PredicateSpec} and returns a
* {@link Route.AsyncBuilder}
@@ -73,7 +73,7 @@ public class RouteLocatorBuilder {
}
/**
* Creates a new {@link Route}
* Creates a new {@link Route}.
* @param fn a function which takes in a {@link PredicateSpec} and returns a
* {@link Route.AsyncBuilder}
* @return a {@link Builder}
@@ -85,7 +85,7 @@ public class RouteLocatorBuilder {
}
/**
* Builds and returns a {@link RouteLocator}
* Builds and returns a {@link RouteLocator}.
* @return a {@link RouteLocator}
*/
public RouteLocator build() {

View File

@@ -16,6 +16,10 @@
package org.springframework.cloud.gateway.support;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
@@ -33,6 +37,8 @@ public final class NameUtils {
*/
public static final String GENERATED_NAME_PREFIX = "_genkey_";
private static final Pattern NAME_PATTERN = Pattern.compile("([A-Z][a-z0-9]+)");
public static String generateName(int i) {
return GENERATED_NAME_PREFIX + i;
}
@@ -43,12 +49,48 @@ public final class NameUtils {
.replace(RoutePredicateFactory.class.getSimpleName(), ""));
}
public static String normalizeRoutePredicateNameAsProperty(
Class<? extends RoutePredicateFactory> clazz) {
return normalizeToCanonicalPropertyFormat(normalizeRoutePredicateName(clazz));
}
public static String normalizeFilterFactoryName(
Class<? extends GatewayFilterFactory> clazz) {
return removeGarbage(clazz.getSimpleName()
.replace(GatewayFilterFactory.class.getSimpleName(), ""));
}
public static String normalizeGlobalFilterName(Class<? extends GlobalFilter> clazz) {
return removeGarbage(
clazz.getSimpleName().replace(GlobalFilter.class.getSimpleName(), ""))
.replace("Filter", "");
}
public static String normalizeFilterFactoryNameAsProperty(
Class<? extends GatewayFilterFactory> clazz) {
return normalizeToCanonicalPropertyFormat(normalizeFilterFactoryName(clazz));
}
public static String normalizeGlobalFilterNameAsProperty(
Class<? extends GlobalFilter> filterClass) {
return normalizeToCanonicalPropertyFormat(normalizeGlobalFilterName(filterClass));
}
public static String normalizeToCanonicalPropertyFormat(String name) {
Matcher matcher = NAME_PATTERN.matcher(name);
StringBuffer stringBuffer = new StringBuffer();
while (matcher.find()) {
if (stringBuffer.length() != 0) {
matcher.appendReplacement(stringBuffer,
"-" + matcher.group(1).toLowerCase());
}
else {
matcher.appendReplacement(stringBuffer, matcher.group(1).toLowerCase());
}
}
return stringBuffer.toString();
}
private static String removeGarbage(String s) {
int garbageIdx = s.indexOf("$Mockito");
if (garbageIdx > 0) {

View File

@@ -1,5 +1,347 @@
{
"properties": [
{
"name": "spring.cloud.gateway.filter.add-request-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the add-request-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.map-request-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the map-request-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.add-request-parameter.enabled",
"type": "java.lang.Boolean",
"description": "Enables the add-request-parameter filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.add-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the add-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.modify-request-body.enabled",
"type": "java.lang.Boolean",
"description": "Enables the modify-request-body filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.dedupe-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the dedupe-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.modify-response-body.enabled",
"type": "java.lang.Boolean",
"description": "Enables the modify-response-body filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.prefix-path.enabled",
"type": "java.lang.Boolean",
"description": "Enables the prefix-path filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.preserve-host-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the preserve-host-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.redirect-to.enabled",
"type": "java.lang.Boolean",
"description": "Enables the redirect-to filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.remove-request-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the remove-request-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.remove-request-parameter.enabled",
"type": "java.lang.Boolean",
"description": "Enables the remove-request-parameter filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.remove-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the remove-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.request-rate-limiter.enabled",
"type": "java.lang.Boolean",
"description": "Enables the request-rate-limiter filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.rewrite-path.enabled",
"type": "java.lang.Boolean",
"description": "Enables the rewrite-path filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.retry.enabled",
"type": "java.lang.Boolean",
"description": "Enables the retry filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.set-path.enabled",
"type": "java.lang.Boolean",
"description": "Enables the set-path filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.secure-headers.enabled",
"type": "java.lang.Boolean",
"description": "Enables the secure-headers filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.set-request-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the set-request-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.set-request-host-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the set-request-host-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.set-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the set-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.rewrite-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the rewrite-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.rewrite-location-response-header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the rewrite-location-response-header filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.rewrite-location.enabled",
"type": "java.lang.Boolean",
"description": "Enables the rewrite-location filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.set-status.enabled",
"type": "java.lang.Boolean",
"description": "Enables the set-status filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.save-session.enabled",
"type": "java.lang.Boolean",
"description": "Enables the save-session filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.strip-prefix.enabled",
"type": "java.lang.Boolean",
"description": "Enables the strip-prefix filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.request-header-to-request-uri.enabled",
"type": "java.lang.Boolean",
"description": "Enables the request-header-to-request-uri filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.request-size.enabled",
"type": "java.lang.Boolean",
"description": "Enables the request-size filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.request-header-size.enabled",
"type": "java.lang.Boolean",
"description": "Enables the request-header-size filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.circuit-breaker.enabled",
"type": "java.lang.Boolean",
"description": "Enables the circuit-breaker filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.hystrix.enabled",
"type": "java.lang.Boolean",
"description": "Enables the hystrix filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.filter.fallback-headers.enabled",
"type": "java.lang.Boolean",
"description": "Enables the fallback-headers filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.adapt-cached-body.enabled",
"type": "java.lang.Boolean",
"description": "Enables the adapt-cached-body global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.remove-cached-body.enabled",
"type": "java.lang.Boolean",
"description": "Enables the remove-cached-body global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.route-to-request-url.enabled",
"type": "java.lang.Boolean",
"description": "Enables the route-to-request-url global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.forward-routing.enabled",
"type": "java.lang.Boolean",
"description": "Enables the forward-routing global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.forward-path.enabled",
"type": "java.lang.Boolean",
"description": "Enables the forward-path global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.websocket-routing.enabled",
"type": "java.lang.Boolean",
"description": "Enables the websocket-routing global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.netty-write-response.enabled",
"type": "java.lang.Boolean",
"description": "Enables the netty-write-response global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.netty-routing.enabled",
"type": "java.lang.Boolean",
"description": "Enables the netty-routing global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.reactive-load-balancer.enabled",
"type": "java.lang.Boolean",
"description": "Enables the reactive-loadbalancer global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.load-balancer-client.enabled",
"type": "java.lang.Boolean",
"description": "Enables the load-balancer-client global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.global-filter.metrics.enabled",
"type": "java.lang.Boolean",
"description": "Enables the metrics global filter.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.after.enabled",
"type": "java.lang.Boolean",
"description": "Enables the after predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.before.enabled",
"type": "java.lang.Boolean",
"description": "Enables the before predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.between.enabled",
"type": "java.lang.Boolean",
"description": "Enables the between predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.cookie.enabled",
"type": "java.lang.Boolean",
"description": "Enables the cookie predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.header.enabled",
"type": "java.lang.Boolean",
"description": "Enables the header predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.host.enabled",
"type": "java.lang.Boolean",
"description": "Enables the host predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.method.enabled",
"type": "java.lang.Boolean",
"description": "Enables the method predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.path.enabled",
"type": "java.lang.Boolean",
"description": "Enables the path predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.query.enabled",
"type": "java.lang.Boolean",
"description": "Enables the query predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.read-body.enabled",
"type": "java.lang.Boolean",
"description": "Enables the read-body predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.remote-addr.enabled",
"type": "java.lang.Boolean",
"description": "Enables the remote-addr predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.weight.enabled",
"type": "java.lang.Boolean",
"description": "Enables the weight predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.predicate.cloud-foundry-route-service.enabled",
"type": "java.lang.Boolean",
"description": "Enables the cloud-foundry-route-service predicate.",
"defaultValue": "true"
},
{
"name": "spring.cloud.gateway.enabled",
"type": "java.lang.Boolean",

View File

@@ -0,0 +1,128 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.List;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
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.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(Enclosed.class)
public class DisableBuiltInFiltersTests {
@EnableAutoConfiguration
@SpringBootConfiguration
protected static class Config {
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class)
public static class FilterDefault {
@Autowired
private List<GatewayFilterFactory<?>> gatewayFilters;
@Test
public void shouldInjectBuiltInFilters() {
assertThat(gatewayFilters).hasSizeGreaterThanOrEqualTo(31);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class,
properties = { "spring.cloud.gateway.filter.add-request-header.enabled=false",
"spring.cloud.gateway.filter.map-request-header.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableSpecificsFiltersByProperty {
@Autowired
private List<GatewayFilterFactory<?>> gatewayFilters;
@Test
public void shouldInjectOnlyEnabledBuiltInFilters() {
assertThat(gatewayFilters).hasSizeGreaterThan(0);
assertThat(gatewayFilters).allSatisfy(filter -> assertThat(filter)
.isNotInstanceOfAny(AddRequestHeaderGatewayFilterFactory.class,
MapRequestHeaderGatewayFilterFactory.class));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class, properties = {
"spring.cloud.gateway.filter.add-request-header.enabled=false",
"spring.cloud.gateway.filter.map-request-header.enabled=false",
"spring.cloud.gateway.filter.add-request-parameter.enabled=false",
"spring.cloud.gateway.filter.add-response-header.enabled=false",
"spring.cloud.gateway.filter.modify-request-body.enabled=false",
"spring.cloud.gateway.filter.dedupe-response-header.enabled=false",
"spring.cloud.gateway.filter.modify-response-body.enabled=false",
"spring.cloud.gateway.filter.prefix-path.enabled=false",
"spring.cloud.gateway.filter.preserve-host-header.enabled=false",
"spring.cloud.gateway.filter.redirect-to.enabled=false",
"spring.cloud.gateway.filter.remove-request-header.enabled=false",
"spring.cloud.gateway.filter.remove-request-parameter.enabled=false",
"spring.cloud.gateway.filter.remove-response-header.enabled=false",
"spring.cloud.gateway.filter.request-rate-limiter.enabled=false",
"spring.cloud.gateway.filter.rewrite-path.enabled=false",
"spring.cloud.gateway.filter.retry.enabled=false",
"spring.cloud.gateway.filter.set-path.enabled=false",
"spring.cloud.gateway.filter.secure-headers.enabled=false",
"spring.cloud.gateway.filter.set-request-header.enabled=false",
"spring.cloud.gateway.filter.set-request-host-header.enabled=false",
"spring.cloud.gateway.filter.set-response-header.enabled=false",
"spring.cloud.gateway.filter.rewrite-response-header.enabled=false",
"spring.cloud.gateway.filter.rewrite-location-response-header.enabled=false",
"spring.cloud.gateway.filter.rewrite-location.enabled=false",
"spring.cloud.gateway.filter.set-status.enabled=false",
"spring.cloud.gateway.filter.save-session.enabled=false",
"spring.cloud.gateway.filter.strip-prefix.enabled=false",
"spring.cloud.gateway.filter.request-header-to-request-uri.enabled=false",
"spring.cloud.gateway.filter.request-size.enabled=false",
"spring.cloud.gateway.filter.request-header-size.enabled=false",
"spring.cloud.gateway.filter.circuit-breaker.enabled=false",
"spring.cloud.gateway.filter.hystrix.enabled=false",
"spring.cloud.gateway.filter.fallback-headers.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableAllFiltersByProperty {
@Autowired(required = false)
private List<GatewayFilterFactory<?>> gatewayFilters;
@Test
public void shouldDisableAllBuiltInFilters() {
assertThat(gatewayFilters).isNull();
}
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.List;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
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.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter;
import org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(Enclosed.class)
public class DisableBuiltInGlobalFiltersTests {
@EnableAutoConfiguration
@SpringBootConfiguration
protected static class Config {
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class)
public static class GlobalFilterDefault {
@Autowired
private List<GlobalFilter> globalFilters;
@Test
public void shouldInjectBuiltInFilters() {
assertThat(globalFilters).hasSizeGreaterThanOrEqualTo(10);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class, properties = {
"spring.cloud.gateway.global-filter.remove-cached-body.enabled=false",
"spring.cloud.gateway.global-filter.route-to-request-url.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableSpecificsFiltersByProperty {
@Autowired
private List<GlobalFilter> globalFilters;
@Test
public void shouldInjectOnlyEnabledBuiltInFilters() {
assertThat(globalFilters).hasSizeGreaterThan(0);
assertThat(globalFilters)
.allSatisfy(filter -> assertThat(filter).isNotInstanceOfAny(
RemoveCachedBodyFilter.class, RouteToRequestUrlFilter.class));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class, properties = {
"spring.cloud.gateway.global-filter.adapt-cached-body.enabled=false",
"spring.cloud.gateway.global-filter.remove-cached-body.enabled=false",
"spring.cloud.gateway.global-filter.route-to-request-url.enabled=false",
"spring.cloud.gateway.global-filter.forward-routing.enabled=false",
"spring.cloud.gateway.global-filter.forward-path.enabled=false",
"spring.cloud.gateway.global-filter.websocket-routing.enabled=false",
"spring.cloud.gateway.global-filter.netty-write-response.enabled=false",
"spring.cloud.gateway.global-filter.netty-routing.enabled=false",
"spring.cloud.gateway.global-filter.reactive-load-balancer.enabled=false",
"spring.cloud.gateway.global-filter.load-balancer-client.enabled=false",
// FIXME:
"spring.cloud.gateway.metrics.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableAllGlobalFiltersByProperty {
@Autowired(required = false)
private List<GlobalFilter> globalFilters;
@Test
public void shouldDisableAllBuiltInFilters() {
assertThat(globalFilters).isNull();
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.List;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
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.cloud.gateway.handler.predicate.AfterRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(Enclosed.class)
public class DisableBuiltInPredicatesTests {
@EnableAutoConfiguration
@SpringBootConfiguration
protected static class Config {
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class)
public static class RoutePredicateDefault {
@Autowired
private List<RoutePredicateFactory<?>> predicates;
@Test
public void shouldInjectBuiltInPredicates() {
assertThat(predicates).hasSizeGreaterThanOrEqualTo(13);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class,
properties = { "spring.cloud.gateway.predicate.after.enabled=false",
"spring.cloud.gateway.predicate.before.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableSpecificsPredicatesByProperty {
@Autowired
private List<RoutePredicateFactory<?>> predicates;
@Test
public void shouldInjectOnlyEnabledBuiltInPredicates() {
assertThat(predicates).hasSizeGreaterThan(0);
assertThat(predicates).allSatisfy(filter -> assertThat(filter)
.isNotInstanceOfAny(AfterRoutePredicateFactory.class,
BeforeRoutePredicateFactory.class));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Config.class, properties = {
"spring.cloud.gateway.predicate.after.enabled=false",
"spring.cloud.gateway.predicate.before.enabled=false",
"spring.cloud.gateway.predicate.between.enabled=false",
"spring.cloud.gateway.predicate.cookie.enabled=false",
"spring.cloud.gateway.predicate.header.enabled=false",
"spring.cloud.gateway.predicate.host.enabled=false",
"spring.cloud.gateway.predicate.method.enabled=false",
"spring.cloud.gateway.predicate.path.enabled=false",
"spring.cloud.gateway.predicate.query.enabled=false",
"spring.cloud.gateway.predicate.read-body.enabled=false",
"spring.cloud.gateway.predicate.remote-addr.enabled=false",
"spring.cloud.gateway.predicate.weight.enabled=false",
"spring.cloud.gateway.predicate.cloud-foundry-route-service.enabled=false" })
@ActiveProfiles("disable-components")
public static class DisableAllPredicatesByProperty {
@Autowired(required = false)
private List<RoutePredicateFactory<?>> predicates;
@Test
public void shouldDisableAllBuiltInPredicates() {
assertThat(predicates).isNull();
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class OnEnabledComponentTests {
private OnEnabledComponent<Object> onEnabledComponent;
private MockEnvironment environment;
private ConditionContext conditionContext;
@BeforeEach
void setUp() {
this.onEnabledComponent = createOnEnabledComponent("test-class");
this.environment = new MockEnvironment();
this.conditionContext = mock(ConditionContext.class);
}
@Test
public void shouldMatchComponent() {
when(conditionContext.getEnvironment()).thenReturn(environment);
ConditionOutcome outcome = onEnabledComponent.getMatchOutcome(conditionContext,
mockMetaData(EnabledComponent.class));
assertThat(outcome.isMatch()).isTrue();
}
@Test
public void shouldNotMatchDisabledComponent() {
String componentName = "disabled-component";
this.onEnabledComponent = createOnEnabledComponent(componentName);
when(conditionContext.getEnvironment()).thenReturn(environment);
environment.setProperty("spring.cloud.gateway." + componentName + ".enabled",
"false");
ConditionOutcome outcome = onEnabledComponent.getMatchOutcome(conditionContext,
mockMetaData(DisabledComponent.class));
assertThat(outcome.isMatch()).isFalse();
assertThat(outcome.getMessage()).contains("DisabledComponent")
.contains("bean is not available");
}
private AnnotatedTypeMetadata mockMetaData(Class<?> value) {
AnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);
when(metadata
.getAnnotationAttributes(eq(ConditionalOnEnabledFilter.class.getName())))
.thenReturn(Collections.singletonMap("value", value));
return metadata;
}
private OnEnabledComponent<Object> createOnEnabledComponent(String componentName) {
return new OnEnabledComponent<Object>() {
@Override
protected String normalizeComponentName(Class<?> componentClass) {
return componentName;
}
@Override
protected Class<?> annotationClass() {
return ConditionalOnEnabledFilter.class;
}
@Override
protected Class<?> defaultValueClass() {
return Object.class;
}
};
}
protected static class EnabledComponent {
}
protected static class DisabledComponent {
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerResilience4JFilterFactory;
import static org.assertj.core.api.Assertions.assertThat;
class OnEnabledFilterTests {
private OnEnabledFilter onEnabledFilter;
@BeforeEach
void setUp() {
this.onEnabledFilter = new OnEnabledFilter();
}
@Test
void shouldNormalizeFiltersNames() {
List<Class<? extends GatewayFilterFactory<?>>> predicates = Arrays.asList(
AddRequestHeaderGatewayFilterFactory.class,
DedupeResponseHeaderGatewayFilterFactory.class,
FallbackHeadersGatewayFilterFactory.class,
HystrixGatewayFilterFactory.class,
MapRequestHeaderGatewayFilterFactory.class,
SpringCloudCircuitBreakerResilience4JFilterFactory.class);
List<String> resultNames = predicates.stream()
.map(onEnabledFilter::normalizeComponentName)
.collect(Collectors.toList());
List<String> expectedNames = Stream
.of("add-request-header", "dedupe-response-header", "fallback-headers",
"hystrix", "map-request-header", "circuit-breaker")
.map(s -> "filter." + s).collect(Collectors.toList());
assertThat(resultNames).isEqualTo(expectedNames);
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter;
import org.springframework.cloud.gateway.filter.ForwardPathFilter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;
import static org.assertj.core.api.Assertions.assertThat;
class OnEnabledGlobalFilterTests {
private OnEnabledGlobalFilter onEnabledGlobalFilter;
@BeforeEach
void setUp() {
this.onEnabledGlobalFilter = new OnEnabledGlobalFilter();
}
@Test
void shouldNormalizeGlobalFiltersNames() {
List<Class<? extends GlobalFilter>> predicates = Arrays.asList(
ForwardPathFilter.class, AdaptCachedBodyGlobalFilter.class,
WebsocketRoutingFilter.class);
List<String> resultNames = predicates.stream()
.map(onEnabledGlobalFilter::normalizeComponentName)
.collect(Collectors.toList());
List<String> expectedNames = Stream
.of("forward-path", "adapt-cached-body", "websocket-routing")
.map(s -> "global-filter." + s).collect(Collectors.toList());
assertThat(resultNames).isEqualTo(expectedNames);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2013-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.config.conditional;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.CloudFoundryRouteServiceRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import static org.assertj.core.api.Assertions.assertThat;
class OnEnabledPredicateTests {
private OnEnabledPredicate onEnabledPredicate;
@BeforeEach
void setUp() {
this.onEnabledPredicate = new OnEnabledPredicate();
}
@Test
void shouldNormalizePredicatesNames() {
List<Class<? extends RoutePredicateFactory<?>>> predicates = Arrays.asList(
AfterRoutePredicateFactory.class,
CloudFoundryRouteServiceRoutePredicateFactory.class,
ReadBodyRoutePredicateFactory.class,
RemoteAddrRoutePredicateFactory.class);
List<String> resultNames = predicates.stream()
.map(onEnabledPredicate::normalizeComponentName)
.collect(Collectors.toList());
List<String> expectedNames = Stream
.of("after", "cloud-foundry-route-service", "read-body", "remote-addr")
.map(s -> "predicate." + s).collect(Collectors.toList());
assertThat(resultNames).isEqualTo(expectedNames);
}
}

View File

@@ -29,7 +29,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory.Config;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory.Config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.test.PermitAllSecurityConfiguration;
@@ -58,7 +58,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@DirtiesContext
public class ReadBodyPredicateFactoryTest {
public class ReadBodyRoutePredicateFactoryTests {
@Autowired
private WebTestClient webClient;

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2013-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.support;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter;
import org.springframework.cloud.gateway.filter.ForwardPathFilter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.CloudFoundryRouteServiceRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import static org.assertj.core.api.Assertions.assertThat;
class NameUtilsTests {
@Test
void shouldNormalizePredicatesNames() {
List<Class<? extends RoutePredicateFactory<?>>> predicates = Arrays.asList(
AfterRoutePredicateFactory.class,
CloudFoundryRouteServiceRoutePredicateFactory.class,
ReadBodyRoutePredicateFactory.class,
RemoteAddrRoutePredicateFactory.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeRoutePredicateName).collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("After", "CloudFoundryRouteService",
"ReadBody", "RemoteAddr");
assertThat(resultNames).isEqualTo(expectedNames);
}
@Test
void shouldNormalizePredicatesNamesAsProperties() {
List<Class<? extends RoutePredicateFactory<?>>> predicates = Arrays.asList(
AfterRoutePredicateFactory.class,
CloudFoundryRouteServiceRoutePredicateFactory.class,
ReadBodyRoutePredicateFactory.class,
RemoteAddrRoutePredicateFactory.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeRoutePredicateNameAsProperty)
.collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("after", "cloud-foundry-route-service",
"read-body", "remote-addr");
assertThat(resultNames).isEqualTo(expectedNames);
}
@Test
void shouldNormalizeFiltersNames() {
List<Class<? extends GatewayFilterFactory<?>>> predicates = Arrays.asList(
AddRequestHeaderGatewayFilterFactory.class,
DedupeResponseHeaderGatewayFilterFactory.class,
FallbackHeadersGatewayFilterFactory.class,
HystrixGatewayFilterFactory.class,
MapRequestHeaderGatewayFilterFactory.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeFilterFactoryName).collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("AddRequestHeader",
"DedupeResponseHeader", "FallbackHeaders", "Hystrix", "MapRequestHeader");
assertThat(resultNames).isEqualTo(expectedNames);
}
@Test
void shouldNormalizeFiltersNamesAsProperties() {
List<Class<? extends GatewayFilterFactory<?>>> predicates = Arrays.asList(
AddRequestHeaderGatewayFilterFactory.class,
DedupeResponseHeaderGatewayFilterFactory.class,
FallbackHeadersGatewayFilterFactory.class,
HystrixGatewayFilterFactory.class,
MapRequestHeaderGatewayFilterFactory.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeFilterFactoryNameAsProperty)
.collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("add-request-header",
"dedupe-response-header", "fallback-headers", "hystrix",
"map-request-header");
assertThat(resultNames).isEqualTo(expectedNames);
}
@Test
void shouldNormalizeGlobalFiltersNames() {
List<Class<? extends GlobalFilter>> predicates = Arrays.asList(
ForwardPathFilter.class, AdaptCachedBodyGlobalFilter.class,
WebsocketRoutingFilter.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeGlobalFilterName).collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("ForwardPath", "AdaptCachedBody",
"WebsocketRouting");
assertThat(resultNames).isEqualTo(expectedNames);
}
@Test
void shouldNormalizeGlobalFiltersNamesAsProperties() {
List<Class<? extends GlobalFilter>> predicates = Arrays.asList(
ForwardPathFilter.class, AdaptCachedBodyGlobalFilter.class,
WebsocketRoutingFilter.class);
List<String> resultNames = predicates.stream()
.map(NameUtils::normalizeGlobalFilterNameAsProperty)
.collect(Collectors.toList());
List<String> expectedNames = Arrays.asList("forward-path", "adapt-cached-body",
"websocket-routing");
assertThat(resultNames).isEqualTo(expectedNames);
}
}

View File

@@ -51,7 +51,7 @@ import static org.junit.Assume.assumeThat;
org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicateFactoryTests.class,
org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactoryTests.class,
org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactoryTests.class,
org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactoryTest.class,
org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactoryTests.class,
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactoryTests.class,
org.springframework.cloud.gateway.handler.predicate.CloudFoundryRouteServiceRoutePredicateFactoryTest.class,
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMappingTests.class,

View File

@@ -0,0 +1,26 @@
server:
error:
include-message: always
spring:
profiles:
include: logging
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
maxAge: 10
allowedOrigins: "*"
allowedMethods:
- GET
default-filters:
#empty to prevent failures in tests disabling components
routes:
#empty to prevent failures in tests disabling components
management:
endpoints:
web:
exposure:
include: "*"