From 3bf194dad9e1dde59a9ffc2f74d9dc8d7f764e2a Mon Sep 17 00:00:00 2001 From: qnnn <65326092+qnnn@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:55:47 +0800 Subject: [PATCH 01/85] ensure generateId executes on the scheduler thread specified by publishOn. Signed-off-by: qnnn <65326092+qnnn@users.noreply.github.com> --- .../cloud/gateway/route/CompositeRouteDefinitionLocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java index 8e54feb1..db116fa7 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java @@ -65,7 +65,7 @@ public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator { } protected Mono randomId() { - return Mono.fromSupplier(idGenerator::generateId).map(UUID::toString).publishOn(Schedulers.boundedElastic()); + return Mono.fromSupplier(idGenerator::generateId).publishOn(Schedulers.boundedElastic()).map(UUID::toString); } } From 73662ea35d403ca12824a73651155c8a890afdc3 Mon Sep 17 00:00:00 2001 From: BEF841CA <83743162+BEF841CA@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:10:03 +0800 Subject: [PATCH 02/85] Fix punctuation error in secureheaders-factory.adoc Signed-off-by: BEF841CA <83743162+BEF841CA@users.noreply.github.com> --- .../gatewayfilter-factories/secureheaders-factory.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc index 84254642..585668ec 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc @@ -10,7 +10,7 @@ The following headers (shown with their default values) are added: * `X-Frame-Options (DENY)` * `X-Content-Type-Options (nosniff)` * `Referrer-Policy (no-referrer)` -* `Content-Security-Policy (default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline)'` +* `Content-Security-Policy (default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline')` * `X-Download-Options (noopen)` * `X-Permitted-Cross-Domain-Policies (none)` From b0003e8f098c873226d351bc97cb86fb971eb8b7 Mon Sep 17 00:00:00 2001 From: myasinkaji Date: Fri, 21 Mar 2025 17:56:25 +0330 Subject: [PATCH 03/85] prevent NullPointerException when pattern is null Signed-off-by: myasinkaji --- .../server/mvc/predicate/GatewayRequestPredicates.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java index 68f54b73..c25671da 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java @@ -272,7 +272,12 @@ public abstract class GatewayRequestPredicates { @Override public void accept(RequestPredicates.Visitor visitor) { - visitor.header(name, pattern.pattern()); + if (pattern != null) { + visitor.header(name, pattern.pattern()); + } + else { + visitor.header(name, ""); + } } @Override From a2866f99f500b1e71f73a11a6e199b925b4d090c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:04:58 +0000 Subject: [PATCH 04/85] Bump @springio/asciidoctor-extensions in /docs Bumps [@springio/asciidoctor-extensions](https://github.com/spring-io/asciidoctor-extensions) from 1.0.0-alpha.16 to 1.0.0-alpha.17. - [Changelog](https://github.com/spring-io/asciidoctor-extensions/blob/main/CHANGELOG.adoc) - [Commits](https://github.com/spring-io/asciidoctor-extensions/compare/v1.0.0-alpha.16...v1.0.0-alpha.17) --- updated-dependencies: - dependency-name: "@springio/asciidoctor-extensions" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6c97a4cc..1e4c440b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,6 @@ "@antora/collector-extension": "1.0.1", "@asciidoctor/tabs": "1.0.0-beta.6", "@springio/antora-extensions": "1.14.4", - "@springio/asciidoctor-extensions": "1.0.0-alpha.16" + "@springio/asciidoctor-extensions": "1.0.0-alpha.17" } } From dc0fcefcd640b544d773f81772dcd58acd4a40ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:34:57 +0000 Subject: [PATCH 05/85] Bump @springio/asciidoctor-extensions in /docs Bumps [@springio/asciidoctor-extensions](https://github.com/spring-io/asciidoctor-extensions) from 1.0.0-alpha.16 to 1.0.0-alpha.17. - [Changelog](https://github.com/spring-io/asciidoctor-extensions/blob/main/CHANGELOG.adoc) - [Commits](https://github.com/spring-io/asciidoctor-extensions/compare/v1.0.0-alpha.16...v1.0.0-alpha.17) --- updated-dependencies: - dependency-name: "@springio/asciidoctor-extensions" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6c97a4cc..1e4c440b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,6 @@ "@antora/collector-extension": "1.0.1", "@asciidoctor/tabs": "1.0.0-beta.6", "@springio/antora-extensions": "1.14.4", - "@springio/asciidoctor-extensions": "1.0.0-alpha.16" + "@springio/asciidoctor-extensions": "1.0.0-alpha.17" } } From d0c070c37d2d768e062c8b4b004b18a3f2efd5be Mon Sep 17 00:00:00 2001 From: lucky8987 Date: Wed, 26 Mar 2025 23:07:02 +0800 Subject: [PATCH 06/85] Clean up the code to make it cleaner Signed-off-by: longtanfei --- spring-cloud-gateway-server/pom.xml | 5 ----- .../cloud/gateway/handler/AsyncPredicate.java | 3 +-- .../handler/predicate/CookieRoutePredicateFactory.java | 7 +------ .../gateway/handler/predicate/GatewayPredicate.java | 7 +++---- .../gateway/route/RouteDefinitionRouteLocator.java | 10 +++------- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 2a61283f..a13b407a 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -212,11 +212,6 @@ spring-cloud-test-support test - - org.springframework.cloud - spring-cloud-starter-stream-rabbit - test - io.projectreactor reactor-test diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java index e15694eb..60277232 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java @@ -77,8 +77,7 @@ public interface AsyncPredicate extends Function>, HasC @Override public void accept(Visitor visitor) { - if (delegate instanceof GatewayPredicate) { - GatewayPredicate gatewayPredicate = (GatewayPredicate) delegate; + if (delegate instanceof GatewayPredicate gatewayPredicate) { gatewayPredicate.accept(visitor); } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java index 0f017025..ded55566 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java @@ -58,12 +58,7 @@ public class CookieRoutePredicateFactory extends AbstractRoutePredicateFactory cookie.getValue().matches(config.regexp)); } @Override diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java index c373296a..40001870 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java @@ -47,8 +47,8 @@ public interface GatewayPredicate extends Predicate, HasConfi static GatewayPredicate wrapIfNeeded(Predicate other) { GatewayPredicate right; - if (other instanceof GatewayPredicate) { - right = (GatewayPredicate) other; + if (other instanceof GatewayPredicate gatewayPredicate) { + right = gatewayPredicate; } else { right = new GatewayPredicateWrapper(other); @@ -72,8 +72,7 @@ public interface GatewayPredicate extends Predicate, HasConfi @Override public void accept(Visitor visitor) { - if (delegate instanceof GatewayPredicate) { - GatewayPredicate gatewayPredicate = (GatewayPredicate) delegate; + if (delegate instanceof GatewayPredicate gatewayPredicate) { gatewayPredicate.accept(visitor); } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java index fce1faee..c8545c68 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java @@ -201,14 +201,10 @@ public class RouteDefinitionRouteLocator implements RouteLocator { // this is a very rare case, but possible, just match all return AsyncPredicate.from(exchange -> true); } - AsyncPredicate predicate = lookup(routeDefinition, predicates.get(0)); - for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { - AsyncPredicate found = lookup(routeDefinition, andPredicate); - predicate = predicate.and(found); - } - - return predicate; + return predicates.stream() + .map(nextPredicate -> lookup(routeDefinition, nextPredicate)) + .reduce(AsyncPredicate.from(exchange -> true), AsyncPredicate::and); } @SuppressWarnings("unchecked") From 92415d15159057004723c1081af89256006ecc00 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 15:53:15 +0000 Subject: [PATCH 07/85] Update SNAPSHOT to 4.1.7 --- docs/pom.xml | 2 +- pom.xml | 8 ++++---- spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 0fed8431..c973f753 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 353ccff7..8eb30ef0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.6-SNAPSHOT + 4.1.5 @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.5-SNAPSHOT - 4.1.6-SNAPSHOT + 3.1.4 + 4.1.5 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 198369ec..27772287 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.1.6-SNAPSHOT + 4.1.5 spring-cloud-gateway-dependencies - 4.1.7-SNAPSHOT + 4.1.7 pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 5df23c4d..8777f39d 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index f74bfb93..71d55cef 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index db507feb..b5fb772d 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 121e9019..ee352b2e 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 6141755d..192c624d 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 2f7b6297..61b38788 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 9ecf0a73..feea1dd8 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 52a624d7..ee5f9810 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 2c529a28..60a29490 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index ccfa5c5f..e5df0de4 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 614e9dd5..032cb65f 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.7 .. spring-cloud-starter-gateway From 8f2f435baff5be7a7b2a5ef1a56b04e7c51b0db9 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 15:55:41 +0000 Subject: [PATCH 08/85] Going back to snapshots --- docs/pom.xml | 2 +- pom.xml | 8 ++++---- spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index c973f753..0fed8431 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 8eb30ef0..353ccff7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.5 + 4.1.6-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.4 - 4.1.5 + 3.1.5-SNAPSHOT + 4.1.6-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 27772287..198369ec 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.1.5 + 4.1.6-SNAPSHOT spring-cloud-gateway-dependencies - 4.1.7 + 4.1.7-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 8777f39d..5df23c4d 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 71d55cef..f74bfb93 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index b5fb772d..db507feb 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index ee352b2e..121e9019 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 192c624d..6141755d 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 61b38788..2f7b6297 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index feea1dd8..9ecf0a73 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index ee5f9810..52a624d7 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 60a29490..2c529a28 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e5df0de4..ccfa5c5f 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 032cb65f..614e9dd5 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7 + 4.1.7-SNAPSHOT .. spring-cloud-starter-gateway From 164d6a4d2a581086659741342e4a3571e0f25caa Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 15:55:42 +0000 Subject: [PATCH 09/85] Bumping versions to 4.1.8-SNAPSHOT after release --- docs/pom.xml | 2 +- pom.xml | 2 +- spring-cloud-gateway-dependencies/pom.xml | 2 +- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 0fed8431..6a82d9f3 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 353ccff7..178f6972 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT pom Spring Cloud Gateway diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 198369ec..3b4ad82e 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -11,7 +11,7 @@ spring-cloud-gateway-dependencies - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 5df23c4d..c8aad0bf 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index f74bfb93..0dcf83d0 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index db507feb..8c679b46 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 121e9019..8fc43a9b 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 6141755d..4b87b3db 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 2f7b6297..1bf2a253 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 9ecf0a73..a5b7bd44 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 52a624d7..72dbd3d9 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 2c529a28..b4402605 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index ccfa5c5f..83a6ea16 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 614e9dd5..04911c29 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.8-SNAPSHOT .. spring-cloud-starter-gateway From f69de10b9e9ce2573607f1bfb7da99d2581fa9e6 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 16:37:02 +0000 Subject: [PATCH 10/85] Update SNAPSHOT to 4.2.2 --- docs/pom.xml | 2 +- pom.xml | 8 ++++---- spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 6819860b..e445f8e3 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index b493fc0f..373ee80d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.2.2-SNAPSHOT + 4.2.1 @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 2.3.0 - 3.2.2-SNAPSHOT - 4.2.2-SNAPSHOT + 3.2.1 + 4.2.1 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index d1da19ac..8dfbc7fb 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.2.2-SNAPSHOT + 4.2.1 spring-cloud-gateway-dependencies - 4.2.2-SNAPSHOT + 4.2.2 pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 7cad9cdc..bbd015e0 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 6e53c34a..ac5b2266 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 05b46aa5..3e0be111 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index d8b10218..8a1c2dea 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 7a38b262..430b34c2 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 135316d2..55b4c6f8 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 2c725c88..9f6ea0ef 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 8abe6b8e..173ebcff 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 901ed835..aa9cea82 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index d5e924ae..a34c7534 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 572ce693..2f2be0e0 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.2 .. spring-cloud-starter-gateway From c476c92c742e51bac07e97a49f81f62de0b77c03 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 16:39:26 +0000 Subject: [PATCH 11/85] Going back to snapshots --- docs/pom.xml | 2 +- pom.xml | 8 ++++---- spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index e445f8e3..6819860b 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 373ee80d..b493fc0f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.2.1 + 4.2.2-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 2.3.0 - 3.2.1 - 4.2.1 + 3.2.2-SNAPSHOT + 4.2.2-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 8dfbc7fb..d1da19ac 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.2.1 + 4.2.2-SNAPSHOT spring-cloud-gateway-dependencies - 4.2.2 + 4.2.2-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index bbd015e0..7cad9cdc 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index ac5b2266..6e53c34a 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 3e0be111..05b46aa5 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 8a1c2dea..d8b10218 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 430b34c2..7a38b262 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 55b4c6f8..135316d2 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 9f6ea0ef..2c725c88 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 173ebcff..8abe6b8e 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index aa9cea82..901ed835 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index a34c7534..d5e924ae 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 2f2be0e0..572ce693 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2 + 4.2.2-SNAPSHOT .. spring-cloud-starter-gateway From ac8f12573fa1b1afa90837d492b31d4bcb943931 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 3 Apr 2025 16:39:27 +0000 Subject: [PATCH 12/85] Bumping versions to 4.2.3-SNAPSHOT after release --- docs/pom.xml | 2 +- pom.xml | 2 +- spring-cloud-gateway-dependencies/pom.xml | 2 +- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 6819860b..290edbb0 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index b493fc0f..d1835c2d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT pom Spring Cloud Gateway diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index d1da19ac..5adb57f7 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -11,7 +11,7 @@ spring-cloud-gateway-dependencies - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 7cad9cdc..5137ce20 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 6e53c34a..4f2780f1 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 05b46aa5..235b8251 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index d8b10218..ff47693a 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 7a38b262..628f1c9d 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 135316d2..05005970 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 2c725c88..04ff9478 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 8abe6b8e..d3e807f2 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 901ed835..9d9f3d2c 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index d5e924ae..554bf41e 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 572ce693..8525da55 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-starter-gateway From eebfb419b2d437bfe8bcf4d9cca376ee2eb75b1c Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 4 Apr 2025 09:55:19 +0000 Subject: [PATCH 13/85] Bumping versions --- docs/pom.xml | 2 +- pom.xml | 2 +- spring-cloud-gateway-dependencies/pom.xml | 2 +- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 290edbb0..6819860b 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index d1835c2d..b493fc0f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT pom Spring Cloud Gateway diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 5adb57f7..d1da19ac 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -11,7 +11,7 @@ spring-cloud-gateway-dependencies - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 5137ce20..7cad9cdc 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 4f2780f1..6e53c34a 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 235b8251..05b46aa5 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index ff47693a..d8b10218 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 628f1c9d..7a38b262 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 05005970..135316d2 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 04ff9478..2c725c88 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index d3e807f2..8abe6b8e 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 9d9f3d2c..901ed835 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 554bf41e..d5e924ae 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8525da55..572ce693 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.3-SNAPSHOT + 4.2.2-SNAPSHOT .. spring-cloud-starter-gateway From fe74519042d6ec4009976f4593156d7a0f14a93a Mon Sep 17 00:00:00 2001 From: spring-builds Date: Sat, 5 Apr 2025 09:55:18 +0000 Subject: [PATCH 14/85] Bumping versions --- docs/pom.xml | 2 +- pom.xml | 2 +- spring-cloud-gateway-dependencies/pom.xml | 2 +- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 6819860b..290edbb0 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index b493fc0f..d1835c2d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT pom Spring Cloud Gateway diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index d1da19ac..5adb57f7 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -11,7 +11,7 @@ spring-cloud-gateway-dependencies - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 7cad9cdc..5137ce20 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 6e53c34a..4f2780f1 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 05b46aa5..235b8251 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index d8b10218..ff47693a 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 7a38b262..628f1c9d 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 135316d2..05005970 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 2c725c88..04ff9478 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 8abe6b8e..d3e807f2 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 901ed835..9d9f3d2c 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index d5e924ae..554bf41e 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 572ce693..8525da55 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.2-SNAPSHOT + 4.2.3-SNAPSHOT .. spring-cloud-starter-gateway From 7951cef77f4c9f366d6944b7fab5220c19f177f9 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Mon, 7 Apr 2025 11:52:16 +0000 Subject: [PATCH 15/85] Update SNAPSHOT to 4.3.0-M3 --- docs/pom.xml | 2 +- pom.xml | 12 ++++++------ spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webflux/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webmvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server-webflux/pom.xml | 2 +- spring-cloud-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway-server-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 20 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 709dc57e..5ec4b05e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index d1c8473c..bff4661e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-SNAPSHOT + 4.3.0-M3 @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-SNAPSHOT - 4.3.0-SNAPSHOT - 4.3.0-SNAPSHOT - 4.3.0-SNAPSHOT + 3.3.0-M3 + 4.3.0-M3 + 4.3.0-M3 + 4.3.0-M3 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 66103cf7..cbede087 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.3.0-SNAPSHOT + 4.3.0-M3 spring-cloud-gateway-dependencies - 4.3.0-SNAPSHOT + 4.3.0-M3 pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 6842696a..e7bec499 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 49e2de46..cf8a3b0b 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 810172ab..ba1ecc38 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 85b3c76d..a40c03cc 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 14d0d2aa..728fdf3e 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index 3243a645..a4724c81 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-proxyexchange-webflux diff --git a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml index 8d04d069..9ae6db77 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-proxyexchange-webmvc diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 20671002..de90648b 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index e9f6b80c..8687154a 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server-webflux/pom.xml b/spring-cloud-gateway-server-webflux/pom.xml index 4f9f40e0..f8d13a02 100644 --- a/spring-cloud-gateway-server-webflux/pom.xml +++ b/spring-cloud-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-server-webflux diff --git a/spring-cloud-gateway-server-webmvc/pom.xml b/spring-cloud-gateway-server-webmvc/pom.xml index 9792dfe9..c0c2e088 100644 --- a/spring-cloud-gateway-server-webmvc/pom.xml +++ b/spring-cloud-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-server-webmvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 2a61283f..c4e7174a 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..6a991f44 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e86d2d1f..43c74463 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index ab94fcc5..9830daf7 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-starter-gateway-server-webflux diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index 00420392..6a65f53b 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-starter-gateway-server-webmvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8de3f70e..6693e7d2 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M3 .. spring-cloud-starter-gateway From e116c072872d3a3151a08411b8715ffe2d052641 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Mon, 7 Apr 2025 11:54:43 +0000 Subject: [PATCH 16/85] Going back to snapshots --- docs/pom.xml | 2 +- pom.xml | 12 ++++++------ spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webflux/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webmvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server-webflux/pom.xml | 2 +- spring-cloud-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway-server-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 20 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 5ec4b05e..709dc57e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index bff4661e..d1c8473c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-M3 + 4.3.0-SNAPSHOT @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-M3 - 4.3.0-M3 - 4.3.0-M3 - 4.3.0-M3 + 3.3.0-SNAPSHOT + 4.3.0-SNAPSHOT + 4.3.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index cbede087..66103cf7 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.3.0-M3 + 4.3.0-SNAPSHOT spring-cloud-gateway-dependencies - 4.3.0-M3 + 4.3.0-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index e7bec499..6842696a 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index cf8a3b0b..49e2de46 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index ba1ecc38..810172ab 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index a40c03cc..85b3c76d 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 728fdf3e..14d0d2aa 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index a4724c81..3243a645 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-proxyexchange-webflux diff --git a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml index 9ae6db77..8d04d069 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-proxyexchange-webmvc diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index de90648b..20671002 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 8687154a..e9f6b80c 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server-webflux/pom.xml b/spring-cloud-gateway-server-webflux/pom.xml index f8d13a02..4f9f40e0 100644 --- a/spring-cloud-gateway-server-webflux/pom.xml +++ b/spring-cloud-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-webflux diff --git a/spring-cloud-gateway-server-webmvc/pom.xml b/spring-cloud-gateway-server-webmvc/pom.xml index c0c2e088..9792dfe9 100644 --- a/spring-cloud-gateway-server-webmvc/pom.xml +++ b/spring-cloud-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-webmvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index c4e7174a..2a61283f 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 6a991f44..5859d52d 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 43c74463..e86d2d1f 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index 9830daf7..ab94fcc5 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-server-webflux diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index 6a65f53b..00420392 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-server-webmvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 6693e7d2..8de3f70e 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M3 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway From 85ab7d9019b762be0bd1faab69cbccf93cf5d79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Richter?= <96986086+joerg-richter-5234@users.noreply.github.com> Date: Mon, 17 Mar 2025 19:14:08 +0100 Subject: [PATCH 17/85] #2975-Suggestion-Add-Permissions-Policy-as-configurable-option-to-SecureHeaders-GatewayFilter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - added Permissions-Policy header as an opt-in header & default value - updated documentation with Permissions-Policy and resources - updated tests to include Permissions-Policy - SecurityHeaders and Permissions-Policy may be configured globally / per route - updated structure of public methods and class members to match previous version structure Fixes gh-2975 Signed-off-by: Jörg Richter <96986086+joerg-richter-5234@users.noreply.github.com> --- .../secureheaders-factory.adoc | 83 +++- .../resources/application-secureheaders.yml | 50 +++ .../SecureHeadersGatewayFilterFactory.java | 373 ++++++++++++------ .../factory/SecureHeadersProperties.java | 165 +++++++- ...ecureHeadersGatewayFilterFactoryTests.java | 22 +- ...eHeadersGatewayFilterFactoryUnitTests.java | 126 +++++- 6 files changed, 662 insertions(+), 157 deletions(-) create mode 100644 spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc index 84254642..12177b8a 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc @@ -29,10 +29,87 @@ The following properties are available: To disable the default values set the `spring.cloud.gateway.filter.secure-headers.disable` property with comma-separated values. The following example shows how to do so: -[source] +.application.yml +[source,yaml] ---- -spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security +spring: + cloud: + gateway: + filter: + secure-headers: + disable: x-frame-options,strict-transport-security ---- -NOTE: The lowercase full name of the secure header needs to be used to disable it.. +To apply the `SecureHeaders` filter to a specific route, add the filter to the list of filters of that route. +You can customize the route filter using arguments. Route configuration overrides the global default configuration for this route. +.application.yml +[source,yaml] +---- + - id: secureheaders_route + uri: http://example.org + predicates: + - Path=/** + filters: + - name: SecureHeaders + args: + disable: x-frame-options +---- + +NOTE: The lowercase full name of the secure header needs to be used to disable it. + +== Further options + +You may opt in to add the `Permissions-Policy` header to the response. Permissions Policy is a security header +that allows web developers to manage which browser features a website can utilize. Please see +https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy[Permissions-Policy] and +https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#directives[Directives] to configure it +for your environment. + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + filter: + secure-headers: + enable: permissions-policy + permissions-policy : geolocation=(self "https://example.com") +---- + +In the above https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/geolocation[example] +the Geolocation API is disabled within all browsing contexts except for its own origin and those whose origin is "https://example.com". +The Permissions-Policy may be configured separately for each route. + +.application.yml +[source,yaml] +---- + - id: secureheaders_route + uri: http://anotherexample.org + predicates: + - Path=/** + filters: + - name: SecureHeaders + args: + disable: x-frame-options + enable: permissions-policy + permissions-policy : geolocation=("https://anotherexample.org") +---- + +WARNING: When you enable Permissions-Policy and do not explicitly configure any directives, a default value will be applied. +Specifically, this default value disables a wide range of standardized and experimental features. +This behavior might not be appropriate for your specific environment or use case. + +Permissions-Policy default value when enabled and no explicit configuration: + +`Permissions-Policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), +display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), +fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), +payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), +web-share=(), xr-spatial-tracking=()` + + +NOTE: You can check the Permissions Policy feature list for Chrome with https://developer.chrome.com/docs/privacy-security/permissions-policy#chrome_devtools_integration[DevTool Integration]. + +When you configure the header value for your environment, make sure to check the browser console for syntax errors. diff --git a/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml b/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml new file mode 100644 index 00000000..ddae382f --- /dev/null +++ b/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml @@ -0,0 +1,50 @@ +test: + hostport: httpbin.org:80 + # hostport: localhost:5000 + uri: http://${test.hostport} + #uri: lb://httpbin + + +spring: + cloud: + gateway: + filter: + default-filters: + #- PrefixPath=/httpbin + #- AddResponseHeader=X-Response-Default-Foo, Default-Bar + + routes: + # ===================================== + # to run server + # $ wscat --listen 9000 + # to run client + # $ wscat --connect ws://localhost:8080/echo + - id: websocket_test + uri: ws://localhost:9000 + order: 9000 + predicates: + - Path=/echo + # ===================================== + - id: default_path_to_httpbin_secureheaders + uri: ${test.uri} + order: 10000 + predicates: + - Path=/** + filters: + - name: SecureHeaders + args: + disable: x-frame-options + enable: permissions-policy + permissions-policy : geolocation=("https://example.net") + +logging: + level: + org.springframework.cloud.gateway: TRACE + org.springframework.http.server.reactive: DEBUG + org.springframework.web.reactive: DEBUG + reactor.ipc.netty: DEBUG + reactor.netty: DEBUG + +management.endpoints.web.exposure.include: '*' + + diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java index 3a079968..ce699763 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java @@ -16,8 +16,10 @@ package org.springframework.cloud.gateway.filter.factory; -import java.util.List; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; import reactor.core.publisher.Mono; @@ -29,9 +31,14 @@ import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; /** - * https://blog.appcanary.com/2017/http-security-headers.html. + * GatewayFilterFactory to provide a route filter that applies security headers to the + * HTTP response. External configuration {@link SecureHeadersProperties} provides + * opinionated defaults. Following the recommendations made in Http-Security-Headers. + * When opt-out headers are not disabled or explicitly configured, sensible defaults are + * applied. Additionally, opt-in headers, such as Permissions-Policy, may be applied. * - * @author Spencer Gibb, Thirunavukkarasu Ravichandran + * @author Spencer Gibb, Thirunavukkarasu Ravichandran, Jörg Richter */ public class SecureHeadersGatewayFilterFactory extends AbstractGatewayFilterFactory { @@ -39,42 +46,43 @@ public class SecureHeadersGatewayFilterFactory /** * Xss-Protection header name. */ - public static final String X_XSS_PROTECTION_HEADER = "X-Xss-Protection"; + public static final String X_XSS_PROTECTION_HEADER = SecureHeadersProperties.X_XSS_PROTECTION_HEADER; /** * Strict transport security header name. */ - public static final String STRICT_TRANSPORT_SECURITY_HEADER = "Strict-Transport-Security"; + public static final String STRICT_TRANSPORT_SECURITY_HEADER = SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER; /** * Frame options header name. */ - public static final String X_FRAME_OPTIONS_HEADER = "X-Frame-Options"; + public static final String X_FRAME_OPTIONS_HEADER = SecureHeadersProperties.X_FRAME_OPTIONS_HEADER; /** * Content-Type Options header name. */ - public static final String X_CONTENT_TYPE_OPTIONS_HEADER = "X-Content-Type-Options"; + public static final String X_CONTENT_TYPE_OPTIONS_HEADER = SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER; /** * Referrer Policy header name. */ - public static final String REFERRER_POLICY_HEADER = "Referrer-Policy"; + public static final String REFERRER_POLICY_HEADER = SecureHeadersProperties.REFERRER_POLICY_HEADER; /** * Content-Security Policy header name. */ - public static final String CONTENT_SECURITY_POLICY_HEADER = "Content-Security-Policy"; + public static final String CONTENT_SECURITY_POLICY_HEADER = SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER; /** * Download Options header name. */ - public static final String X_DOWNLOAD_OPTIONS_HEADER = "X-Download-Options"; + public static final String X_DOWNLOAD_OPTIONS_HEADER = SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER; /** * Permitted Cross-Domain Policies header name. */ - public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = "X-Permitted-Cross-Domain-Policies"; + public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; + private final SecureHeadersProperties properties; @@ -83,50 +91,23 @@ public class SecureHeadersGatewayFilterFactory this.properties = properties; } + /** + * Returns a GatewayFilter that applies security headers to the HTTP response. + * @param originalConfig the original security configuration + * @return a GatewayFilter instance that applies security headers to the HTTP response + */ @Override public GatewayFilter apply(Config originalConfig) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - HttpHeaders headers = exchange.getResponse().getHeaders(); - List disabled = properties.getDisable(); + HttpHeaders responseHeaders = exchange.getResponse().getHeaders(); + Set headersToAddToResponse = assembleHeaders(originalConfig, properties); + Config config = originalConfig.withDefaults(properties); - - return chain.filter(exchange).then(Mono.fromRunnable(() -> { - if (isEnabled(disabled, X_XSS_PROTECTION_HEADER)) { - headers.addIfAbsent(X_XSS_PROTECTION_HEADER, config.getXssProtectionHeader()); - } - - if (isEnabled(disabled, STRICT_TRANSPORT_SECURITY_HEADER)) { - headers.addIfAbsent(STRICT_TRANSPORT_SECURITY_HEADER, config.getStrictTransportSecurity()); - } - - if (isEnabled(disabled, X_FRAME_OPTIONS_HEADER)) { - headers.addIfAbsent(X_FRAME_OPTIONS_HEADER, config.getFrameOptions()); - } - - if (isEnabled(disabled, X_CONTENT_TYPE_OPTIONS_HEADER)) { - headers.addIfAbsent(X_CONTENT_TYPE_OPTIONS_HEADER, config.getContentTypeOptions()); - } - - if (isEnabled(disabled, REFERRER_POLICY_HEADER)) { - headers.addIfAbsent(REFERRER_POLICY_HEADER, config.getReferrerPolicy()); - } - - if (isEnabled(disabled, CONTENT_SECURITY_POLICY_HEADER)) { - headers.addIfAbsent(CONTENT_SECURITY_POLICY_HEADER, config.getContentSecurityPolicy()); - } - - if (isEnabled(disabled, X_DOWNLOAD_OPTIONS_HEADER)) { - headers.addIfAbsent(X_DOWNLOAD_OPTIONS_HEADER, config.getDownloadOptions()); - } - - if (isEnabled(disabled, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER)) { - headers.addIfAbsent(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, - config.getPermittedCrossDomainPolicies()); - } - })); + return chain.filter(exchange).then(Mono.fromRunnable(() -> + applySecurityHeaders(responseHeaders, headersToAddToResponse, config))); } @Override @@ -136,135 +117,299 @@ public class SecureHeadersGatewayFilterFactory }; } - private boolean isEnabled(List disabledHeaders, String header) { - return !disabledHeaders.contains(header.toLowerCase(Locale.ROOT)); + /** + * Applies security headers to the response using the given filter configuration. + * @param responseHeaders - the http headers of the response + * @param headersToAddToResponse - the security headers that are to be added to the response + * @param config - the security filter configuration + */ + private void applySecurityHeaders(HttpHeaders responseHeaders, Set headersToAddToResponse, Config config) { + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.X_XSS_PROTECTION_HEADER, config.getXssProtectionHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER, + config.getStrictTransportSecurityHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.X_FRAME_OPTIONS_HEADER, + config.getFrameOptionsHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER, + config.getContentTypeOptionsHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.REFERRER_POLICY_HEADER, + config.getReferrerPolicyHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER, + config.getContentSecurityPolicyHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER, + config.getDownloadOptionsHeaderValue()); + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, + config.getPermittedCrossDomainPoliciesHeaderValue()); + + String permissionPolicyHeaderValue = config.getPermissionPolicyHeaderValue(); + if (config.isRouteFilterConfigProvided()) { + String routePermissionPolicyHeaderValue = config.getRoutePermissionsPolicyHeaderValue(); + if (routePermissionPolicyHeaderValue != null) { + permissionPolicyHeaderValue = routePermissionPolicyHeaderValue; + } + } + + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, + SecureHeadersProperties.PERMISSIONS_POLICY_HEADER, + permissionPolicyHeaderValue); } + /** + * Assembles the set of security headers that are to be applied to the response + * - When route specific arguments are set, route specific headers are applied. + * - When no route specific arguments are set, global default headers are applied. + * @param config - the global / route configuration supplied + * @param properties - default security headers configuration provided + * @return set of security headers that are to be added to the response + */ + private Set assembleHeaders(Config config, SecureHeadersProperties properties) { + Set headersToAddToResponse = new HashSet<>(properties.getDefaultHeaders()); + if (config.isRouteFilterConfigProvided()) { + headersToAddToResponse.addAll(config.getRouteEnabledHeaders()); + headersToAddToResponse.removeAll(config.getRouteDisabledHeaders()); + } + else { + headersToAddToResponse.addAll(properties.getEnabledHeaders()); + headersToAddToResponse.removeAll(properties.getDisabledHeaders()); + } + return headersToAddToResponse; + } + + + private void addHeaderIfEnabled(HttpHeaders headers, Set headersToAdd, String headerName, String headerValue) { + if (headersToAdd.contains(headerName.toLowerCase(Locale.ROOT))) { + headers.addIfAbsent(headerName, headerValue); + } + } + + /** + * POJO for {@link SecureHeadersGatewayFilterFactory} filter configuration. + */ public static class Config { - private String xssProtectionHeader; + private Set routeEnabledHeaders = new HashSet<>(); - private String strictTransportSecurity; + private Set routeDisabledHeaders = new HashSet<>(); - private String frameOptions; + private String routePermissionsPolicyHeaderValue; - private String contentTypeOptions; + private boolean routeFilterConfigProvided; - private String referrerPolicy; + private String xssProtectionHeaderValue; - private String contentSecurityPolicy; + private String strictTransportSecurityHeaderValue; - private String downloadOptions; + private String frameOptionsHeaderValue; - private String permittedCrossDomainPolicies; + private String contentTypeOptionsHeaderValue; + + private String referrerPolicyHeaderValue; + + private String contentSecurityPolicyHeaderValue; + + private String downloadOptionsHeaderValue; + + private String permittedCrossDomainPoliciesHeaderValue; + + private String permissionPolicyHeaderValue; public Config withDefaults(SecureHeadersProperties properties) { Config config = new Config(); - config.setXssProtectionHeader(xssProtectionHeader); - config.setStrictTransportSecurity(strictTransportSecurity); - config.setFrameOptions(frameOptions); - config.setContentTypeOptions(contentTypeOptions); - config.setReferrerPolicy(referrerPolicy); - config.setContentSecurityPolicy(contentSecurityPolicy); - config.setDownloadOptions(downloadOptions); - config.setPermittedCrossDomainPolicies(permittedCrossDomainPolicies); - if (config.xssProtectionHeader == null) { - config.xssProtectionHeader = properties.getXssProtectionHeader(); + config.setEnable(routeEnabledHeaders); + config.setDisable(routeDisabledHeaders); + config.setPermissionsPolicy(routePermissionsPolicyHeaderValue); + + config.setXssProtectionHeaderValue(xssProtectionHeaderValue); + config.setStrictTransportSecurityHeaderValue(strictTransportSecurityHeaderValue); + config.setFrameOptionsHeaderValue(frameOptionsHeaderValue); + config.setContentTypeOptionsHeaderValue(contentTypeOptionsHeaderValue); + config.setReferrerPolicyHeaderValue(referrerPolicyHeaderValue); + config.setContentSecurityPolicyHeaderValue(contentSecurityPolicyHeaderValue); + config.setDownloadOptionsHeaderValue(downloadOptionsHeaderValue); + config.setPermittedCrossDomainPoliciesHeaderValue(permittedCrossDomainPoliciesHeaderValue); + config.setPermissionPolicyHeaderValue(permissionPolicyHeaderValue); + + if (config.xssProtectionHeaderValue == null) { + config.xssProtectionHeaderValue = properties.getXssProtectionHeader(); } - if (config.strictTransportSecurity == null) { - config.strictTransportSecurity = properties.getStrictTransportSecurity(); + if (config.strictTransportSecurityHeaderValue == null) { + config.strictTransportSecurityHeaderValue = properties.getStrictTransportSecurity(); } - if (config.frameOptions == null) { - config.frameOptions = properties.getFrameOptions(); + if (config.frameOptionsHeaderValue == null) { + config.frameOptionsHeaderValue = properties.getFrameOptions(); } - if (config.contentTypeOptions == null) { - config.contentTypeOptions = properties.getContentTypeOptions(); + if (config.contentTypeOptionsHeaderValue == null) { + config.contentTypeOptionsHeaderValue = properties.getContentTypeOptions(); } - if (config.referrerPolicy == null) { - config.referrerPolicy = properties.getReferrerPolicy(); + if (config.referrerPolicyHeaderValue == null) { + config.referrerPolicyHeaderValue = properties.getReferrerPolicy(); } - if (config.contentSecurityPolicy == null) { - config.contentSecurityPolicy = properties.getContentSecurityPolicy(); + if (config.contentSecurityPolicyHeaderValue == null) { + config.contentSecurityPolicyHeaderValue = properties.getContentSecurityPolicy(); } - if (config.downloadOptions == null) { - config.downloadOptions = properties.getDownloadOptions(); + if (config.downloadOptionsHeaderValue == null) { + config.downloadOptionsHeaderValue = properties.getDownloadOptions(); } - if (config.permittedCrossDomainPolicies == null) { - config.permittedCrossDomainPolicies = properties.getPermittedCrossDomainPolicies(); + if (config.permittedCrossDomainPoliciesHeaderValue == null) { + config.permittedCrossDomainPoliciesHeaderValue = properties.getPermittedCrossDomainPolicies(); } + + if (config.permissionPolicyHeaderValue == null) { + config.permissionPolicyHeaderValue = properties.getPermissionsPolicy(); + } + return config; } - public String getXssProtectionHeader() { - return xssProtectionHeader; + public String getXssProtectionHeaderValue() { + return xssProtectionHeaderValue; } - public void setXssProtectionHeader(String xssProtectionHeader) { - this.xssProtectionHeader = xssProtectionHeader; + public void setXssProtectionHeaderValue(String xssProtectionHeaderHeaderValue) { + this.xssProtectionHeaderValue = xssProtectionHeaderHeaderValue; } - public String getStrictTransportSecurity() { - return strictTransportSecurity; + public String getStrictTransportSecurityHeaderValue() { + return strictTransportSecurityHeaderValue; } - public void setStrictTransportSecurity(String strictTransportSecurity) { - this.strictTransportSecurity = strictTransportSecurity; + public void setStrictTransportSecurityHeaderValue(String strictTransportSecurityHeaderValue) { + this.strictTransportSecurityHeaderValue = strictTransportSecurityHeaderValue; } - public String getFrameOptions() { - return frameOptions; + public String getFrameOptionsHeaderValue() { + return frameOptionsHeaderValue; } - public void setFrameOptions(String frameOptions) { - this.frameOptions = frameOptions; + public void setFrameOptionsHeaderValue(String frameOptionsHeaderValue) { + this.frameOptionsHeaderValue = frameOptionsHeaderValue; } - public String getContentTypeOptions() { - return contentTypeOptions; + public String getContentTypeOptionsHeaderValue() { + return contentTypeOptionsHeaderValue; } - public void setContentTypeOptions(String contentTypeOptions) { - this.contentTypeOptions = contentTypeOptions; + public void setContentTypeOptionsHeaderValue(String contentTypeOptionsHeaderValue) { + this.contentTypeOptionsHeaderValue = contentTypeOptionsHeaderValue; } - public String getReferrerPolicy() { - return referrerPolicy; + public String getReferrerPolicyHeaderValue() { + return referrerPolicyHeaderValue; } - public void setReferrerPolicy(String referrerPolicy) { - this.referrerPolicy = referrerPolicy; + public void setReferrerPolicyHeaderValue(String referrerPolicyHeaderValue) { + this.referrerPolicyHeaderValue = referrerPolicyHeaderValue; } - public String getContentSecurityPolicy() { - return contentSecurityPolicy; + public String getContentSecurityPolicyHeaderValue() { + return contentSecurityPolicyHeaderValue; } - public void setContentSecurityPolicy(String contentSecurityPolicy) { - this.contentSecurityPolicy = contentSecurityPolicy; + public void setContentSecurityPolicyHeaderValue(String contentSecurityPolicyHeaderValue) { + this.contentSecurityPolicyHeaderValue = contentSecurityPolicyHeaderValue; } - public String getDownloadOptions() { - return downloadOptions; + public String getDownloadOptionsHeaderValue() { + return downloadOptionsHeaderValue; } - public void setDownloadOptions(String downloadOptions) { - this.downloadOptions = downloadOptions; + public void setDownloadOptionsHeaderValue(String downloadOptionHeaderValue) { + this.downloadOptionsHeaderValue = downloadOptionsHeaderValue; } - public String getPermittedCrossDomainPolicies() { - return permittedCrossDomainPolicies; + public String getPermittedCrossDomainPoliciesHeaderValue() { + return permittedCrossDomainPoliciesHeaderValue; } - public void setPermittedCrossDomainPolicies(String permittedCrossDomainPolicies) { - this.permittedCrossDomainPolicies = permittedCrossDomainPolicies; + public void setPermittedCrossDomainPoliciesHeaderValue(String permittedCrossDomainPoliciesHeaderValue) { + this.permittedCrossDomainPoliciesHeaderValue = permittedCrossDomainPoliciesHeaderValue; + } + + public String getPermissionPolicyHeaderValue() { + return permissionPolicyHeaderValue; + } + + public void setPermissionPolicyHeaderValue(String permissionPolicyHeaderValue) { + this.permissionPolicyHeaderValue = permissionPolicyHeaderValue; + } + + /** + * bind the route specific/opt-in header names to enable, in lower case. + */ + void setEnable(Set enable) { + if (enable != null) { + this.routeFilterConfigProvided = true; + this.routeEnabledHeaders = enable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + } + } + + /** + * @return the route specific/opt-in header names to enable, in lower case. + */ + Set getRouteEnabledHeaders() { + return routeEnabledHeaders; + } + + /** + * bind the route specific/opt-out header names to disable, in lower case. + */ + void setDisable(Set disable) { + if (disable != null) { + this.routeFilterConfigProvided = true; + this.routeDisabledHeaders = disable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + } + } + + /** + * @return the route specific/opt-out header names to disable, in lower case + */ + Set getRouteDisabledHeaders() { + return routeDisabledHeaders; + } + + /** + * @return the route specific/opt-out permission policies. + */ + String getRoutePermissionsPolicyHeaderValue() { + return routePermissionsPolicyHeaderValue; + } + + /** + * bind the route specific/opt-out permissions policy. + */ + void setPermissionsPolicy(String permissionsPolicy) { + this.routeFilterConfigProvided = true; + this.routePermissionsPolicyHeaderValue = permissionsPolicy; + } + + /** + * @return flag whether route specific arguments were bound. + */ + boolean isRouteFilterConfigProvided() { + return routeFilterConfigProvided; } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java index 6802575a..f9ec7b35 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java @@ -16,57 +16,135 @@ package org.springframework.cloud.gateway.filter.factory; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.springframework.boot.context.properties.ConfigurationProperties; /** - * @author Spencer Gibb, Thirunavukkarasu Ravichandran + * @author Spencer Gibb, Thirunavukkarasu Ravichandran, Jörg Richter */ @ConfigurationProperties("spring.cloud.gateway.filter.secure-headers") public class SecureHeadersProperties { + /** + * Xss-Protection header name. + */ + public static final String X_XSS_PROTECTION_HEADER = "X-Xss-Protection"; + /** * Xss-Protection header default. */ public static final String X_XSS_PROTECTION_HEADER_DEFAULT = "1 ; mode=block"; + /** + * Strict transport security header name. + */ + public static final String STRICT_TRANSPORT_SECURITY_HEADER = "Strict-Transport-Security"; + /** * Strict transport security header default. */ public static final String STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT = "max-age=631138519"; + /** + * Frame options header name. + */ + public static final String X_FRAME_OPTIONS_HEADER = "X-Frame-Options"; + /** * Frame Options header default. */ public static final String X_FRAME_OPTIONS_HEADER_DEFAULT = "DENY"; + /** + * Content-Type Options header name. + */ + public static final String X_CONTENT_TYPE_OPTIONS_HEADER = "X-Content-Type-Options"; + /** * Content-Type Options header default. */ public static final String X_CONTENT_TYPE_OPTIONS_HEADER_DEFAULT = "nosniff"; + /** + * Referrer Policy header name. + */ + public static final String REFERRER_POLICY_HEADER = "Referrer-Policy"; + /** * Referrer Policy header default. */ public static final String REFERRER_POLICY_HEADER_DEFAULT = "no-referrer"; + /** + * Content-Security Policy header name. + */ + public static final String CONTENT_SECURITY_POLICY_HEADER = "Content-Security-Policy"; + /** * Content-Security Policy header default. */ public static final String CONTENT_SECURITY_POLICY_HEADER_DEFAULT = "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'"; + /** + * Download Options header name. + */ + public static final String X_DOWNLOAD_OPTIONS_HEADER = "X-Download-Options"; + /** * Download Options header default. */ public static final String X_DOWNLOAD_OPTIONS_HEADER_DEFAULT = "noopen"; + /** + * Permitted Cross-Domain Policies header name. + */ + public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = "X-Permitted-Cross-Domain-Policies"; + /** * Permitted Cross-Domain Policies header default. */ public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT = "none"; + /** + * Permissions Policy header name. Opt-In required by external configuration. + */ + public static final String PERMISSIONS_POLICY_HEADER = "Permissions-Policy"; + + /** + * Permissions Policy header default. Opt-In by external configuration required, + * because the header default disables a comprehensive list of features. + */ + public static final String PERMISSIONS_POLICY_HEADER_OPT_IN_DEFAULT = "accelerometer=(), ambient-light-sensor=(), " + + "autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), " + + "encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), " + + "geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), " + + "navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), " + + "screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"; + + + /** + * Default constructor for {@link SecureHeadersProperties}. + * Initializes the `defaultHeaders` set with a predefined list of security headers. + * The headers are transformed to lowercase for case-insensitive comparison. + **/ + public SecureHeadersProperties() { + + defaultHeaders = Stream.of(SecureHeadersProperties.X_XSS_PROTECTION_HEADER, + SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER, + SecureHeadersProperties.X_FRAME_OPTIONS_HEADER, SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER, + SecureHeadersProperties.REFERRER_POLICY_HEADER, SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER, + SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER, + SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER) + .map(String::toLowerCase) + .collect(Collectors.toUnmodifiableSet()); + + } + private String xssProtectionHeader = X_XSS_PROTECTION_HEADER_DEFAULT; private String strictTransportSecurity = STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT; @@ -83,7 +161,13 @@ public class SecureHeadersProperties { private String permittedCrossDomainPolicies = X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT; - private List disable = new ArrayList<>(); + private String permissionsPolicy = PERMISSIONS_POLICY_HEADER_OPT_IN_DEFAULT; + + private final Set defaultHeaders; + + private Set enabledHeaders = new HashSet<>(); + + private Set disabledHeaders = new HashSet<>(); public String getXssProtectionHeader() { return xssProtectionHeader; @@ -149,28 +233,73 @@ public class SecureHeadersProperties { this.permittedCrossDomainPolicies = permittedCrossDomainPolicies; } - public List getDisable() { - return disable; + public String getPermissionsPolicy() { + return permissionsPolicy; } + public void setPermissionsPolicy(String permissionsPolicy) { + this.permissionsPolicy = permissionsPolicy; + } + + /** + * @return the default/opt-out header names to disable + */ + public List getDisable() { + return disabledHeaders.stream().toList(); + } + + /** + * Binds the list of default/opt-out header names to disable, transforms them into a lowercase set. + * This is to ensure case-insensitive comparison. + * @param disable - list of default/opt-out header names to disable + */ public void setDisable(List disable) { - this.disable = disable; + if (disable != null) { + disabledHeaders = disable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + } + } + + /** + * @return the opt-in header names to enable + */ + public Set getEnabledHeaders() { + return enabledHeaders; + } + + /** + * Binds the list of default/opt-out header names to enable, transforms them into a lowercase set. + * This is to ensure case-insensitive comparison. + * @param enable - list of default/opt-out header enable + */ + public void setEnable(List enable) { + if (enable != null) { + enabledHeaders = enable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + } + } + + /** + * @return the default/opt-out header names to disable + */ + public Set getDisabledHeaders() { + return disabledHeaders; + } + + /** + * @return the default/opt-out header names to apply + */ + public Set getDefaultHeaders() { + return defaultHeaders; } @Override public String toString() { - final StringBuffer sb = new StringBuffer("SecureHeadersProperties{"); - sb.append("xssProtectionHeader='").append(xssProtectionHeader).append('\''); - sb.append(", strictTransportSecurity='").append(strictTransportSecurity).append('\''); - sb.append(", frameOptions='").append(frameOptions).append('\''); - sb.append(", contentTypeOptions='").append(contentTypeOptions).append('\''); - sb.append(", referrerPolicy='").append(referrerPolicy).append('\''); - sb.append(", contentSecurityPolicy='").append(contentSecurityPolicy).append('\''); - sb.append(", downloadOptions='").append(downloadOptions).append('\''); - sb.append(", permittedCrossDomainPolicies='").append(permittedCrossDomainPolicies).append('\''); - sb.append(", disabled='").append(disable).append('\''); - sb.append('}'); - return sb.toString(); + return "SecureHeadersProperties{" + "xssProtectionHeader='" + xssProtectionHeader + '\'' + + ", strictTransportSecurity='" + strictTransportSecurity + '\'' + ", frameOptions='" + frameOptions + + '\'' + ", contentTypeOptions='" + contentTypeOptions + '\'' + ", referrerPolicy='" + referrerPolicy + + '\'' + ", contentSecurityPolicy='" + contentSecurityPolicy + '\'' + ", downloadOptions='" + + downloadOptions + '\'' + ", permittedCrossDomainPolicies='" + permittedCrossDomainPolicies + '\'' + + ", permissionsPolicy='" + permissionsPolicy + '\'' + ", defaultHeaders=" + defaultHeaders + + ", enable=" + enabledHeaders + ", disable=" + disabledHeaders + '}'; } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java index 1742a19e..75751f05 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java @@ -34,19 +34,25 @@ import org.springframework.web.reactive.function.client.ClientResponse; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.CONTENT_SECURITY_POLICY_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.REFERRER_POLICY_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.STRICT_TRANSPORT_SECURITY_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_CONTENT_TYPE_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_DOWNLOAD_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_FRAME_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.PERMISSIONS_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.REFERRER_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_FRAME_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; import static org.springframework.cloud.gateway.test.TestUtils.assertStatus; @SpringBootTest(webEnvironment = RANDOM_PORT) @DirtiesContext public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { + /** + * This test ensures that the response includes a set of default security headers, + * which are defined in {@link SecureHeadersProperties}. It also confirms that the + * opt-in "Permissions-Policy" header is not included in the response. + */ @Test public void secureHeadersFilterWorks() { Mono result = webClient.get() @@ -59,7 +65,6 @@ public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { StepVerifier.create(result).consumeNextWith(response -> { assertStatus(response, HttpStatus.OK); HttpHeaders httpHeaders = response.headers().asHttpHeaders(); - // assertThat(httpHeaders.getFirst(X_XSS_PROTECTION_HEADER)).isEqualTo(defaults.getXssProtectionHeader()); assertThat(httpHeaders.getFirst(STRICT_TRANSPORT_SECURITY_HEADER)) .isEqualTo(defaults.getStrictTransportSecurity()); assertThat(httpHeaders.getFirst(X_FRAME_OPTIONS_HEADER)).isEqualTo(defaults.getFrameOptions()); @@ -70,6 +75,7 @@ public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { assertThat(httpHeaders.getFirst(X_DOWNLOAD_OPTIONS_HEADER)).isEqualTo(defaults.getDownloadOptions()); assertThat(httpHeaders.getFirst(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER)) .isEqualTo(defaults.getPermittedCrossDomainPolicies()); + assertThat(httpHeaders.getOrEmpty(PERMISSIONS_POLICY_HEADER)).isEmpty(); }).expectComplete().verify(DURATION); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java index 65dc9809..46284f91 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java @@ -16,6 +16,10 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Collections; +import java.util.List; +import java.util.Set; + import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,18 +37,19 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.CONTENT_SECURITY_POLICY_HEADER; import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.Config; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.REFERRER_POLICY_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.STRICT_TRANSPORT_SECURITY_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_CONTENT_TYPE_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_DOWNLOAD_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_FRAME_OPTIONS_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; -import static org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory.X_XSS_PROTECTION_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.PERMISSIONS_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.REFERRER_POLICY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_FRAME_OPTIONS_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; +import static org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties.X_XSS_PROTECTION_HEADER; /** - * @author Thirunavukkarasu Ravichandran + * @author Thirunavukkarasu Ravichandran, Jörg Richter */ public class SecureHeadersGatewayFilterFactoryUnitTests { @@ -75,7 +80,7 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { filter.filter(exchange, filterChain).block(); ServerHttpResponse response = exchange.getResponse(); - assertThat(response.getHeaders()).containsKeys(X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, + assertThat(response.getHeaders()).containsOnlyKeys(X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, CONTENT_SECURITY_POLICY_HEADER, X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER); } @@ -105,8 +110,8 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory( new SecureHeadersProperties()); Config config = new Config(); - config.setStrictTransportSecurity("max-age=65535"); - config.setReferrerPolicy("referrer"); + config.setStrictTransportSecurityHeaderValue("max-age=65535"); + config.setReferrerPolicyHeaderValue("referrer"); filter = filterFactory.apply(config); filter.filter(exchange, filterChain).block(); @@ -135,13 +140,19 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { @Test public void doesNotDuplicateHeaders() { String originalHeaderValue = "original-header-value"; + + SecureHeadersProperties secureHeadersProperties = new SecureHeadersProperties(); + secureHeadersProperties.setDisable(Collections.emptyList()); + secureHeadersProperties.setEnable(List.of(PERMISSIONS_POLICY_HEADER)); + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory( - new SecureHeadersProperties()); + secureHeadersProperties); + Config config = new Config(); String[] headers = { X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, CONTENT_SECURITY_POLICY_HEADER, - X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER }; + X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, PERMISSIONS_POLICY_HEADER }; for (String header : headers) { filter = filterFactory.apply(config); @@ -163,4 +174,91 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { Assertions.assertThat(filter.toString()).contains("SecureHeaders"); } + @Test + public void doNotAddPermissionsPolicyWhenNotEnabled() { + SecureHeadersProperties properties = new SecureHeadersProperties(); + + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(properties); + filter = filterFactory.apply(new Config()); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = captor.getValue().getResponse(); + assertThat(response.getHeaders()).doesNotContainKeys(PERMISSIONS_POLICY_HEADER); + } + + @Test + public void addPermissionsPolicyWhenEnabled() { + SecureHeadersProperties properties = new SecureHeadersProperties(); + properties.setEnable(List.of("permissions-policy")); + + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(properties); + filter = filterFactory.apply(new Config()); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = captor.getValue().getResponse(); + + assertThat(response.getHeaders()).containsKeys(X_XSS_PROTECTION_HEADER, STRICT_TRANSPORT_SECURITY_HEADER, + X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, + CONTENT_SECURITY_POLICY_HEADER, X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER); + + assertThat(response.getHeaders().get(PERMISSIONS_POLICY_HEADER)) + .containsExactly(SecureHeadersProperties.PERMISSIONS_POLICY_HEADER_OPT_IN_DEFAULT); + } + + @Test + public void addPermissionsPolicyAndOverrideDefaults() { + SecureHeadersProperties properties = new SecureHeadersProperties(); + properties.setEnable(List.of("permissions-policy")); + properties.setPermissionsPolicy("camera=*"); + + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(properties); + filter = filterFactory.apply(new Config()); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = captor.getValue().getResponse(); + assertThat(response.getHeaders().get(PERMISSIONS_POLICY_HEADER)).containsExactly("camera=*"); + } + + @Test + public void applyCompositionWithDisabledHeadersAndPermissionPolicy() { + SecureHeadersProperties properties = new SecureHeadersProperties(); + properties.setDisable(asList("x-xss-protection", "strict-transport-security", "x-frame-options", + "x-content-type-options", "referrer-policy", "content-security-policy", "x-download-options")); + properties.setEnable(List.of("permissions-policy")); + + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(properties); + filter = filterFactory.apply(new Config()); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = captor.getValue().getResponse(); + assertThat(response.getHeaders()).containsOnlyKeys(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, + PERMISSIONS_POLICY_HEADER); + } + + @Test + public void overrideDefaultInSecurityPropertiesWhenRouteConfigIsProvided() { + + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(new SecureHeadersProperties()); + + Config config = new Config(); + config.setDisable(Set.of("strict-transport-security")); + config.setEnable(Set.of("permissions-policy")); + config.setPermissionsPolicy("camera=*"); + + filter = filterFactory.apply(config); + + filter.filter(exchange, filterChain).block(); + + ServerHttpResponse response = exchange.getResponse(); + assertThat(response.getHeaders()).containsOnlyKeys(X_XSS_PROTECTION_HEADER, X_FRAME_OPTIONS_HEADER, + X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, CONTENT_SECURITY_POLICY_HEADER, + X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, + PERMISSIONS_POLICY_HEADER); + assertThat(response.getHeaders().get(PERMISSIONS_POLICY_HEADER)).containsExactly("camera=*"); + } + } From b883487f722d50ae17f3f677794dfc52fd2e533b Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 8 Apr 2025 18:55:11 +0000 Subject: [PATCH 18/85] Bumping versions --- docs/modules/ROOT/partials/_configprops.adoc | 4 ++ .../SecureHeadersGatewayFilterFactory.java | 49 +++++++++---------- .../factory/SecureHeadersProperties.java | 15 +++--- ...ecureHeadersGatewayFilterFactoryTests.java | 8 +-- ...eHeadersGatewayFilterFactoryUnitTests.java | 6 +-- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/docs/modules/ROOT/partials/_configprops.adoc b/docs/modules/ROOT/partials/_configprops.adoc index ae7609d3..a92c4dd8 100644 --- a/docs/modules/ROOT/partials/_configprops.adoc +++ b/docs/modules/ROOT/partials/_configprops.adoc @@ -49,10 +49,14 @@ |spring.cloud.gateway.filter.save-session.enabled | `+++true+++` | Enables the save-session filter. |spring.cloud.gateway.filter.secure-headers.content-security-policy | `+++default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'+++` | |spring.cloud.gateway.filter.secure-headers.content-type-options | `+++nosniff+++` | +|spring.cloud.gateway.filter.secure-headers.default-headers | | |spring.cloud.gateway.filter.secure-headers.disable | | +|spring.cloud.gateway.filter.secure-headers.disabled-headers | | |spring.cloud.gateway.filter.secure-headers.download-options | `+++noopen+++` | |spring.cloud.gateway.filter.secure-headers.enabled | `+++true+++` | Enables the secure-headers filter. +|spring.cloud.gateway.filter.secure-headers.enabled-headers | | |spring.cloud.gateway.filter.secure-headers.frame-options | `+++DENY+++` | +|spring.cloud.gateway.filter.secure-headers.permissions-policy | `+++accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()+++` | |spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies | `+++none+++` | |spring.cloud.gateway.filter.secure-headers.referrer-policy | `+++no-referrer+++` | |spring.cloud.gateway.filter.secure-headers.strict-transport-security | `+++max-age=631138519+++` | diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java index ce699763..188f4c40 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java @@ -83,7 +83,6 @@ public class SecureHeadersGatewayFilterFactory */ public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = SecureHeadersProperties.X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER; - private final SecureHeadersProperties properties; public SecureHeadersGatewayFilterFactory(SecureHeadersProperties properties) { @@ -106,8 +105,9 @@ public class SecureHeadersGatewayFilterFactory Set headersToAddToResponse = assembleHeaders(originalConfig, properties); Config config = originalConfig.withDefaults(properties); - return chain.filter(exchange).then(Mono.fromRunnable(() -> - applySecurityHeaders(responseHeaders, headersToAddToResponse, config))); + return chain.filter(exchange) + .then(Mono + .fromRunnable(() -> applySecurityHeaders(responseHeaders, headersToAddToResponse, config))); } @Override @@ -120,36 +120,32 @@ public class SecureHeadersGatewayFilterFactory /** * Applies security headers to the response using the given filter configuration. * @param responseHeaders - the http headers of the response - * @param headersToAddToResponse - the security headers that are to be added to the response + * @param headersToAddToResponse - the security headers that are to be added to the + * response * @param config - the security filter configuration */ private void applySecurityHeaders(HttpHeaders responseHeaders, Set headersToAddToResponse, Config config) { - addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.X_XSS_PROTECTION_HEADER, config.getXssProtectionHeaderValue()); + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.X_XSS_PROTECTION_HEADER, + config.getXssProtectionHeaderValue()); addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.STRICT_TRANSPORT_SECURITY_HEADER, config.getStrictTransportSecurityHeaderValue()); - addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.X_FRAME_OPTIONS_HEADER, + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.X_FRAME_OPTIONS_HEADER, config.getFrameOptionsHeaderValue()); addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER, - config.getContentTypeOptionsHeaderValue()); + SecureHeadersProperties.X_CONTENT_TYPE_OPTIONS_HEADER, config.getContentTypeOptionsHeaderValue()); - addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.REFERRER_POLICY_HEADER, + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.REFERRER_POLICY_HEADER, config.getReferrerPolicyHeaderValue()); addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER, - config.getContentSecurityPolicyHeaderValue()); + SecureHeadersProperties.CONTENT_SECURITY_POLICY_HEADER, config.getContentSecurityPolicyHeaderValue()); - addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER, + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.X_DOWNLOAD_OPTIONS_HEADER, config.getDownloadOptionsHeaderValue()); addHeaderIfEnabled(responseHeaders, headersToAddToResponse, @@ -164,15 +160,14 @@ public class SecureHeadersGatewayFilterFactory } } - addHeaderIfEnabled(responseHeaders, headersToAddToResponse, - SecureHeadersProperties.PERMISSIONS_POLICY_HEADER, + addHeaderIfEnabled(responseHeaders, headersToAddToResponse, SecureHeadersProperties.PERMISSIONS_POLICY_HEADER, permissionPolicyHeaderValue); } /** - * Assembles the set of security headers that are to be applied to the response - * - When route specific arguments are set, route specific headers are applied. - * - When no route specific arguments are set, global default headers are applied. + * Assembles the set of security headers that are to be applied to the response - When + * route specific arguments are set, route specific headers are applied. - When no + * route specific arguments are set, global default headers are applied. * @param config - the global / route configuration supplied * @param properties - default security headers configuration provided * @return set of security headers that are to be added to the response @@ -190,8 +185,8 @@ public class SecureHeadersGatewayFilterFactory return headersToAddToResponse; } - - private void addHeaderIfEnabled(HttpHeaders headers, Set headersToAdd, String headerName, String headerValue) { + private void addHeaderIfEnabled(HttpHeaders headers, Set headersToAdd, String headerName, + String headerValue) { if (headersToAdd.contains(headerName.toLowerCase(Locale.ROOT))) { headers.addIfAbsent(headerName, headerValue); } @@ -362,7 +357,9 @@ public class SecureHeadersGatewayFilterFactory void setEnable(Set enable) { if (enable != null) { this.routeFilterConfigProvided = true; - this.routeEnabledHeaders = enable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + this.routeEnabledHeaders = enable.stream() + .map(String::toLowerCase) + .collect(Collectors.toUnmodifiableSet()); } } @@ -379,7 +376,9 @@ public class SecureHeadersGatewayFilterFactory void setDisable(Set disable) { if (disable != null) { this.routeFilterConfigProvided = true; - this.routeDisabledHeaders = disable.stream().map(String::toLowerCase).collect(Collectors.toUnmodifiableSet()); + this.routeDisabledHeaders = disable.stream() + .map(String::toLowerCase) + .collect(Collectors.toUnmodifiableSet()); } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java index f9ec7b35..2456a6f4 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java @@ -126,11 +126,10 @@ public class SecureHeadersProperties { + "navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), " + "screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"; - /** - * Default constructor for {@link SecureHeadersProperties}. - * Initializes the `defaultHeaders` set with a predefined list of security headers. - * The headers are transformed to lowercase for case-insensitive comparison. + * Default constructor for {@link SecureHeadersProperties}. Initializes the + * `defaultHeaders` set with a predefined list of security headers. The headers are + * transformed to lowercase for case-insensitive comparison. **/ public SecureHeadersProperties() { @@ -249,8 +248,8 @@ public class SecureHeadersProperties { } /** - * Binds the list of default/opt-out header names to disable, transforms them into a lowercase set. - * This is to ensure case-insensitive comparison. + * Binds the list of default/opt-out header names to disable, transforms them into a + * lowercase set. This is to ensure case-insensitive comparison. * @param disable - list of default/opt-out header names to disable */ public void setDisable(List disable) { @@ -267,8 +266,8 @@ public class SecureHeadersProperties { } /** - * Binds the list of default/opt-out header names to enable, transforms them into a lowercase set. - * This is to ensure case-insensitive comparison. + * Binds the list of default/opt-out header names to enable, transforms them into a + * lowercase set. This is to ensure case-insensitive comparison. * @param enable - list of default/opt-out header enable */ public void setEnable(List enable) { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java index 75751f05..f555dc51 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java @@ -49,10 +49,10 @@ import static org.springframework.cloud.gateway.test.TestUtils.assertStatus; public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { /** - * This test ensures that the response includes a set of default security headers, - * which are defined in {@link SecureHeadersProperties}. It also confirms that the - * opt-in "Permissions-Policy" header is not included in the response. - */ + * This test ensures that the response includes a set of default security headers, + * which are defined in {@link SecureHeadersProperties}. It also confirms that the + * opt-in "Permissions-Policy" header is not included in the response. + */ @Test public void secureHeadersFilterWorks() { Mono result = webClient.get() diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java index 46284f91..33de696f 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryUnitTests.java @@ -242,7 +242,8 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { @Test public void overrideDefaultInSecurityPropertiesWhenRouteConfigIsProvided() { - SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory(new SecureHeadersProperties()); + SecureHeadersGatewayFilterFactory filterFactory = new SecureHeadersGatewayFilterFactory( + new SecureHeadersProperties()); Config config = new Config(); config.setDisable(Set.of("strict-transport-security")); @@ -256,8 +257,7 @@ public class SecureHeadersGatewayFilterFactoryUnitTests { ServerHttpResponse response = exchange.getResponse(); assertThat(response.getHeaders()).containsOnlyKeys(X_XSS_PROTECTION_HEADER, X_FRAME_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_HEADER, REFERRER_POLICY_HEADER, CONTENT_SECURITY_POLICY_HEADER, - X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, - PERMISSIONS_POLICY_HEADER); + X_DOWNLOAD_OPTIONS_HEADER, X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, PERMISSIONS_POLICY_HEADER); assertThat(response.getHeaders().get(PERMISSIONS_POLICY_HEADER)).containsExactly("camera=*"); } From 329143c28e8a09d2fca27b79f0c9a49273c5ce90 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Fri, 11 Apr 2025 17:18:04 -0400 Subject: [PATCH 19/85] User Assert4J --- .../gateway/route/builder/GatewayFilterSpec.java | 2 +- .../actuate/GatewayControllerEndpointTests.java | 3 +-- .../filter/RouteToRequestUrlFilterTests.java | 4 ++-- .../ratelimit/RedisRateLimiterUnitTests.java | 5 +++-- .../cloud/gateway/handler/AsyncPredicateTest.java | 7 ++++--- .../RoutePredicateHandlerMappingTests.java | 15 ++++++++------- .../support/ConfigurationServiceTests.java | 6 +++--- .../test/CustomBlockHoundIntegrationTest.java | 5 +++-- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index 0e1a2df7..47723b74 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -31,7 +31,6 @@ import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.core.ParameterizedTypeReference; import reactor.retry.Repeat; import reactor.retry.Retry; @@ -84,6 +83,7 @@ import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter; import org.springframework.cloud.gateway.route.Route; import org.springframework.core.Ordered; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpStatus; import org.springframework.util.unit.DataSize; import org.springframework.web.server.ServerWebExchange; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java index ef599fb6..b24e7d1e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java @@ -26,7 +26,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.assertj.core.util.Maps; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -200,7 +199,7 @@ public class GatewayControllerEndpointTests { .expectBody(ResponseEntity.class) .consumeWith(result -> { HttpStatusCode httpStatus = result.getStatus(); - Assertions.assertEquals(HttpStatus.OK, httpStatus); + assertThat(HttpStatus.OK).isEqualTo(httpStatus); }); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java index f48d6312..d2ea0b90 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/RouteToRequestUrlFilterTests.java @@ -18,7 +18,6 @@ package org.springframework.cloud.gateway.filter; import java.net.URI; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import reactor.core.publisher.Mono; @@ -32,6 +31,7 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -64,7 +64,7 @@ public class RouteToRequestUrlFilterTests { @Test public void invalidHost() { - Assertions.assertThrows(IllegalStateException.class, () -> { + assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost/getb").build(); testFilter(request, "lb://my_host"); }); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java index f2fd7b70..0e4fe3b4 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java @@ -18,7 +18,6 @@ package org.springframework.cloud.gateway.filter.ratelimit; import io.lettuce.core.RedisException; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,6 +31,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -78,7 +78,8 @@ public class RedisRateLimiterUnitTests { @Test public void shouldThrowWhenNotInitialized() { - Assertions.assertThrows(IllegalStateException.class, () -> redisRateLimiter.isAllowed(ROUTE_ID, REQUEST_ID)); + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> redisRateLimiter.isAllowed(ROUTE_ID, REQUEST_ID)); } @Test diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/AsyncPredicateTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/AsyncPredicateTest.java index 876e5fed..321d5ceb 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/AsyncPredicateTest.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/AsyncPredicateTest.java @@ -18,13 +18,14 @@ package org.springframework.cloud.gateway.handler; import java.util.function.Predicate; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import static org.assertj.core.api.Assertions.assertThat; + public class AsyncPredicateTest { @Test @@ -110,12 +111,12 @@ public class AsyncPredicateTest { @DisplayName("predicate must have been tested") public void assertTested() { - Assertions.assertTrue(tested); + assertThat(tested).isTrue(); } @DisplayName("predicate must not have been tested") public void assertUntested() { - Assertions.assertFalse(tested); + assertThat(tested).isFalse(); } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMappingTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMappingTests.java index cee04bdb..fa6da9f9 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMappingTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMappingTests.java @@ -16,7 +16,6 @@ package org.springframework.cloud.gateway.handler; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -32,6 +31,8 @@ import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.mock.env.MockEnvironment; import org.springframework.web.server.ServerWebExchange; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Simon Baslé */ @@ -57,8 +58,8 @@ public class RoutePredicateHandlerMappingTests { final Mono routeMono = mapping.lookupRoute(Mockito.mock(ServerWebExchange.class)); StepVerifier.create(routeMono.map(Route::getId)).expectNext("routeTrue").verifyComplete(); - Assertions.assertTrue(capturedOutput.getOut().contains("Error applying predicate for route: routeFail")); - Assertions.assertTrue(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom")); + assertThat(capturedOutput.getOut().contains("Error applying predicate for route: routeFail")).isTrue(); + assertThat(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom")).isTrue(); } @Test @@ -89,11 +90,11 @@ public class RoutePredicateHandlerMappingTests { StepVerifier.create(routeMono.map(Route::getId)).expectNext("routeTrue").verifyComplete(); - Assertions.assertTrue(capturedOutput.getOut().contains("Error applying predicate for route: routeError")); - Assertions.assertTrue(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom1")); + assertThat(capturedOutput.getOut().contains("Error applying predicate for route: routeError")).isTrue(); + assertThat(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom1")).isTrue(); - Assertions.assertTrue(capturedOutput.getOut().contains("Error applying predicate for route: routeFail")); - Assertions.assertTrue(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom2")); + assertThat(capturedOutput.getOut().contains("Error applying predicate for route: routeFail")).isTrue(); + assertThat(capturedOutput.getOut().contains("java.lang.IllegalStateException: boom2")).isTrue(); } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ConfigurationServiceTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ConfigurationServiceTests.java index e4c8db84..82f7644e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ConfigurationServiceTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ConfigurationServiceTests.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.Map; import jakarta.validation.constraints.Max; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.bind.BindException; @@ -30,6 +29,7 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class ConfigurationServiceTests { @@ -37,7 +37,7 @@ public class ConfigurationServiceTests { public void validationOnCreateWorks() { Map map = Collections.singletonMap("config.value", 11); - Assertions.assertThrows(BindException.class, () -> ConfigurationService + assertThatExceptionOfType(BindException.class).isThrownBy(() -> ConfigurationService .bindOrCreate(Bindable.of(ValidatedConfig.class), map, "config", getValidator(), null)); } @@ -57,7 +57,7 @@ public class ConfigurationServiceTests { ValidatedConfig config = new ValidatedConfig(); - Assertions.assertThrows(BindException.class, () -> ConfigurationService + assertThatExceptionOfType(BindException.class).isThrownBy(() -> ConfigurationService .bindOrCreate(Bindable.ofInstance(config), map, "config", getValidator(), null)); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java index 308c0b93..7b0119a7 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java @@ -16,7 +16,6 @@ package org.springframework.cloud.gateway.test; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; @@ -24,6 +23,8 @@ import org.junit.jupiter.api.condition.JRE; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + /** * @author Tim Ysewyn */ @@ -34,7 +35,7 @@ public class CustomBlockHoundIntegrationTest { // Disable this test for now flaky on GitHub Actions @Disabled public void shouldThrowErrorForBlockingCallWithCustomBlockHoundIntegration() { - Assertions.assertThrows(RuntimeException.class, () -> Mono.fromCallable(() -> { + assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> Mono.fromCallable(() -> { Thread.sleep(1); return null; }).subscribeOn(Schedulers.parallel()).block()); From c6ed8455579fd64ec15b9f56da6ec38f029531cb Mon Sep 17 00:00:00 2001 From: Stepan Mikhailiuk Date: Sun, 13 Apr 2025 22:11:33 +0800 Subject: [PATCH 20/85] feat(gateway-filter): add SetRequestUri gateway filter Signed-off-by: Stepan Mikhailiuk --- .../seturi-factory.adoc | 26 ++++ .../config/GatewayAutoConfiguration.java | 7 ++ .../SetRequestUriGatewayFilterFactory.java | 112 ++++++++++++++++++ .../route/builder/GatewayFilterSpec.java | 11 ++ ...iGatewayFilterFactoryIntegrationTests.java | 79 ++++++++++++ ...etRequestUriGatewayFilterFactoryTests.java | 83 +++++++++++++ .../cloud/gateway/test/AdhocTestSuite.java | 2 + 7 files changed, 320 insertions(+) create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc new file mode 100644 index 00000000..2251d13b --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/seturi-factory.adoc @@ -0,0 +1,26 @@ +[[seturi-gatewayfilter-factory]] += `SetRequestUri` `GatewayFilter` Factory + +The `SetRequestUri` `GatewayFilter` factory takes a `uri` parameter. +It offers a simple way to manipulate the request uri by allowing templated segments of the path. +This uses the URI templates from Spring Framework. +Multiple matching segments are allowed. +The following listing configures a `SetRequestUri` `GatewayFilter`: + +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: seturi_route + uri: no://op + predicates: + - Path=/{appId}/** + filters: + - SetRequestUri=http://{appId}.example.com +---- + +For a request path of `/red-application/blue`, this sets the uri to `http://red-application.example.com` before making the downstream request and the final url, including path is going to be `http://red-application.example.com/red-application/blue` + diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 5d399d95..60108fa6 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -110,6 +110,7 @@ import org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties; import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetRequestHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetRequestHostHeaderGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory; @@ -718,6 +719,12 @@ public class GatewayAutoConfiguration { return new RequestHeaderToRequestUriGatewayFilterFactory(); } + @Bean + @ConditionalOnEnabledFilter + public SetRequestUriGatewayFilterFactory setRequestUriGatewayFilterFactory() { + return new SetRequestUriGatewayFilterFactory(); + } + @Bean @ConditionalOnEnabledFilter public RequestSizeGatewayFilterFactory requestSizeGatewayFilterFactory() { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java new file mode 100644 index 00000000..2910d88d --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java @@ -0,0 +1,112 @@ +/* + * 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.filter.factory; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; + +import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.getUriTemplateVariables; + +/** + * This filter changes the request uri. + * + * @author Stepan Mikhailiuk + */ +public class SetRequestUriGatewayFilterFactory + extends AbstractChangeRequestUriGatewayFilterFactory { + + private static final Logger log = LoggerFactory.getLogger(SetRequestUriGatewayFilterFactory.class); + + public SetRequestUriGatewayFilterFactory() { + super(Config.class); + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList(NAME_KEY); + } + + @Override + public GatewayFilter apply(Config config) { + // AbstractChangeRequestUriGatewayFilterFactory.apply() returns + // OrderedGatewayFilter + OrderedGatewayFilter gatewayFilter = (OrderedGatewayFilter) super.apply(config); + return new OrderedGatewayFilter(gatewayFilter, gatewayFilter.getOrder()) { + @Override + public String toString() { + return filterToStringCreator(SetRequestUriGatewayFilterFactory.this) + .append("template", config.getTemplate()) + .toString(); + } + }; + } + + String getUri(ServerWebExchange exchange, Config config) { + String template = config.getTemplate(); + + if (template.indexOf('{') == -1) { + return template; + } + + Map variables = getUriTemplateVariables(exchange); + return UriComponentsBuilder.fromUriString(template).build().expand(variables).toUriString(); + } + + @Override + protected Optional determineRequestUri(ServerWebExchange exchange, Config config) { + try { + String url = getUri(exchange, config); + URI uri = URI.create(url); + if (!uri.isAbsolute()) { + throw new IllegalArgumentException("URI is not absolute"); + } + return Optional.of(uri); + } + catch (IllegalArgumentException e) { + + log.info("Request url is invalid : url={}, error={}", config.getTemplate(), e.getMessage()); + return Optional.ofNullable(null); + } + } + + public static class Config { + + private String template; + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index 47723b74..8b87e45a 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -58,6 +58,7 @@ import org.springframework.cloud.gateway.filter.factory.RemoveRequestParameterGa import org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestHeaderSizeGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory; @@ -869,6 +870,16 @@ public class GatewayFilterSpec extends UriSpec { return filter(getBean(RequestHeaderToRequestUriGatewayFilterFactory.class).apply(c -> c.setName(headerName))); } + /** + * A filter which changes the URI the request will be routed to by the Gateway by + * pulling it from a header on the request. + * @param uri the URI + * @return a {@link GatewayFilterSpec} that can be used to apply additional filters + */ + public GatewayFilterSpec setRequestUri(String uri) { + return filter(getBean(SetRequestUriGatewayFilterFactory.class).apply(c -> c.setTemplate(uri))); + } + /** * A filter which change the URI the request will be routed to by the Gateway. * @param determineRequestUri a {@link Function} which takes a diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java new file mode 100644 index 00000000..b52a81af --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryIntegrationTests.java @@ -0,0 +1,79 @@ +/* + * 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.filter.factory; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Stepan Mikhailiuk + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +public class SetRequestUriGatewayFilterFactoryIntegrationTests extends BaseWebClientTests { + + @LocalServerPort + int port; + + @Test + public void setUriWorkWithProperties() { + testClient.get().uri("/").header("Host", "testservice.setrequesturi.org").exchange().expectStatus().isOk(); + + testClient.get() + .uri("/service/testservice") + .header("Host", "setrequesturi.org") + .exchange() + .expectStatus() + .isOk(); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + @Bean + public RouteLocator routeLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("map_subdomain_to_service_name", + r -> r.host("{serviceName}.setrequesturi.org") + .filters(f -> f.prefixPath("/httpbin").setRequestUri("lb://{serviceName}")) + .uri("no://op")) + .route("map_path_to_service_name", + r -> r.host("setrequesturi.org") + .and() + .path("/service/{serviceName}") + .filters(f -> f.rewritePath("/.*", "/").setRequestUri("lb://{serviceName}")) + .uri("no://op")) + .build(); + } + + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java new file mode 100644 index 00000000..2366b0c8 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactoryTests.java @@ -0,0 +1,83 @@ +/* + * 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.filter.factory; + +import java.net.URI; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.server.ServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; + +/** + * @author Stepan Mikhailiuk + */ +public class SetRequestUriGatewayFilterFactoryTests { + + @Test + public void filterChangeRequestUri() { + SetRequestUriGatewayFilterFactory factory = new SetRequestUriGatewayFilterFactory(); + GatewayFilter filter = factory.apply(c -> c.setTemplate("https://example.com")); + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost").build(); + ServerWebExchange exchange = MockServerWebExchange.from(request); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost")); + GatewayFilterChain filterChain = mock(GatewayFilterChain.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + when(filterChain.filter(captor.capture())).thenReturn(Mono.empty()); + filter.filter(exchange, filterChain); + ServerWebExchange webExchange = captor.getValue(); + URI uri = (URI) webExchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR); + assertThat(uri).isNotNull(); + assertThat(uri.toString()).isEqualTo("https://example.com"); + } + + @Test + public void filterDoesNotChangeRequestUriIfUriIsInvalid() throws Exception { + SetRequestUriGatewayFilterFactory factory = new SetRequestUriGatewayFilterFactory(); + GatewayFilter filter = factory.apply(c -> c.setTemplate("invalid_uri")); + MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost").build(); + ServerWebExchange exchange = MockServerWebExchange.from(request); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost")); + GatewayFilterChain filterChain = mock(GatewayFilterChain.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + when(filterChain.filter(captor.capture())).thenReturn(Mono.empty()); + filter.filter(exchange, filterChain); + ServerWebExchange webExchange = captor.getValue(); + URI uri = (URI) webExchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR); + assertThat(uri).isNotNull(); + assertThat(uri.toURL().toString()).isEqualTo("http://localhost"); + } + + @Test + public void toStringFormat() { + SetRequestUriGatewayFilterFactory.Config config = new SetRequestUriGatewayFilterFactory.Config(); + config.setTemplate("http://localhost:8080"); + GatewayFilter filter = new SetRequestUriGatewayFilterFactory().apply(config); + assertThat(filter.toString()).contains("http://localhost:8080"); + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java index 38041174..bba39646 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java @@ -66,6 +66,8 @@ import static org.junit.Assume.assumeThat; RewriteLocationResponseHeaderGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactoryIntegrationTests.class, + org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactoryTests.class, + org.springframework.cloud.gateway.filter.factory.SetRequestUriGatewayFilterFactoryIntegrationTests.class, org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactoryTests.class, org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactoryIntegrationTests.class, From d973fcb224e18531382986801f57b048f813b074 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:44:01 +0000 Subject: [PATCH 21/85] Bump grpc.version from 1.71.0 to 1.72.0 Bumps `grpc.version` from 1.71.0 to 1.72.0. Updates `io.grpc:grpc-netty` from 1.71.0 to 1.72.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.71.0...v1.72.0) Updates `io.grpc:grpc-protobuf` from 1.71.0 to 1.72.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.71.0...v1.72.0) Updates `io.grpc:grpc-stub` from 1.71.0 to 1.72.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.71.0...v1.72.0) --- updated-dependencies: - dependency-name: io.grpc:grpc-netty dependency-version: 1.72.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.grpc:grpc-protobuf dependency-version: 1.72.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.grpc:grpc-stub dependency-version: 1.72.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 6842696a..7fb5e368 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -12,7 +12,7 @@ 3.25.1 - 1.71.0 + 1.72.0 diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 2a61283f..97394898 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -16,7 +16,7 @@ Spring Cloud Gateway Server ${basedir}/.. - 1.71.0 + 1.72.0 1.0.0 From cd46e48e2b00868c5b20b4eb02c4bf3cd55553dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E4=BB=98=E4=B8=80=E7=94=B7?= Date: Thu, 16 Jan 2025 22:14:09 +0800 Subject: [PATCH 22/85] Support setting Spring.webflux.base-path and supporting it in path predicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 郭付一男 --- .../config/GatewayAutoConfiguration.java | 6 +- .../predicate/PathRoutePredicateFactory.java | 26 ++++++- .../GatewayPredicateVisitorTests.java | 75 ++++++++++++++++++- .../PathRoutePredicateFactoryTests.java | 5 +- ...dicatePathContainerAttrBenchMarkTests.java | 3 +- .../GatewayPathTagsProviderTests.java | 7 +- 6 files changed, 111 insertions(+), 11 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index be86096b..e9d920f3 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -56,6 +56,7 @@ import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.ssl.SslBundles; @@ -190,6 +191,7 @@ import org.springframework.web.reactive.socket.server.upgrade.ReactorNettyReques * @author Mete Alpaslan Katırcıoğlu * @author Alberto C. Ríos * @author Olga Maciaszek-Sharma + * @author FuYiNan Guo */ @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) @@ -471,8 +473,8 @@ public class GatewayAutoConfiguration { @Bean @ConditionalOnEnabledPredicate - public PathRoutePredicateFactory pathRoutePredicateFactory() { - return new PathRoutePredicateFactory(); + public PathRoutePredicateFactory pathRoutePredicateFactory(WebFluxProperties webFluxProperties) { + return new PathRoutePredicateFactory(webFluxProperties); } @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java index 509b78d7..45550df5 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java @@ -24,8 +24,10 @@ import java.util.function.Predicate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; import org.springframework.core.style.ToStringCreator; import org.springframework.http.server.PathContainer; +import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.pattern.PathPattern; import org.springframework.web.util.pattern.PathPattern.PathMatchInfo; @@ -41,6 +43,7 @@ import static org.springframework.http.server.PathContainer.parsePath; /** * @author Spencer Gibb * @author Dhawal Kapil + * @author FuYiNan Guo */ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory { @@ -50,8 +53,20 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory { - PathPattern pathPattern = this.pathPatternParser.parse(pattern); + String basePath = webFluxProperties.getBasePath(); + boolean basePathIsNotBlank = StringUtils.hasText(basePath); + String pathPatternStr = pattern; + if (basePathIsNotBlank) { + if (pattern.length() > 1 && !pattern.startsWith("/")) { + basePath += ("/"); + } + pathPatternStr = basePath + pattern; + } + PathPattern pathPattern = this.pathPatternParser.parse(pathPatternStr); pathPatterns.add(pathPattern); }); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java index bb5c0d12..c55087fc 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java @@ -16,25 +16,41 @@ package org.springframework.cloud.gateway.handler.predicate; +import java.net.URI; import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; import java.util.function.Predicate; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import reactor.core.publisher.Mono; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory; import org.springframework.cloud.gateway.handler.AsyncPredicate; import org.springframework.cloud.gateway.route.Route; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; /** * @author Spencer Gibb + * @author FuYiNan Guo */ public class GatewayPredicateVisitorTests { @Test public void asyncPredicateVisitVisitsEachNode() { - PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(); + PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties()); HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory(); ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory1 = new ReadBodyRoutePredicateFactory(); ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory2 = new ReadBodyRoutePredicateFactory(); @@ -55,7 +71,7 @@ public class GatewayPredicateVisitorTests { @Test public void predicateVisitVisitsEachNode() { - PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(); + PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(new WebFluxProperties()); HostRoutePredicateFactory hostRoutePredicateFactory = new HostRoutePredicateFactory(); Predicate predicate = pathRoutePredicateFactory.apply(pathRoutePredicateFactory.newConfig()) .and(hostRoutePredicateFactory.apply(hostRoutePredicateFactory.newConfig())); @@ -68,4 +84,59 @@ public class GatewayPredicateVisitorTests { .hasExactlyElementsOfTypes(PathRoutePredicateFactory.Config.class, HostRoutePredicateFactory.Config.class); } + @Test + public void pathRoutePredicateVisitWithSetWebfluxBasePath() { + WebFluxProperties webFluxProperties = new WebFluxProperties(); + webFluxProperties.setBasePath("/gw/api/v1"); + + PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties); + PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() + .setPatterns(List.of("/temp/**")) + .setMatchTrailingSlash(true); + + Predicate predicate = pathRoutePredicateFactory.apply(config); + + ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test") + .build()); + + assertThat(predicate.test(exchange)).isEqualTo(true); + } + + @Test + public void pathRoutePredicateVisitWithSetWebfluxBasePathStripPrefix() { + WebFluxProperties webFluxProperties = new WebFluxProperties(); + webFluxProperties.setBasePath("/gw/api/v1"); + + PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties); + PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() + .setPatterns(List.of("/temp/**")) + .setMatchTrailingSlash(true); + + Predicate predicate = pathRoutePredicateFactory.apply(config); + + ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test") + .build()); + + assertThat(predicate.test(exchange)).isEqualTo(true); + + // webflux base path strips prefix is 3 + GatewayFilter filter = new StripPrefixGatewayFilterFactory().apply(c -> c.setParts(3)); + + GatewayFilterChain filterChain = mock(GatewayFilterChain.class); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + when(filterChain.filter(captor.capture())).thenReturn(Mono.empty()); + + filter.filter(exchange, filterChain); + + ServerWebExchange webExchange = captor.getValue(); + + assertThat(webExchange.getRequest().getURI()).hasPath("/temp/test"); + + URI requestUrl = webExchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); + assertThat(requestUrl).hasScheme("http").hasHost("127.0.0.1").hasPort(8080).hasPath("/temp/test"); + + LinkedHashSet uris = webExchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR); + assertThat(uris).contains(exchange.getRequest().getURI()); + } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactoryTests.java index a27c7559..539d8564 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactoryTests.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config; @@ -133,14 +134,14 @@ public class PathRoutePredicateFactoryTests extends BaseWebClientTests { @Test public void toStringFormat() { Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(false); - Predicate predicate = new PathRoutePredicateFactory().apply(config); + Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config); assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("false"); } @Test public void toStringFormatMatchTrailingSlashTrue() { Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB")).setMatchTrailingSlash(true); - Predicate predicate = new PathRoutePredicateFactory().apply(config); + Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config); assertThat(predicate.toString()).contains("patternA").contains("patternB").contains("true"); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java index 41055e5c..5fb9a092 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java @@ -30,6 +30,7 @@ import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.web.server.ServerWebExchange; @@ -54,7 +55,7 @@ public class PathRoutePredicatePathContainerAttrBenchMarkTests { PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() .setPatterns(Collections.singletonList(PATH_PATTERN_PREFIX + i)) .setMatchTrailingSlash(true); - Predicate predicate = new PathRoutePredicateFactory().apply(config); + Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config); predicates.add(predicate); } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayPathTagsProviderTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayPathTagsProviderTests.java index bb058821..ccdc9ba6 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayPathTagsProviderTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayPathTagsProviderTests.java @@ -22,6 +22,7 @@ import java.util.List; import io.micrometer.core.instrument.Tags; import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties; import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory; import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory; import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory; @@ -56,7 +57,7 @@ public class GatewayPathTagsProviderTests { Route route = Route.async() .id("git") .uri(ROUTE_URI) - .predicate(new PathRoutePredicateFactory().apply(pathConfig) + .predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig) .and(new HostRoutePredicateFactory().apply(hostConfig))) .build(); @@ -81,8 +82,8 @@ public class GatewayPathTagsProviderTests { Route route = Route.async() .id("git") .uri(ROUTE_URI) - .predicate(new PathRoutePredicateFactory().apply(pathConfig) - .or(new PathRoutePredicateFactory().apply(pathConfig2))) + .predicate(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig) + .or(new PathRoutePredicateFactory(new WebFluxProperties()).apply(pathConfig2))) .build(); ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(ROUTE_URI).build()); From ac5e8f7cecfe95f06c429375ad5386bf350795ce Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Mon, 21 Apr 2025 15:28:18 -0400 Subject: [PATCH 23/85] Allow bean registration of server-webmcv components (#3763) * Allow bean registration of server-webmcv components This replaces the spring.factories mechanism. * Adds support for loading FilterSuppliers via beans * Adds support for loading PredicateSuppliers via beans * Use beanFactory conversionService Fixes gh-3250 --- ...writing-custom-predicates-and-filters.adoc | 43 +++++- .../GatewayServerMvcAutoConfiguration.java | 16 ++- .../common/BeanFactoryGatewayDiscoverer.java | 38 ++++++ .../GatewayMvcAotRuntimeHintsRegistrar.java | 11 +- .../config/RouterFunctionHolderFactory.java | 127 +++++++++++++----- .../mvc/filter/FilterAutoConfiguration.java | 107 +++++++++++++++ .../filter/FilterBeanFactoryDiscoverer.java | 34 +++++ .../filter/LoadBalancerHandlerSupplier.java | 47 ------- .../mvc/handler/DefaultHandlerSupplier.java | 113 ---------------- .../HandlerFunctionAutoConfiguration.java | 93 +++++++++++++ .../handler/HandlerFunctionDefinition.java | 45 +++++++ .../predicate/PredicateAutoConfiguration.java | 41 ++++++ .../PredicateBeanFactoryDiscoverer.java | 34 +++++ .../main/resources/META-INF/spring.factories | 15 --- ...ot.autoconfigure.AutoConfiguration.imports | 3 + ...atewayServerMvcAutoConfigurationTests.java | 9 +- .../mvc/filter/FilterDiscovererTests.java | 45 +++++++ .../PredicateBeanFactoryDiscovererTests.java | 49 +++++++ .../mvc/test/TestPredicateSupplier.java | 37 +++++ .../test/resources/META-INF/spring.factories | 3 + 20 files changed, 689 insertions(+), 221 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/BeanFactoryGatewayDiscoverer.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterBeanFactoryDiscoverer.java delete mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java delete mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateAutoConfiguration.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscoverer.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/FilterDiscovererTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscovererTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestPredicateSupplier.java diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc index 597b00fe..1364150e 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc @@ -240,13 +240,12 @@ The above route will add a `X-Response-Id` header to the response. Note the use == How To Register Custom Predicates and Filters for Configuration -To use custom Predicates and Filters in external configuration you need to create a special Supplier class and register it in `META-INF/spring.factories`. +To use custom Predicates and Filters in external configuration you need to create a special Supplier class and register it a bean in the application context. === Registering Custom Predicates To register custom predicates you need to implement `PredicateSupplier`. The `PredicateDiscoverer` looks for static methods that return `RequestPredicates` to register. - SampleFilterSupplier.java [source,java] ---- @@ -254,7 +253,6 @@ package com.example; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier; -@Configuration class SamplePredicateSupplier implements PredicateSupplier { @Override @@ -265,7 +263,24 @@ class SamplePredicateSupplier implements PredicateSupplier { } ---- -You then need to add the class in `META-INF/spring.factories`. +To register the `PredicateSupplier` for use in config files, you then need to add the class as a bean as in the example below: + +.PredicateConfiguration.java +[source,java] +---- +package com.example; + +@Configuration +class PredicateConfiguration { + + @Bean + public SamplePredicateSupplier samplePredicateSupplier() { + return new SamplePredicateSupplier(); + } +} +---- + +The requirement to add the class to `META-INF/spring.factories` is deprecated and will be removed in the next major release. .META-INF/spring.factories [source] @@ -285,7 +300,6 @@ package com.example; import org.springframework.cloud.gateway.server.mvc.filter.SimpleFilterSupplier; -@Configuration class SampleFilterSupplier extends SimpleFilterSupplier { public SampleFilterSupplier() { @@ -294,7 +308,24 @@ class SampleFilterSupplier extends SimpleFilterSupplier { } ---- -You then need to add the class in `META-INF/spring.factories`. +To register the `FilterSupplier` for use in config files, you then need to add the class as a bean as in the example below: + +.FilterConfiguration.java +[source,java] +---- +package com.example; + +@Configuration +class FilterConfiguration { + + @Bean + public SampleFilterSupplier sampleFilterSupplier() { + return new SampleFilterSupplier(); + } +} +---- + +The requirement to add the class to `META-INF/spring.factories` is deprecated and will be removed in the next major release. .META-INF/spring.factories [source] diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index dabf7d2d..dfdbd1bc 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -18,6 +18,7 @@ package org.springframework.cloud.gateway.server.mvc; import java.util.Map; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -35,6 +36,8 @@ import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcAotRuntimeH import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar; import org.springframework.cloud.gateway.server.mvc.config.RouterFunctionHolderFactory; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.filter.FilterBeanFactoryDiscoverer; import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; import org.springframework.cloud.gateway.server.mvc.filter.ForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.HttpHeadersFilter.RequestHttpHeadersFilter; @@ -47,9 +50,12 @@ import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNorma import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchange; import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction; import org.springframework.cloud.gateway.server.mvc.handler.RestClientProxyExchange; +import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.predicate.PredicateBeanFactoryDiscoverer; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateDiscoverer; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; @@ -70,7 +76,8 @@ import org.springframework.web.client.RestClient; * @author Jürgen Wißkirchen */ @AutoConfiguration(after = { HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, - RestClientAutoConfiguration.class }) + RestClientAutoConfiguration.class, FilterAutoConfiguration.class, HandlerFunctionAutoConfiguration.class, + PredicateAutoConfiguration.class }) @ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) @Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class) @ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class) @@ -83,8 +90,11 @@ public class GatewayServerMvcAutoConfiguration { } @Bean - public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env) { - return new RouterFunctionHolderFactory(env); + public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env, BeanFactory beanFactory, + FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer, + PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer) { + return new RouterFunctionHolderFactory(env, beanFactory, filterBeanFactoryDiscoverer, + predicateBeanFactoryDiscoverer); } @Bean diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/BeanFactoryGatewayDiscoverer.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/BeanFactoryGatewayDiscoverer.java new file mode 100644 index 00000000..5a519573 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/BeanFactoryGatewayDiscoverer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.common; + +import java.util.List; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ObjectProvider; + +public abstract class BeanFactoryGatewayDiscoverer extends AbstractGatewayDiscoverer { + + protected final BeanFactory beanFactory; + + protected BeanFactoryGatewayDiscoverer(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override + protected List loadSuppliers(Class supplierClass) { + ObjectProvider beanProvider = beanFactory.getBeanProvider(supplierClass); + return beanProvider.orderedStream().toList(); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java index e4482d3a..c171c240 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java @@ -29,9 +29,9 @@ import org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions import org.springframework.cloud.gateway.server.mvc.filter.BodyFilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions; -import org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerHandlerSupplier; import org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions; import org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions; import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions; @@ -46,11 +46,12 @@ import org.springframework.util.ClassUtils; */ public class GatewayMvcAotRuntimeHintsRegistrar implements RuntimeHintsRegistrar { + // TODO: fix AOT HINTS private static final Set> FUNCTION_PROVIDERS = Set.of(HandlerFunctions.class, - LoadBalancerHandlerSupplier.class, FilterFunctions.class, BeforeFilterFunctions.class, - AfterFilterFunctions.class, TokenRelayFilterFunctions.class, BodyFilterFunctions.class, - CircuitBreakerFilterFunctions.class, GatewayRouterFunctions.class, LoadBalancerFilterFunctions.class, - GatewayRequestPredicates.class, Bucket4jFilterFunctions.class); + FilterAutoConfiguration.LoadBalancerHandlerConfiguration.class, FilterFunctions.class, + BeforeFilterFunctions.class, AfterFilterFunctions.class, TokenRelayFilterFunctions.class, + BodyFilterFunctions.class, CircuitBreakerFilterFunctions.class, GatewayRouterFunctions.class, + LoadBalancerFilterFunctions.class, GatewayRequestPredicates.class, Bucket4jFilterFunctions.class); private static final Set> PROPERTIES = Set.of(FilterProperties.class, PredicateProperties.class, RouteProperties.class); diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java index 6bc52a52..0973f657 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java @@ -28,10 +28,15 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.handler.IgnoreTopLevelConverterNotFoundBindHandler; @@ -39,8 +44,10 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.cloud.gateway.server.mvc.common.Configurable; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; +import org.springframework.cloud.gateway.server.mvc.filter.FilterBeanFactoryDiscoverer; import org.springframework.cloud.gateway.server.mvc.filter.FilterDiscoverer; import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionDefinition; import org.springframework.cloud.gateway.server.mvc.invoke.InvocationContext; import org.springframework.cloud.gateway.server.mvc.invoke.OperationArgumentResolver; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; @@ -49,10 +56,13 @@ import org.springframework.cloud.gateway.server.mvc.invoke.ParameterValueMapper; import org.springframework.cloud.gateway.server.mvc.invoke.convert.ConversionServiceParameterValueMapper; import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod; import org.springframework.cloud.gateway.server.mvc.invoke.reflect.ReflectiveOperationInvoker; +import org.springframework.cloud.gateway.server.mvc.predicate.PredicateBeanFactoryDiscoverer; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateDiscoverer; +import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.Environment; import org.springframework.core.log.LogMessage; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.servlet.function.HandlerFilterFunction; @@ -102,8 +112,37 @@ public class RouterFunctionHolderFactory { private final ParameterValueMapper parameterValueMapper = new ConversionServiceParameterValueMapper(); + private final BeanFactory beanFactory; + + private final FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer; + + private final PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer; + + private final ConversionService conversionService; + + @Deprecated public RouterFunctionHolderFactory(Environment env) { + this(env, null, null, null); + } + + public RouterFunctionHolderFactory(Environment env, BeanFactory beanFactory, + FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer, + PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer) { this.env = env; + this.beanFactory = beanFactory; + this.filterBeanFactoryDiscoverer = filterBeanFactoryDiscoverer; + this.predicateBeanFactoryDiscoverer = predicateBeanFactoryDiscoverer; + if (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) { + if (configurableBeanFactory.getConversionService() != null) { + this.conversionService = configurableBeanFactory.getConversionService(); + } + else { + this.conversionService = DefaultConversionService.getSharedInstance(); + } + } + else { + this.conversionService = DefaultConversionService.getSharedInstance(); + } } /** @@ -153,41 +192,65 @@ public class RouterFunctionHolderFactory { // TODO: cache? // translate handlerFunction String scheme = routeProperties.getUri().getScheme(); - Map handlerArgs = new HashMap<>(); - Optional handlerOperationMethod = findOperation(handlerOperations, - scheme.toLowerCase(Locale.ROOT), handlerArgs); - if (handlerOperationMethod.isEmpty()) { - // single RouteProperties param - handlerArgs.clear(); - String routePropsKey = StringUtils.uncapitalize(RouteProperties.class.getSimpleName()); - handlerArgs.put(routePropsKey, routeProperties); - handlerOperationMethod = findOperation(handlerOperations, scheme.toLowerCase(Locale.ROOT), handlerArgs); - if (handlerOperationMethod.isEmpty()) { - throw new IllegalStateException("Unable to find HandlerFunction for scheme: " + scheme); - } - } - NormalizedOperationMethod normalizedOpMethod = handlerOperationMethod.get(); - Object response = invokeOperation(normalizedOpMethod, normalizedOpMethod.getNormalizedArgs()); - HandlerFunction handlerFunction = null; // filters added by HandlerDiscoverer need to go last, so save them + HandlerFunction handlerFunction = null; List> lowerPrecedenceFilters = new ArrayList<>(); List> higherPrecedenceFilters = new ArrayList<>(); - if (response instanceof HandlerFunction) { - handlerFunction = (HandlerFunction) response; - } - else if (response instanceof HandlerDiscoverer.Result result) { - handlerFunction = result.getHandlerFunction(); - lowerPrecedenceFilters.addAll(result.getLowerPrecedenceFilters()); - higherPrecedenceFilters.addAll(result.getHigherPrecedenceFilters()); + + if (beanFactory != null) { + try { + // TODO: configurable bean name? + String name = scheme + "HandlerFunctionDefinition"; + Function factory = beanFactory.getBean(name, Function.class); + HandlerFunctionDefinition definition = (HandlerFunctionDefinition) factory.apply(routeProperties); + handlerFunction = definition.handlerFunction(); + lowerPrecedenceFilters.addAll(definition.lowerPrecedenceFilters()); + higherPrecedenceFilters.addAll(definition.higherPrecedenceFilters()); + } + catch (NoSuchBeanDefinitionException | BeanNotOfRequiredTypeException | ClassCastException e) { + log.trace(LogMessage.format("Unable to locate bean of HandlerFunction for scheme %s", scheme), e); + } } + if (handlerFunction == null) { - throw new IllegalStateException( - "Unable to find HandlerFunction for scheme: " + scheme + " and response " + response); + Map handlerArgs = new HashMap<>(); + Optional handlerOperationMethod = findOperation(handlerOperations, + scheme.toLowerCase(Locale.ROOT), handlerArgs); + if (handlerOperationMethod.isEmpty()) { + // single RouteProperties param + handlerArgs.clear(); + String routePropsKey = StringUtils.uncapitalize(RouteProperties.class.getSimpleName()); + handlerArgs.put(routePropsKey, routeProperties); + handlerOperationMethod = findOperation(handlerOperations, scheme.toLowerCase(Locale.ROOT), handlerArgs); + if (handlerOperationMethod.isEmpty()) { + throw new IllegalStateException("Unable to find HandlerFunction for scheme: " + scheme); + } + } + + NormalizedOperationMethod normalizedOpMethod = handlerOperationMethod.get(); + Object response = invokeOperation(normalizedOpMethod, normalizedOpMethod.getNormalizedArgs()); + + if (response instanceof HandlerFunction) { + handlerFunction = (HandlerFunction) response; + } + else if (response instanceof HandlerDiscoverer.Result result) { + handlerFunction = result.getHandlerFunction(); + lowerPrecedenceFilters.addAll(result.getLowerPrecedenceFilters()); + higherPrecedenceFilters.addAll(result.getHigherPrecedenceFilters()); + } + if (handlerFunction == null) { + throw new IllegalStateException( + "Unable to find HandlerFunction for scheme: " + scheme + " and response " + response); + } } // translate predicates - MultiValueMap predicateOperations = predicateDiscoverer.getOperations(); + MultiValueMap predicateOperations = new LinkedMultiValueMap<>(); + if (predicateBeanFactoryDiscoverer != null) { + predicateOperations.addAll(predicateBeanFactoryDiscoverer.getOperations()); + } + predicateOperations.addAll(predicateDiscoverer.getOperations()); final AtomicReference predicate = new AtomicReference<>(); routeProperties.getPredicates().forEach(predicateProperties -> { @@ -214,7 +277,11 @@ public class RouterFunctionHolderFactory { lowerPrecedenceFilters.forEach(builder::filter); // translate filters - MultiValueMap filterOperations = filterDiscoverer.getOperations(); + MultiValueMap filterOperations = new LinkedMultiValueMap<>(); + if (filterBeanFactoryDiscoverer != null) { + filterOperations.addAll(filterBeanFactoryDiscoverer.getOperations()); + } + filterOperations.addAll(filterDiscoverer.getOperations()); routeProperties.getFilters().forEach(filterProperties -> { Map args = new LinkedHashMap<>(filterProperties.getArgs()); translate(filterOperations, filterProperties.getName(), args, HandlerFilterFunction.class, builder::filter); @@ -295,7 +362,7 @@ public class RouterFunctionHolderFactory { return operationInvoker.invoke(context); } - private static Object bindConfigurable(OperationMethod operationMethod, Map args, + private Object bindConfigurable(OperationMethod operationMethod, Map args, OperationParameter operationParameter) { Class configurableType = operationParameter.getType(); Configurable configurable = operationMethod.getMethod().getAnnotation(Configurable.class); @@ -305,8 +372,8 @@ public class RouterFunctionHolderFactory { Bindable bindable = Bindable.of(configurableType); List propertySources = Collections .singletonList(new MapConfigurationPropertySource(args)); - // TODO: potentially deal with conversion service - Binder binder = new Binder(propertySources, null, DefaultConversionService.getSharedInstance()); + + Binder binder = new Binder(propertySources, null, conversionService); Object config = binder.bindOrCreate("", bindable, new IgnoreTopLevelConverterNotFoundBindHandler()); return config; } diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java new file mode 100644 index 00000000..8f4126cf --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java @@ -0,0 +1,107 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.filter; + +import java.util.Collections; +import java.util.function.Function; + +import io.github.bucket4j.BucketConfiguration; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; +import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionDefinition; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.retry.support.RetryTemplate; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; + +@AutoConfiguration +public class FilterAutoConfiguration { + + @Bean + public FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer(BeanFactory beanFactory) { + return new FilterBeanFactoryDiscoverer(beanFactory); + } + + @Bean + public FilterFunctions.FilterSupplier filterFunctionsSupplier() { + return new FilterFunctions.FilterSupplier(); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(BucketConfiguration.class) + static class Bucket4jFilterConfiguration { + + @Bean + public Bucket4jFilterFunctions.FilterSupplier bucket4jFilterFunctionsSupplier() { + return new Bucket4jFilterFunctions.FilterSupplier(); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(CircuitBreaker.class) + static class CircuitBreakerFilterConfiguration { + + @Bean + public CircuitBreakerFilterFunctions.FilterSupplier circuitBreakerFilterFunctionsSupplier() { + return new CircuitBreakerFilterFunctions.FilterSupplier(); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(LoadBalancerClient.class) + public static class LoadBalancerHandlerConfiguration { + + @Bean + public Function lbHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("lb", HandlerFunctions.http(), + Collections.emptyList(), + Collections.singletonList(LoadBalancerFilterFunctions.lb(routeProperties.getUri().getHost()))); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(RetryTemplate.class) + static class RetryFilterConfiguration { + + @Bean + public RetryFilterFunctions.FilterSupplier retryFilterFunctionsSupplier() { + return new RetryFilterFunctions.FilterSupplier(); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(OAuth2AuthorizedClient.class) + static class TokenRelayFilterConfiguration { + + @Bean + public TokenRelayFilterFunctions.FilterSupplier tokenRelayFilterFunctionsSupplier() { + return new TokenRelayFilterFunctions.FilterSupplier(); + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterBeanFactoryDiscoverer.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterBeanFactoryDiscoverer.java new file mode 100644 index 00000000..cb9f47f0 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterBeanFactoryDiscoverer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.filter; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.gateway.server.mvc.common.BeanFactoryGatewayDiscoverer; +import org.springframework.web.servlet.function.HandlerFilterFunction; + +public class FilterBeanFactoryDiscoverer extends BeanFactoryGatewayDiscoverer { + + protected FilterBeanFactoryDiscoverer(BeanFactory beanFactory) { + super(beanFactory); + } + + @Override + public void discover() { + doDiscover(FilterSupplier.class, HandlerFilterFunction.class); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java deleted file mode 100644 index c2a0ad58..00000000 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.gateway.server.mvc.filter; - -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; -import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer; -import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions; -import org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier; - -public class LoadBalancerHandlerSupplier implements HandlerSupplier { - - @Override - public Collection get() { - return Arrays.asList(getClass().getMethods()); - } - - public static HandlerDiscoverer.Result lb(RouteProperties routeProperties) { - return lb(routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result lb(URI uri) { - // TODO: how to do something other than http - return new HandlerDiscoverer.Result(HandlerFunctions.http(), Collections.emptyList(), - Collections.singletonList(LoadBalancerFilterFunctions.lb(uri.getHost()))); - } - -} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java deleted file mode 100644 index 0adc142e..00000000 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2013-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.gateway.server.mvc.handler; - -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; -import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; -import org.springframework.web.servlet.function.HandlerFilterFunction; -import org.springframework.web.servlet.function.HandlerFunction; -import org.springframework.web.servlet.function.ServerResponse; - -class DefaultHandlerSupplier implements HandlerSupplier { - - @Override - public Collection get() { - return Arrays.asList(getClass().getMethods()); - } - - public static HandlerDiscoverer.Result fn(RouteProperties routeProperties) { - // fn:fnName - return fn(routeProperties.getUri().getSchemeSpecificPart()); - } - - public static HandlerDiscoverer.Result fn(String functionName) { - return new HandlerDiscoverer.Result(HandlerFunctions.fn(functionName), Collections.emptyList(), - Collections.emptyList()); - } - - public static HandlerDiscoverer.Result forward(RouteProperties routeProperties) { - return forward(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result forward(String id, URI uri) { - return new HandlerDiscoverer.Result(HandlerFunctions.forward(uri.getPath()), Collections.emptyList()); - } - - public static HandlerDiscoverer.Result http(RouteProperties routeProperties) { - return http(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result http(String id, URI uri) { - HandlerFunction http = HandlerFunctions.http(); - return getResult(id, uri, http); - } - - public static HandlerDiscoverer.Result https(RouteProperties routeProperties) { - return https(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result https(String id, URI uri) { - return getResult(id, uri, HandlerFunctions.https()); - } - - public static HandlerDiscoverer.Result no(RouteProperties routeProperties) { - return no(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result no(String id, URI uri) { - return getResult(id, uri, HandlerFunctions.no()); - } - - // for properties - public static HandlerDiscoverer.Result stream(RouteProperties routeProperties) { - // stream:bindingName - return stream(routeProperties.getUri().getSchemeSpecificPart()); - } - - public static HandlerDiscoverer.Result stream(String bindingName) { - return new HandlerDiscoverer.Result(HandlerFunctions.stream(bindingName), Collections.emptyList(), - Collections.emptyList()); - } - - private static HandlerDiscoverer.Result getResult(String id, URI uri, - HandlerFunction handlerFunction) { - HandlerFilterFunction setId = setIdFilter(id); - HandlerFilterFunction setRequest = setRequestUrlFilter(uri); - return new HandlerDiscoverer.Result(handlerFunction, Arrays.asList(setId, setRequest), Collections.emptyList()); - } - - private static HandlerFilterFunction setIdFilter(String id) { - return (request, next) -> { - MvcUtils.setRouteId(request, id); - return next.handle(request); - }; - } - - private static HandlerFilterFunction setRequestUrlFilter(URI uri) { - return (request, next) -> { - MvcUtils.setRequestUrl(request, uri); - return next.handle(request); - }; - } - -} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java new file mode 100644 index 00000000..3e4d3781 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java @@ -0,0 +1,93 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.handler; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Function; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; +import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.function.HandlerFilterFunction; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; + +@AutoConfiguration +public class HandlerFunctionAutoConfiguration { + + @Bean + public Function fnHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("fn", + HandlerFunctions.fn(routeProperties.getUri().getSchemeSpecificPart())); + } + + @Bean + public Function forwardHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("forward", + HandlerFunctions.forward(routeProperties.getUri().getPath())); + } + + @Bean + public Function httpHandlerFunctionDefinition() { + return routeProperties -> getResult("http", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.http()); + } + + @Bean + public Function httpsHandlerFunctionDefinition() { + return routeProperties -> getResult("https", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.https()); + } + + @Bean + public Function noHandlerFunctionDefinition() { + return routeProperties -> getResult("no", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.no()); + } + + @Bean + public Function streamHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("stream", + HandlerFunctions.stream(routeProperties.getUri().getSchemeSpecificPart())); + } + + private static HandlerFunctionDefinition getResult(String scheme, String id, URI uri, + HandlerFunction handlerFunction) { + HandlerFilterFunction setId = setIdFilter(id); + HandlerFilterFunction setRequest = setRequestUrlFilter(uri); + return new HandlerFunctionDefinition.Default(scheme, handlerFunction, Arrays.asList(setId, setRequest), + Collections.emptyList()); + } + + private static HandlerFilterFunction setIdFilter(String id) { + return (request, next) -> { + MvcUtils.setRouteId(request, id); + return next.handle(request); + }; + } + + private static HandlerFilterFunction setRequestUrlFilter(URI uri) { + return (request, next) -> { + MvcUtils.setRequestUrl(request, uri); + return next.handle(request); + }; + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java new file mode 100644 index 00000000..12d79fe6 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.handler; + +import java.util.Collections; +import java.util.List; + +import org.springframework.web.servlet.function.HandlerFilterFunction; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; + +public interface HandlerFunctionDefinition { + + HandlerFunction handlerFunction(); + + List> lowerPrecedenceFilters(); + + List> higherPrecedenceFilters(); + + record Default(String scheme, HandlerFunction handlerFunction, + List> lowerPrecedenceFilters, + List> higherPrecedenceFilters) + implements + HandlerFunctionDefinition { + + public Default(String scheme, HandlerFunction handlerFunction) { + this(scheme, handlerFunction, Collections.emptyList(), Collections.emptyList()); + } + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateAutoConfiguration.java new file mode 100644 index 00000000..4a3c612d --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateAutoConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.predicate; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +@AutoConfiguration +public class PredicateAutoConfiguration { + + @Bean + public PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer(BeanFactory beanFactory) { + return new PredicateBeanFactoryDiscoverer(beanFactory); + } + + @Bean + MvcPredicateSupplier mvcPredicateSupplier() { + return new MvcPredicateSupplier(); + } + + @Bean + GatewayRequestPredicates.PredicateSupplier gatewayRequestPredicateSupplier() { + return new GatewayRequestPredicates.PredicateSupplier(); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscoverer.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscoverer.java new file mode 100644 index 00000000..90f77967 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscoverer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.predicate; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.gateway.server.mvc.common.BeanFactoryGatewayDiscoverer; +import org.springframework.web.servlet.function.RequestPredicate; + +public class PredicateBeanFactoryDiscoverer extends BeanFactoryGatewayDiscoverer { + + protected PredicateBeanFactoryDiscoverer(BeanFactory beanFactory) { + super(beanFactory); + } + + @Override + public void discover() { + doDiscover(PredicateSupplier.class, RequestPredicate.class); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories index b7002f15..c208d466 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories @@ -15,21 +15,6 @@ # # -org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\ - org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.FilterSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.FilterSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.FilterSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions.FilterSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.FilterSupplier - -org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier=\ - org.springframework.cloud.gateway.server.mvc.handler.DefaultHandlerSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerHandlerSupplier - -org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\ - org.springframework.cloud.gateway.server.mvc.predicate.MvcPredicateSupplier,\ - org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.PredicateSupplier - org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration.GatewayHttpClientEnvironmentPostProcessor,\ org.springframework.cloud.gateway.server.mvc.common.MultipartEnvironmentPostProcessor diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 94282943..81772855 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,5 +1,8 @@ org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration org.springframework.cloud.gateway.server.mvc.GatewayMvcClassPathWarningAutoConfiguration +org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration +org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration org.springframework.cloud.gateway.server.mvc.handler.GatewayMultipartAutoConfiguration +org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration org.springframework.cloud.gateway.server.mvc.config.DefaultFunctionConfiguration \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 7eb56405..917c0a54 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -35,6 +35,7 @@ import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; import org.springframework.cloud.gateway.server.mvc.filter.ForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.RemoveContentLengthRequestHeadersFilter; @@ -44,6 +45,8 @@ import org.springframework.cloud.gateway.server.mvc.filter.RemoveHttp2StatusResp import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNormalizationRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration; import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -109,7 +112,8 @@ public class GatewayServerMvcAutoConfigurationTests { @Test void filterEnabledPropertiesWork() { new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(GatewayServerMvcAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class, SslAutoConfiguration.class)) .withPropertyValues("spring.cloud.gateway.mvc.form-filter.enabled=false", @@ -161,7 +165,8 @@ public class GatewayServerMvcAutoConfigurationTests { @Test void bootHttpClientPropertiesWork() { new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(GatewayServerMvcAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class, SslAutoConfiguration.class)) .withPropertyValues("spring.http.client.connect-timeout=1s", "spring.http.client.read-timeout=2s", diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/FilterDiscovererTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/FilterDiscovererTests.java new file mode 100644 index 00000000..0edce139 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/FilterDiscovererTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.filter; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod; +import org.springframework.util.MultiValueMap; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class FilterDiscovererTests { + + @Test + void contextLoads() { + MultiValueMap operations = new FilterDiscoverer().getOperations(); + assertThat(operations).isNotEmpty(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + static class Config { + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscovererTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscovererTests.java new file mode 100644 index 00000000..dcbe4ba1 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/predicate/PredicateBeanFactoryDiscovererTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.predicate; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod; +import org.springframework.util.MultiValueMap; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class PredicateBeanFactoryDiscovererTests { + + @Autowired + PredicateBeanFactoryDiscoverer discoverer; + + @Test + void contextLoads() { + MultiValueMap operations = discoverer.getOperations(); + assertThat(operations).isNotEmpty(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + static class Config { + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestPredicateSupplier.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestPredicateSupplier.java new file mode 100644 index 00000000..2ace83bd --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestPredicateSupplier.java @@ -0,0 +1,37 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.test; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; + +import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier; +import org.springframework.web.servlet.function.RequestPredicate; + +public class TestPredicateSupplier implements PredicateSupplier { + + public static RequestPredicate alwaysTrue() { + return request -> true; + } + + @Override + public Collection get() { + return List.of(TestPredicateSupplier.class.getMethods()); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/META-INF/spring.factories b/spring-cloud-gateway-server-mvc/src/test/resources/META-INF/spring.factories index bca78c94..b99d378a 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server-mvc/src/test/resources/META-INF/spring.factories @@ -1,2 +1,5 @@ +org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\ + org.springframework.cloud.gateway.server.mvc.test.TestPredicateSupplier + org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\ org.springframework.cloud.gateway.server.mvc.test.TestFilterSupplier \ No newline at end of file From 85cd06351ce1ac1a544dd6e44fb55ad0351a3bad Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 22 Apr 2025 10:10:04 -0400 Subject: [PATCH 24/85] Merge pull request #3737 from myasinkaji2/bugfix/npe prevent NullPointerException when pattern is null --- .../server/mvc/predicate/GatewayRequestPredicates.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java index 68f54b73..c25671da 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java @@ -272,7 +272,12 @@ public abstract class GatewayRequestPredicates { @Override public void accept(RequestPredicates.Visitor visitor) { - visitor.header(name, pattern.pattern()); + if (pattern != null) { + visitor.header(name, pattern.pattern()); + } + else { + visitor.header(name, ""); + } } @Override From 4e18e714f9a8ba6a72bec766a84206cd4544a76b Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 22 Apr 2025 10:10:04 -0400 Subject: [PATCH 25/85] Merge pull request #3737 from myasinkaji2/bugfix/npe prevent NullPointerException when pattern is null --- .../server/mvc/predicate/GatewayRequestPredicates.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java index 68f54b73..c25671da 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java @@ -272,7 +272,12 @@ public abstract class GatewayRequestPredicates { @Override public void accept(RequestPredicates.Visitor visitor) { - visitor.header(name, pattern.pattern()); + if (pattern != null) { + visitor.header(name, pattern.pattern()); + } + else { + visitor.header(name, ""); + } } @Override From bd8c3cc736d310aed7a1dad604015e75b4becd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E4=BB=98=E4=B8=80=E7=94=B7?= Date: Tue, 22 Apr 2025 22:34:49 +0800 Subject: [PATCH 26/85] docs: explain spring.webflux.base-path influence on Path Route Predicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 郭付一男 --- .../spring-cloud-gateway/request-predicates-factories.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc index 93a1e10e..c1cb13ee 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc @@ -192,6 +192,8 @@ This route matches if the request path was, for example: `/red/1` or `/red/1/` o If `matchTrailingSlash` is set to `false`, then request path `/red/1/` will not be matched. +If you have set `spring.webflux.base-path` property, this will influence the path matching. The property value will be automatically prepended to the path patterns. For example, with `spring.webflux.base-path=/app` and a path pattern of `/red/{segment}`, the full pattern used for matching would be `/app/red/{segment}`. + This predicate extracts the URI template variables (such as `segment`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. Those values are then available for use by <> From b1abe379cf25a6b0dfb6ca7c21aebc9629024e7d Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 22 Apr 2025 12:50:51 -0400 Subject: [PATCH 27/85] Removes deprecated properties in XForwardedRequestHeadersFilter. Fixes gh-3237 --- .../XForwardedRequestHeadersFilter.java | 329 +----------------- 1 file changed, 14 insertions(+), 315 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java index bee93756..da95fa4b 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java @@ -22,9 +22,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; -import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; @@ -32,9 +29,6 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.servlet.function.ServerRequest; -import static org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties.PREFIX; - -@ConfigurationProperties("spring.cloud.gateway.x-forwarded") public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.RequestHttpHeadersFilter, Ordered { /** Default http port. */ @@ -64,310 +58,15 @@ public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.Request /** X-Forwarded-Prefix Header. */ public static final String X_FORWARDED_PREFIX_HEADER = "X-Forwarded-Prefix"; - /** The order of the XForwardedHeadersFilter. */ - private int order = 0; + private final XForwardedRequestHeadersFilterProperties properties; - /** If the XForwardedHeadersFilter is enabled. */ - private boolean enabled = true; - - /** If X-Forwarded-For is enabled. */ - private boolean forEnabled = true; - - /** If X-Forwarded-Host is enabled. */ - private boolean hostEnabled = true; - - /** If X-Forwarded-Port is enabled. */ - private boolean portEnabled = true; - - /** If X-Forwarded-Proto is enabled. */ - private boolean protoEnabled = true; - - /** If X-Forwarded-Prefix is enabled. */ - private boolean prefixEnabled = true; - - /** If appending X-Forwarded-For as a list is enabled. */ - private boolean forAppend = true; - - /** If appending X-Forwarded-Host as a list is enabled. */ - private boolean hostAppend = true; - - /** If appending X-Forwarded-Port as a list is enabled. */ - private boolean portAppend = true; - - /** If appending X-Forwarded-Proto as a list is enabled. */ - private boolean protoAppend = true; - - /** If appending X-Forwarded-Prefix as a list is enabled. */ - private boolean prefixAppend = true; - - @Deprecated - public XForwardedRequestHeadersFilter() { - this(new XForwardedRequestHeadersFilterProperties()); + public XForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties properties) { + this.properties = properties; } - public XForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties props) { - // TODO: remove individual properties in 4.2.0 - // this.properties = properties; - PropertyMapper map = PropertyMapper.get(); - map.from(props::getOrder).to(o -> this.order = o); - map.from(props::isEnabled).to(b -> this.enabled = b); - map.from(props::isForEnabled).to(b -> this.forEnabled = b); - map.from(props::isHostEnabled).to(b -> this.hostEnabled = b); - map.from(props::isPortEnabled).to(b -> this.portEnabled = b); - map.from(props::isProtoEnabled).to(b -> this.protoEnabled = b); - map.from(props::isPrefixEnabled).to(b -> this.prefixEnabled = b); - map.from(props::isForAppend).to(b -> this.forAppend = b); - map.from(props::isHostAppend).to(b -> this.hostAppend = b); - map.from(props::isPortAppend).to(b -> this.portAppend = b); - map.from(props::isProtoAppend).to(b -> this.protoAppend = b); - map.from(props::isPrefixAppend).to(b -> this.prefixAppend = b); - } - - @DeprecatedConfigurationProperty(replacement = PREFIX + ".order") @Override public int getOrder() { - return this.order; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setOrder(int)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setOrder(int order) { - this.order = order; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".enabled") - public boolean isEnabled() { - return enabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isForEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".for-enabled") - public boolean isForEnabled() { - return forEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setForEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setForEnabled(boolean forEnabled) { - this.forEnabled = forEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isHostEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".host-enabled") - public boolean isHostEnabled() { - return hostEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setHostEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setHostEnabled(boolean hostEnabled) { - this.hostEnabled = hostEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isPortEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".port-enabled") - public boolean isPortEnabled() { - return portEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setPortEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setPortEnabled(boolean portEnabled) { - this.portEnabled = portEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isProtoEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".proto-enabled") - public boolean isProtoEnabled() { - return protoEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setProtoEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setProtoEnabled(boolean protoEnabled) { - this.protoEnabled = protoEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isPrefixEnabled()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".prefix-enabled") - public boolean isPrefixEnabled() { - return prefixEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setPrefixEnabled(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setPrefixEnabled(boolean prefixEnabled) { - this.prefixEnabled = prefixEnabled; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isForAppend()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".for-append") - public boolean isForAppend() { - return forAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setForAppend(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setForAppend(boolean forAppend) { - this.forAppend = forAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isHostAppend()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".host-append") - public boolean isHostAppend() { - return hostAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setHostAppend(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setHostAppend(boolean hostAppend) { - this.hostAppend = hostAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isPortAppend()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".port-append") - public boolean isPortAppend() { - return portAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setPortAppend(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setPortAppend(boolean portAppend) { - this.portAppend = portAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isProtoAppend()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".proto-append") - public boolean isProtoAppend() { - return protoAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setProtoAppend(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setProtoAppend(boolean protoAppend) { - this.protoAppend = protoAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#isPrefixAppend()} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - @DeprecatedConfigurationProperty(replacement = PREFIX + ".prefix-append") - public boolean isPrefixAppend() { - return prefixAppend; - } - - /** - * @deprecated since 4.1.2 for removal in 4.2.0 in favor of - * {@link XForwardedRequestHeadersFilterProperties#setPrefixAppend(boolean)} )} - */ - @SuppressWarnings("removal") - @Deprecated(since = "4.1.2", forRemoval = true) - public void setPrefixAppend(boolean prefixAppend) { - this.prefixAppend = prefixAppend; + return properties.getOrder(); } @Override @@ -380,17 +79,17 @@ public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.Request } InetSocketAddress remoteAddress = request.remoteAddress().orElse(null); - if (isForEnabled() && remoteAddress != null && remoteAddress.getAddress() != null) { + if (properties.isForEnabled() && remoteAddress != null && remoteAddress.getAddress() != null) { String remoteAddr = remoteAddress.getAddress().getHostAddress(); - write(updated, X_FORWARDED_FOR_HEADER, remoteAddr, isForAppend()); + write(updated, X_FORWARDED_FOR_HEADER, remoteAddr, properties.isForAppend()); } String proto = request.uri().getScheme(); - if (isProtoEnabled()) { - write(updated, X_FORWARDED_PROTO_HEADER, proto, isProtoAppend()); + if (properties.isProtoEnabled()) { + write(updated, X_FORWARDED_PROTO_HEADER, proto, properties.isProtoAppend()); } - if (isPrefixEnabled()) { + if (properties.isPrefixEnabled()) { // If the path of the url that the gw is routing to is a subset // (and ending part) of the url that it is routing from then the difference // is the prefix e.g. if request original.com/prefix/get/ is routed @@ -419,17 +118,17 @@ public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.Request } } - if (isPortEnabled()) { + if (properties.isPortEnabled()) { String port = String.valueOf(request.uri().getPort()); if (request.uri().getPort() < 0) { port = String.valueOf(getDefaultPort(proto)); } - write(updated, X_FORWARDED_PORT_HEADER, port, isPortAppend()); + write(updated, X_FORWARDED_PORT_HEADER, port, properties.isPortAppend()); } - if (isHostEnabled()) { + if (properties.isHostEnabled()) { String host = toHostHeader(request); - write(updated, X_FORWARDED_HOST_HEADER, host, isHostAppend()); + write(updated, X_FORWARDED_HOST_HEADER, host, properties.isHostAppend()); } return updated; @@ -440,7 +139,7 @@ public class XForwardedRequestHeadersFilter implements HttpHeadersFilter.Request if (requestUriPath != null && (originalUriPath.endsWith(requestUriPath))) { prefix = substringBeforeLast(originalUriPath, requestUriPath); if (prefix != null && prefix.length() > 0 && prefix.length() <= originalUri.getPath().length()) { - write(updated, X_FORWARDED_PREFIX_HEADER, prefix, isPrefixAppend()); + write(updated, X_FORWARDED_PREFIX_HEADER, prefix, properties.isPrefixAppend()); } } } From abd126f02ef1f006029217db0ef03013ac026d34 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 22 Apr 2025 12:52:26 -0400 Subject: [PATCH 28/85] Formatting --- .../route/RouteDefinitionRouteLocator.java | 4 ++-- .../predicate/GatewayPredicateVisitorTests.java | 17 +++++++++-------- ...redicatePathContainerAttrBenchMarkTests.java | 3 ++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java index c8545c68..aef1a699 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java @@ -203,8 +203,8 @@ public class RouteDefinitionRouteLocator implements RouteLocator { } return predicates.stream() - .map(nextPredicate -> lookup(routeDefinition, nextPredicate)) - .reduce(AsyncPredicate.from(exchange -> true), AsyncPredicate::and); + .map(nextPredicate -> lookup(routeDefinition, nextPredicate)) + .reduce(AsyncPredicate.from(exchange -> true), AsyncPredicate::and); } @SuppressWarnings("unchecked") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java index c55087fc..c97992ad 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicateVisitorTests.java @@ -91,13 +91,13 @@ public class GatewayPredicateVisitorTests { PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties); PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() - .setPatterns(List.of("/temp/**")) - .setMatchTrailingSlash(true); + .setPatterns(List.of("/temp/**")) + .setMatchTrailingSlash(true); Predicate predicate = pathRoutePredicateFactory.apply(config); - ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test") - .build()); + ServerWebExchange exchange = MockServerWebExchange + .from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test").build()); assertThat(predicate.test(exchange)).isEqualTo(true); } @@ -109,13 +109,13 @@ public class GatewayPredicateVisitorTests { PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory(webFluxProperties); PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() - .setPatterns(List.of("/temp/**")) - .setMatchTrailingSlash(true); + .setPatterns(List.of("/temp/**")) + .setMatchTrailingSlash(true); Predicate predicate = pathRoutePredicateFactory.apply(config); - ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test") - .build()); + ServerWebExchange exchange = MockServerWebExchange + .from(MockServerHttpRequest.get("http://127.0.0.1:8080/gw/api/v1/temp/test").build()); assertThat(predicate.test(exchange)).isEqualTo(true); @@ -139,4 +139,5 @@ public class GatewayPredicateVisitorTests { LinkedHashSet uris = webExchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR); assertThat(uris).contains(exchange.getRequest().getURI()); } + } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java index 5fb9a092..a607248b 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java @@ -55,7 +55,8 @@ public class PathRoutePredicatePathContainerAttrBenchMarkTests { PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config() .setPatterns(Collections.singletonList(PATH_PATTERN_PREFIX + i)) .setMatchTrailingSlash(true); - Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()).apply(config); + Predicate predicate = new PathRoutePredicateFactory(new WebFluxProperties()) + .apply(config); predicates.add(predicate); } } From af52387538179135748d5ffae13aef1e6767781c Mon Sep 17 00:00:00 2001 From: qnnn <65326092+qnnn@users.noreply.github.com> Date: Thu, 23 Jan 2025 23:59:24 +0800 Subject: [PATCH 29/85] Support for reloading httpClient connectTimeout Configuration Signed-off-by: Nan Chiu <1543393961@qq.com> Signed-off-by: qnnn <65326092+qnnn@users.noreply.github.com> --- .../cloud/gateway/filter/NettyRoutingFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java index bf4f6ad7..2350d4d2 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2013-2025 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. @@ -254,7 +254,8 @@ public class NettyRoutingFilter implements GlobalFilter, Ordered { * @return the configured HttpClient. */ protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) { - Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR); + Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR) != null + ? route.getMetadata().get(CONNECT_TIMEOUT_ATTR) : properties.getConnectTimeout(); if (connectTimeoutAttr != null) { Integer connectTimeout = getInteger(connectTimeoutAttr); return this.httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout); From 03e99ad618827dabb5555470d63fbf62941af523 Mon Sep 17 00:00:00 2001 From: qnnn <65326092+qnnn@users.noreply.github.com> Date: Fri, 24 Jan 2025 01:43:21 +0800 Subject: [PATCH 30/85] add unit test testConnectTimeoutConfigurationReloadWorks. Signed-off-by: qnnn <65326092+qnnn@users.noreply.github.com> --- .../filter/NettyRoutingFilterTests.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java index ace0bcc2..b96bb9fa 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2013-2025 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. @@ -16,18 +16,26 @@ package org.springframework.cloud.gateway.filter; +import java.util.Collections; +import java.util.HashMap; + +import io.netty.channel.ChannelOption; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import reactor.netty.DisposableServer; +import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.HttpClientConfig; import reactor.netty.http.server.HttpServer; 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.context.environment.EnvironmentChangeEvent; +import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.gateway.test.BaseWebClientTests; @@ -35,6 +43,8 @@ import org.springframework.cloud.gateway.test.PermitAllSecurityConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; import org.springframework.test.util.TestSocketUtils; import org.springframework.test.web.reactive.server.WebTestClient; @@ -48,6 +58,12 @@ class NettyRoutingFilterTests extends BaseWebClientTests { @Autowired private ApplicationContext context; + @Autowired + private NettyRoutingFilter nettyRoutingFilter; + + @Autowired + private RouteLocator routeLocator; + @BeforeAll public static void beforeAll() { port = TestSocketUtils.findAvailableTcpPort(); @@ -88,6 +104,30 @@ class NettyRoutingFilterTests extends BaseWebClientTests { } } + @Test + void testConnectTimeoutConfigurationReloadWorks() { + ConfigurableEnvironment environment = (ConfigurableEnvironment) this.context.getEnvironment(); + HashMap map = new HashMap<>(); + environment.getPropertySources().addFirst(new MapPropertySource("mock", map)); + map.put("spring.cloud.gateway.httpclient.connect-timeout", "1000"); + this.context.publishEvent(new EnvironmentChangeEvent(this.context, + Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); + Route route = routeLocator.getRoutes() + .filter(r -> r.getId().equals("refreshable_configuration_test")).blockLast(); + assertThat(route).isNotNull(); + HttpClient httpClient = nettyRoutingFilter.getHttpClient(route, null); + HttpClientConfig configuration = httpClient.configuration(); + assertThat(configuration.options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS)).isEqualTo(1000); + + map.put("spring.cloud.gateway.httpclient.connect-timeout", "5000"); + this.context.publishEvent(new EnvironmentChangeEvent(this.context, + Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); + httpClient = nettyRoutingFilter.getHttpClient(route, null); + configuration = httpClient.configuration(); + assertThat(configuration.options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS)).isEqualTo(5000); + environment.getPropertySources().remove("mock"); + } + @SpringBootConfiguration @EnableAutoConfiguration @Import(PermitAllSecurityConfiguration.class) @@ -98,6 +138,7 @@ class NettyRoutingFilterTests extends BaseWebClientTests { return builder.routes() .route(p -> p.path("/mockexample").filters(f -> f.prefixPath("/httpbin")).uri("http://example.com")) .route(p -> p.path("/issue").uri("HTTP://127.0.0.1:" + port)) + .route("refreshable_configuration_test", p -> p.path("/refresh").uri("http://example.com")) .build(); } From 2ebd776f1bec94d1480e417e5f4e293671fad0e5 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 24 Apr 2025 13:27:51 +0000 Subject: [PATCH 31/85] Bumping versions --- .../cloud/gateway/filter/NettyRoutingFilterTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java index b96bb9fa..b071212d 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java @@ -113,7 +113,8 @@ class NettyRoutingFilterTests extends BaseWebClientTests { this.context.publishEvent(new EnvironmentChangeEvent(this.context, Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); Route route = routeLocator.getRoutes() - .filter(r -> r.getId().equals("refreshable_configuration_test")).blockLast(); + .filter(r -> r.getId().equals("refreshable_configuration_test")) + .blockLast(); assertThat(route).isNotNull(); HttpClient httpClient = nettyRoutingFilter.getHttpClient(route, null); HttpClientConfig configuration = httpClient.configuration(); From fe27edfbbbaa21e2ea5c863dc2655098614083ce Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 24 Apr 2025 10:15:26 -0400 Subject: [PATCH 32/85] Escape brackets in docs Signed-off-by: Ryan Baxter --- .../request-predicates-factories.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc index c1cb13ee..2a786bb9 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc @@ -192,7 +192,7 @@ This route matches if the request path was, for example: `/red/1` or `/red/1/` o If `matchTrailingSlash` is set to `false`, then request path `/red/1/` will not be matched. -If you have set `spring.webflux.base-path` property, this will influence the path matching. The property value will be automatically prepended to the path patterns. For example, with `spring.webflux.base-path=/app` and a path pattern of `/red/{segment}`, the full pattern used for matching would be `/app/red/{segment}`. +If you have set `spring.webflux.base-path` property, this will influence the path matching. The property value will be automatically prepended to the path patterns. For example, with `spring.webflux.base-path=/app` and a path pattern of `/red/\{segment\}`, the full pattern used for matching would be `/app/red/\{segment\}`. This predicate extracts the URI template variables (such as `segment`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`. Those values are then available for use by <> From c990c926ba3e3641422a79c7bf2da9a6a19bb6e1 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 24 Apr 2025 18:53:13 +0000 Subject: [PATCH 33/85] Bumping versions --- .../cloud/gateway/filter/NettyRoutingFilterTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java index b96bb9fa..b071212d 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java @@ -113,7 +113,8 @@ class NettyRoutingFilterTests extends BaseWebClientTests { this.context.publishEvent(new EnvironmentChangeEvent(this.context, Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); Route route = routeLocator.getRoutes() - .filter(r -> r.getId().equals("refreshable_configuration_test")).blockLast(); + .filter(r -> r.getId().equals("refreshable_configuration_test")) + .blockLast(); assertThat(route).isNotNull(); HttpClient httpClient = nettyRoutingFilter.getHttpClient(route, null); HttpClientConfig configuration = httpClient.configuration(); From 2cae387df608edb42999804d108edcf3645ad578 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Mon, 28 Apr 2025 11:46:14 -0400 Subject: [PATCH 34/85] Uses new spring.http.client.settings namespace Fixes gh-3781 --- .../server/mvc/GatewayServerMvcAutoConfiguration.java | 11 ++++++----- .../mvc/GatewayServerMvcAutoConfigurationTests.java | 11 ++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index dfdbd1bc..d515b906 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -24,12 +24,12 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.http.client.AbstractHttpRequestFactoryProperties.Factory; import org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration; -import org.springframework.boot.autoconfigure.http.client.HttpClientProperties.Factory; import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.env.EnvironmentPostProcessor; -import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; +import org.springframework.boot.http.client.HttpRedirects; import org.springframework.boot.web.client.RestClientCustomizer; import org.springframework.cloud.gateway.server.mvc.common.ArgumentSupplierBeanPostProcessor; import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcAotRuntimeHintsRegistrar; @@ -219,14 +219,15 @@ public class GatewayServerMvcAutoConfiguration { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - Redirects redirects = environment.getProperty("spring.http.client.redirects", Redirects.class); + HttpRedirects redirects = environment.getProperty("spring.http.client.settings.redirects", + HttpRedirects.class); if (redirects == null) { // the user hasn't set anything, change the default environment.getPropertySources() .addFirst(new MapPropertySource("gatewayHttpClientProperties", - Map.of("spring.http.client.redirects", Redirects.DONT_FOLLOW))); + Map.of("spring.http.client.settings.redirects", HttpRedirects.DONT_FOLLOW))); } - Factory factory = environment.getProperty("spring.http.client.factory", Factory.class); + Factory factory = environment.getProperty("spring.http.client.settings.factory", Factory.class); boolean setJdkHttpClientProperties = false; if (factory == null && !HIGHER_PRIORITY) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 917c0a54..2ffaa203 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -190,7 +190,7 @@ public class GatewayServerMvcAutoConfigurationTests { } @Test - void settingHttpClientFactoryWorks() { + void settingHttpClientFactoryOldPropertyWorks() { ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class) .properties("spring.main.web-application-type=none", "spring.http.client.factory=simple") .run(); @@ -198,6 +198,15 @@ public class GatewayServerMvcAutoConfigurationTests { assertThat(builder).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class); } + @Test + void settingHttpClientFactoryWorks() { + ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class) + .properties("spring.main.web-application-type=none", "spring.http.client.settings.factory=simple") + .run(); + ClientHttpRequestFactoryBuilder builder = context.getBean(ClientHttpRequestFactoryBuilder.class); + assertThat(builder).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class); + } + @SpringBootConfiguration @EnableAutoConfiguration static class TestConfig { From a57533e3731e1c5629757b8e301ee9026a5fb2f5 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 1 May 2025 13:14:07 +0000 Subject: [PATCH 35/85] Update SNAPSHOT to 4.3.0-RC1 --- docs/pom.xml | 2 +- pom.xml | 12 ++++++------ spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webflux/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webmvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server-webflux/pom.xml | 2 +- spring-cloud-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway-server-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 20 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 709dc57e..6438c7f4 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index d1c8473c..57024ce6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-SNAPSHOT + 4.3.0-RC1 @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-SNAPSHOT - 4.3.0-SNAPSHOT - 4.3.0-SNAPSHOT - 4.3.0-SNAPSHOT + 3.3.0-RC1 + 4.3.0-RC1 + 4.3.0-RC1 + 4.3.0-RC1 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 66103cf7..d1de3394 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.3.0-SNAPSHOT + 4.3.0-RC1 spring-cloud-gateway-dependencies - 4.3.0-SNAPSHOT + 4.3.0-RC1 pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 7fb5e368..9f38d245 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 49e2de46..b198156c 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index 810172ab..e128d92f 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 85b3c76d..ec3d3fe6 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 14d0d2aa..befe4fdc 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index 3243a645..efd3e654 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-proxyexchange-webflux diff --git a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml index 8d04d069..a1c31198 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-proxyexchange-webmvc diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 20671002..35001ee8 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index e9f6b80c..095bb87e 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server-webflux/pom.xml b/spring-cloud-gateway-server-webflux/pom.xml index 4f9f40e0..2782d7e0 100644 --- a/spring-cloud-gateway-server-webflux/pom.xml +++ b/spring-cloud-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-server-webflux diff --git a/spring-cloud-gateway-server-webmvc/pom.xml b/spring-cloud-gateway-server-webmvc/pom.xml index 9792dfe9..172aa3b6 100644 --- a/spring-cloud-gateway-server-webmvc/pom.xml +++ b/spring-cloud-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-server-webmvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index dd390a1a..f019c43d 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..890a72d8 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e86d2d1f..9ff56638 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index ab94fcc5..812cc856 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-starter-gateway-server-webflux diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index 00420392..a2a59086 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-starter-gateway-server-webmvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8de3f70e..5cfda638 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-RC1 .. spring-cloud-starter-gateway From 0d1cf2774c600d6903e5fa2c5b4f5f5174660ef2 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 1 May 2025 13:17:24 +0000 Subject: [PATCH 36/85] Going back to snapshots --- docs/pom.xml | 2 +- pom.xml | 12 ++++++------ spring-cloud-gateway-dependencies/pom.xml | 4 ++-- spring-cloud-gateway-integration-tests/grpc/pom.xml | 2 +- spring-cloud-gateway-integration-tests/http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- spring-cloud-gateway-integration-tests/pom.xml | 2 +- spring-cloud-gateway-mvc/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webflux/pom.xml | 2 +- spring-cloud-gateway-proxyexchange-webmvc/pom.xml | 2 +- spring-cloud-gateway-sample/pom.xml | 2 +- spring-cloud-gateway-server-mvc/pom.xml | 2 +- spring-cloud-gateway-server-webflux/pom.xml | 2 +- spring-cloud-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-gateway-server/pom.xml | 2 +- spring-cloud-gateway-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-mvc/pom.xml | 2 +- spring-cloud-starter-gateway-server-webflux/pom.xml | 2 +- spring-cloud-starter-gateway-server-webmvc/pom.xml | 2 +- spring-cloud-starter-gateway/pom.xml | 2 +- 20 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 6438c7f4..709dc57e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 57024ce6..d1c8473c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-RC1 + 4.3.0-SNAPSHOT @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-RC1 - 4.3.0-RC1 - 4.3.0-RC1 - 4.3.0-RC1 + 3.3.0-SNAPSHOT + 4.3.0-SNAPSHOT + 4.3.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index d1de3394..66103cf7 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,12 +6,12 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.3.0-RC1 + 4.3.0-SNAPSHOT spring-cloud-gateway-dependencies - 4.3.0-RC1 + 4.3.0-SNAPSHOT pom spring-cloud-gateway-dependencies diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 9f38d245..7fb5e368 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -18,7 +18,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index b198156c..49e2de46 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml index e128d92f..810172ab 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index ec3d3fe6..85b3c76d 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index befe4fdc..14d0d2aa 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index efd3e654..3243a645 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-proxyexchange-webflux diff --git a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml index a1c31198..8d04d069 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml +++ b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-proxyexchange-webmvc diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 35001ee8..20671002 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 095bb87e..e9f6b80c 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server-webflux/pom.xml b/spring-cloud-gateway-server-webflux/pom.xml index 2782d7e0..4f9f40e0 100644 --- a/spring-cloud-gateway-server-webflux/pom.xml +++ b/spring-cloud-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-webflux diff --git a/spring-cloud-gateway-server-webmvc/pom.xml b/spring-cloud-gateway-server-webmvc/pom.xml index 172aa3b6..9792dfe9 100644 --- a/spring-cloud-gateway-server-webmvc/pom.xml +++ b/spring-cloud-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-webmvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index f019c43d..dd390a1a 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 890a72d8..5859d52d 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 9ff56638..e86d2d1f 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index 812cc856..ab94fcc5 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-server-webflux diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index a2a59086..00420392 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-server-webmvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 5cfda638..8de3f70e 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-RC1 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway From 092492ab28aabafddc2a7a594f92db2c7389fe90 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Mon, 5 May 2025 18:50:30 -0400 Subject: [PATCH 37/85] Migrate server-webmvc properties to new namespace (#3782) * Migrate server-webmvc properties to new namespace Currently, prefix is spring.cloud.gateway.mvc, the new convention is spring.cloud.gateway.server.webmvc See gh-3363 Fixes gh-3647 * Properties migration for server-webmvc Migrate from spring.cloud.gateway.mvc to spring.cloud.gateway.server.webmvc Fixes gh-3647 * formatting * Fixes test properties * Fixes test properties --- .../mvc/config/GatewayMvcProperties.java | 2 +- ...rverWebMvcPropertiesMigrationListener.java | 193 ++++++++++ ...itional-spring-configuration-metadata.json | 342 +++++++++++++++++- .../main/resources/META-INF/spring.factories | 4 + .../GatewayMvcPropertiesMigrationTests.java | 82 +++++ ...atewayServerMvcAutoConfigurationTests.java | 18 +- ...ropertiesBeanDefinitionRegistrarTests.java | 15 +- .../application-propertiesmigrationtests.yml | 47 +++ 8 files changed, 676 insertions(+), 27 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayServerWebMvcPropertiesMigrationListener.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcPropertiesMigrationTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesmigrationtests.yml diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java index 728ee4b8..fac05cb0 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java @@ -36,7 +36,7 @@ public class GatewayMvcProperties { /** * Properties prefix. */ - public static final String PREFIX = "spring.cloud.gateway.mvc"; + public static final String PREFIX = "spring.cloud.gateway.server.webmvc"; /** * List of Routes. diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayServerWebMvcPropertiesMigrationListener.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayServerWebMvcPropertiesMigrationListener.java new file mode 100644 index 00000000..8fdf6de4 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayServerWebMvcPropertiesMigrationListener.java @@ -0,0 +1,193 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.config; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.context.event.SpringApplicationEvent; +import org.springframework.boot.context.properties.source.ConfigurationProperty; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.context.properties.source.IterableConfigurationPropertySource; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.boot.origin.Origin; +import org.springframework.boot.origin.OriginTrackedValue; +import org.springframework.boot.origin.PropertySourceOrigin; +import org.springframework.boot.origin.TextResourceOrigin; +import org.springframework.context.ApplicationListener; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; +import org.springframework.util.ClassUtils; +import org.springframework.util.LinkedMultiValueMap; + +class GatewayServerWebMvcPropertiesMigrationListener implements ApplicationListener { + + private static final Log logger = LogFactory.getLog(GatewayServerWebMvcPropertiesMigrationListener.class); + + private static final String PROPERTIES_MIGRATOR_CLASS = "org.springframework.boot.context.properties.migrator.PropertiesMigrationListener"; + + private static final String DEPRECATED_ROOT = "spring.cloud.gateway.mvc"; + + private static final String DEPRECATED_ROUTES_LIST_KEY = DEPRECATED_ROOT + ".routes"; + + private static final String DEPRECATED_ROUTES_MAP_KEY = DEPRECATED_ROOT + ".routes-map"; + + private static final String DEPRECATED_ROUTESMAP_KEY = DEPRECATED_ROOT + ".routesMap"; + + private static final String GATEWAY_PROPERTY_SOURCE_PREFIX = "migrategatewaymvc"; + + private static final String NEW_ROUTES_LIST_KEY = GatewayMvcProperties.PREFIX + ".routes"; + + private static final String NEW_ROUTES_MAP_KEY = GatewayMvcProperties.PREFIX + ".routes-map"; + + private final List routesMigrations = new ArrayList<>(); + + @Override + public void onApplicationEvent(SpringApplicationEvent event) { + // only run if spring-boot-properties-migrator is on the classpath + if (!ClassUtils.isPresent(PROPERTIES_MIGRATOR_CLASS, null)) { + return; + } + if (event instanceof ApplicationPreparedEvent preparedEvent) { + onApplicationPreparedEvent(preparedEvent); + } + if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) { + logLegacyPropertiesReport(); + } + } + + private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { + // find deprecated keys + ConfigurableEnvironment env = event.getApplicationContext().getEnvironment(); + + ConfigurationPropertySources.get(env).forEach(propertySource -> { + routesMigrations.addAll(migrate(env, propertySource, GATEWAY_PROPERTY_SOURCE_PREFIX + "routes-", + DEPRECATED_ROUTES_LIST_KEY, NEW_ROUTES_LIST_KEY)); + routesMigrations.addAll(migrate(env, propertySource, GATEWAY_PROPERTY_SOURCE_PREFIX + "routes-map-", + DEPRECATED_ROUTES_MAP_KEY, NEW_ROUTES_MAP_KEY)); + routesMigrations.addAll(migrate(env, propertySource, GATEWAY_PROPERTY_SOURCE_PREFIX + "routesMap-", + DEPRECATED_ROUTES_MAP_KEY, NEW_ROUTES_MAP_KEY)); + }); + } + + private List migrate(ConfigurableEnvironment env, ConfigurationPropertySource propertySource, + String propertySourcePrefix, String deprecatedKey, String newKeyPrefix) { + List migrations = new ArrayList<>(); + + if (propertySource instanceof IterableConfigurationPropertySource iterableSource) { + ConfigurationPropertyName routesParentName = ConfigurationPropertyName.of(deprecatedKey); + List matchingConfigProps = iterableSource.filter(n -> { + if (n.getNumberOfElements() < routesParentName.getNumberOfElements()) { + return false; + } + ConfigurationPropertyName chop = n.chop(routesParentName.getNumberOfElements()); + return routesParentName.equals(chop); + }).stream().toList(); + if (!matchingConfigProps.isEmpty()) { + String originalPropertySourceName; + if (propertySource.getUnderlyingSource() instanceof PropertySource underlyingSource) { + originalPropertySourceName = underlyingSource.getName(); + } + else { + originalPropertySourceName = propertySource.getUnderlyingSource().toString(); + } + String newPropertySourceName = propertySourcePrefix + originalPropertySourceName; + Map content = new LinkedHashMap<>(); + // migrate to new keys + for (ConfigurationPropertyName originalPropertyName : matchingConfigProps) { + ConfigurationPropertyName suffix = originalPropertyName + .subName(routesParentName.getNumberOfElements()); + ConfigurationPropertyName newProperty = ConfigurationPropertyName.of(newKeyPrefix).append(suffix); + ConfigurationProperty configurationProperty = propertySource + .getConfigurationProperty(originalPropertyName); + Object value = configurationProperty.getValue(); + OriginTrackedValue originTrackedValue = OriginTrackedValue.of(value, + configurationProperty.getOrigin()); + content.put(newProperty.toString(), originTrackedValue); + migrations.add(new Migration(originalPropertySourceName, originalPropertyName, + configurationProperty, newProperty)); + } + env.getPropertySources() + .addBefore(originalPropertySourceName, + new OriginTrackedMapPropertySource(newPropertySourceName, content)); + } + } + return migrations; + } + + private void logLegacyPropertiesReport() { + // log warnings + if (!routesMigrations.isEmpty()) { + LinkedMultiValueMap content = new LinkedMultiValueMap<>(); + routesMigrations.forEach(migration -> content.add(migration.originalPropertySourceName(), migration)); + + StringBuilder report = new StringBuilder(); + report.append(String + .format("%nThe use of configuration keys that have been renamed was found in the environment:%n%n")); + + content.forEach((name, properties) -> { + report.append(String.format("Property source '%s':%n", name)); + // properties.sort(PropertyMigration.COMPARATOR); + properties.forEach((property) -> { + ConfigurationPropertyName originalPropertyName = property.originalPropertyName(); + report.append(String.format("\tKey: %s%n", originalPropertyName)); + Integer lineNumber = property.determineLineNumber(); + if (lineNumber != null) { + report.append(String.format("\t\tLine: %d%n", lineNumber)); + } + report.append(String.format("\t\tReplacement: %s%n", property.newProperty().toString())); + }); + report.append(String.format("%n")); + }); + + report.append(String.format("%n")); + report.append("Each configuration key has been temporarily mapped to its " + + "replacement for your convenience. To silence this warning, please " + + "update your configuration to use the new keys."); + report.append(String.format("%n")); + logger.warn(report.toString()); + } + } + + private record Migration(String originalPropertySourceName, ConfigurationPropertyName originalPropertyName, + ConfigurationProperty originalProperty, ConfigurationPropertyName newProperty) { + + private Integer determineLineNumber() { + Origin origin = originalProperty.getOrigin(); + if (origin instanceof PropertySourceOrigin propertySourceOrigin) { + origin = propertySourceOrigin.getOrigin(); + } + if (origin instanceof TextResourceOrigin textOrigin) { + if (textOrigin.getLocation() != null) { + return textOrigin.getLocation().getLine() + 1; + } + } + return null; + } + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ff054ce3..ce35f3ef 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,46 +1,370 @@ { "properties": [ { - "name": "spring.cloud.gateway.mvc.form-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.form-filter.enabled", "type": "java.lang.Boolean", "description": "Enables the form-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.forwarded-request-headers-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.forwarded-request-headers-filter.enabled", "type": "java.lang.Boolean", "description": "Enables the forwarded-request-headers-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.remove-content-length-request-headers-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.remove-content-length-request-headers-filter.enabled", "type": "java.lang.Boolean", "description": "Enables the remove-content-length-request-headers-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-request-headers-filter.enabled", "type": "java.lang.Boolean", - "description": "Enables the forwarded-request-headers-filter.", + "description": "Enables the remove-hop-by-hop-request-headers-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-response-headers-filter.enabled", "type": "java.lang.Boolean", - "description": "Enables the forwarded-request-headers-filter.", + "description": "Enables the remove-hop-by-hop-response-headers-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.transfer-encoding-normalization-request-headers-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.remove-http2-status-response-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-http2-status-response-headers-filter.", + "defaultValue": "true" + }, + { + "name": "spring.cloud.gateway.server.webmvc.transfer-encoding-normalization-request-headers-filter.enabled", "type": "java.lang.Boolean", "description": "Enables the transfer-encoding-normalization-request-headers-filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.mvc.weight-calculator-filter.enabled", + "name": "spring.cloud.gateway.server.webmvc.weight-calculator-filter.enabled", "type": "java.lang.Boolean", "description": "Enables the weight-calculator-filter.", "defaultValue": "true" + }, + { + "name": "spring.cloud.gateway.mvc.form-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the form-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.form-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.forwarded-request-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the forwarded-request-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.forwarded-request-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.remove-content-length-request-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-content-length-request-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.remove-content-length-request-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-hop-by-hop-request-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-request-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-hop-by-hop-response-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-response-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.remove-http2-status-response-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-http2-status-response-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.remove-http2-status-response-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.routes", + "type": "java.util.List", + "description": "List of Routes.", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.routes", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.routes-map", + "type": "java.util.LinkedHashMap", + "description": "Map of Routes.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.routes-map", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.streaming-buffer-size", + "type": "java.lang.Integer", + "description": "Buffer size for streaming media mime-types.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties", + "defaultValue": 16384, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.streaming-buffer-size", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.streaming-media-types", + "type": "java.util.List", + "description": "Mime-types that are streaming.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.streaming-media-types", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.transfer-encoding-normalization-request-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the transfer-encoding-normalization-request-headers-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.transfer-encoding-normalization-request-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.weight-calculator-filter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the weight-calculator-filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.weight-calculator-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.enabled", + "type": "java.lang.Boolean", + "description": "If the XForwardedHeadersFilter is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.for-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-For as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.for-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.for-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-For is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.for-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.host-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Host as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.host-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.host-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Host is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.host-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.order", + "type": "java.lang.Integer", + "description": "The order of the XForwardedHeadersFilter.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": 0, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.order", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.port-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Port as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.port-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.port-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Port is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.port-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.prefix-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Prefix as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.prefix-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.prefix-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Prefix is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.prefix-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Proto as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Proto is enabled.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.http-client.connect-timeout", + "type": "java.time.Duration", + "description": "The HttpClient connect timeout.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties$HttpClient", + "deprecated": true, + "deprecation": { + "replacement": "spring.http.client.connect-timeout", + "since": "4.2.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.http-client.read-timeout", + "type": "java.time.Duration", + "description": "The HttpClient read timeout.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties$HttpClient", + "deprecated": true, + "deprecation": { + "replacement": "spring.http.client.read-timeout", + "since": "4.2.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.http-client.ssl-bundle", + "type": "java.lang.String", + "description": "The name of the SSL bundle to use.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties$HttpClient", + "deprecated": true, + "deprecation": { + "replacement": "spring.http.client.ssl.bundle", + "since": "4.2.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.http-client.type", + "type": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties$HttpClientType", + "description": "The HttpClient type. Defaults to JDK.", + "sourceType": "org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties$HttpClient", + "defaultValue": "jdk", + "deprecated": true, + "deprecation": {} } ] } diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories index c208d466..6ce983dc 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories @@ -18,3 +18,7 @@ org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration.GatewayHttpClientEnvironmentPostProcessor,\ org.springframework.cloud.gateway.server.mvc.common.MultipartEnvironmentPostProcessor + +# Application Listeners +org.springframework.context.ApplicationListener=\ + org.springframework.cloud.gateway.server.mvc.config.GatewayServerWebMvcPropertiesMigrationListener \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcPropertiesMigrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcPropertiesMigrationTests.java new file mode 100644 index 00000000..2043fc73 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcPropertiesMigrationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; +import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; +import org.springframework.cloud.gateway.server.mvc.filter.ForwardedRequestHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveContentLengthRequestHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopRequestHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopResponseHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveHttp2StatusResponseHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNormalizationRequestHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; +import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("propertiesmigrationtests") +public class GatewayMvcPropertiesMigrationTests { + + @Autowired + ApplicationContext context; + + @Autowired + GatewayMvcProperties properties; + + @SuppressWarnings("rawtypes") + @Test + public void deprecatedFilterEnabledPropertiesWork() { + assertBeanDoesNotExist(FormFilter.class); + assertBeanDoesNotExist(ForwardedRequestHeadersFilter.class); + assertBeanDoesNotExist(RemoveContentLengthRequestHeadersFilter.class); + assertBeanDoesNotExist(RemoveHopByHopRequestHeadersFilter.class); + assertBeanDoesNotExist(RemoveHopByHopResponseHeadersFilter.class); + assertBeanDoesNotExist(RemoveHttp2StatusResponseHeadersFilter.class); + assertBeanDoesNotExist(TransferEncodingNormalizationRequestHeadersFilter.class); + assertBeanDoesNotExist(WeightCalculatorFilter.class); + assertBeanDoesNotExist(XForwardedRequestHeadersFilter.class); + } + + @Test + public void deprecatedRoutePropertiesWork() { + assertThat(properties.getRoutes()).hasSize(2); + assertThat(properties.getRoutesMap()).hasSize(2); + } + + private void assertBeanDoesNotExist(Class type) { + assertThat(context.getBeanNamesForType(type)).isEmpty(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 2ffaa203..886a7429 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -116,15 +116,15 @@ public class GatewayServerMvcAutoConfigurationTests { HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class, SslAutoConfiguration.class)) - .withPropertyValues("spring.cloud.gateway.mvc.form-filter.enabled=false", - "spring.cloud.gateway.mvc.forwarded-request-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.remove-content-length-request-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.remove-http2-status-response-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.transfer-encoding-normalization-request-headers-filter.enabled=false", - "spring.cloud.gateway.mvc.weight-calculator-filter.enabled=false", - "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.enabled=false") + .withPropertyValues("spring.cloud.gateway.server.webmvc.form-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.forwarded-request-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.remove-content-length-request-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-request-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.remove-hop-by-hop-response-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.remove-http2-status-response-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.transfer-encoding-normalization-request-headers-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.weight-calculator-filter.enabled=false", + "spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.enabled=false") .run(context -> { assertThat(context).doesNotHaveBean(FormFilter.class); assertThat(context).doesNotHaveBean(ForwardedRequestHeadersFilter.class); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java index 41f6bff8..f0d34697 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java @@ -199,14 +199,13 @@ public class GatewayMvcPropertiesBeanDefinitionRegistrarTests { void refreshWorks(ConfigurableApplicationContext context) { Map routerFunctions = getRouterFunctions(context); assertThat(routerFunctions).hasSize(6); - TestPropertyValues - .of("spring.cloud.gateway.mvc.routesMap.route3.uri=https://example3.com", - "spring.cloud.gateway.mvc.routesMap.route3.predicates[0].name=Path", - "spring.cloud.gateway.mvc.routesMap.route3.predicates[0].args.pattern=/anything/mapRoute3", - "spring.cloud.gateway.mvc.routesMap.route3.filters[0].Name=HttpbinUriResolver", - "spring.cloud.gateway.mvc.routesMap.route3.filters[1].Name=AddRequestHeader", - "spring.cloud.gateway.mvc.routesMap.route3.filters[1].args.name=X-Test", - "spring.cloud.gateway.mvc.routesMap.route3.filters[1].args.values=mapRoute3") + TestPropertyValues.of("spring.cloud.gateway.server.webmvc.routesMap.route3.uri=https://example3.com", + "spring.cloud.gateway.server.webmvc.routesMap.route3.predicates[0].name=Path", + "spring.cloud.gateway.server.webmvc.routesMap.route3.predicates[0].args.pattern=/anything/mapRoute3", + "spring.cloud.gateway.server.webmvc.routesMap.route3.filters[0].Name=HttpbinUriResolver", + "spring.cloud.gateway.server.webmvc.routesMap.route3.filters[1].Name=AddRequestHeader", + "spring.cloud.gateway.server.webmvc.routesMap.route3.filters[1].args.name=X-Test", + "spring.cloud.gateway.server.webmvc.routesMap.route3.filters[1].args.values=mapRoute3") .applyTo(context); ContextRefresher contextRefresher = context.getBean(ContextRefresher.class); contextRefresher.refresh(); diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesmigrationtests.yml new file mode 100644 index 00000000..32dc4133 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesmigrationtests.yml @@ -0,0 +1,47 @@ +spring.cloud.gateway.mvc: + form-filter.enabled: false + forwarded-request-headers-filter.enabled: false + remove-content-length-request-headers-filter.enabled: false + remove-hop-by-hop-request-headers-filter.enabled: false + remove-hop-by-hop-response-headers-filter.enabled: false + remove-http2-status-response-headers-filter.enabled: false + transfer-encoding-normalization-request-headers-filter.enabled: false + weight-calculator-filter.enabled: false + x-forwarded-request-headers-filter.enabled: false + routes: + - id: listRoute1 + uri: https://examplel1.com + predicates: + - name: Method + args: + methods: GET + - name: Path + args: + pattern: /anything/listRoute1 + filters: + - HttpbinUriResolver= + - AddRequestHeader=X-Test,listRoute1 + - id: listRoute2 + uri: https://examplel2.com + predicates: + - name: Method + args: + methods: GET + - name: Path + args: + pattern: /anything/listRoute2 + filters: + - HttpbinUriResolver= + - AddRequestHeader=X-Test,listRoute2 + routesMap: + route1: + uri: https://example1.com + predicates: + - Path=/anything/example1 + route2: + uri: https://example2.com + predicates: + - Path=/anything/example2 +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE From 789b661c0b90c1855d0f1dface0626b556beeb51 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 6 May 2025 18:53:21 +0000 Subject: [PATCH 38/85] Bumping versions --- docs/modules/ROOT/partials/_configprops.adoc | 33 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/partials/_configprops.adoc b/docs/modules/ROOT/partials/_configprops.adoc index a92c4dd8..3e3115a7 100644 --- a/docs/modules/ROOT/partials/_configprops.adoc +++ b/docs/modules/ROOT/partials/_configprops.adoc @@ -129,8 +129,9 @@ |spring.cloud.gateway.mvc.http-client.ssl-bundle | | The name of the SSL bundle to use. |spring.cloud.gateway.mvc.http-client.type | `+++jdk+++` | The HttpClient type. Defaults to JDK. |spring.cloud.gateway.mvc.remove-content-length-request-headers-filter.enabled | `+++true+++` | Enables the remove-content-length-request-headers-filter. -|spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled | `+++true+++` | Enables the forwarded-request-headers-filter. -|spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled | `+++true+++` | Enables the forwarded-request-headers-filter. +|spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled | `+++true+++` | Enables the remove-hop-by-hop-request-headers-filter. +|spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled | `+++true+++` | Enables the remove-hop-by-hop-response-headers-filter. +|spring.cloud.gateway.mvc.remove-http2-status-response-headers-filter.enabled | `+++true+++` | Enables the remove-http2-status-response-headers-filter. |spring.cloud.gateway.mvc.routes | | List of Routes. |spring.cloud.gateway.mvc.routes-map | | Map of Routes. |spring.cloud.gateway.mvc.streaming-buffer-size | `+++16384+++` | Buffer size for streaming media mime-types. @@ -176,6 +177,34 @@ |spring.cloud.gateway.route-filter-cache-enabled | `+++false+++` | Enables the route filter cache, defaults to false. |spring.cloud.gateway.route-refresh-listener.enabled | `+++true+++` | If RouteRefreshListener should be turned on. |spring.cloud.gateway.routes | | List of Routes. +|spring.cloud.gateway.server.webmvc.form-filter.enabled | `+++true+++` | Enables the form-filter. +|spring.cloud.gateway.server.webmvc.forwarded-request-headers-filter.enabled | `+++true+++` | Enables the forwarded-request-headers-filter. +|spring.cloud.gateway.server.webmvc.http-client.connect-timeout | | The HttpClient connect timeout. +|spring.cloud.gateway.server.webmvc.http-client.read-timeout | | The HttpClient read timeout. +|spring.cloud.gateway.server.webmvc.http-client.ssl-bundle | | The name of the SSL bundle to use. +|spring.cloud.gateway.server.webmvc.http-client.type | `+++jdk+++` | The HttpClient type. Defaults to JDK. +|spring.cloud.gateway.server.webmvc.remove-content-length-request-headers-filter.enabled | `+++true+++` | Enables the remove-content-length-request-headers-filter. +|spring.cloud.gateway.server.webmvc.remove-hop-by-hop-request-headers-filter.enabled | `+++true+++` | Enables the remove-hop-by-hop-request-headers-filter. +|spring.cloud.gateway.server.webmvc.remove-hop-by-hop-response-headers-filter.enabled | `+++true+++` | Enables the remove-hop-by-hop-response-headers-filter. +|spring.cloud.gateway.server.webmvc.remove-http2-status-response-headers-filter.enabled | `+++true+++` | Enables the remove-http2-status-response-headers-filter. +|spring.cloud.gateway.server.webmvc.routes | | List of Routes. +|spring.cloud.gateway.server.webmvc.routes-map | | Map of Routes. +|spring.cloud.gateway.server.webmvc.streaming-buffer-size | `+++16384+++` | Buffer size for streaming media mime-types. +|spring.cloud.gateway.server.webmvc.streaming-media-types | | Mime-types that are streaming. +|spring.cloud.gateway.server.webmvc.transfer-encoding-normalization-request-headers-filter.enabled | `+++true+++` | Enables the transfer-encoding-normalization-request-headers-filter. +|spring.cloud.gateway.server.webmvc.weight-calculator-filter.enabled | `+++true+++` | Enables the weight-calculator-filter. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.enabled | `+++true+++` | If the XForwardedHeadersFilter is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.for-append | `+++true+++` | If appending X-Forwarded-For as a list is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.for-enabled | `+++true+++` | If X-Forwarded-For is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.host-append | `+++true+++` | If appending X-Forwarded-Host as a list is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.host-enabled | `+++true+++` | If X-Forwarded-Host is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.order | `+++0+++` | The order of the XForwardedHeadersFilter. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.port-append | `+++true+++` | If appending X-Forwarded-Port as a list is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.port-enabled | `+++true+++` | If X-Forwarded-Port is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.prefix-append | `+++true+++` | If appending X-Forwarded-Prefix as a list is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.prefix-enabled | `+++true+++` | If X-Forwarded-Prefix is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-append | `+++true+++` | If appending X-Forwarded-Proto as a list is enabled. +|spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-enabled | `+++true+++` | If X-Forwarded-Proto is enabled. |spring.cloud.gateway.set-status.original-status-header-name | | The name of the header which contains http code of the proxied request. |spring.cloud.gateway.streaming-media-types | | |spring.cloud.gateway.x-forwarded.enabled | `+++true+++` | If the XForwardedHeadersFilter is enabled. From eca63cba65acdbd0f7adaf707fa8bdaabba118ab Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 9 May 2025 15:40:33 -0400 Subject: [PATCH 39/85] Migrates server-webflux properties to new namespace (#3793) Currently, prefix is spring.cloud.gateway and this is ambiguous now that server-webmvc exists. spring.cloud.gateway.server.webflux is the new prefix Fixes gh-3363 --- docs/modules/ROOT/partials/_configprops.adoc | 181 ++ .../grpc/src/test/resources/application.yml | 2 +- .../http2/src/main/resources/application.yml | 2 +- .../src/test/resources/application-nossl.yml | 2 +- .../MvcFailureAnalyzerApplicationTests.java | 2 +- .../resources/application-secureheaders.yml | 2 +- .../src/main/resources/application.yml | 2 +- spring-cloud-gateway-server/pom.xml | 5 + .../config/GatewayAutoConfiguration.java | 26 +- ...ewayClassPathWarningAutoConfiguration.java | 2 +- .../GatewayFunctionAutoConfiguration.java | 2 +- .../config/GatewayLoadBalancerProperties.java | 2 +- .../config/GatewayMetricsProperties.java | 2 +- .../gateway/config/GatewayProperties.java | 2 +- .../config/GatewayRedisAutoConfiguration.java | 4 +- ...ence4JCircuitBreakerAutoConfiguration.java | 2 +- ...verWebfluxPropertiesMigrationListener.java | 183 ++ .../GatewayStreamAutoConfiguration.java | 2 +- .../gateway/config/GlobalCorsProperties.java | 2 +- .../gateway/config/HttpClientProperties.java | 2 +- .../LocalResponseCacheAutoConfiguration.java | 8 +- ...lerMappingGlobalCorsAutoConfiguration.java | 2 +- .../conditional/OnEnabledComponent.java | 2 +- .../discovery/DiscoveryLocatorProperties.java | 2 +- ...tewayDiscoveryClientAutoConfiguration.java | 4 +- ...equestRateLimiterGatewayFilterFactory.java | 2 +- .../factory/SecureHeadersProperties.java | 2 +- .../SetStatusGatewayFilterFactory.java | 2 +- ...ocalResponseCacheGatewayFilterFactory.java | 3 +- .../cache/LocalResponseCacheProperties.java | 2 +- .../headers/RemoveHopByHopHeadersFilter.java | 2 +- .../headers/XForwardedHeadersFilter.java | 2 +- .../filter/ratelimit/RedisRateLimiter.java | 3 +- .../gateway/support/ShortcutConfigurable.java | 4 +- ...itional-spring-configuration-metadata.json | 2148 ++++++++++++++++- .../main/resources/META-INF/spring.factories | 6 +- .../config/GatewayAutoConfigurationTests.java | 30 +- .../GatewayMetricsAutoConfigurationTests.java | 4 +- .../GatewayPropertiesMigrationTests.java | 71 + .../GatewayRedisAutoConfigurationTests.java | 4 +- ...itionRepositoryEnabledByPropertyTests.java | 2 +- ...alResponseCacheAutoConfigurationTests.java | 4 +- .../DisableBuiltInFiltersTests.java | 82 +- .../DisableBuiltInGlobalFiltersTests.java | 34 +- .../DisableBuiltInPredicatesTests.java | 31 +- .../conditional/OnEnabledComponentTests.java | 2 +- .../cloud/gateway/cors/CorsGlobalTests.java | 3 +- .../cors/SimpleUrlHandlerCorsTests.java | 2 +- ...outeDefinitionLocatorIntegrationTests.java | 4 +- ...veryClientRouteDefinitionLocatorTests.java | 18 +- ...DiscoveryClientAutoConfigurationTests.java | 4 +- .../filter/NettyRoutingFilterTests.java | 8 +- ...yGatewayFilterFactoryIntegrationTests.java | 4 +- ...esponseCacheGatewayFilterFactoryTests.java | 19 +- .../LocalResponseCacheGlobalFilterTests.java | 6 +- ...dyGatewayFilterFactorySslTimeoutTests.java | 2 +- .../ratelimit/Bucket4jRateLimiterTests.java | 2 +- .../ratelimit/RedisRateLimiterTests.java | 3 +- ...ebHandlerCacheEnabledIntegrationTests.java | 4 +- ...ortcutConfigurableNonRestrictiveTests.java | 2 +- .../PropertiesTagsProviderTests.java | 4 +- .../gateway/test/GatewayIntegrationTests.java | 3 +- .../test/ssl/ClientCertAuthSSLTests.java | 6 +- .../test/ssl/SSLHandshakeTimeoutTests.java | 2 +- .../application-client-auth-ssl-bundle.yml | 2 +- .../resources/application-client-auth-ssl.yml | 2 +- .../application-cors-global-config.yml | 2 +- .../application-cors-per-route-config.yml | 2 +- .../test/resources/application-defaultid.yml | 2 +- .../application-disable-components.yml | 2 +- .../resources/application-forwardstatic.yml | 2 +- .../resources/application-multi-cert-ssl.yml | 2 +- .../application-netty-routing-filter.yml | 2 +- .../application-propertiesmigrationtests.yml | 32 + .../application-redis-rate-limiter-config.yml | 2 +- ...tion-redis-rate-limiter-default-config.yml | 2 +- .../application-redis-route-repository.yml | 2 +- .../resources/application-remote-address.yml | 2 +- .../application-removenonproxyheaders.yml | 2 +- .../application-request-header-web-filter.yml | 2 +- ...uest-headers-if-not-present-web-filter.yml | 2 +- ...lication-request-map-header-web-filter.yml | 2 +- ...plication-request-parameter-web-filter.yml | 2 +- .../test/resources/application-retrytests.yml | 2 +- .../application-save-session-web-filter.yml | 2 +- .../resources/application-single-cert-ssl.yml | 2 +- .../application-verification-route.yml | 2 +- .../resources/application-weights-404.yml | 2 +- .../src/test/resources/application.yml | 2 +- 89 files changed, 2777 insertions(+), 286 deletions(-) create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayServerWebfluxPropertiesMigrationListener.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayPropertiesMigrationTests.java create mode 100644 spring-cloud-gateway-server/src/test/resources/application-propertiesmigrationtests.yml diff --git a/docs/modules/ROOT/partials/_configprops.adoc b/docs/modules/ROOT/partials/_configprops.adoc index 3e3115a7..5b4433b0 100644 --- a/docs/modules/ROOT/partials/_configprops.adoc +++ b/docs/modules/ROOT/partials/_configprops.adoc @@ -1,7 +1,9 @@ |=== |Name | Default | Description +|spring.cloud.gateway | | |spring.cloud.gateway.default-filters | | List of filter definitions that are applied to every route. +|spring.cloud.gateway.discovery.locator | | |spring.cloud.gateway.discovery.locator.enabled | `+++false+++` | Flag that enables DiscoveryClient gateway integration. |spring.cloud.gateway.discovery.locator.filters | | |spring.cloud.gateway.discovery.locator.include-expression | `+++true+++` | SpEL expression that will evaluate whether to include a service in gateway integration or not, defaults to: true. @@ -19,7 +21,9 @@ |spring.cloud.gateway.filter.fallback-headers.enabled | `+++true+++` | Enables the fallback-headers filter. |spring.cloud.gateway.filter.hystrix.enabled | `+++true+++` | Enables the hystrix filter. |spring.cloud.gateway.filter.json-to-grpc.enabled | `+++true+++` | Enables the JSON to gRPC filter. +|spring.cloud.gateway.filter.local-response-cache | | |spring.cloud.gateway.filter.local-response-cache.enabled | `+++false+++` | Enables the local-response-cache filter. +|spring.cloud.gateway.filter.local-response-cache.request | | |spring.cloud.gateway.filter.local-response-cache.request.no-cache-strategy | `+++skip-update-cache-entry+++` | |spring.cloud.gateway.filter.local-response-cache.size | | Maximum size of the cache to evict entries for this route (in KB, MB and GB). |spring.cloud.gateway.filter.local-response-cache.time-to-live | `+++5m+++` | Time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours). @@ -29,6 +33,7 @@ |spring.cloud.gateway.filter.prefix-path.enabled | `+++true+++` | Enables the prefix-path filter. |spring.cloud.gateway.filter.preserve-host-header.enabled | `+++true+++` | Enables the preserve-host-header filter. |spring.cloud.gateway.filter.redirect-to.enabled | `+++true+++` | Enables the redirect-to filter. +|spring.cloud.gateway.filter.remove-hop-by-hop | | |spring.cloud.gateway.filter.remove-hop-by-hop.headers | | |spring.cloud.gateway.filter.remove-hop-by-hop.order | `+++0+++` | |spring.cloud.gateway.filter.remove-request-header.enabled | `+++true+++` | Enables the remove-request-header filter. @@ -36,6 +41,7 @@ |spring.cloud.gateway.filter.remove-response-header.enabled | `+++true+++` | Enables the remove-response-header filter. |spring.cloud.gateway.filter.request-header-size.enabled | `+++true+++` | Enables the request-header-size filter. |spring.cloud.gateway.filter.request-header-to-request-uri.enabled | `+++true+++` | Enables the request-header-to-request-uri filter. +|spring.cloud.gateway.filter.request-rate-limiter | | |spring.cloud.gateway.filter.request-rate-limiter.default-key-resolver | | |spring.cloud.gateway.filter.request-rate-limiter.default-rate-limiter | | |spring.cloud.gateway.filter.request-rate-limiter.enabled | `+++true+++` | Enables the request-rate-limiter filter. @@ -47,6 +53,7 @@ |spring.cloud.gateway.filter.rewrite-request-parameter.enabled | `+++true+++` | Enables the rewrite-request-parameter filter. |spring.cloud.gateway.filter.rewrite-response-header.enabled | `+++true+++` | Enables the rewrite-response-header filter. |spring.cloud.gateway.filter.save-session.enabled | `+++true+++` | Enables the save-session filter. +|spring.cloud.gateway.filter.secure-headers | | |spring.cloud.gateway.filter.secure-headers.content-security-policy | `+++default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'+++` | |spring.cloud.gateway.filter.secure-headers.content-type-options | `+++nosniff+++` | |spring.cloud.gateway.filter.secure-headers.default-headers | | @@ -80,13 +87,16 @@ |spring.cloud.gateway.global-filter.remove-cached-body.enabled | `+++true+++` | Enables the remove-cached-body global filter. |spring.cloud.gateway.global-filter.route-to-request-url.enabled | `+++true+++` | Enables the route-to-request-url global filter. |spring.cloud.gateway.global-filter.websocket-routing.enabled | `+++true+++` | Enables the websocket-routing global filter. +|spring.cloud.gateway.globalcors | | |spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping | `+++false+++` | If global CORS config should be added to the URL handler. |spring.cloud.gateway.globalcors.cors-configurations | | |spring.cloud.gateway.handler-mapping.order | `+++1+++` | The order of RoutePredicateHandlerMapping. +|spring.cloud.gateway.httpclient | | |spring.cloud.gateway.httpclient.compression | `+++false+++` | Enables compression for Netty HttpClient. |spring.cloud.gateway.httpclient.connect-timeout | | The connect timeout in millis, the default is 30s. |spring.cloud.gateway.httpclient.max-header-size | | The max response header size. |spring.cloud.gateway.httpclient.max-initial-line-length | | The max initial line length. +|spring.cloud.gateway.httpclient.pool | | |spring.cloud.gateway.httpclient.pool.acquire-timeout | | Only for type FIXED, the maximum time in millis to wait for acquiring. |spring.cloud.gateway.httpclient.pool.eviction-interval | `+++0+++` | Perform regular eviction checks in the background at a specified interval. Disabled by default ({@link Duration#ZERO}) |spring.cloud.gateway.httpclient.pool.leasing-strategy | `+++fifo+++` | Configures the leasing strategy for the pool (fifo or lifo), defaults to FIFO which is Netty's default. @@ -96,6 +106,7 @@ |spring.cloud.gateway.httpclient.pool.metrics | `+++false+++` | Enables channel pools metrics to be collected and registered in Micrometer. Disabled by default. |spring.cloud.gateway.httpclient.pool.name | `+++proxy+++` | The channel pool map name, defaults to proxy. |spring.cloud.gateway.httpclient.pool.type | `+++elastic+++` | Type of pool for HttpClient to use (elastic, fixed or disabled). +|spring.cloud.gateway.httpclient.proxy | | |spring.cloud.gateway.httpclient.proxy.host | | Hostname for proxy configuration of Netty HttpClient. |spring.cloud.gateway.httpclient.proxy.non-proxy-hosts-pattern | | Regular expression (Java) for a configured list of hosts. that should be reached directly, bypassing the proxy |spring.cloud.gateway.httpclient.proxy.password | | Password for proxy configuration of Netty HttpClient. @@ -103,6 +114,7 @@ |spring.cloud.gateway.httpclient.proxy.type | `+++http+++` | proxyType for proxy configuration of Netty HttpClient (http, socks4 or socks5). |spring.cloud.gateway.httpclient.proxy.username | | Username for proxy configuration of Netty HttpClient. |spring.cloud.gateway.httpclient.response-timeout | | The response timeout. +|spring.cloud.gateway.httpclient.ssl | | |spring.cloud.gateway.httpclient.ssl.close-notify-flush-timeout | `+++3000ms+++` | SSL close_notify flush timeout. Default to 3000 ms. |spring.cloud.gateway.httpclient.ssl.close-notify-read-timeout | `+++0+++` | SSL close_notify read timeout. Default to 0 ms. |spring.cloud.gateway.httpclient.ssl.handshake-timeout | `+++10000ms+++` | SSL handshake timeout. Default to 10000 ms @@ -114,11 +126,14 @@ |spring.cloud.gateway.httpclient.ssl.ssl-bundle | | The name of the SSL bundle to use. |spring.cloud.gateway.httpclient.ssl.trusted-x509-certificates | | Trusted certificates for verifying the remote endpoint's certificate. |spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager | `+++false+++` | Installs the netty InsecureTrustManagerFactory. This is insecure and not suitable for production. +|spring.cloud.gateway.httpclient.websocket | | |spring.cloud.gateway.httpclient.websocket.max-frame-payload-length | | Max frame payload length. |spring.cloud.gateway.httpclient.websocket.proxy-ping | `+++true+++` | Proxy ping frames to downstream services, defaults to true. |spring.cloud.gateway.httpclient.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpClient. |spring.cloud.gateway.httpserver.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpServer. +|spring.cloud.gateway.loadbalancer | | |spring.cloud.gateway.loadbalancer.use404 | `+++false+++` | +|spring.cloud.gateway.metrics | | |spring.cloud.gateway.metrics.enabled | `+++false+++` | Enables the collection of metrics data. |spring.cloud.gateway.metrics.prefix | `+++spring.cloud.gateway+++` | The prefix of all metrics emitted by gateway. |spring.cloud.gateway.metrics.tags | | Tags map that added to metrics. @@ -151,6 +166,7 @@ |spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-append | `+++true+++` | If appending X-Forwarded-Proto as a list is enabled. |spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-enabled | `+++true+++` | If X-Forwarded-Proto is enabled. |spring.cloud.gateway.observability.enabled | `+++true+++` | If Micrometer Observability support should be turned on. +|spring.cloud.gateway.oldval | | oldval doc. |spring.cloud.gateway.predicate.after.enabled | `+++true+++` | Enables the after predicate. |spring.cloud.gateway.predicate.before.enabled | `+++true+++` | Enables the before predicate. |spring.cloud.gateway.predicate.between.enabled | `+++true+++` | Enables the between predicate. @@ -166,6 +182,7 @@ |spring.cloud.gateway.predicate.remote-addr.enabled | `+++true+++` | Enables the remote-addr predicate. |spring.cloud.gateway.predicate.weight.enabled | `+++true+++` | Enables the weight predicate. |spring.cloud.gateway.predicate.xforwarded-remote-addr.enabled | `+++true+++` | Enables the xforwarded-remote-addr predicate. +|spring.cloud.gateway.redis-rate-limiter | | |spring.cloud.gateway.redis-rate-limiter.burst-capacity-header | `+++X-RateLimit-Burst-Capacity+++` | The name of the header that returns the burst capacity configuration. |spring.cloud.gateway.redis-rate-limiter.config | | |spring.cloud.gateway.redis-rate-limiter.include-headers | `+++true+++` | Whether or not to include headers containing rate limiter information, defaults to true. @@ -177,6 +194,168 @@ |spring.cloud.gateway.route-filter-cache-enabled | `+++false+++` | Enables the route filter cache, defaults to false. |spring.cloud.gateway.route-refresh-listener.enabled | `+++true+++` | If RouteRefreshListener should be turned on. |spring.cloud.gateway.routes | | List of Routes. +|spring.cloud.gateway.server.webflux.default-filters | | List of filter definitions that are applied to every route. +|spring.cloud.gateway.server.webflux.discovery.locator.enabled | `+++false+++` | Flag that enables DiscoveryClient gateway integration. +|spring.cloud.gateway.server.webflux.discovery.locator.filters | | +|spring.cloud.gateway.server.webflux.discovery.locator.include-expression | `+++true+++` | SpEL expression that will evaluate whether to include a service in gateway integration or not, defaults to: true. +|spring.cloud.gateway.server.webflux.discovery.locator.lower-case-service-id | `+++false+++` | Option to lower case serviceId in predicates and filters, defaults to false. Useful with eureka when it automatically uppercases serviceId. so MYSERIVCE, would match /myservice/** +|spring.cloud.gateway.server.webflux.discovery.locator.predicates | | +|spring.cloud.gateway.server.webflux.discovery.locator.route-id-prefix | | The prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName() + "_". Service Id will be appended to create the routeId. +|spring.cloud.gateway.server.webflux.discovery.locator.url-expression | `+++'lb://'+serviceId+++` | SpEL expression that create the uri for each route, defaults to: 'lb://'+serviceId. +|spring.cloud.gateway.server.webflux.enabled | `+++true+++` | Enables gateway functionality. +|spring.cloud.gateway.server.webflux.fail-on-route-definition-error | `+++true+++` | Option to fail on route definition errors, defaults to true. Otherwise, a warning is logged. +|spring.cloud.gateway.server.webflux.filter.add-request-header.enabled | `+++true+++` | Enables the add-request-header filter. +|spring.cloud.gateway.server.webflux.filter.add-request-parameter.enabled | `+++true+++` | Enables the add-request-parameter filter. +|spring.cloud.gateway.server.webflux.filter.add-response-header.enabled | `+++true+++` | Enables the add-response-header filter. +|spring.cloud.gateway.server.webflux.filter.circuit-breaker.enabled | `+++true+++` | Enables the circuit-breaker filter. +|spring.cloud.gateway.server.webflux.filter.dedupe-response-header.enabled | `+++true+++` | Enables the dedupe-response-header filter. +|spring.cloud.gateway.server.webflux.filter.fallback-headers.enabled | `+++true+++` | Enables the fallback-headers filter. +|spring.cloud.gateway.server.webflux.filter.hystrix.enabled | `+++true+++` | Enables the hystrix filter. +|spring.cloud.gateway.server.webflux.filter.json-to-grpc.enabled | `+++true+++` | Enables the JSON to gRPC filter. +|spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled | `+++false+++` | Enables the local-response-cache filter. +|spring.cloud.gateway.server.webflux.filter.local-response-cache.request.no-cache-strategy | `+++skip-update-cache-entry+++` | +|spring.cloud.gateway.server.webflux.filter.local-response-cache.size | | Maximum size of the cache to evict entries for this route (in KB, MB and GB). +|spring.cloud.gateway.server.webflux.filter.local-response-cache.time-to-live | `+++5m+++` | Time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours). +|spring.cloud.gateway.server.webflux.filter.map-request-header.enabled | `+++true+++` | Enables the map-request-header filter. +|spring.cloud.gateway.server.webflux.filter.modify-request-body.enabled | `+++true+++` | Enables the modify-request-body filter. +|spring.cloud.gateway.server.webflux.filter.modify-response-body.enabled | `+++true+++` | Enables the modify-response-body filter. +|spring.cloud.gateway.server.webflux.filter.prefix-path.enabled | `+++true+++` | Enables the prefix-path filter. +|spring.cloud.gateway.server.webflux.filter.preserve-host-header.enabled | `+++true+++` | Enables the preserve-host-header filter. +|spring.cloud.gateway.server.webflux.filter.redirect-to.enabled | `+++true+++` | Enables the redirect-to filter. +|spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop.headers | | +|spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop.order | `+++0+++` | +|spring.cloud.gateway.server.webflux.filter.remove-request-header.enabled | `+++true+++` | Enables the remove-request-header filter. +|spring.cloud.gateway.server.webflux.filter.remove-request-parameter.enabled | `+++true+++` | Enables the remove-request-parameter filter. +|spring.cloud.gateway.server.webflux.filter.remove-response-header.enabled | `+++true+++` | Enables the remove-response-header filter. +|spring.cloud.gateway.server.webflux.filter.request-header-size.enabled | `+++true+++` | Enables the request-header-size filter. +|spring.cloud.gateway.server.webflux.filter.request-header-to-request-uri.enabled | `+++true+++` | Enables the request-header-to-request-uri filter. +|spring.cloud.gateway.server.webflux.filter.request-rate-limiter.default-key-resolver | | +|spring.cloud.gateway.server.webflux.filter.request-rate-limiter.default-rate-limiter | | +|spring.cloud.gateway.server.webflux.filter.request-rate-limiter.enabled | `+++true+++` | Enables the request-rate-limiter filter. +|spring.cloud.gateway.server.webflux.filter.request-size.enabled | `+++true+++` | Enables the request-size filter. +|spring.cloud.gateway.server.webflux.filter.retry.enabled | `+++true+++` | Enables the retry filter. +|spring.cloud.gateway.server.webflux.filter.rewrite-location-response-header.enabled | `+++true+++` | Enables the rewrite-location-response-header filter. +|spring.cloud.gateway.server.webflux.filter.rewrite-location.enabled | `+++true+++` | Enables the rewrite-location filter. +|spring.cloud.gateway.server.webflux.filter.rewrite-path.enabled | `+++true+++` | Enables the rewrite-path filter. +|spring.cloud.gateway.server.webflux.filter.rewrite-request-parameter.enabled | `+++true+++` | Enables the rewrite-request-parameter filter. +|spring.cloud.gateway.server.webflux.filter.rewrite-response-header.enabled | `+++true+++` | Enables the rewrite-response-header filter. +|spring.cloud.gateway.server.webflux.filter.save-session.enabled | `+++true+++` | Enables the save-session filter. +|spring.cloud.gateway.server.webflux.filter.secure-headers.content-security-policy | `+++default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.content-type-options | `+++nosniff+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.default-headers | | +|spring.cloud.gateway.server.webflux.filter.secure-headers.disable | | +|spring.cloud.gateway.server.webflux.filter.secure-headers.disabled-headers | | +|spring.cloud.gateway.server.webflux.filter.secure-headers.download-options | `+++noopen+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.enabled | `+++true+++` | Enables the secure-headers filter. +|spring.cloud.gateway.server.webflux.filter.secure-headers.enabled-headers | | +|spring.cloud.gateway.server.webflux.filter.secure-headers.frame-options | `+++DENY+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.permissions-policy | `+++accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.permitted-cross-domain-policies | `+++none+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.referrer-policy | `+++no-referrer+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.strict-transport-security | `+++max-age=631138519+++` | +|spring.cloud.gateway.server.webflux.filter.secure-headers.xss-protection-header | `+++1 ; mode=block+++` | +|spring.cloud.gateway.server.webflux.filter.set-path.enabled | `+++true+++` | Enables the set-path filter. +|spring.cloud.gateway.server.webflux.filter.set-request-header.enabled | `+++true+++` | Enables the set-request-header filter. +|spring.cloud.gateway.server.webflux.filter.set-request-host-header.enabled | `+++true+++` | Enables the set-request-host-header filter. +|spring.cloud.gateway.server.webflux.filter.set-response-header.enabled | `+++true+++` | Enables the set-response-header filter. +|spring.cloud.gateway.server.webflux.filter.set-status.enabled | `+++true+++` | Enables the set-status filter. +|spring.cloud.gateway.server.webflux.filter.strip-prefix.enabled | `+++true+++` | Enables the strip-prefix filter. +|spring.cloud.gateway.server.webflux.forwarded.by.enabled | `+++false+++` | Enables the Forwarded: by header part. +|spring.cloud.gateway.server.webflux.forwarded.enabled | `+++true+++` | Enables the ForwardedHeadersFilter. +|spring.cloud.gateway.server.webflux.global-filter.adapt-cached-body.enabled | `+++true+++` | Enables the adapt-cached-body global filter. +|spring.cloud.gateway.server.webflux.global-filter.forward-path.enabled | `+++true+++` | Enables the forward-path global filter. +|spring.cloud.gateway.server.webflux.global-filter.forward-routing.enabled | `+++true+++` | Enables the forward-routing global filter. +|spring.cloud.gateway.server.webflux.global-filter.load-balancer-client.enabled | `+++true+++` | Enables the load-balancer-client global filter. +|spring.cloud.gateway.server.webflux.global-filter.local-response-cache.enabled | `+++true+++` | Enables the local-response-cache filter for all routes, it allows to add a specific configuration at route level using LocalResponseCache filter. +|spring.cloud.gateway.server.webflux.global-filter.netty-routing.enabled | `+++true+++` | Enables the netty-routing global filter. +|spring.cloud.gateway.server.webflux.global-filter.netty-write-response.enabled | `+++true+++` | Enables the netty-write-response global filter. +|spring.cloud.gateway.server.webflux.global-filter.reactive-load-balancer-client.enabled | `+++true+++` | Enables the reactive-load-balancer-client global filter. +|spring.cloud.gateway.server.webflux.global-filter.remove-cached-body.enabled | `+++true+++` | Enables the remove-cached-body global filter. +|spring.cloud.gateway.server.webflux.global-filter.route-to-request-url.enabled | `+++true+++` | Enables the route-to-request-url global filter. +|spring.cloud.gateway.server.webflux.global-filter.websocket-routing.enabled | `+++true+++` | Enables the websocket-routing global filter. +|spring.cloud.gateway.server.webflux.globalcors.add-to-simple-url-handler-mapping | `+++false+++` | If global CORS config should be added to the URL handler. +|spring.cloud.gateway.server.webflux.globalcors.cors-configurations | | +|spring.cloud.gateway.server.webflux.handler-mapping.order | `+++1+++` | The order of RoutePredicateHandlerMapping. +|spring.cloud.gateway.server.webflux.httpclient.compression | `+++false+++` | Enables compression for Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.connect-timeout | | The connect timeout in millis, the default is 30s. +|spring.cloud.gateway.server.webflux.httpclient.max-header-size | | The max response header size. +|spring.cloud.gateway.server.webflux.httpclient.max-initial-line-length | | The max initial line length. +|spring.cloud.gateway.server.webflux.httpclient.pool.acquire-timeout | | Only for type FIXED, the maximum time in millis to wait for acquiring. +|spring.cloud.gateway.server.webflux.httpclient.pool.eviction-interval | `+++0+++` | Perform regular eviction checks in the background at a specified interval. Disabled by default ({@link Duration#ZERO}) +|spring.cloud.gateway.server.webflux.httpclient.pool.leasing-strategy | `+++fifo+++` | Configures the leasing strategy for the pool (fifo or lifo), defaults to FIFO which is Netty's default. +|spring.cloud.gateway.server.webflux.httpclient.pool.max-connections | | Only for type FIXED, the maximum number of connections before starting pending acquisition on existing ones. +|spring.cloud.gateway.server.webflux.httpclient.pool.max-idle-time | | Time in millis after which the channel will be closed. If NULL, there is no max idle time. +|spring.cloud.gateway.server.webflux.httpclient.pool.max-life-time | | Duration after which the channel will be closed. If NULL, there is no max life time. +|spring.cloud.gateway.server.webflux.httpclient.pool.metrics | `+++false+++` | Enables channel pools metrics to be collected and registered in Micrometer. Disabled by default. +|spring.cloud.gateway.server.webflux.httpclient.pool.name | `+++proxy+++` | The channel pool map name, defaults to proxy. +|spring.cloud.gateway.server.webflux.httpclient.pool.type | `+++elastic+++` | Type of pool for HttpClient to use (elastic, fixed or disabled). +|spring.cloud.gateway.server.webflux.httpclient.proxy.host | | Hostname for proxy configuration of Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.proxy.non-proxy-hosts-pattern | | Regular expression (Java) for a configured list of hosts. that should be reached directly, bypassing the proxy +|spring.cloud.gateway.server.webflux.httpclient.proxy.password | | Password for proxy configuration of Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.proxy.port | | Port for proxy configuration of Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.proxy.type | `+++http+++` | proxyType for proxy configuration of Netty HttpClient (http, socks4 or socks5). +|spring.cloud.gateway.server.webflux.httpclient.proxy.username | | Username for proxy configuration of Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.response-timeout | | The response timeout. +|spring.cloud.gateway.server.webflux.httpclient.ssl.close-notify-flush-timeout | `+++3000ms+++` | SSL close_notify flush timeout. Default to 3000 ms. +|spring.cloud.gateway.server.webflux.httpclient.ssl.close-notify-read-timeout | `+++0+++` | SSL close_notify read timeout. Default to 0 ms. +|spring.cloud.gateway.server.webflux.httpclient.ssl.handshake-timeout | `+++10000ms+++` | SSL handshake timeout. Default to 10000 ms +|spring.cloud.gateway.server.webflux.httpclient.ssl.key-password | | Key password, default is same as keyStorePassword. +|spring.cloud.gateway.server.webflux.httpclient.ssl.key-store | | Keystore path for Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-password | | Keystore password. +|spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-provider | | Keystore provider for Netty HttpClient, optional field. +|spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-type | `+++JKS+++` | Keystore type for Netty HttpClient, default is JKS. +|spring.cloud.gateway.server.webflux.httpclient.ssl.ssl-bundle | | The name of the SSL bundle to use. +|spring.cloud.gateway.server.webflux.httpclient.ssl.trusted-x509-certificates | | Trusted certificates for verifying the remote endpoint's certificate. +|spring.cloud.gateway.server.webflux.httpclient.ssl.use-insecure-trust-manager | `+++false+++` | Installs the netty InsecureTrustManagerFactory. This is insecure and not suitable for production. +|spring.cloud.gateway.server.webflux.httpclient.websocket.max-frame-payload-length | | Max frame payload length. +|spring.cloud.gateway.server.webflux.httpclient.websocket.proxy-ping | `+++true+++` | Proxy ping frames to downstream services, defaults to true. +|spring.cloud.gateway.server.webflux.httpclient.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpClient. +|spring.cloud.gateway.server.webflux.httpserver.wiretap | `+++false+++` | Enables wiretap debugging for Netty HttpServer. +|spring.cloud.gateway.server.webflux.loadbalancer.use404 | `+++false+++` | +|spring.cloud.gateway.server.webflux.metrics.enabled | `+++false+++` | Enables the collection of metrics data. +|spring.cloud.gateway.server.webflux.metrics.prefix | `+++spring.cloud.gateway+++` | The prefix of all metrics emitted by gateway. +|spring.cloud.gateway.server.webflux.metrics.tags | | Tags map that added to metrics. +|spring.cloud.gateway.server.webflux.observability.enabled | `+++true+++` | If Micrometer Observability support should be turned on. +|spring.cloud.gateway.server.webflux.predicate.after.enabled | `+++true+++` | Enables the after predicate. +|spring.cloud.gateway.server.webflux.predicate.before.enabled | `+++true+++` | Enables the before predicate. +|spring.cloud.gateway.server.webflux.predicate.between.enabled | `+++true+++` | Enables the between predicate. +|spring.cloud.gateway.server.webflux.predicate.cloud-foundry-route-service.enabled | `+++true+++` | Enables the cloud-foundry-route-service predicate. +|spring.cloud.gateway.server.webflux.predicate.cookie.enabled | `+++true+++` | Enables the cookie predicate. +|spring.cloud.gateway.server.webflux.predicate.header.enabled | `+++true+++` | Enables the header predicate. +|spring.cloud.gateway.server.webflux.predicate.host.enabled | `+++true+++` | Enables the host predicate. +|spring.cloud.gateway.server.webflux.predicate.host.include-port | `+++true+++` | Include the port in matching the host name. +|spring.cloud.gateway.server.webflux.predicate.method.enabled | `+++true+++` | Enables the method predicate. +|spring.cloud.gateway.server.webflux.predicate.path.enabled | `+++true+++` | Enables the path predicate. +|spring.cloud.gateway.server.webflux.predicate.query.enabled | `+++true+++` | Enables the query predicate. +|spring.cloud.gateway.server.webflux.predicate.read-body.enabled | `+++true+++` | Enables the read-body predicate. +|spring.cloud.gateway.server.webflux.predicate.remote-addr.enabled | `+++true+++` | Enables the remote-addr predicate. +|spring.cloud.gateway.server.webflux.predicate.weight.enabled | `+++true+++` | Enables the weight predicate. +|spring.cloud.gateway.server.webflux.predicate.xforwarded-remote-addr.enabled | `+++true+++` | Enables the xforwarded-remote-addr predicate. +|spring.cloud.gateway.server.webflux.redis-rate-limiter.burst-capacity-header | `+++X-RateLimit-Burst-Capacity+++` | The name of the header that returns the burst capacity configuration. +|spring.cloud.gateway.server.webflux.redis-rate-limiter.config | | +|spring.cloud.gateway.server.webflux.redis-rate-limiter.include-headers | `+++true+++` | Whether or not to include headers containing rate limiter information, defaults to true. +|spring.cloud.gateway.server.webflux.redis-rate-limiter.remaining-header | `+++X-RateLimit-Remaining+++` | The name of the header that returns number of remaining requests during the current second. +|spring.cloud.gateway.server.webflux.redis-rate-limiter.replenish-rate-header | `+++X-RateLimit-Replenish-Rate+++` | The name of the header that returns the replenish rate configuration. +|spring.cloud.gateway.server.webflux.redis-rate-limiter.requested-tokens-header | `+++X-RateLimit-Requested-Tokens+++` | The name of the header that returns the requested tokens configuration. +|spring.cloud.gateway.server.webflux.redis-route-definition-repository.enabled | `+++true+++` | If RedisRouteDefinitionRepository should be enabled. +|spring.cloud.gateway.server.webflux.restrictive-property-accessor.enabled | `+++true+++` | Restricts method and property access in SpEL. +|spring.cloud.gateway.server.webflux.route-filter-cache-enabled | `+++false+++` | Enables the route filter cache, defaults to false. +|spring.cloud.gateway.server.webflux.route-refresh-listener.enabled | `+++true+++` | If RouteRefreshListener should be turned on. +|spring.cloud.gateway.server.webflux.routes | | List of Routes. +|spring.cloud.gateway.server.webflux.set-status.original-status-header-name | | The name of the header which contains http code of the proxied request. +|spring.cloud.gateway.server.webflux.streaming-media-types | | +|spring.cloud.gateway.server.webflux.x-forwarded.enabled | `+++true+++` | If the XForwardedHeadersFilter is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.for-append | `+++true+++` | If appending X-Forwarded-For as a list is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.for-enabled | `+++true+++` | If X-Forwarded-For is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.host-append | `+++true+++` | If appending X-Forwarded-Host as a list is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.host-enabled | `+++true+++` | If X-Forwarded-Host is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.order | `+++0+++` | The order of the XForwardedHeadersFilter. +|spring.cloud.gateway.server.webflux.x-forwarded.port-append | `+++true+++` | If appending X-Forwarded-Port as a list is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.port-enabled | `+++true+++` | If X-Forwarded-Port is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.prefix-append | `+++true+++` | If appending X-Forwarded-Prefix as a list is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.prefix-enabled | `+++true+++` | If X-Forwarded-Prefix is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.proto-append | `+++true+++` | If appending X-Forwarded-Proto as a list is enabled. +|spring.cloud.gateway.server.webflux.x-forwarded.proto-enabled | `+++true+++` | If X-Forwarded-Proto is enabled. |spring.cloud.gateway.server.webmvc.form-filter.enabled | `+++true+++` | Enables the form-filter. |spring.cloud.gateway.server.webmvc.forwarded-request-headers-filter.enabled | `+++true+++` | Enables the forwarded-request-headers-filter. |spring.cloud.gateway.server.webmvc.http-client.connect-timeout | | The HttpClient connect timeout. @@ -205,8 +384,10 @@ |spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.prefix-enabled | `+++true+++` | If X-Forwarded-Prefix is enabled. |spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-append | `+++true+++` | If appending X-Forwarded-Proto as a list is enabled. |spring.cloud.gateway.server.webmvc.x-forwarded-request-headers-filter.proto-enabled | `+++true+++` | If X-Forwarded-Proto is enabled. +|spring.cloud.gateway.set-status | | |spring.cloud.gateway.set-status.original-status-header-name | | The name of the header which contains http code of the proxied request. |spring.cloud.gateway.streaming-media-types | | +|spring.cloud.gateway.x-forwarded | | |spring.cloud.gateway.x-forwarded.enabled | `+++true+++` | If the XForwardedHeadersFilter is enabled. |spring.cloud.gateway.x-forwarded.for-append | `+++true+++` | If appending X-Forwarded-For as a list is enabled. |spring.cloud.gateway.x-forwarded.for-enabled | `+++true+++` | If X-Forwarded-For is enabled. diff --git a/spring-cloud-gateway-integration-tests/grpc/src/test/resources/application.yml b/spring-cloud-gateway-integration-tests/grpc/src/test/resources/application.yml index 97c1b950..1edaa78e 100644 --- a/spring-cloud-gateway-integration-tests/grpc/src/test/resources/application.yml +++ b/spring-cloud-gateway-integration-tests/grpc/src/test/resources/application.yml @@ -20,7 +20,7 @@ management: spring: cloud: - gateway: + gateway.server.webflux: httpserver: wiretap: true httpclient: diff --git a/spring-cloud-gateway-integration-tests/http2/src/main/resources/application.yml b/spring-cloud-gateway-integration-tests/http2/src/main/resources/application.yml index 8438b1d5..4db549c3 100644 --- a/spring-cloud-gateway-integration-tests/http2/src/main/resources/application.yml +++ b/spring-cloud-gateway-integration-tests/http2/src/main/resources/application.yml @@ -13,7 +13,7 @@ server: spring: cloud: - gateway: + gateway.server.webflux: # httpserver: # wiretap: true httpclient: diff --git a/spring-cloud-gateway-integration-tests/http2/src/test/resources/application-nossl.yml b/spring-cloud-gateway-integration-tests/http2/src/test/resources/application-nossl.yml index 6143bf9d..4b2cf96a 100644 --- a/spring-cloud-gateway-integration-tests/http2/src/test/resources/application-nossl.yml +++ b/spring-cloud-gateway-integration-tests/http2/src/test/resources/application-nossl.yml @@ -9,5 +9,5 @@ server: spring: cloud: - gateway: + gateway.server.webflux: enabled: false \ No newline at end of file diff --git a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/src/test/java/org/springframework/cloud/gateway/sample/MvcFailureAnalyzerApplicationTests.java b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/src/test/java/org/springframework/cloud/gateway/sample/MvcFailureAnalyzerApplicationTests.java index ea702715..f9a33ba3 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/src/test/java/org/springframework/cloud/gateway/sample/MvcFailureAnalyzerApplicationTests.java +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/src/test/java/org/springframework/cloud/gateway/sample/MvcFailureAnalyzerApplicationTests.java @@ -48,7 +48,7 @@ public class MvcFailureAnalyzerApplicationTests { @Test public void exceptionNotThrownWhenDisabled(CapturedOutput output) { assertThatCode(() -> new SpringApplication(MvcFailureAnalyzerApplication.class) - .run("--spring.cloud.gateway.enabled=false", "--server.port=0")).doesNotThrowAnyException(); + .run("--spring.cloud.gateway.server.webflux.enabled=false", "--server.port=0")).doesNotThrowAnyException(); assertThat(output).doesNotContain(MvcFoundOnClasspathFailureAnalyzer.MESSAGE, MvcFoundOnClasspathFailureAnalyzer.ACTION); } diff --git a/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml b/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml index ddae382f..c6952c89 100644 --- a/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml +++ b/spring-cloud-gateway-sample/src/main/resources/application-secureheaders.yml @@ -7,7 +7,7 @@ test: spring: cloud: - gateway: + gateway.server.webflux: filter: default-filters: #- PrefixPath=/httpbin diff --git a/spring-cloud-gateway-sample/src/main/resources/application.yml b/spring-cloud-gateway-sample/src/main/resources/application.yml index 4cf839df..10339112 100644 --- a/spring-cloud-gateway-sample/src/main/resources/application.yml +++ b/spring-cloud-gateway-sample/src/main/resources/application.yml @@ -9,7 +9,7 @@ spring: jmx: enabled: false cloud: - gateway: + gateway.server.webflux: default-filters: - PrefixPath=/httpbin - AddResponseHeader=X-Response-Default-Foo, Default-Bar diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index dd390a1a..6430185a 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -192,6 +192,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-properties-migrator + test + org.springframework.boot spring-boot-testcontainers diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index bebcf9b3..3acaa689 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -196,7 +196,7 @@ import org.springframework.web.reactive.socket.server.upgrade.ReactorNettyReques * @author FuYiNan Guo */ @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.enabled", matchIfMissing = true) @EnableConfigurationProperties @AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class }) @AutoConfigureAfter({ GatewayReactiveLoadBalancerClientAutoConfiguration.class, @@ -272,7 +272,7 @@ public class GatewayAutoConfiguration { @Bean @ConditionalOnClass(name = "org.springframework.cloud.client.discovery.event.HeartbeatMonitor") - @ConditionalOnProperty(prefix = GatewayProperties.PREFIX, name = ".route-refresh-listener.enabled", + @ConditionalOnProperty(prefix = GatewayProperties.PREFIX, name = "route-refresh-listener.enabled", matchIfMissing = true) public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) { return new RouteRefreshListener(publisher); @@ -290,7 +290,7 @@ public class GatewayAutoConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.globalcors.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.globalcors.enabled", matchIfMissing = true) public CorsGatewayFilterApplicationListener corsGatewayFilterApplicationListener( GlobalCorsProperties globalCorsProperties, RoutePredicateHandlerMapping routePredicateHandlerMapping, RouteLocator routeLocator) { @@ -318,9 +318,10 @@ public class GatewayAutoConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.forwarded.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.forwarded.enabled", matchIfMissing = true) public ForwardedHeadersFilter forwardedHeadersFilter(Environment env, ServerProperties serverProperties) { - boolean forwardedByEnabled = env.getProperty("spring.cloud.gateway.forwarded.by.enabled", Boolean.class, false); + boolean forwardedByEnabled = env.getProperty("spring.cloud.gateway.server.webflux.forwarded.by.enabled", + Boolean.class, false); ForwardedHeadersFilter forwardedHeadersFilter = new ForwardedHeadersFilter(); forwardedHeadersFilter.setForwardedByEnabled(forwardedByEnabled); forwardedHeadersFilter.setServerPort(serverProperties.getPort()); @@ -335,7 +336,7 @@ public class GatewayAutoConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.x-forwarded.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.x-forwarded.enabled", matchIfMissing = true) public XForwardedHeadersFilter xForwardedHeadersFilter() { return new XForwardedHeadersFilter(); } @@ -468,7 +469,8 @@ public class GatewayAutoConfiguration { @Bean @ConditionalOnEnabledPredicate public HostRoutePredicateFactory hostRoutePredicateFactory(Environment env) { - boolean includePort = env.getProperty("spring.cloud.gateway.predicate.host.include-port", Boolean.class, true); + boolean includePort = env.getProperty("spring.cloud.gateway.server.webflux.predicate.host.include-port", + Boolean.class, true); return new HostRoutePredicateFactory(includePort); } @@ -769,7 +771,7 @@ public class GatewayAutoConfiguration { protected final Log logger = LogFactory.getLog(getClass()); @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.httpserver.wiretap") + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.httpserver.wiretap") public NettyWebServerFactoryCustomizer nettyServerWiretapCustomizer(Environment environment, ServerProperties serverProperties) { return new NettyWebServerFactoryCustomizer(environment, serverProperties) { @@ -853,7 +855,8 @@ public class GatewayAutoConfiguration { protected static class GatewayActuatorConfiguration { @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.actuator.verbose.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.actuator.verbose.enabled", + matchIfMissing = true) @ConditionalOnAvailableEndpoint public GatewayControllerEndpoint gatewayControllerEndpoint(List globalFilters, List gatewayFilters, List routePredicates, @@ -883,7 +886,8 @@ public class GatewayAutoConfiguration { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnProperty(name = "spring.cloud.gateway.actuator.verbose.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.actuator.verbose.enabled", + matchIfMissing = true) static class VerboseDisabled { } @@ -891,7 +895,7 @@ public class GatewayAutoConfiguration { } @Configuration(proxyBeanMethods = false) - @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.enabled", matchIfMissing = true) @ConditionalOnClass({ OAuth2AuthorizedClient.class, SecurityWebFilterChain.class, SecurityProperties.class }) @ConditionalOnEnabledFilter(TokenRelayGatewayFilterFactory.class) protected static class TokenRelayConfiguration { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayClassPathWarningAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayClassPathWarningAutoConfiguration.java index 46507016..88cfed09 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayClassPathWarningAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayClassPathWarningAutoConfiguration.java @@ -29,7 +29,7 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @AutoConfigureBefore(GatewayAutoConfiguration.class) -@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".enabled", matchIfMissing = true) public class GatewayClassPathWarningAutoConfiguration { private static final Log log = LogFactory.getLog(GatewayClassPathWarningAutoConfiguration.class); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java index 0afedfbe..fdb7d659 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java @@ -38,7 +38,7 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureAfter(ContextFunctionCatalogAutoConfiguration.class) @AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, GatewayAutoConfiguration.class }) @ConditionalOnClass({ FunctionCatalog.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.function.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".function.enabled", matchIfMissing = true) class GatewayFunctionAutoConfiguration { @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayLoadBalancerProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayLoadBalancerProperties.java index b2be55c9..0814fb31 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayLoadBalancerProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayLoadBalancerProperties.java @@ -21,7 +21,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author Ryan Baxter */ -@ConfigurationProperties("spring.cloud.gateway.loadbalancer") +@ConfigurationProperties(GatewayProperties.PREFIX + ".loadbalancer") public class GatewayLoadBalancerProperties { private boolean use404; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsProperties.java index b0ca9d43..0d9e4183 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsProperties.java @@ -28,7 +28,7 @@ import org.springframework.validation.annotation.Validated; /** * @author Ingyu Hwang */ -@ConfigurationProperties("spring.cloud.gateway.metrics") +@ConfigurationProperties(GatewayProperties.PREFIX + ".metrics") @Validated public class GatewayMetricsProperties { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java index 356185f5..67e85c6d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java @@ -42,7 +42,7 @@ public class GatewayProperties { /** * Properties prefix. */ - public static final String PREFIX = "spring.cloud.gateway"; + public static final String PREFIX = "spring.cloud.gateway.server.webflux"; private final Log logger = LogFactory.getLog(getClass()); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java index 7b52c0a3..65407533 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfiguration.java @@ -50,7 +50,7 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureBefore(GatewayAutoConfiguration.class) @ConditionalOnBean(ReactiveRedisTemplate.class) @ConditionalOnClass({ RedisTemplate.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.redis.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".redis.enabled", matchIfMissing = true) class GatewayRedisAutoConfiguration { @Bean @@ -72,7 +72,7 @@ class GatewayRedisAutoConfiguration { } @Bean - @ConditionalOnProperty(value = "spring.cloud.gateway.redis-route-definition-repository.enabled", + @ConditionalOnProperty(value = GatewayProperties.PREFIX + ".redis-route-definition-repository.enabled", havingValue = "true") @ConditionalOnClass(ReactiveRedisTemplate.class) public RedisRouteDefinitionRepository redisRouteDefinitionRepository( diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayResilience4JCircuitBreakerAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayResilience4JCircuitBreakerAutoConfiguration.java index 598b1ef2..af44c795 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayResilience4JCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayResilience4JCircuitBreakerAutoConfiguration.java @@ -36,7 +36,7 @@ import org.springframework.web.reactive.DispatcherHandler; * @author Ryan Baxter */ @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".enabled", matchIfMissing = true) @AutoConfigureAfter({ ReactiveResilience4JAutoConfiguration.class }) @ConditionalOnClass({ DispatcherHandler.class, ReactiveResilience4JAutoConfiguration.class, ReactiveCircuitBreakerFactory.class, ReactiveResilience4JCircuitBreakerFactory.class }) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayServerWebfluxPropertiesMigrationListener.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayServerWebfluxPropertiesMigrationListener.java new file mode 100644 index 00000000..eb7ef6d2 --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayServerWebfluxPropertiesMigrationListener.java @@ -0,0 +1,183 @@ +/* + * Copyright 2013-2025 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; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.context.event.SpringApplicationEvent; +import org.springframework.boot.context.properties.source.ConfigurationProperty; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.context.properties.source.IterableConfigurationPropertySource; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.boot.origin.Origin; +import org.springframework.boot.origin.OriginTrackedValue; +import org.springframework.boot.origin.PropertySourceOrigin; +import org.springframework.boot.origin.TextResourceOrigin; +import org.springframework.context.ApplicationListener; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; +import org.springframework.util.ClassUtils; +import org.springframework.util.LinkedMultiValueMap; + +class GatewayServerWebfluxPropertiesMigrationListener implements ApplicationListener { + + private static final Log logger = LogFactory.getLog(GatewayServerWebfluxPropertiesMigrationListener.class); + + private static final String PROPERTIES_MIGRATOR_CLASS = "org.springframework.boot.context.properties.migrator.PropertiesMigrationListener"; + + private static final String DEPRECATED_ROOT = "spring.cloud.gateway"; + + private static final String DEPRECATED_ROUTES_LIST_KEY = DEPRECATED_ROOT + ".routes"; + + private static final String GATEWAY_PROPERTY_SOURCE_PREFIX = "migrategatewayflux"; + + private static final String NEW_ROUTES_LIST_KEY = GatewayProperties.PREFIX + ".routes"; + + private final List routesMigrations = new ArrayList<>(); + + @Override + public void onApplicationEvent(SpringApplicationEvent event) { + // only run if spring-boot-properties-migrator is on the classpath + if (!ClassUtils.isPresent(PROPERTIES_MIGRATOR_CLASS, null)) { + return; + } + if (event instanceof ApplicationPreparedEvent preparedEvent) { + onApplicationPreparedEvent(preparedEvent); + } + if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) { + logLegacyPropertiesReport(); + } + } + + private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { + // find deprecated keys + ConfigurableEnvironment env = event.getApplicationContext().getEnvironment(); + + ConfigurationPropertySources.get(env).forEach(propertySource -> { + routesMigrations.addAll(migrate(env, propertySource, GATEWAY_PROPERTY_SOURCE_PREFIX + "routes-", + DEPRECATED_ROUTES_LIST_KEY, NEW_ROUTES_LIST_KEY)); + }); + } + + private List migrate(ConfigurableEnvironment env, ConfigurationPropertySource propertySource, + String propertySourcePrefix, String deprecatedKey, String newKeyPrefix) { + List migrations = new ArrayList<>(); + + if (propertySource instanceof IterableConfigurationPropertySource iterableSource) { + ConfigurationPropertyName routesParentName = ConfigurationPropertyName.of(deprecatedKey); + List matchingConfigProps = iterableSource.filter(n -> { + if (n.getNumberOfElements() < routesParentName.getNumberOfElements()) { + return false; + } + ConfigurationPropertyName chop = n.chop(routesParentName.getNumberOfElements()); + return routesParentName.equals(chop); + }).stream().toList(); + if (!matchingConfigProps.isEmpty()) { + String originalPropertySourceName; + if (propertySource.getUnderlyingSource() instanceof PropertySource underlyingSource) { + originalPropertySourceName = underlyingSource.getName(); + } + else { + originalPropertySourceName = propertySource.getUnderlyingSource().toString(); + } + String newPropertySourceName = propertySourcePrefix + originalPropertySourceName; + Map content = new LinkedHashMap<>(); + // migrate to new keys + for (ConfigurationPropertyName originalPropertyName : matchingConfigProps) { + ConfigurationPropertyName suffix = originalPropertyName + .subName(routesParentName.getNumberOfElements()); + ConfigurationPropertyName newProperty = ConfigurationPropertyName.of(newKeyPrefix).append(suffix); + ConfigurationProperty configurationProperty = propertySource + .getConfigurationProperty(originalPropertyName); + Object value = configurationProperty.getValue(); + OriginTrackedValue originTrackedValue = OriginTrackedValue.of(value, + configurationProperty.getOrigin()); + content.put(newProperty.toString(), originTrackedValue); + migrations.add(new Migration(originalPropertySourceName, originalPropertyName, + configurationProperty, newProperty)); + } + env.getPropertySources() + .addBefore(originalPropertySourceName, + new OriginTrackedMapPropertySource(newPropertySourceName, content)); + } + } + return migrations; + } + + private void logLegacyPropertiesReport() { + // log warnings + if (!routesMigrations.isEmpty()) { + LinkedMultiValueMap content = new LinkedMultiValueMap<>(); + routesMigrations.forEach(migration -> content.add(migration.originalPropertySourceName(), migration)); + + StringBuilder report = new StringBuilder(); + report.append(String + .format("%nThe use of configuration keys that have been renamed was found in the environment:%n%n")); + + content.forEach((name, properties) -> { + report.append(String.format("Property source '%s':%n", name)); + // properties.sort(PropertyMigration.COMPARATOR); + properties.forEach((property) -> { + ConfigurationPropertyName originalPropertyName = property.originalPropertyName(); + report.append(String.format("\tKey: %s%n", originalPropertyName)); + Integer lineNumber = property.determineLineNumber(); + if (lineNumber != null) { + report.append(String.format("\t\tLine: %d%n", lineNumber)); + } + report.append(String.format("\t\tReplacement: %s%n", property.newProperty().toString())); + }); + report.append(String.format("%n")); + }); + + report.append(String.format("%n")); + report.append("Each configuration key has been temporarily mapped to its " + + "replacement for your convenience. To silence this warning, please " + + "update your configuration to use the new keys."); + report.append(String.format("%n")); + logger.warn(report.toString()); + } + } + + private record Migration(String originalPropertySourceName, ConfigurationPropertyName originalPropertyName, + ConfigurationProperty originalProperty, ConfigurationPropertyName newProperty) { + + private Integer determineLineNumber() { + Origin origin = originalProperty.getOrigin(); + if (origin instanceof PropertySourceOrigin propertySourceOrigin) { + origin = propertySourceOrigin.getOrigin(); + } + if (origin instanceof TextResourceOrigin textOrigin) { + if (textOrigin.getLocation() != null) { + return textOrigin.getLocation().getLine() + 1; + } + } + return null; + } + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java index ba5dcbb4..262a6078 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java @@ -35,7 +35,7 @@ import org.springframework.web.reactive.DispatcherHandler; @AutoConfigureAfter(BindingServiceConfiguration.class) @AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, GatewayAutoConfiguration.class }) @ConditionalOnClass({ StreamBridge.class, DispatcherHandler.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.stream.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".stream.enabled", matchIfMissing = true) class GatewayStreamAutoConfiguration { @Bean diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java index db102fd8..b0b3851d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GlobalCorsProperties.java @@ -27,7 +27,7 @@ import org.springframework.web.cors.CorsConfiguration; * Configuration properties for global configuration of cors. See * {@link RoutePredicateHandlerMapping} */ -@ConfigurationProperties("spring.cloud.gateway.globalcors") +@ConfigurationProperties(GatewayProperties.PREFIX + ".globalcors") public class GlobalCorsProperties { private final Map corsConfigurations = new LinkedHashMap<>(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/HttpClientProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/HttpClientProperties.java index fef1d54c..96538e93 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/HttpClientProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/HttpClientProperties.java @@ -32,7 +32,7 @@ import org.springframework.validation.annotation.Validated; /** * Configuration properties for the Netty {@link reactor.netty.http.client.HttpClient}. */ -@ConfigurationProperties("spring.cloud.gateway.httpclient") +@ConfigurationProperties(GatewayProperties.PREFIX + ".httpclient") @Validated public class HttpClientProperties { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfiguration.java index 908e2883..71e2641c 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfiguration.java @@ -108,17 +108,19 @@ public class LocalResponseCacheAutoConfiguration { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnProperty(value = "spring.cloud.gateway.enabled", havingValue = "true", matchIfMissing = true) + @ConditionalOnProperty(value = GatewayProperties.PREFIX + ".enabled", havingValue = "true", + matchIfMissing = true) static class OnGatewayPropertyEnabled { } - @ConditionalOnProperty(value = "spring.cloud.gateway.filter.local-response-cache.enabled", havingValue = "true") + @ConditionalOnProperty(value = GatewayProperties.PREFIX + ".filter.local-response-cache.enabled", + havingValue = "true") static class OnLocalResponseCachePropertyEnabled { } - @ConditionalOnProperty(name = "spring.cloud.gateway.global-filter.local-response-cache.enabled", + @ConditionalOnProperty(name = GatewayProperties.PREFIX + ".global-filter.local-response-cache.enabled", havingValue = "true", matchIfMissing = true) static class OnGlobalLocalResponseCachePropertyEnabled { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/SimpleUrlHandlerMappingGlobalCorsAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/SimpleUrlHandlerMappingGlobalCorsAutoConfiguration.java index 62c7ffad..28bdea81 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/SimpleUrlHandlerMappingGlobalCorsAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/SimpleUrlHandlerMappingGlobalCorsAutoConfiguration.java @@ -30,7 +30,7 @@ import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(SimpleUrlHandlerMapping.class) -@ConditionalOnProperty(name = "spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping", +@ConditionalOnProperty(name = GatewayProperties.PREFIX + ".globalcors.add-to-simple-url-handler-mapping", matchIfMissing = false) public class SimpleUrlHandlerMappingGlobalCorsAutoConfiguration { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponent.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponent.java index b3211dd5..5b48cabd 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponent.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponent.java @@ -34,7 +34,7 @@ import static org.springframework.boot.autoconfigure.condition.ConditionMessage. public abstract class OnEnabledComponent extends SpringBootCondition implements ConfigurationCondition { - private static final String PREFIX = "spring.cloud.gateway."; + private static final String PREFIX = "spring.cloud.gateway.server.webflux."; private static final String SUFFIX = ".enabled"; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java index 9426ed37..ba0d5557 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java @@ -24,7 +24,7 @@ import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.core.style.ToStringCreator; -@ConfigurationProperties("spring.cloud.gateway.discovery.locator") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.discovery.locator") public class DiscoveryLocatorProperties { /** Flag that enables DiscoveryClient gateway integration. */ diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/GatewayDiscoveryClientAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/GatewayDiscoveryClientAutoConfiguration.java index 94cc64e2..06efe748 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/GatewayDiscoveryClientAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/discovery/GatewayDiscoveryClientAutoConfiguration.java @@ -45,7 +45,7 @@ import static org.springframework.cloud.gateway.support.NameUtils.normalizeRoute * @author Spencer Gibb */ @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.enabled", matchIfMissing = true) @AutoConfigureBefore(GatewayAutoConfiguration.class) @AutoConfigureAfter(CompositeDiscoveryClientAutoConfiguration.class) @ConditionalOnClass({ DispatcherHandler.class, CompositeDiscoveryClientAutoConfiguration.class }) @@ -92,7 +92,7 @@ public class GatewayDiscoveryClientAutoConfiguration { public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration { @Bean - @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled") + @ConditionalOnProperty(name = "spring.cloud.gateway.server.webflux.discovery.locator.enabled") public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator( ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) { return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java index e0eb2102..e3f0b2f6 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java @@ -34,7 +34,7 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.s * User Request Rate Limiter filter. See https://stripe.com/blog/rate-limiters and * https://gist.github.com/ptarjan/e38f45f2dfe601419ca3af937fff574d#file-1-check_request_rate_limiter-rb-L11-L34. */ -@ConfigurationProperties("spring.cloud.gateway.filter.request-rate-limiter") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.filter.request-rate-limiter") public class RequestRateLimiterGatewayFilterFactory extends AbstractGatewayFilterFactory { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java index 2456a6f4..7ad3cfaf 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java @@ -27,7 +27,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author Spencer Gibb, Thirunavukkarasu Ravichandran, Jörg Richter */ -@ConfigurationProperties("spring.cloud.gateway.filter.secure-headers") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.filter.secure-headers") public class SecureHeadersProperties { /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java index 4ca59ec8..428e267e 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java @@ -35,7 +35,7 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.s /** * @author Spencer Gibb */ -@ConfigurationProperties("spring.cloud.gateway.set-status") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.set-status") public class SetStatusGatewayFilterFactory extends AbstractGatewayFilterFactory { /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java index a1738827..c28a00e4 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java @@ -40,7 +40,8 @@ import org.springframework.validation.annotation.Validated; * @author Marta Medio * @author Ignacio Lozano */ -@ConditionalOnProperty(value = "spring.cloud.gateway.filter.local-response-cache.enabled", havingValue = "true") +@ConditionalOnProperty(value = "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled", + havingValue = "true") public class LocalResponseCacheGatewayFilterFactory extends AbstractGatewayFilterFactory { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java index 1aead89a..56e026e4 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java @@ -30,7 +30,7 @@ import org.springframework.util.unit.DataSize; @ConfigurationProperties(prefix = LocalResponseCacheProperties.PREFIX) public class LocalResponseCacheProperties { - static final String PREFIX = "spring.cloud.gateway.filter.local-response-cache"; + static final String PREFIX = "spring.cloud.gateway.server.webflux.filter.local-response-cache"; private static final Log LOGGER = LogFactory.getLog(LocalResponseCacheProperties.class); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java index 556f1c97..fa8ff08a 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java @@ -30,7 +30,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; -@ConfigurationProperties("spring.cloud.gateway.filter.remove-hop-by-hop") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop") public class RemoveHopByHopHeadersFilter implements HttpHeadersFilter, Ordered { /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java index 2c1e8363..2dea38fc 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java @@ -32,7 +32,7 @@ import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; -@ConfigurationProperties("spring.cloud.gateway.x-forwarded") +@ConfigurationProperties("spring.cloud.gateway.server.webflux.x-forwarded") public class XForwardedHeadersFilter implements HttpHeadersFilter, Ordered { /** Default http port. */ diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java index 6ae0c467..5d4d73cb 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java @@ -31,6 +31,7 @@ import reactor.core.publisher.Mono; import org.springframework.beans.BeansException; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.gateway.config.GatewayProperties; import org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator; import org.springframework.cloud.gateway.support.ConfigurationService; import org.springframework.context.ApplicationContext; @@ -50,7 +51,7 @@ import org.springframework.validation.annotation.Validated; * @author Denis Cutic * @author Andrey Muchnik */ -@ConfigurationProperties("spring.cloud.gateway.redis-rate-limiter") +@ConfigurationProperties(GatewayProperties.PREFIX + ".redis-rate-limiter") public class RedisRateLimiter extends AbstractRateLimiter implements ApplicationContextAware { /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java index 30e2cc2e..16c3f30e 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java @@ -183,8 +183,8 @@ public interface ShortcutConfigurable { public GatewayEvaluationContext(BeanFactory beanFactory) { this.beanFactoryResolver = new BeanFactoryResolver(beanFactory); Environment env = beanFactory.getBean(Environment.class); - boolean restrictive = env.getProperty("spring.cloud.gateway.restrictive-property-accessor.enabled", - Boolean.class, true); + boolean restrictive = env.getProperty( + "spring.cloud.gateway.server.webflux.restrictive-property-accessor.enabled", Boolean.class, true); if (restrictive) { delegate = SimpleEvaluationContext.forPropertyAccessors(new RestrictivePropertyAccessor()) .withMethodResolvers((context, targetObject, name, argumentTypes) -> null) diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1aea9f85..1a646d71 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,447 +1,2447 @@ { "properties": [ { - "name": "spring.cloud.gateway.filter.add-request-header.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.filter.add-response-header.enabled", "type": "java.lang.Boolean", "description": "Enables the add-response-header filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.json-to-grpc.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.json-to-grpc.enabled", "type": "java.lang.Boolean", "description": "Enables the JSON to gRPC filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.modify-request-body.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.modify-request-body.enabled", "type": "java.lang.Boolean", "description": "Enables the modify-request-body filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.local-response-cache.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled", "type": "java.lang.Boolean", "description": "Enables the local-response-cache filter.", "defaultValue": "false" }, { - "name": "spring.cloud.gateway.filter.local-response-cache.size", + "name": "spring.cloud.gateway.server.webflux.filter.local-response-cache.size", "type": "org.springframework.util.unit.DataSize", "description": "Maximum size of the cache to evict entries for this route (in KB, MB and GB)." }, { - "name": "spring.cloud.gateway.filter.local-response-cache.time-to-live", + "name": "spring.cloud.gateway.server.webflux.filter.local-response-cache.time-to-live", "type": "java.time.Duration", "description": "Time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours).", "defaultValue": "5m" }, { - "name": "spring.cloud.gateway.filter.dedupe-response-header.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.filter.rewrite-path.enabled", "type": "java.lang.Boolean", "description": "Enables the rewrite-path filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.retry.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.retry.enabled", "type": "java.lang.Boolean", "description": "Enables the retry filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.set-path.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.set-path.enabled", "type": "java.lang.Boolean", "description": "Enables the set-path filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.secure-headers.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.filter.rewrite-location.enabled", "type": "java.lang.Boolean", "description": "Enables the rewrite-location filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.rewrite-request-parameter.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.rewrite-request-parameter.enabled", "type": "java.lang.Boolean", "description": "Enables the rewrite-request-parameter filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.set-status.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.set-status.enabled", "type": "java.lang.Boolean", "description": "Enables the set-status filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.save-session.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.save-session.enabled", "type": "java.lang.Boolean", "description": "Enables the save-session filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.strip-prefix.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.filter.circuit-breaker.enabled", "type": "java.lang.Boolean", "description": "Enables the circuit-breaker filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.hystrix.enabled", + "name": "spring.cloud.gateway.server.webflux.filter.hystrix.enabled", "type": "java.lang.Boolean", "description": "Enables the hystrix filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.filter.fallback-headers.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.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-client.enabled", + "name": "spring.cloud.gateway.server.webflux.global-filter.reactive-load-balancer-client.enabled", "type": "java.lang.Boolean", "description": "Enables the reactive-load-balancer-client global filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.global-filter.load-balancer-client.enabled", + "name": "spring.cloud.gateway.server.webflux.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.local-response-cache.enabled", + "name": "spring.cloud.gateway.server.webflux.global-filter.local-response-cache.enabled", "type": "java.lang.Boolean", "description": "Enables the local-response-cache filter for all routes, it allows to add a specific configuration at route level using LocalResponseCache filter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.after.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.after.enabled", "type": "java.lang.Boolean", "description": "Enables the after predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.before.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.before.enabled", "type": "java.lang.Boolean", "description": "Enables the before predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.between.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.between.enabled", "type": "java.lang.Boolean", "description": "Enables the between predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.cookie.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.cookie.enabled", "type": "java.lang.Boolean", "description": "Enables the cookie predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.header.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.header.enabled", "type": "java.lang.Boolean", "description": "Enables the header predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.host.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.host.enabled", "type": "java.lang.Boolean", "description": "Enables the host predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.method.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.method.enabled", "type": "java.lang.Boolean", "description": "Enables the method predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.path.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.path.enabled", "type": "java.lang.Boolean", "description": "Enables the path predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.query.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.query.enabled", "type": "java.lang.Boolean", "description": "Enables the query predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.read-body.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.read-body.enabled", "type": "java.lang.Boolean", "description": "Enables the read-body predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.remote-addr.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.remote-addr.enabled", "type": "java.lang.Boolean", "description": "Enables the remote-addr predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.xforwarded-remote-addr.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.xforwarded-remote-addr.enabled", "type": "java.lang.Boolean", "description": "Enables the xforwarded-remote-addr predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.weight.enabled", + "name": "spring.cloud.gateway.server.webflux.predicate.weight.enabled", "type": "java.lang.Boolean", "description": "Enables the weight predicate.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.cloud-foundry-route-service.enabled", + "name": "spring.cloud.gateway.server.webflux.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", + "name": "spring.cloud.gateway.server.webflux.enabled", "type": "java.lang.Boolean", "description": "Enables gateway functionality.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.forwarded.enabled", + "name": "spring.cloud.gateway.server.webflux.forwarded.enabled", "type": "java.lang.Boolean", "description": "Enables the ForwardedHeadersFilter.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.forwarded.by.enabled", + "name": "spring.cloud.gateway.server.webflux.forwarded.by.enabled", "type": "java.lang.Boolean", "description": "Enables the Forwarded: by header part.", "defaultValue": "false" }, { - "name": "spring.cloud.gateway.httpserver.wiretap", + "name": "spring.cloud.gateway.server.webflux.httpserver.wiretap", "type": "java.lang.Boolean", "description": "Enables wiretap debugging for Netty HttpServer.", "defaultValue": "false" }, { - "name": "spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping", + "name": "spring.cloud.gateway.server.webflux.globalcors.add-to-simple-url-handler-mapping", "type": "java.lang.Boolean", "description": "If global CORS config should be added to the URL handler.", "defaultValue": "false" }, { - "name": "spring.cloud.gateway.handler-mapping.order", + "name": "spring.cloud.gateway.server.webflux.handler-mapping.order", "type": "java.lang.Integer", "description": "The order of RoutePredicateHandlerMapping.", "defaultValue": "1" }, { - "name": "spring.cloud.gateway.restrictive-property-accessor.enabled", + "name": "spring.cloud.gateway.server.webflux.restrictive-property-accessor.enabled", "type": "java.lang.Boolean", "description": "Restricts method and property access in SpEL.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.observability.enabled", + "name": "spring.cloud.gateway.server.webflux.observability.enabled", "type": "java.lang.Boolean", "description": "If Micrometer Observability support should be turned on.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.predicate.host.include-port", + "name": "spring.cloud.gateway.server.webflux.predicate.host.include-port", "type": "java.lang.Boolean", "description": "Include the port in matching the host name.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.route-refresh-listener.enabled", + "name": "spring.cloud.gateway.server.webflux.route-refresh-listener.enabled", "type": "java.lang.Boolean", "description": "If RouteRefreshListener should be turned on.", "defaultValue": "true" }, { - "name": "spring.cloud.gateway.redis-route-definition-repository.enabled", + "name": "spring.cloud.gateway.server.webflux.redis-route-definition-repository.enabled", "type": "java.lang.Boolean", "description": "If RedisRouteDefinitionRepository should be enabled.", "defaultValue": "true" + }, + { + "name": "spring.cloud.gateway", + "type": "org.springframework.cloud.gateway.config.GatewayProperties", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator", + "type": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache", + "type": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties", + "sourceType": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache.request", + "type": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties$RequestOptions", + "sourceType": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache.request", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-hop-by-hop", + "type": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter", + "sourceType": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-rate-limiter", + "type": "org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory", + "sourceType": "org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-rate-limiter", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers", + "type": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.globalcors", + "type": "org.springframework.cloud.gateway.config.GlobalCorsProperties", + "sourceType": "org.springframework.cloud.gateway.config.GlobalCorsProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.globalcors", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.websocket", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Websocket", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.websocket", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.loadbalancer", + "type": "org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties", + "sourceType": "org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.loadbalancer", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.metrics", + "type": "org.springframework.cloud.gateway.config.GatewayMetricsProperties", + "sourceType": "org.springframework.cloud.gateway.config.GatewayMetricsProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.metrics", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter", + "type": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.set-status", + "type": "org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.set-status", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded", + "type": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.default-filters", + "type": "java.util.List", + "description": "List of filter definitions that are applied to every route.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.default-filters", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.enabled", + "type": "java.lang.Boolean", + "description": "Flag that enables DiscoveryClient gateway integration.", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.filters", + "type": "java.util.List", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.filters", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.include-expression", + "type": "java.lang.String", + "description": "SpEL expression that will evaluate whether to include a service in gateway integration or not, defaults to: true.", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.include-expression", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.lower-case-service-id", + "type": "java.lang.Boolean", + "description": "Option to lower case serviceId in predicates and filters, defaults to false. Useful with eureka when it automatically uppercases serviceId. so MYSERIVCE, would match \/myservice\/**", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.lower-case-service-id", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.predicates", + "type": "java.util.List", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.predicates", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.route-id-prefix", + "type": "java.lang.String", + "description": "The prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName() + \"_\". Service Id will be appended to create the routeId.", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.route-id-prefix", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.discovery.locator.url-expression", + "type": "java.lang.String", + "description": "SpEL expression that create the uri for each route, defaults to: 'lb:\/\/'+serviceId.", + "sourceType": "org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties", + "defaultValue": "'lb:\/\/'+serviceId", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.discovery.locator.url-expression", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.enabled", + "type": "java.lang.Boolean", + "description": "Enables gateway functionality.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.fail-on-route-definition-error", + "type": "java.lang.Boolean", + "description": "Option to fail on route definition errors, defaults to true. Otherwise, a warning is logged.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.fail-on-route-definition-error", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.add-request-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the add-request-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.add-request-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.add-request-parameter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the add-request-parameter filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.add-request-parameter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.add-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the add-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.add-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.circuit-breaker.enabled", + "type": "java.lang.Boolean", + "description": "Enables the circuit-breaker filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.circuit-breaker.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.dedupe-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the dedupe-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.dedupe-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.fallback-headers.enabled", + "type": "java.lang.Boolean", + "description": "Enables the fallback-headers filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.fallback-headers.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.hystrix.enabled", + "type": "java.lang.Boolean", + "description": "Enables the hystrix filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.hystrix.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.json-to-grpc.enabled", + "type": "java.lang.Boolean", + "description": "Enables the JSON to gRPC filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.json-to-grpc.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache.enabled", + "type": "java.lang.Boolean", + "description": "Enables the local-response-cache filter.", + "defaultValue": "false", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache.request.no-cache-strategy", + "type": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties$NoCacheStrategy", + "sourceType": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties$RequestOptions", + "defaultValue": "skip-update-cache-entry", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache.request.no-cache-strategy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache.size", + "type": "org.springframework.util.unit.DataSize", + "description": "Maximum size of the cache to evict entries for this route (in KB, MB and GB).", + "sourceType": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache.size", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.local-response-cache.time-to-live", + "type": "java.time.Duration", + "description": "Time to expire a cache entry (expressed in s for seconds, m for minutes, and h for hours).", + "sourceType": "org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties", + "defaultValue": "5m", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.local-response-cache.time-to-live", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.map-request-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the map-request-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.map-request-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.modify-request-body.enabled", + "type": "java.lang.Boolean", + "description": "Enables the modify-request-body filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.modify-request-body.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.modify-response-body.enabled", + "type": "java.lang.Boolean", + "description": "Enables the modify-response-body filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.modify-response-body.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.prefix-path.enabled", + "type": "java.lang.Boolean", + "description": "Enables the prefix-path filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.prefix-path.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.preserve-host-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the preserve-host-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.preserve-host-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.redirect-to.enabled", + "type": "java.lang.Boolean", + "description": "Enables the redirect-to filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.redirect-to.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-hop-by-hop.headers", + "type": "java.util.Set", + "sourceType": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop.headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-hop-by-hop.order", + "type": "java.lang.Integer", + "sourceType": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter", + "defaultValue": 0, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop.order", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-request-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-request-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-request-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-request-parameter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-request-parameter filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-request-parameter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.remove-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.remove-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-header-size.enabled", + "type": "java.lang.Boolean", + "description": "Enables the request-header-size filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-header-size.enabled", + "since": "4.3.0" + } + }, + { + "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", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-header-to-request-uri.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-rate-limiter.default-key-resolver", + "type": "org.springframework.cloud.gateway.filter.ratelimit.KeyResolver", + "sourceType": "org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-rate-limiter.default-key-resolver", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-rate-limiter.default-rate-limiter", + "type": "org.springframework.cloud.gateway.filter.ratelimit.RateLimiter", + "sourceType": "org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-rate-limiter.default-rate-limiter", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-rate-limiter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the request-rate-limiter filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-rate-limiter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.request-size.enabled", + "type": "java.lang.Boolean", + "description": "Enables the request-size filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.request-size.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.retry.enabled", + "type": "java.lang.Boolean", + "description": "Enables the retry filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.retry.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.rewrite-location-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the rewrite-location-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.rewrite-location-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.rewrite-location.enabled", + "type": "java.lang.Boolean", + "description": "Enables the rewrite-location filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.rewrite-location.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.rewrite-path.enabled", + "type": "java.lang.Boolean", + "description": "Enables the rewrite-path filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.rewrite-path.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.rewrite-request-parameter.enabled", + "type": "java.lang.Boolean", + "description": "Enables the rewrite-request-parameter filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.rewrite-request-parameter.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.rewrite-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the rewrite-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.rewrite-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.save-session.enabled", + "type": "java.lang.Boolean", + "description": "Enables the save-session filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.save-session.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.content-security-policy", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.content-security-policy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.content-type-options", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "nosniff", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.content-type-options", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.default-headers", + "type": "java.util.Set", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.default-headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.disable", + "type": "java.util.List", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.disable", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.disabled-headers", + "type": "java.util.Set", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.disabled-headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.download-options", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "noopen", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.download-options", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.enabled", + "type": "java.lang.Boolean", + "description": "Enables the secure-headers filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.enabled-headers", + "type": "java.util.Set", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.enabled-headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.frame-options", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "DENY", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.frame-options", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.permissions-policy", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.permissions-policy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "none", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.permitted-cross-domain-policies", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.referrer-policy", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "no-referrer", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.referrer-policy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.strict-transport-security", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "max-age=631138519", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.strict-transport-security", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.secure-headers.xss-protection-header", + "type": "java.lang.String", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", + "defaultValue": "1 ; mode=block", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.secure-headers.xss-protection-header", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.set-path.enabled", + "type": "java.lang.Boolean", + "description": "Enables the set-path filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.set-path.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.set-request-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the set-request-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.set-request-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.set-request-host-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the set-request-host-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.set-request-host-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.set-response-header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the set-response-header filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.set-response-header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.set-status.enabled", + "type": "java.lang.Boolean", + "description": "Enables the set-status filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.set-status.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.filter.strip-prefix.enabled", + "type": "java.lang.Boolean", + "description": "Enables the strip-prefix filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.filter.strip-prefix.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.forwarded.by.enabled", + "type": "java.lang.Boolean", + "description": "Enables the Forwarded: by header part.", + "defaultValue": "false", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.forwarded.by.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.forwarded.enabled", + "type": "java.lang.Boolean", + "description": "Enables the ForwardedHeadersFilter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.forwarded.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.adapt-cached-body.enabled", + "type": "java.lang.Boolean", + "description": "Enables the adapt-cached-body global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.adapt-cached-body.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.forward-path.enabled", + "type": "java.lang.Boolean", + "description": "Enables the forward-path global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.forward-path.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.forward-routing.enabled", + "type": "java.lang.Boolean", + "description": "Enables the forward-routing global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.forward-routing.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.load-balancer-client.enabled", + "type": "java.lang.Boolean", + "description": "Enables the load-balancer-client global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.load-balancer-client.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.local-response-cache.enabled", + "type": "java.lang.Boolean", + "description": "Enables the local-response-cache filter for all routes, it allows to add a specific configuration at route level using LocalResponseCache filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.local-response-cache.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.netty-routing.enabled", + "type": "java.lang.Boolean", + "description": "Enables the netty-routing global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.netty-routing.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.netty-write-response.enabled", + "type": "java.lang.Boolean", + "description": "Enables the netty-write-response global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.netty-write-response.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.reactive-load-balancer-client.enabled", + "type": "java.lang.Boolean", + "description": "Enables the reactive-load-balancer-client global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.reactive-load-balancer-client.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.remove-cached-body.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remove-cached-body global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.remove-cached-body.enabled", + "since": "4.3.0" + } + }, + { + "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", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.route-to-request-url.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.global-filter.websocket-routing.enabled", + "type": "java.lang.Boolean", + "description": "Enables the websocket-routing global filter.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.global-filter.websocket-routing.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping", + "type": "java.lang.Boolean", + "description": "If global CORS config should be added to the URL handler.", + "defaultValue": "false", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.globalcors.add-to-simple-url-handler-mapping", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.globalcors.cors-configurations", + "type": "java.util.Map", + "sourceType": "org.springframework.cloud.gateway.config.GlobalCorsProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.globalcors.cors-configurations", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.handler-mapping.order", + "type": "java.lang.Integer", + "description": "The order of RoutePredicateHandlerMapping.", + "defaultValue": "1", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.handler-mapping.order", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.compression", + "type": "java.lang.Boolean", + "description": "Enables compression for Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.compression", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.connect-timeout", + "type": "java.lang.Integer", + "description": "The connect timeout in millis, the default is 30s.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.connect-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.max-header-size", + "type": "org.springframework.util.unit.DataSize", + "description": "The max response header size.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.max-header-size", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.max-initial-line-length", + "type": "org.springframework.util.unit.DataSize", + "description": "The max initial line length.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.max-initial-line-length", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.acquire-timeout", + "type": "java.lang.Long", + "description": "Only for type FIXED, the maximum time in millis to wait for acquiring.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.acquire-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.eviction-interval", + "type": "java.time.Duration", + "description": "Perform regular eviction checks in the background at a specified interval. Disabled by default ({@link Duration#ZERO})", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "defaultValue": 0, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.eviction-interval", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.leasing-strategy", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool$LeasingStrategy", + "description": "Configures the leasing strategy for the pool (fifo or lifo), defaults to FIFO which is Netty's default.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "defaultValue": "fifo", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.leasing-strategy", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.max-connections", + "type": "java.lang.Integer", + "description": "Only for type FIXED, the maximum number of connections before starting pending acquisition on existing ones.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.max-connections", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.max-idle-time", + "type": "java.time.Duration", + "description": "Time in millis after which the channel will be closed. If NULL, there is no max idle time.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.max-idle-time", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.max-life-time", + "type": "java.time.Duration", + "description": "Duration after which the channel will be closed. If NULL, there is no max life time.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.max-life-time", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.metrics", + "type": "java.lang.Boolean", + "description": "Enables channel pools metrics to be collected and registered in Micrometer. Disabled by default.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.metrics", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.name", + "type": "java.lang.String", + "description": "The channel pool map name, defaults to proxy.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "defaultValue": "proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.name", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.pool.type", + "type": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool$PoolType", + "description": "Type of pool for HttpClient to use (elastic, fixed or disabled).", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool", + "defaultValue": "elastic", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.pool.type", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.host", + "type": "java.lang.String", + "description": "Hostname for proxy configuration of Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.host", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.non-proxy-hosts-pattern", + "type": "java.lang.String", + "description": "Regular expression (Java) for a configured list of hosts. that should be reached directly, bypassing the proxy", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.non-proxy-hosts-pattern", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.password", + "type": "java.lang.String", + "description": "Password for proxy configuration of Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.password", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.port", + "type": "java.lang.Integer", + "description": "Port for proxy configuration of Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.port", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.type", + "type": "reactor.netty.transport.ProxyProvider$Proxy", + "description": "proxyType for proxy configuration of Netty HttpClient (http, socks4 or socks5).", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "defaultValue": "http", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.type", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.proxy.username", + "type": "java.lang.String", + "description": "Username for proxy configuration of Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.proxy.username", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.response-timeout", + "type": "java.time.Duration", + "description": "The response timeout.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.response-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.close-notify-flush-timeout", + "type": "java.time.Duration", + "description": "SSL close_notify flush timeout. Default to 3000 ms.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "defaultValue": "3000ms", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.close-notify-flush-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.close-notify-read-timeout", + "type": "java.time.Duration", + "description": "SSL close_notify read timeout. Default to 0 ms.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "defaultValue": 0, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.close-notify-read-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.handshake-timeout", + "type": "java.time.Duration", + "description": "SSL handshake timeout. Default to 10000 ms", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "defaultValue": "10000ms", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.handshake-timeout", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.key-password", + "type": "java.lang.String", + "description": "Key password, default is same as keyStorePassword.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.key-password", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.key-store", + "type": "java.lang.String", + "description": "Keystore path for Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.key-store", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.key-store-password", + "type": "java.lang.String", + "description": "Keystore password.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-password", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.key-store-provider", + "type": "java.lang.String", + "description": "Keystore provider for Netty HttpClient, optional field.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-provider", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.key-store-type", + "type": "java.lang.String", + "description": "Keystore type for Netty HttpClient, default is JKS.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "defaultValue": "JKS", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-type", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.ssl-bundle", + "type": "java.lang.String", + "description": "The name of the SSL bundle to use.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.ssl-bundle", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.trusted-x509-certificates", + "type": "java.util.List", + "description": "Trusted certificates for verifying the remote endpoint's certificate.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.trusted-x509-certificates", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager", + "type": "java.lang.Boolean", + "description": "Installs the netty InsecureTrustManagerFactory. This is insecure and not suitable for production.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.ssl.use-insecure-trust-manager", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.websocket.max-frame-payload-length", + "type": "java.lang.Integer", + "description": "Max frame payload length.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Websocket", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.websocket.max-frame-payload-length", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.websocket.proxy-ping", + "type": "java.lang.Boolean", + "description": "Proxy ping frames to downstream services, defaults to true.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties$Websocket", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.websocket.proxy-ping", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpclient.wiretap", + "type": "java.lang.Boolean", + "description": "Enables wiretap debugging for Netty HttpClient.", + "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpclient.wiretap", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.httpserver.wiretap", + "type": "java.lang.Boolean", + "description": "Enables wiretap debugging for Netty HttpServer.", + "defaultValue": "false", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.httpserver.wiretap", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.loadbalancer.use404", + "type": "java.lang.Boolean", + "sourceType": "org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.loadbalancer.use404", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.metrics.enabled", + "type": "java.lang.Boolean", + "description": "Enables the collection of metrics data.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayMetricsProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.metrics.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.metrics.prefix", + "type": "java.lang.String", + "description": "The prefix of all metrics emitted by gateway.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayMetricsProperties", + "defaultValue": "spring.cloud.gateway", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.metrics.prefix", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.metrics.tags", + "type": "java.util.Map", + "description": "Tags map that added to metrics.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayMetricsProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.metrics.tags", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.mvc.routes", + "type": "java.util.List", + "description": "List of Routes.", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.mvc.routes", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.observability.enabled", + "type": "java.lang.Boolean", + "description": "If Micrometer Observability support should be turned on.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.observability.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.after.enabled", + "type": "java.lang.Boolean", + "description": "Enables the after predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.after.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.before.enabled", + "type": "java.lang.Boolean", + "description": "Enables the before predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.before.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.between.enabled", + "type": "java.lang.Boolean", + "description": "Enables the between predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.between.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.cloud-foundry-route-service.enabled", + "type": "java.lang.Boolean", + "description": "Enables the cloud-foundry-route-service predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.cloud-foundry-route-service.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.cookie.enabled", + "type": "java.lang.Boolean", + "description": "Enables the cookie predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.cookie.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.header.enabled", + "type": "java.lang.Boolean", + "description": "Enables the header predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.header.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.host.enabled", + "type": "java.lang.Boolean", + "description": "Enables the host predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.host.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.host.include-port", + "type": "java.lang.Boolean", + "description": "Include the port in matching the host name.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.host.include-port", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.method.enabled", + "type": "java.lang.Boolean", + "description": "Enables the method predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.method.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.path.enabled", + "type": "java.lang.Boolean", + "description": "Enables the path predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.path.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.query.enabled", + "type": "java.lang.Boolean", + "description": "Enables the query predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.query.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.read-body.enabled", + "type": "java.lang.Boolean", + "description": "Enables the read-body predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.read-body.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.remote-addr.enabled", + "type": "java.lang.Boolean", + "description": "Enables the remote-addr predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.remote-addr.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.weight.enabled", + "type": "java.lang.Boolean", + "description": "Enables the weight predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.weight.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.predicate.xforwarded-remote-addr.enabled", + "type": "java.lang.Boolean", + "description": "Enables the xforwarded-remote-addr predicate.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.predicate.xforwarded-remote-addr.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.burst-capacity-header", + "type": "java.lang.String", + "description": "The name of the header that returns the burst capacity configuration.", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "defaultValue": "X-RateLimit-Burst-Capacity", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.burst-capacity-header", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.config", + "type": "java.util.Map", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.config", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.include-headers", + "type": "java.lang.Boolean", + "description": "Whether or not to include headers containing rate limiter information, defaults to true.", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.include-headers", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.remaining-header", + "type": "java.lang.String", + "description": "The name of the header that returns number of remaining requests during the current second.", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "defaultValue": "X-RateLimit-Remaining", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.remaining-header", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.replenish-rate-header", + "type": "java.lang.String", + "description": "The name of the header that returns the replenish rate configuration.", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "defaultValue": "X-RateLimit-Replenish-Rate", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.replenish-rate-header", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-rate-limiter.requested-tokens-header", + "type": "java.lang.String", + "description": "The name of the header that returns the requested tokens configuration.", + "sourceType": "org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter", + "defaultValue": "X-RateLimit-Requested-Tokens", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-rate-limiter.requested-tokens-header", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.redis-route-definition-repository.enabled", + "type": "java.lang.Boolean", + "description": "If RedisRouteDefinitionRepository should be enabled.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.redis-route-definition-repository.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.restrictive-property-accessor.enabled", + "type": "java.lang.Boolean", + "description": "Restricts method and property access in SpEL.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.restrictive-property-accessor.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.route-filter-cache-enabled", + "type": "java.lang.Boolean", + "description": "Enables the route filter cache, defaults to false.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "defaultValue": false, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.route-filter-cache-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.route-refresh-listener.enabled", + "type": "java.lang.Boolean", + "description": "If RouteRefreshListener should be turned on.", + "defaultValue": "true", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.route-refresh-listener.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.routes", + "type": "java.util.List", + "description": "List of Routes.", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.routes", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.set-status.original-status-header-name", + "type": "java.lang.String", + "description": "The name of the header which contains http code of the proxied request.", + "sourceType": "org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.set-status.original-status-header-name", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.streaming-media-types", + "type": "java.util.List", + "sourceType": "org.springframework.cloud.gateway.config.GatewayProperties", + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.streaming-media-types", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.enabled", + "type": "java.lang.Boolean", + "description": "If the XForwardedHeadersFilter is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.for-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-For as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.for-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.for-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-For is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.for-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.host-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Host as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.host-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.host-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Host is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.host-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.order", + "type": "java.lang.Integer", + "description": "The order of the XForwardedHeadersFilter.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": 0, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.order", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.port-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Port as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.port-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.port-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Port is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.port-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.prefix-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Prefix as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.prefix-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.prefix-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Prefix is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.prefix-enabled", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.proto-append", + "type": "java.lang.Boolean", + "description": "If appending X-Forwarded-Proto as a list is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.proto-append", + "since": "4.3.0" + } + }, + { + "name": "spring.cloud.gateway.x-forwarded.proto-enabled", + "type": "java.lang.Boolean", + "description": "If X-Forwarded-Proto is enabled.", + "sourceType": "org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter", + "defaultValue": true, + "deprecated": true, + "deprecation": { + "replacement": "spring.cloud.gateway.server.webflux.x-forwarded.proto-enabled", + "since": "4.3.0" + } } ] } diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/spring.factories b/spring-cloud-gateway-server/src/main/resources/META-INF/spring.factories index dd7e5a51..38fc4166 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/spring.factories @@ -3,4 +3,8 @@ org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ -org.springframework.cloud.gateway.support.MvcFoundOnClasspathFailureAnalyzer \ No newline at end of file +org.springframework.cloud.gateway.support.MvcFoundOnClasspathFailureAnalyzer + +# Application Listeners +org.springframework.context.ApplicationListener=\ + org.springframework.cloud.gateway.config.GatewayServerWebfluxPropertiesMigrationListener \ No newline at end of file diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java index 34fdd032..0e1445dd 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java @@ -118,19 +118,20 @@ public class GatewayAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class, GatewayAutoConfiguration.class, HttpClientCustomizedConfig.class, ServerPropertiesConfig.class)) - .withPropertyValues("spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager=true", - "spring.cloud.gateway.httpclient.ssl.ssl-bundle=mybundle", - "spring.cloud.gateway.httpclient.connect-timeout=10", - "spring.cloud.gateway.httpclient.response-timeout=10s", - "spring.cloud.gateway.httpclient.pool.eviction-interval=10s", - "spring.cloud.gateway.httpclient.pool.type=fixed", - "spring.cloud.gateway.httpclient.pool.metrics=true", - "spring.cloud.gateway.httpclient.pool.leasing-strategy=lifo", - "spring.cloud.gateway.httpclient.compression=true", "spring.cloud.gateway.httpclient.wiretap=true", + .withPropertyValues("spring.cloud.gateway.server.webflux.httpclient.ssl.use-insecure-trust-manager=true", + "spring.cloud.gateway.server.webflux.httpclient.ssl.ssl-bundle=mybundle", + "spring.cloud.gateway.server.webflux.httpclient.connect-timeout=10", + "spring.cloud.gateway.server.webflux.httpclient.response-timeout=10s", + "spring.cloud.gateway.server.webflux.httpclient.pool.eviction-interval=10s", + "spring.cloud.gateway.server.webflux.httpclient.pool.type=fixed", + "spring.cloud.gateway.server.webflux.httpclient.pool.metrics=true", + "spring.cloud.gateway.server.webflux.httpclient.pool.leasing-strategy=lifo", + "spring.cloud.gateway.server.webflux.httpclient.compression=true", + "spring.cloud.gateway.server.webflux.httpclient.wiretap=true", // greater than integer max value - "spring.cloud.gateway.httpclient.max-initial-line-length=2147483647", - "spring.cloud.gateway.httpclient.proxy.host=myhost", - "spring.cloud.gateway.httpclient.websocket.max-frame-payload-length=1024") + "spring.cloud.gateway.server.webflux.httpclient.max-initial-line-length=2147483647", + "spring.cloud.gateway.server.webflux.httpclient.proxy.host=myhost", + "spring.cloud.gateway.server.webflux.httpclient.websocket.max-frame-payload-length=1024") .run(context -> { assertThat(context).hasSingleBean(HttpClient.class); HttpClient httpClient = context.getBean(HttpClient.class); @@ -185,7 +186,7 @@ public class GatewayAutoConfigurationTests { @Test public void verboseActuatorDisabled() { try (ConfigurableApplicationContext ctx = SpringApplication.run(Config.class, "--spring.jmx.enabled=false", - "--server.port=0", "--spring.cloud.gateway.actuator.verbose.enabled=false", + "--server.port=0", "--spring.cloud.gateway.server.webflux.actuator.verbose.enabled=false", "--management.endpoint.gateway.enabled=true")) { assertThat(ctx.getBeanNamesForType(GatewayLegacyControllerEndpoint.class)).hasSize(1); } @@ -233,7 +234,8 @@ public class GatewayAutoConfigurationTests { public void noTokenRelayFilter() { assertThatThrownBy(() -> { try (ConfigurableApplicationContext ctx = SpringApplication.run(RouteLocatorBuilderConfig.class, - "--spring.jmx.enabled=false", "--spring.cloud.gateway.filter.token-relay.enabled=false", + "--spring.jmx.enabled=false", + "--spring.cloud.gateway.server.webflux.filter.token-relay.enabled=false", "--spring.security.oauth2.client.provider[testprovider].authorization-uri=http://localhost", "--spring.security.oauth2.client.provider[testprovider].token-uri=http://localhost/token", "--spring.security.oauth2.client.registration[test].provider=testprovider", diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfigurationTests.java index d8e71d86..e06d7226 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfigurationTests.java @@ -88,7 +88,7 @@ public class GatewayMetricsAutoConfigurationTests { } @Nested - @SpringBootTest(classes = Config.class, properties = "spring.cloud.gateway.metrics.enabled=false") + @SpringBootTest(classes = Config.class, properties = GatewayProperties.PREFIX + ".metrics.enabled=false") public class DisabledByProperty { @Autowired(required = false) @@ -110,7 +110,7 @@ public class GatewayMetricsAutoConfigurationTests { } @Nested - @SpringBootTest(classes = Config.class, properties = "spring.cloud.gateway.observability.enabled=false") + @SpringBootTest(classes = Config.class, properties = GatewayProperties.PREFIX + ".observability.enabled=false") public class ObservabilityDisabledByProperty { @Autowired diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayPropertiesMigrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayPropertiesMigrationTests.java new file mode 100644 index 00000000..9cb9c4d0 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayPropertiesMigrationTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2013-2025 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; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter; +import org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter; +import org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicateFactory; +import org.springframework.cloud.gateway.route.RouteRefreshListener; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = { "debug=true" }, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("propertiesmigrationtests") +public class GatewayPropertiesMigrationTests { + + @Autowired + ApplicationContext context; + + @Autowired + GatewayProperties properties; + + @Test + public void deprecatedPropertiesWork() { + assertBeanDoesNotExist(AddRequestParameterGatewayFilterFactory.class); + assertBeanDoesNotExist(AfterRoutePredicateFactory.class); + assertBeanDoesNotExist(ForwardedHeadersFilter.class); + assertBeanDoesNotExist(RouteRefreshListener.class); + assertBeanDoesNotExist(XForwardedHeadersFilter.class); + } + + @Test + public void deprecatedRoutePropertiesWork() { + assertThat(properties.getRoutes()).hasSize(2); + } + + private void assertBeanDoesNotExist(Class type) { + assertThat(context.getBeanNamesForType(type)).isEmpty(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfigurationTests.java index a3a1b6ce..66028470 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisAutoConfigurationTests.java @@ -75,7 +75,7 @@ public class GatewayRedisAutoConfigurationTests { } @Nested - @SpringBootTest(classes = Config.class, properties = "spring.cloud.gateway.redis.enabled=false") + @SpringBootTest(classes = Config.class, properties = GatewayProperties.PREFIX + ".redis.enabled=false") class DisabledByProperty { @Autowired(required = false) @@ -97,7 +97,7 @@ public class GatewayRedisAutoConfigurationTests { */ @Nested @SpringBootTest(classes = GatewayRedisAutoConfigurationTests.Config.class, - properties = "spring.cloud.gateway.redis-route-definition-repository.enabled=false") + properties = GatewayProperties.PREFIX + ".redis-route-definition-repository.enabled=false") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class RedisRouteDefinitionRepositoryDisabledByProperty { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisRouteDefinitionRepositoryEnabledByPropertyTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisRouteDefinitionRepositoryEnabledByPropertyTests.java index ccf240e8..232d6e93 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisRouteDefinitionRepositoryEnabledByPropertyTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayRedisRouteDefinitionRepositoryEnabledByPropertyTests.java @@ -33,7 +33,7 @@ import org.springframework.test.context.DynamicPropertySource; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(classes = GatewayRedisAutoConfigurationTests.Config.class, - properties = "spring.cloud.gateway.redis-route-definition-repository.enabled=true") + properties = GatewayProperties.PREFIX + ".redis-route-definition-repository.enabled=true") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @Testcontainers @Tag("DockerRequired") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfigurationTests.java index e0aee8cf..8b61ae27 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfigurationTests.java @@ -33,7 +33,7 @@ public class LocalResponseCacheAutoConfigurationTests { void onlyOneCacheManagerBeanCreated() { new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(LocalResponseCacheAutoConfiguration.class)) - .withPropertyValues("spring.cloud.gateway.filter.local-response-cache.enabled=true") + .withPropertyValues(GatewayProperties.PREFIX + ".filter.local-response-cache.enabled=true") .run(context -> { context.containsBean(LocalResponseCacheAutoConfiguration.RESPONSE_CACHE_MANAGER_NAME); context.assertThat().hasSingleBean(GlobalLocalResponseCacheGatewayFilter.class); @@ -45,7 +45,7 @@ public class LocalResponseCacheAutoConfigurationTests { new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of(CustomCacheManagerConfig.class, LocalResponseCacheAutoConfiguration.class)) - .withPropertyValues("spring.cloud.gateway.filter.local-response-cache.enabled=true") + .withPropertyValues(GatewayProperties.PREFIX + ".filter.local-response-cache.enabled=true") .run(context -> { context.containsBean(LocalResponseCacheAutoConfiguration.RESPONSE_CACHE_MANAGER_NAME); context.containsBean("myCacheManager"); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java index 2669059d..b581dfa0 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java @@ -56,8 +56,8 @@ public class DisableBuiltInFiltersTests { @Nested @SpringBootTest(classes = Config.class, - properties = { "spring.cloud.gateway.filter.add-request-header.enabled=false", - "spring.cloud.gateway.filter.map-request-header.enabled=false" }) + properties = { "spring.cloud.gateway.server.webflux.filter.add-request-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.map-request-header.enabled=false" }) @ActiveProfiles("disable-components") public class DisableSpecificsFiltersByProperty { @@ -76,45 +76,45 @@ public class DisableBuiltInFiltersTests { @Nested @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-headers-if-not-present.enabled=false", - "spring.cloud.gateway.filter.add-request-parameter.enabled=false", - "spring.cloud.gateway.filter.add-response-header.enabled=false", - "spring.cloud.gateway.filter.json-to-grpc.enabled=false", - "spring.cloud.gateway.filter.modify-request-body.enabled=false", - "spring.cloud.gateway.filter.local-response-cache.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-json-attributes-response-body.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.rewrite-request-parameter.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.token-relay.enabled=false", - "spring.cloud.gateway.filter.cache-request-body.enabled=false", - "spring.cloud.gateway.filter.fallback-headers.enabled=false" }) + properties = { "spring.cloud.gateway.server.webflux.filter.add-request-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.map-request-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.add-request-headers-if-not-present.enabled=false", + "spring.cloud.gateway.server.webflux.filter.add-request-parameter.enabled=false", + "spring.cloud.gateway.server.webflux.filter.add-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.json-to-grpc.enabled=false", + "spring.cloud.gateway.server.webflux.filter.modify-request-body.enabled=false", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=false", + "spring.cloud.gateway.server.webflux.filter.dedupe-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.modify-response-body.enabled=false", + "spring.cloud.gateway.server.webflux.filter.prefix-path.enabled=false", + "spring.cloud.gateway.server.webflux.filter.preserve-host-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.redirect-to.enabled=false", + "spring.cloud.gateway.server.webflux.filter.remove-json-attributes-response-body.enabled=false", + "spring.cloud.gateway.server.webflux.filter.remove-request-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.remove-request-parameter.enabled=false", + "spring.cloud.gateway.server.webflux.filter.remove-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.request-rate-limiter.enabled=false", + "spring.cloud.gateway.server.webflux.filter.rewrite-path.enabled=false", + "spring.cloud.gateway.server.webflux.filter.retry.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-path.enabled=false", + "spring.cloud.gateway.server.webflux.filter.secure-headers.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-request-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-request-host-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.rewrite-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.rewrite-location-response-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.rewrite-location.enabled=false", + "spring.cloud.gateway.server.webflux.filter.rewrite-request-parameter.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-status.enabled=false", + "spring.cloud.gateway.server.webflux.filter.save-session.enabled=false", + "spring.cloud.gateway.server.webflux.filter.strip-prefix.enabled=false", + "spring.cloud.gateway.server.webflux.filter.request-header-to-request-uri.enabled=false", + "spring.cloud.gateway.server.webflux.filter.request-size.enabled=false", + "spring.cloud.gateway.server.webflux.filter.request-header-size.enabled=false", + "spring.cloud.gateway.server.webflux.filter.circuit-breaker.enabled=false", + "spring.cloud.gateway.server.webflux.filter.token-relay.enabled=false", + "spring.cloud.gateway.server.webflux.filter.cache-request-body.enabled=false", + "spring.cloud.gateway.server.webflux.filter.fallback-headers.enabled=false" }) @ActiveProfiles("disable-components") public class DisableAllFiltersByProperty { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInGlobalFiltersTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInGlobalFiltersTests.java index 95217bab..519ea449 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInGlobalFiltersTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInGlobalFiltersTests.java @@ -56,8 +56,8 @@ public class DisableBuiltInGlobalFiltersTests { @Nested @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" }) + properties = { "spring.cloud.gateway.server.webflux.global-filter.remove-cached-body.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.route-to-request-url.enabled=false" }) @ActiveProfiles("disable-components") public class DisableSpecificsFiltersByProperty { @@ -74,21 +74,21 @@ public class DisableBuiltInGlobalFiltersTests { } @Nested - @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-client.enabled=false", - "spring.cloud.gateway.global-filter.load-balancer-client.enabled=false", - "spring.cloud.gateway.global-filter.load-balancer-service-instance-cookie.enabled=false", - "spring.cloud.gateway.global-filter.function-routing.enabled=false", - "spring.cloud.gateway.global-filter.stream-routing.enabled=false", - "spring.cloud.gateway.metrics.enabled=false" }) + @SpringBootTest(classes = Config.class, properties = { + "spring.cloud.gateway.server.webflux.global-filter.adapt-cached-body.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.remove-cached-body.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.route-to-request-url.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.forward-routing.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.forward-path.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.websocket-routing.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.netty-write-response.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.netty-routing.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.reactive-load-balancer-client.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.load-balancer-client.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.load-balancer-service-instance-cookie.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.function-routing.enabled=false", + "spring.cloud.gateway.server.webflux.global-filter.stream-routing.enabled=false", + "spring.cloud.gateway.server.webflux.metrics.enabled=false" }) @ActiveProfiles("disable-components") public class DisableAllGlobalFiltersByProperty { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInPredicatesTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInPredicatesTests.java index e5871bd9..1e0a4453 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInPredicatesTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInPredicatesTests.java @@ -56,8 +56,8 @@ public class DisableBuiltInPredicatesTests { @Nested @SpringBootTest(classes = Config.class, - properties = { "spring.cloud.gateway.predicate.after.enabled=false", - "spring.cloud.gateway.predicate.before.enabled=false" }) + properties = { "spring.cloud.gateway.server.webflux.predicate.after.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.before.enabled=false" }) @ActiveProfiles("disable-components") public class DisableSpecificsPredicatesByProperty { @@ -74,18 +74,21 @@ public class DisableBuiltInPredicatesTests { } @Nested - @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.xforwarded-remote-addr.enabled=false", - "spring.cloud.gateway.predicate.weight.enabled=false", - "spring.cloud.gateway.predicate.cloud-foundry-route-service.enabled=false" }) + @SpringBootTest(classes = Config.class, + properties = { "spring.cloud.gateway.server.webflux.predicate.after.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.before.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.between.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.cookie.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.header.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.host.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.method.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.path.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.query.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.read-body.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.remote-addr.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.xforwarded-remote-addr.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.weight.enabled=false", + "spring.cloud.gateway.server.webflux.predicate.cloud-foundry-route-service.enabled=false" }) @ActiveProfiles("disable-components") public class DisableAllPredicatesByProperty { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponentTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponentTests.java index 0bc62eeb..b1853ab2 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponentTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/OnEnabledComponentTests.java @@ -61,7 +61,7 @@ class OnEnabledComponentTests { String componentName = "disabled-component"; this.onEnabledComponent = createOnEnabledComponent(componentName); when(conditionContext.getEnvironment()).thenReturn(environment); - environment.setProperty("spring.cloud.gateway." + componentName + ".enabled", "false"); + environment.setProperty("spring.cloud.gateway.server.webflux." + componentName + ".enabled", "false"); ConditionOutcome outcome = onEnabledComponent.getMatchOutcome(conditionContext, mockMetaData(DisabledComponent.class)); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/CorsGlobalTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/CorsGlobalTests.java index f4e2f791..4ce14ce0 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/CorsGlobalTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/CorsGlobalTests.java @@ -89,7 +89,8 @@ public class CorsGlobalTests extends BaseWebClientTests { } - @SpringBootTest(classes = TestConfig.class, properties = "spring.cloud.gateway.globalcors.enabled=false") + @SpringBootTest(classes = TestConfig.class, + properties = "spring.cloud.gateway.server.webflux.globalcors.enabled=false") public static class DisabledByProperty { @Autowired(required = false) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java index 4784fd3f..1ed009f9 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @SpringBootTest(webEnvironment = RANDOM_PORT, - properties = "spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping=true") + properties = "spring.cloud.gateway.server.webflux.globalcors.add-to-simple-url-handler-mapping=true") @DirtiesContext @ActiveProfiles("request-header-web-filter") public class SimpleUrlHandlerCorsTests extends BaseWebClientTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java index 1178515c..16b4fd2a 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java @@ -38,8 +38,8 @@ import org.springframework.context.annotation.Bean; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(classes = DiscoveryClientRouteDefinitionLocatorIntegrationTests.Config.class, - properties = { "spring.cloud.gateway.discovery.locator.enabled=true", - "spring.cloud.gateway.discovery.locator.route-id-prefix=test__" }) + properties = { "spring.cloud.gateway.server.webflux.discovery.locator.enabled=true", + "spring.cloud.gateway.server.webflux.discovery.locator.route-id-prefix=test__" }) public class DiscoveryClientRouteDefinitionLocatorIntegrationTests { @Autowired diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java index fc26a822..6e2f6d60 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorTests.java @@ -42,17 +42,17 @@ import static org.springframework.cloud.gateway.filter.factory.RewritePathGatewa import static org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory.PATTERN_KEY; @SpringBootTest(classes = DiscoveryClientRouteDefinitionLocatorTests.Config.class, - properties = { "spring.cloud.gateway.discovery.locator.enabled=true", - "spring.cloud.gateway.discovery.locator.route-id-prefix=testedge_", - "spring.cloud.gateway.discovery.locator.include-expression=metadata['edge'] == 'true'", - "spring.cloud.gateway.discovery.locator.lower-case-service-id=true" + properties = { "spring.cloud.gateway.server.webflux.discovery.locator.enabled=true", + "spring.cloud.gateway.server.webflux.discovery.locator.route-id-prefix=testedge_", + "spring.cloud.gateway.server.webflux.discovery.locator.include-expression=metadata['edge'] == 'true'", + "spring.cloud.gateway.server.webflux.discovery.locator.lower-case-service-id=true" /* - * "spring.cloud.gateway.discovery.locator.predicates[0].name=Path", - * "spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]='/'+serviceId.toLowerCase(Locale.ROOT)+'/**'", - * "spring.cloud.gateway.discovery.locator.filters[0].name=RewritePath", - * "spring.cloud.gateway.discovery.locator.filters[0].args[regexp]='/' + serviceId.toLowerCase(Locale.ROOT) + '/(?.*)'" + * "spring.cloud.gateway.server.webflux.discovery.locator.predicates[0].name=Path", + * "spring.cloud.gateway.server.webflux.discovery.locator.predicates[0].args[pattern]='/'+serviceId.toLowerCase(Locale.ROOT)+'/**'", + * "spring.cloud.gateway.server.webflux.discovery.locator.filters[0].name=RewritePath", + * "spring.cloud.gateway.server.webflux.discovery.locator.filters[0].args[regexp]='/' + serviceId.toLowerCase(Locale.ROOT) + '/(?.*)'" * , - * "spring.cloud.gateway.discovery.locator.filters[0].args[replacement]='/$\\\\{remaining}'", + * "spring.cloud.gateway.server.webflux.discovery.locator.filters[0].args[replacement]='/$\\\\{remaining}'", */ }) public class DiscoveryClientRouteDefinitionLocatorTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/ReactiveGatewayDiscoveryClientAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/ReactiveGatewayDiscoveryClientAutoConfigurationTests.java index ef03d723..22eadc7e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/ReactiveGatewayDiscoveryClientAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/discovery/ReactiveGatewayDiscoveryClientAutoConfigurationTests.java @@ -35,8 +35,8 @@ public class ReactiveGatewayDiscoveryClientAutoConfigurationTests { @Nested @SpringBootTest(classes = Config.class, - properties = { "spring.cloud.gateway.discovery.locator.enabled=true", - "spring.cloud.gateway.loadbalancer.use404=true", + properties = { "spring.cloud.gateway.server.webflux.discovery.locator.enabled=true", + "spring.cloud.gateway.server.webflux.loadbalancer.use404=true", "spring.cloud.discovery.client.simple.instances.service[0].uri=https://service1:443" }) public class EnabledByProperty { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java index b071212d..744dbc4e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java @@ -109,9 +109,9 @@ class NettyRoutingFilterTests extends BaseWebClientTests { ConfigurableEnvironment environment = (ConfigurableEnvironment) this.context.getEnvironment(); HashMap map = new HashMap<>(); environment.getPropertySources().addFirst(new MapPropertySource("mock", map)); - map.put("spring.cloud.gateway.httpclient.connect-timeout", "1000"); + map.put("spring.cloud.gateway.server.webflux.httpclient.connect-timeout", "1000"); this.context.publishEvent(new EnvironmentChangeEvent(this.context, - Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); + Collections.singleton("spring.cloud.gateway.server.webflux.httpclient.connect-timeout"))); Route route = routeLocator.getRoutes() .filter(r -> r.getId().equals("refreshable_configuration_test")) .blockLast(); @@ -120,9 +120,9 @@ class NettyRoutingFilterTests extends BaseWebClientTests { HttpClientConfig configuration = httpClient.configuration(); assertThat(configuration.options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS)).isEqualTo(1000); - map.put("spring.cloud.gateway.httpclient.connect-timeout", "5000"); + map.put("spring.cloud.gateway.server.webflux.httpclient.connect-timeout", "5000"); this.context.publishEvent(new EnvironmentChangeEvent(this.context, - Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); + Collections.singleton("spring.cloud.gateway.server.webflux.httpclient.connect-timeout"))); httpClient = nettyRoutingFilter.getHttpClient(route, null); configuration = httpClient.configuration(); assertThat(configuration.options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS)).isEqualTo(5000); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java index fb1439d1..fdc20f33 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java @@ -64,8 +64,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @SpringBootTest(webEnvironment = RANDOM_PORT, - properties = { "spring.cloud.gateway.httpclient.connect-timeout=500", - "spring.cloud.gateway.httpclient.response-timeout=2s", + properties = { "spring.cloud.gateway.server.webflux.httpclient.connect-timeout=500", + "spring.cloud.gateway.server.webflux.httpclient.response-timeout=2s", "logging.level.org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory=TRACE" }) @DirtiesContext // default filter AddResponseHeader suppresses bug diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactoryTests.java index 1325e75e..9c218228 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactoryTests.java @@ -69,7 +69,7 @@ public class LocalResponseCacheGatewayFilterFactoryTests extends BaseWebClientTe } @Nested - @SpringBootTest(properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true" }, + @SpringBootTest(properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UsingFilterParams extends BaseWebClientTests { @@ -441,8 +441,8 @@ public class LocalResponseCacheGatewayFilterFactoryTests extends BaseWebClientTe @Nested @SpringBootTest( - properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true", - "spring.cloud.gateway.filter.local-response-cache.timeToLive=20s" }, + properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.timeToLive=20s" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UsingPropertiesAsDefault extends BaseWebClientTests { @@ -550,9 +550,9 @@ public class LocalResponseCacheGatewayFilterFactoryTests extends BaseWebClientTe } @Nested - @SpringBootTest(properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true", - "spring.cloud.gateway.filter.local-response-cache.time-to-live=2m", - "spring.cloud.gateway.filter.local-response-cache.request.no-cache-strategy=skip-update-cache-entry" }, + @SpringBootTest(properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.time-to-live=2m", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.request.no-cache-strategy=skip-update-cache-entry" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class DirectiveNoCacheSkippingUpdate extends BaseWebClientTests { @@ -656,10 +656,9 @@ public class LocalResponseCacheGatewayFilterFactoryTests extends BaseWebClientTe } @Nested - @SpringBootTest( - properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true", - "spring.cloud.gateway.filter.local-response-cache.time-to-live=2m", - "spring.cloud.gateway.filter.local-response-cache.request.no-cache-strategy=update-cache-entry" }, + @SpringBootTest(properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.time-to-live=2m", + "spring.cloud.gateway.server.webflux.filter.local-response-cache.request.no-cache-strategy=update-cache-entry" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class DirectiveNoCacheWithUpdate extends BaseWebClientTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGlobalFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGlobalFilterTests.java index f5f4c668..11b8cef4 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGlobalFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGlobalFilterTests.java @@ -46,8 +46,8 @@ public class LocalResponseCacheGlobalFilterTests { @Nested @SpringBootTest( - properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true", - "spring.cloud.gateway.global-filter.local-response-cache.enabled=false" }, + properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true", + "spring.cloud.gateway.server.webflux.global-filter.local-response-cache.enabled=false" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GlobalCacheNotEnabled extends BaseWebClientTests { @@ -98,7 +98,7 @@ public class LocalResponseCacheGlobalFilterTests { } @Nested - @SpringBootTest(properties = { "spring.cloud.gateway.filter.local-response-cache.enabled=true" }, + @SpringBootTest(properties = { "spring.cloud.gateway.server.webflux.filter.local-response-cache.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GlobalCacheEnabled extends BaseWebClientTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactorySslTimeoutTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactorySslTimeoutTests.java index 8ffc9794..0f7113c5 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactorySslTimeoutTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactorySslTimeoutTests.java @@ -60,7 +60,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author fangfeikun */ @SpringBootTest(webEnvironment = RANDOM_PORT, - properties = { "spring.cloud.gateway.httpclient.ssl.handshake-timeout=1ms", + properties = { "spring.cloud.gateway.server.webflux.httpclient.ssl.handshake-timeout=1ms", "spring.main.allow-bean-definition-overriding=true" }) @DirtiesContext @ActiveProfiles("single-cert-ssl") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java index f262300b..43831cd8 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java @@ -43,7 +43,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen /** * @author Spencer Gibb */ -@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.cloud.gateway.redis.enabled=false") +@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.cloud.gateway.server.webflux.redis.enabled=false") @DirtiesContext public class Bucket4jRateLimiterTests extends BaseWebClientTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterTests.java index 2be6617a..febb514c 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterTests.java @@ -54,7 +54,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Denis Cutic * @author Andrey Muchnik */ -@SpringBootTest(webEnvironment = RANDOM_PORT, properties = { "spring.cloud.gateway.function.enabled=false" }) +@SpringBootTest(webEnvironment = RANDOM_PORT, + properties = { "spring.cloud.gateway.server.webflux.function.enabled=false" }) @DirtiesContext @Testcontainers @Tag("DockerRequired") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/FilteringWebHandlerCacheEnabledIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/FilteringWebHandlerCacheEnabledIntegrationTests.java index 650a8a08..8ce29893 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/FilteringWebHandlerCacheEnabledIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/FilteringWebHandlerCacheEnabledIntegrationTests.java @@ -42,9 +42,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @SpringBootTest(webEnvironment = RANDOM_PORT, - properties = { "spring.cloud.gateway.route-filter-cache-enabled=true", + properties = { "spring.cloud.gateway.server.webflux.route-filter-cache-enabled=true", "management.endpoint.gateway.enabled=true", "management.endpoints.web.exposure.include=*", - "spring.cloud.gateway.actuator.verbose.enabled=true" }) + "spring.cloud.gateway.server.webflux.actuator.verbose.enabled=true" }) @DirtiesContext public class FilteringWebHandlerCacheEnabledIntegrationTests extends BaseWebClientTests { diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableNonRestrictiveTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableNonRestrictiveTests.java index c4cf3c80..daf6413a 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableNonRestrictiveTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableNonRestrictiveTests.java @@ -34,7 +34,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(properties = "spring.cloud.gateway.restrictive-property-accessor.enabled=false") +@SpringBootTest(properties = "spring.cloud.gateway.server.webflux.restrictive-property-accessor.enabled=false") public class ShortcutConfigurableNonRestrictiveTests { @Autowired diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/PropertiesTagsProviderTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/PropertiesTagsProviderTests.java index 922b43f4..e3745435 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/PropertiesTagsProviderTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/tagsprovider/PropertiesTagsProviderTests.java @@ -37,8 +37,8 @@ public class PropertiesTagsProviderTests { @Test public void test() { contextRunner.withConfiguration(AutoConfigurations.of(GatewayMetricsAutoConfiguration.class)) - .withPropertyValues("spring.cloud.gateway.metrics.tags.foo1=bar1", - "spring.cloud.gateway.metrics.tags.foo2=bar2") + .withPropertyValues("spring.cloud.gateway.server.webflux.metrics.tags.foo1=bar1", + "spring.cloud.gateway.server.webflux.metrics.tags.foo2=bar2") .run(context -> { PropertiesTagsProvider provider = context.getBean(PropertiesTagsProvider.class); Tags tags = provider.apply(MockServerWebExchange.from(MockServerHttpRequest.get("").build())); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java index 2ca53a27..8af9e456 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java @@ -62,7 +62,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.cloud.gateway.test.TestUtils.getMap; -@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.cloud.gateway.forwarded.by.enabled=true") +@SpringBootTest(webEnvironment = RANDOM_PORT, + properties = "spring.cloud.gateway.server.webflux.forwarded.by.enabled=true") @DirtiesContext @SuppressWarnings("unchecked") @ExtendWith(OutputCaptureExtension.class) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLTests.java index 39c13f74..d9bd3d4a 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLTests.java @@ -44,13 +44,13 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @ActiveProfiles("client-auth-ssl") public class ClientCertAuthSSLTests extends SingleCertSSLTests { - @Value("${spring.cloud.gateway.httpclient.ssl.key-store}") + @Value("${spring.cloud.gateway.server.webflux.httpclient.ssl.key-store}") private String keyStore; - @Value("${spring.cloud.gateway.httpclient.ssl.key-store-password}") + @Value("${spring.cloud.gateway.server.webflux.httpclient.ssl.key-store-password}") private String keyStorePassword; - @Value("${spring.cloud.gateway.httpclient.ssl.key-password}") + @Value("${spring.cloud.gateway.server.webflux.httpclient.ssl.key-password}") private String keyPassword; @BeforeEach diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/SSLHandshakeTimeoutTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/SSLHandshakeTimeoutTests.java index a0f5a479..f7b0c90f 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/SSLHandshakeTimeoutTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/SSLHandshakeTimeoutTests.java @@ -29,7 +29,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen // this test works because it assumes TLS hand shake cannot be done in 1ms. It takes // closer to 80ms @SpringBootTest(webEnvironment = RANDOM_PORT, - properties = { "spring.cloud.gateway.httpclient.ssl.handshake-timeout=1ms" }) + properties = { "spring.cloud.gateway.server.webflux.httpclient.ssl.handshake-timeout=1ms" }) @DirtiesContext @ActiveProfiles("ssl") public class SSLHandshakeTimeoutTests extends SingleCertSSLTests { diff --git a/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml b/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml index 2ca408d5..07660e90 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml @@ -15,7 +15,7 @@ server: client-auth: Need spring: cloud: - gateway: + gateway.server.webflux: httpclient: ssl: ssl-bundle: scg-keystore-with-different-key-password diff --git a/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl.yml b/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl.yml index 88d1b138..cb01f770 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl.yml @@ -15,7 +15,7 @@ server: client-auth: Need spring: cloud: - gateway: + gateway.server.webflux: httpclient: ssl: key-store: classpath:scg-keystore-with-different-key-password.jks diff --git a/spring-cloud-gateway-server/src/test/resources/application-cors-global-config.yml b/spring-cloud-gateway-server/src/test/resources/application-cors-global-config.yml index f210add2..3205c85c 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-cors-global-config.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-cors-global-config.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: globalcors: cors-configurations: '[/**]': diff --git a/spring-cloud-gateway-server/src/test/resources/application-cors-per-route-config.yml b/spring-cloud-gateway-server/src/test/resources/application-cors-per-route-config.yml index 0017f4a6..b1a87536 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-cors-per-route-config.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-cors-per-route-config.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: cors_preflight_test uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-defaultid.yml b/spring-cloud-gateway-server/src/test/resources/application-defaultid.yml index ecb94e4c..29133646 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-defaultid.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-defaultid.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: - PrefixPath=/httpbin routes: diff --git a/spring-cloud-gateway-server/src/test/resources/application-disable-components.yml b/spring-cloud-gateway-server/src/test/resources/application-disable-components.yml index 7ebfe2f5..ade6bdf3 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-disable-components.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-disable-components.yml @@ -7,7 +7,7 @@ spring: import: classpath:application-logging.yml cloud: - gateway: + gateway.server.webflux: globalcors: cors-configurations: '[/**]': diff --git a/spring-cloud-gateway-server/src/test/resources/application-forwardstatic.yml b/spring-cloud-gateway-server/src/test/resources/application-forwardstatic.yml index 35b5b4a0..8cb53a4b 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-forwardstatic.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-forwardstatic.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - uri: forward:/docs.html id: static_docs_route diff --git a/spring-cloud-gateway-server/src/test/resources/application-multi-cert-ssl.yml b/spring-cloud-gateway-server/src/test/resources/application-multi-cert-ssl.yml index 5ab3bed3..f58715a8 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-multi-cert-ssl.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-multi-cert-ssl.yml @@ -11,7 +11,7 @@ server: spring: cloud: - gateway: + gateway.server.webflux: httpclient: ssl: trustedX509Certificates: diff --git a/spring-cloud-gateway-server/src/test/resources/application-netty-routing-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-netty-routing-filter.yml index 8f81445f..9356078b 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-netty-routing-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-netty-routing-filter.yml @@ -14,7 +14,7 @@ spring: - logging cloud: - gateway: + gateway.server.webflux: routes: # ===================================== - id: per_route_connect_timeout diff --git a/spring-cloud-gateway-server/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-server/src/test/resources/application-propertiesmigrationtests.yml new file mode 100644 index 00000000..2f781c6a --- /dev/null +++ b/spring-cloud-gateway-server/src/test/resources/application-propertiesmigrationtests.yml @@ -0,0 +1,32 @@ +spring.cloud.gateway: + route-refresh-listener.enabled: false + forwarded.enabled: false + x-forwarded.enabled: false + predicate.after.enabled: false + filter.add-request-parameter.enabled: false + routes: + - id: listRoute1 + uri: https://examplel1.com + predicates: + - name: Method + args: + methods: GET + - name: Path + args: + pattern: /anything/listRoute1 + filters: + - AddRequestHeader=X-Test,listRoute1 + - id: listRoute2 + uri: https://examplel2.com + predicates: + - name: Method + args: + methods: GET + - name: Path + args: + pattern: /anything/listRoute2 + filters: + - AddRequestHeader=X-Test,listRoute2 +logging: + level: + org.springframework.cloud.gateway: TRACE diff --git a/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-config.yml b/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-config.yml index a6c5726d..dd37bd2b 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-config.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-config.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: routes: # ===================================== diff --git a/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-default-config.yml b/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-default-config.yml index 94ae146a..2cdd500e 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-default-config.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-redis-rate-limiter-default-config.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: - name: RequestRateLimiter args: diff --git a/spring-cloud-gateway-server/src/test/resources/application-redis-route-repository.yml b/spring-cloud-gateway-server/src/test/resources/application-redis-route-repository.yml index 3baeb637..25300f92 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-redis-route-repository.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-redis-route-repository.yml @@ -1,5 +1,5 @@ spring: cloud: - gateway: + gateway.server.webflux: redis-route-definition-repository: enabled: true diff --git a/spring-cloud-gateway-server/src/test/resources/application-remote-address.yml b/spring-cloud-gateway-server/src/test/resources/application-remote-address.yml index 12795440..dbb64c4d 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-remote-address.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-remote-address.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: routes: # ===================================== diff --git a/spring-cloud-gateway-server/src/test/resources/application-removenonproxyheaders.yml b/spring-cloud-gateway-server/src/test/resources/application-removenonproxyheaders.yml index f95895db..aa7903f0 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-removenonproxyheaders.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-removenonproxyheaders.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: - RemoveNonProxyHeaders - PrefixPath=/httpbin diff --git a/spring-cloud-gateway-server/src/test/resources/application-request-header-web-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-request-header-web-filter.yml index 021ac0af..b42959b5 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-request-header-web-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-request-header-web-filter.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: add_request_header_test uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-request-headers-if-not-present-web-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-request-headers-if-not-present-web-filter.yml index 23a88f20..e073bada 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-request-headers-if-not-present-web-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-request-headers-if-not-present-web-filter.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: add_request_headers_if_not_present_test uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-request-map-header-web-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-request-map-header-web-filter.yml index fefe27db..8f3713e5 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-request-map-header-web-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-request-map-header-web-filter.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: map_request_header_test_singleresponse uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-request-parameter-web-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-request-parameter-web-filter.yml index b0190007..b80f0fd9 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-request-parameter-web-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-request-parameter-web-filter.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: add_request_parameter_test uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-retrytests.yml b/spring-cloud-gateway-server/src/test/resources/application-retrytests.yml index ea5e1be8..afc8dc7a 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-retrytests.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-retrytests.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: - PrefixPath=/httpbin routes: diff --git a/spring-cloud-gateway-server/src/test/resources/application-save-session-web-filter.yml b/spring-cloud-gateway-server/src/test/resources/application-save-session-web-filter.yml index 110bb930..87539c45 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-save-session-web-filter.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-save-session-web-filter.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: routes: - id: save_session_test uri: ${test.uri} diff --git a/spring-cloud-gateway-server/src/test/resources/application-single-cert-ssl.yml b/spring-cloud-gateway-server/src/test/resources/application-single-cert-ssl.yml index 61866d25..7483e2a7 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-single-cert-ssl.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-single-cert-ssl.yml @@ -11,7 +11,7 @@ server: spring: cloud: - gateway: + gateway.server.webflux: httpclient: ssl: trustedX509Certificates: diff --git a/spring-cloud-gateway-server/src/test/resources/application-verification-route.yml b/spring-cloud-gateway-server/src/test/resources/application-verification-route.yml index eb648d38..75a109e3 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-verification-route.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-verification-route.yml @@ -1,7 +1,7 @@ server.port: 0 spring: cloud: - gateway: + gateway.server.webflux: routes: - uri: https://example.com predicates: diff --git a/spring-cloud-gateway-server/src/test/resources/application-weights-404.yml b/spring-cloud-gateway-server/src/test/resources/application-weights-404.yml index 49ffb6d5..776c12f9 100644 --- a/spring-cloud-gateway-server/src/test/resources/application-weights-404.yml +++ b/spring-cloud-gateway-server/src/test/resources/application-weights-404.yml @@ -1,6 +1,6 @@ spring: cloud: - gateway: + gateway.server.webflux: default-filters: - PrefixPath=/httpbin routes: diff --git a/spring-cloud-gateway-server/src/test/resources/application.yml b/spring-cloud-gateway-server/src/test/resources/application.yml index ac989a01..c8b6a23f 100644 --- a/spring-cloud-gateway-server/src/test/resources/application.yml +++ b/spring-cloud-gateway-server/src/test/resources/application.yml @@ -14,7 +14,7 @@ spring: - logging cloud: - gateway: + gateway.server.webflux: globalcors: cors-configurations: '[/**]': From ebef2879a74c48f34c76ad4c5a71052b7ff95df0 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 9 May 2025 16:16:58 -0400 Subject: [PATCH 40/85] Migrates proxy-exchange-webflux properties to new namespace from spring.cloud.gateway.proxy to spring.cloud.gateway.proxy-exchange.webflux Fixes gh-3362 --- spring-cloud-gateway-webflux/pom.xml | 5 + .../ProxyExchangeWebfluxProperties.java | 117 ++++++++++++++++++ .../webflux/config/ProxyProperties.java | 11 +- .../ProxyResponseAutoConfiguration.java | 16 +-- .../webflux/ProductionConfigurationTests.java | 3 +- ...changeWebfluxPropertiesMigrationTests.java | 52 ++++++++ .../application-propertiesmigrationtests.yml | 12 ++ 7 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java create mode 100644 spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java create mode 100644 spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..c74106d3 100644 --- a/spring-cloud-gateway-webflux/pom.xml +++ b/spring-cloud-gateway-webflux/pom.xml @@ -30,6 +30,11 @@ spring-boot-starter-actuator test + + org.springframework.boot + spring-boot-properties-migrator + test + org.springframework.boot spring-boot-configuration-processor diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java new file mode 100644 index 00000000..3c83cceb --- /dev/null +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxProperties.java @@ -0,0 +1,117 @@ +/* + * Copyright 2016-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.webflux.config; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.gateway.webflux.ProxyExchange; +import org.springframework.http.HttpHeaders; + +/** + * Configuration properties for the {@link ProxyExchange} argument handler in + * @RequestMapping methods. + * + * @author Dave Syer + * @author Tim Ysewyn + * @author Joris Kuipers + * @author Spencer Gibb + * + */ +@ConfigurationProperties(ProxyExchangeWebfluxProperties.PREFIX) +public class ProxyExchangeWebfluxProperties { + + /** + * Properties prefix. + */ + public static final String PREFIX = "spring.cloud.gateway.proxy-exchange.webflux"; + + /** + * Contains headers that are considered case-sensitive by default. + */ + public static Set DEFAULT_SENSITIVE = Set.of("cookie", "authorization"); + + /** + * Contains headers that are skipped by default. + */ + public static Set DEFAULT_SKIPPED = Set.of("content-length", "host"); + + /** + * Fixed header values that will be added to all downstream requests. + */ + private Map headers = new LinkedHashMap<>(); + + /** + * A set of header names that should be sent downstream by default. + */ + private Set autoForward = new HashSet<>(); + + /** + * A set of sensitive header names that will not be sent downstream by default. + */ + private Set sensitive = DEFAULT_SENSITIVE; + + /** + * A set of header names that will not be sent downstream because they could be + * problematic. + */ + private Set skipped = DEFAULT_SKIPPED; + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Set getAutoForward() { + return autoForward; + } + + public void setAutoForward(Set autoForward) { + this.autoForward = autoForward; + } + + public Set getSensitive() { + return sensitive; + } + + public void setSensitive(Set sensitive) { + this.sensitive = sensitive; + } + + public Set getSkipped() { + return skipped; + } + + public void setSkipped(Set skipped) { + this.skipped = skipped; + } + + public HttpHeaders convertHeaders() { + HttpHeaders headers = new HttpHeaders(); + for (String key : this.headers.keySet()) { + headers.set(key, this.headers.get(key)); + } + return headers; + } + +} diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java index 38e000d5..0c7184ca 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyProperties.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.cloud.gateway.webflux.ProxyExchange; import org.springframework.http.HttpHeaders; @@ -32,8 +33,10 @@ import org.springframework.http.HttpHeaders; * @author Dave Syer * @author Tim Ysewyn * @author Joris Kuipers + * @deprecated {@link ProxyExchangeWebfluxProperties} * */ +@Deprecated @ConfigurationProperties("spring.cloud.gateway.proxy") public class ProxyProperties { @@ -53,7 +56,7 @@ public class ProxyProperties { private Map headers = new LinkedHashMap<>(); /** - * A set of header names that should be send downstream by default. + * A set of header names that should be sent downstream by default. */ private Set autoForward = new HashSet<>(); @@ -68,6 +71,7 @@ public class ProxyProperties { */ private Set skipped = DEFAULT_SKIPPED; + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".headers", since = "4.3.0") public Map getHeaders() { return headers; } @@ -76,6 +80,8 @@ public class ProxyProperties { this.headers = headers; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".auto-forward", + since = "4.3.0") public Set getAutoForward() { return autoForward; } @@ -84,6 +90,8 @@ public class ProxyProperties { this.autoForward = autoForward; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".sensitive", + since = "4.3.0") public Set getSensitive() { return sensitive; } @@ -92,6 +100,7 @@ public class ProxyProperties { this.sensitive = sensitive; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebfluxProperties.PREFIX + ".skipped", since = "4.3.0") public Set getSkipped() { return skipped; } diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java index 20ff720d..116f0b10 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java @@ -48,7 +48,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication @ConditionalOnClass({ HandlerMethodReturnValueHandler.class, WebClient.class }) -@EnableConfigurationProperties(ProxyProperties.class) +@EnableConfigurationProperties({ ProxyExchangeWebfluxProperties.class, ProxyProperties.class }) public class ProxyResponseAutoConfiguration implements WebFluxConfigurer { @Autowired @@ -57,18 +57,18 @@ public class ProxyResponseAutoConfiguration implements WebFluxConfigurer { @Bean @ConditionalOnMissingBean public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver(Optional optional, - ProxyProperties proxy) { + ProxyExchangeWebfluxProperties properties) { WebClient.Builder builder = optional.orElse(WebClient.builder()); WebClient template = builder.build(); ProxyExchangeArgumentResolver resolver = new ProxyExchangeArgumentResolver(template); - resolver.setHeaders(proxy.convertHeaders()); - resolver.setAutoForwardedHeaders(proxy.getAutoForward()); + resolver.setHeaders(properties.convertHeaders()); + resolver.setAutoForwardedHeaders(properties.getAutoForward()); Set excludedHeaderNames = new HashSet<>(); - if (proxy.getSensitive() != null) { - excludedHeaderNames.addAll(proxy.getSensitive()); + if (properties.getSensitive() != null) { + excludedHeaderNames.addAll(properties.getSensitive()); } - if (proxy.getSkipped() != null) { - excludedHeaderNames.addAll(proxy.getSkipped()); + if (properties.getSkipped() != null) { + excludedHeaderNames.addAll(properties.getSkipped()); } resolver.setExcluded(excludedHeaderNames); return resolver; diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java index 62b26201..732f71f8 100644 --- a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java @@ -62,7 +62,8 @@ import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(properties = { "spring.cloud.gateway.proxy.skipped=host" }, webEnvironment = WebEnvironment.RANDOM_PORT) +@SpringBootTest(properties = { "spring.cloud.gateway.proxy-exchange.webflux.skipped=host" }, + webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = TestApplication.class) @DirtiesContext @ExtendWith(OutputCaptureExtension.class) diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java new file mode 100644 index 00000000..b86058a8 --- /dev/null +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2025 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.webflux.config; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("propertiesmigrationtests") +public class ProxyExchangeWebfluxPropertiesMigrationTests { + + @Autowired + ProxyProperties properties; + + @Test + public void deprecatedRoutePropertiesWork() { + assertThat(properties.getHeaders()).hasSize(2); + assertThat(properties.getAutoForward()).hasSize(2); + assertThat(properties.getSensitive()).hasSize(2); + assertThat(properties.getSkipped()).hasSize(3); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + } + +} diff --git a/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml new file mode 100644 index 00000000..3d9b1d93 --- /dev/null +++ b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml @@ -0,0 +1,12 @@ +spring.cloud.gateway.proxy: + headers: + X-Foo: xfooval + X-Bar: xbarval + auto-forward: + - X-FWD1 + - X-FWD2 + sensitive: X-S1, X-S21 + skipped: X-SK1, X-SK2, X-SK3 +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE From 9cd6b4af32833024dca93718e45adc3b3a4b561e Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 9 May 2025 16:26:54 -0400 Subject: [PATCH 41/85] Fixes ProxyExchangeWebfluxPropertiesMigrationTests See gh-3362 --- .../config/ProxyExchangeWebfluxPropertiesMigrationTests.java | 2 +- .../test/resources/application-propertiesmigrationtests.yml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java index b86058a8..974294ba 100644 --- a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeWebfluxPropertiesMigrationTests.java @@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class ProxyExchangeWebfluxPropertiesMigrationTests { @Autowired - ProxyProperties properties; + ProxyExchangeWebfluxProperties properties; @Test public void deprecatedRoutePropertiesWork() { diff --git a/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml index 3d9b1d93..d6b6dfe5 100644 --- a/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml +++ b/spring-cloud-gateway-webflux/src/test/resources/application-propertiesmigrationtests.yml @@ -2,9 +2,7 @@ spring.cloud.gateway.proxy: headers: X-Foo: xfooval X-Bar: xbarval - auto-forward: - - X-FWD1 - - X-FWD2 + auto-forward: X-FWD1, X-FWD2 sensitive: X-S1, X-S21 skipped: X-SK1, X-SK2, X-SK3 logging: From ca9721f4ee8096beaaae3d2e57c59148fcd5a065 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 9 May 2025 16:29:56 -0400 Subject: [PATCH 42/85] Migrates proxy-exchange-webmvc properties to new namespace from spring.cloud.gateway.proxy to spring.cloud.gateway.proxy-exchange.webmvc Fixes gh-3361 --- spring-cloud-gateway-mvc/pom.xml | 5 + .../config/ProxyExchangeWebMvcProperties.java | 116 ++++++++++++++++++ .../gateway/mvc/config/ProxyProperties.java | 10 +- .../ProxyResponseAutoConfiguration.java | 16 +-- ...xchangeWebmvcPropertiesMigrationTests.java | 52 ++++++++ .../application-propertiesmigrationtests.yml | 10 ++ 6 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebMvcProperties.java create mode 100644 spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebmvcPropertiesMigrationTests.java create mode 100644 spring-cloud-gateway-mvc/src/test/resources/application-propertiesmigrationtests.yml diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 14d0d2aa..e339f496 100644 --- a/spring-cloud-gateway-mvc/pom.xml +++ b/spring-cloud-gateway-mvc/pom.xml @@ -41,6 +41,11 @@ 4.5.14 test + + org.springframework.boot + spring-boot-properties-migrator + test + org.springframework.boot spring-boot-configuration-processor diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebMvcProperties.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebMvcProperties.java new file mode 100644 index 00000000..12e75015 --- /dev/null +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebMvcProperties.java @@ -0,0 +1,116 @@ +/* + * Copyright 2016-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.mvc.config; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.gateway.mvc.ProxyExchange; +import org.springframework.http.HttpHeaders; + +/** + * Configuration properties for the {@link ProxyExchange} argument handler in + * @RequestMapping methods. + * + * @author Dave Syer + * @author Tim Ysewyn + * @author Joris Kuipers + * + */ +@ConfigurationProperties(ProxyExchangeWebMvcProperties.PREFIX) +public class ProxyExchangeWebMvcProperties { + + /** + * Properties prefix. + */ + public static final String PREFIX = "spring.cloud.gateway.proxy-exchange.webmvc"; + + /** + * Contains headers that are considered sensitive by default. + */ + public static Set DEFAULT_SENSITIVE = Set.of("cookie", "authorization"); + + /** + * Contains headers that are skipped by default. + */ + public static Set DEFAULT_SKIPPED = Set.of("content-length", "host"); + + /** + * Fixed header values that will be added to all downstream requests. + */ + private Map headers = new LinkedHashMap<>(); + + /** + * A set of header names that should be sent downstream by default. + */ + private Set autoForward = new HashSet<>(); + + /** + * A set of sensitive header names that will not be sent downstream by default. + */ + private Set sensitive = DEFAULT_SENSITIVE; + + /** + * A set of header names that will not be sent downstream because they could be + * problematic. + */ + private Set skipped = DEFAULT_SKIPPED; + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Set getAutoForward() { + return autoForward; + } + + public void setAutoForward(Set autoForward) { + this.autoForward = autoForward; + } + + public Set getSensitive() { + return sensitive; + } + + public void setSensitive(Set sensitive) { + this.sensitive = sensitive; + } + + public Set getSkipped() { + return skipped; + } + + public void setSkipped(Set skipped) { + this.skipped = skipped; + } + + public HttpHeaders convertHeaders() { + HttpHeaders headers = new HttpHeaders(); + for (String key : this.headers.keySet()) { + headers.set(key, this.headers.get(key)); + } + return headers; + } + +} diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java index 59296583..e9b546bf 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyProperties.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.cloud.gateway.mvc.ProxyExchange; import org.springframework.http.HttpHeaders; @@ -32,8 +33,10 @@ import org.springframework.http.HttpHeaders; * @author Dave Syer * @author Tim Ysewyn * @author Joris Kuipers - * + * @author Spencer Gibb + * @deprecated {@link ProxyExchangeWebMvcProperties} */ +@Deprecated @ConfigurationProperties("spring.cloud.gateway.proxy") public class ProxyProperties { @@ -68,6 +71,7 @@ public class ProxyProperties { */ private Set skipped = DEFAULT_SKIPPED; + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebMvcProperties.PREFIX + ".headers", since = "4.3.0") public Map getHeaders() { return headers; } @@ -76,6 +80,8 @@ public class ProxyProperties { this.headers = headers; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebMvcProperties.PREFIX + ".auto-forward", + since = "4.3.0") public Set getAutoForward() { return autoForward; } @@ -84,6 +90,7 @@ public class ProxyProperties { this.autoForward = autoForward; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebMvcProperties.PREFIX + ".sensitive", since = "4.3.0") public Set getSensitive() { return sensitive; } @@ -92,6 +99,7 @@ public class ProxyProperties { this.sensitive = sensitive; } + @DeprecatedConfigurationProperty(replacement = ProxyExchangeWebMvcProperties.PREFIX + ".skipped", since = "4.3.0") public Set getSkipped() { return skipped; } diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java index 0a840d78..b7cfeb18 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java @@ -57,7 +57,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication @ConditionalOnClass({ HandlerMethodReturnValueHandler.class }) -@EnableConfigurationProperties(ProxyProperties.class) +@EnableConfigurationProperties({ ProxyExchangeWebMvcProperties.class, ProxyProperties.class }) public class ProxyResponseAutoConfiguration implements WebMvcConfigurer { @Autowired @@ -66,7 +66,7 @@ public class ProxyResponseAutoConfiguration implements WebMvcConfigurer { @Bean @ConditionalOnMissingBean public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver(Optional optional, - ProxyProperties proxy) { + ProxyExchangeWebMvcProperties properties) { RestTemplateBuilder builder = optional.orElse(new RestTemplateBuilder()); RestTemplate template = builder.build(); template.setErrorHandler(new NoOpResponseErrorHandler()); @@ -77,14 +77,14 @@ public class ProxyResponseAutoConfiguration implements WebMvcConfigurer { } }); ProxyExchangeArgumentResolver resolver = new ProxyExchangeArgumentResolver(template); - resolver.setHeaders(proxy.convertHeaders()); - resolver.setAutoForwardedHeaders(proxy.getAutoForward()); + resolver.setHeaders(properties.convertHeaders()); + resolver.setAutoForwardedHeaders(properties.getAutoForward()); Set excludedHeaderNames = new HashSet<>(); - if (proxy.getSensitive() != null) { - excludedHeaderNames.addAll(proxy.getSensitive()); + if (properties.getSensitive() != null) { + excludedHeaderNames.addAll(properties.getSensitive()); } - if (proxy.getSkipped() != null) { - excludedHeaderNames.addAll(proxy.getSkipped()); + if (properties.getSkipped() != null) { + excludedHeaderNames.addAll(properties.getSkipped()); } resolver.setExcluded(excludedHeaderNames); return resolver; diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebmvcPropertiesMigrationTests.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebmvcPropertiesMigrationTests.java new file mode 100644 index 00000000..4c15b7f3 --- /dev/null +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeWebmvcPropertiesMigrationTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.mvc.config; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("propertiesmigrationtests") +public class ProxyExchangeWebmvcPropertiesMigrationTests { + + @Autowired + ProxyExchangeWebMvcProperties properties; + + @Test + public void deprecatedRoutePropertiesWork() { + assertThat(properties.getHeaders()).hasSize(2); + assertThat(properties.getAutoForward()).hasSize(2); + assertThat(properties.getSensitive()).hasSize(2); + assertThat(properties.getSkipped()).hasSize(3); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + } + +} diff --git a/spring-cloud-gateway-mvc/src/test/resources/application-propertiesmigrationtests.yml b/spring-cloud-gateway-mvc/src/test/resources/application-propertiesmigrationtests.yml new file mode 100644 index 00000000..d6b6dfe5 --- /dev/null +++ b/spring-cloud-gateway-mvc/src/test/resources/application-propertiesmigrationtests.yml @@ -0,0 +1,10 @@ +spring.cloud.gateway.proxy: + headers: + X-Foo: xfooval + X-Bar: xbarval + auto-forward: X-FWD1, X-FWD2 + sensitive: X-S1, X-S21 + skipped: X-SK1, X-SK2, X-SK3 +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE From b83915cff2516bc7be7f988f58765c0c1db5502c Mon Sep 17 00:00:00 2001 From: spring-builds Date: Sun, 11 May 2025 18:54:33 +0000 Subject: [PATCH 43/85] Bumping versions --- docs/modules/ROOT/partials/_configprops.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/modules/ROOT/partials/_configprops.adoc b/docs/modules/ROOT/partials/_configprops.adoc index 5b4433b0..d4660a70 100644 --- a/docs/modules/ROOT/partials/_configprops.adoc +++ b/docs/modules/ROOT/partials/_configprops.adoc @@ -166,7 +166,6 @@ |spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-append | `+++true+++` | If appending X-Forwarded-Proto as a list is enabled. |spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.proto-enabled | `+++true+++` | If X-Forwarded-Proto is enabled. |spring.cloud.gateway.observability.enabled | `+++true+++` | If Micrometer Observability support should be turned on. -|spring.cloud.gateway.oldval | | oldval doc. |spring.cloud.gateway.predicate.after.enabled | `+++true+++` | Enables the after predicate. |spring.cloud.gateway.predicate.before.enabled | `+++true+++` | Enables the before predicate. |spring.cloud.gateway.predicate.between.enabled | `+++true+++` | Enables the between predicate. From 24585036cee9c6fa63defa36bc1be22b36ab8ab8 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Sat, 19 Apr 2025 16:45:02 +0900 Subject: [PATCH 44/85] Refactored the filter that removes fields from JSON response bodies factory Signed-off-by: raccoonback --- ...butesResponseBodyGatewayFilterFactory.java | 32 +++++-------- ...ResponseBodyGatewayFilterFactoryTests.java | 48 ++++++++++++++++--- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java index cb5b7d49..deea4c63 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2013-2025 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. @@ -22,7 +22,6 @@ import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Mono; @@ -34,6 +33,7 @@ import org.springframework.http.MediaType; /** * @author Marta Medio + * @author raccoonback */ public class RemoveJsonAttributesResponseBodyGatewayFilterFactory extends AbstractGatewayFilterFactory { @@ -72,14 +72,14 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactory extends RewriteFunction rewriteFunction = (exchange, body) -> { if (MediaType.APPLICATION_JSON.isCompatibleWith(exchange.getResponse().getHeaders().getContentType())) { try { - JsonNode jsonBodyContent = mapper.readValue(body, JsonNode.class); + JsonNode jsonNode = mapper.readValue(body, JsonNode.class); - removeJsonAttribute(jsonBodyContent, config.getFieldList(), config.isDeleteRecursively()); + removeJsonAttributes(jsonNode, config.getFieldList(), config.isDeleteRecursively()); - body = mapper.writeValueAsString(jsonBodyContent); + body = mapper.writeValueAsString(jsonNode); } catch (JsonProcessingException e) { - throw new RuntimeException(e); + return Mono.error(new IllegalStateException("Failed to process JSON of response body.", e)); } } return Mono.just(body); @@ -93,22 +93,12 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactory extends private ObjectMapper mapper = new ObjectMapper(); - private void removeJsonAttribute(JsonNode jsonBodyContent, List fieldsToRemove, boolean deleteRecursively) { - if (deleteRecursively) { - for (JsonNode jsonNode : jsonBodyContent) { - if (jsonNode instanceof ObjectNode) { - ((ObjectNode) jsonNode).remove(fieldsToRemove); - removeJsonAttribute(jsonNode, fieldsToRemove, true); - } - if (jsonNode instanceof ArrayNode) { - for (JsonNode node : jsonNode) { - removeJsonAttribute(node, fieldsToRemove, true); - } - } - } + private void removeJsonAttributes(JsonNode jsonNode, List fieldNames, boolean deleteRecursively) { + if (jsonNode instanceof ObjectNode objectNode) { + objectNode.remove(fieldNames); } - if (jsonBodyContent instanceof ObjectNode) { - ((ObjectNode) jsonBodyContent).remove(fieldsToRemove); + if (deleteRecursively) { + jsonNode.forEach(childNode -> removeJsonAttributes(childNode, fieldNames, true)); } } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests.java index 12482d1a..228a1990 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests.java @@ -19,6 +19,7 @@ package org.springframework.cloud.gateway.filter.factory; import java.util.Map; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringBootConfiguration; @@ -30,8 +31,12 @@ import org.springframework.cloud.gateway.test.BaseWebClientTests; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -42,10 +47,10 @@ import static org.springframework.cloud.gateway.test.TestUtils.getMap; */ @SpringBootTest(webEnvironment = RANDOM_PORT) @DirtiesContext -public class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends BaseWebClientTests { +class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends BaseWebClientTests { @Test - public void removeJsonAttributeRootWorks() { + void removeJsonAttributeRootWorks() { testClient.post() .uri("/post") .header("Host", "www.removejsonattributes.org") @@ -70,8 +75,7 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends B } @Test - public void removeJsonAttributeRecursivelyWorks() { - + void removeJsonAttributeRecursivelyWorks() { testClient.post() .uri("/post") .header("Host", "www.removejsonattributesrecursively.org") @@ -93,8 +97,7 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends B } @Test - public void removeJsonAttributeNoMatchesWorks() { - + void removeJsonAttributeNoMatchesWorks() { testClient.post() .uri("/post") .header("Host", "www.removejsonattributesnomatches.org") @@ -113,6 +116,21 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends B }); } + @Test + void raisedWhenRemoveJsonAttributes() { + testClient.post() + .uri("/post") + .header("Host", "www.raisederrorwhenremovejsonattributes.org") + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .exchange() + .expectStatus() + .is5xxServerError() + .expectBody(String.class) + .consumeWith(result -> { + assertThat(result.getResponseBody()).isEqualTo("Failed to process JSON of response body."); + }); + } + @EnableAutoConfiguration @SpringBootConfiguration @Import(DefaultTestConfig.class) @@ -142,9 +160,27 @@ public class RemoveJsonAttributesResponseBodyGatewayFilterFactoryTests extends B .host("{sub}.removejsonattributesnomatches.org") .filters(f -> f.removeJsonAttributes("test")) .uri(uri)) + .route("raised_error_when_remove_json_attributes", + r -> r.path("/post") + .and() + .host("{sub}.raisederrorwhenremovejsonattributes.org") + .filters(f -> f.removeJsonAttributes("test") + .modifyResponseBody(String.class, String.class, + (exchange, response) -> Mono.just("{\"invalid_json\": test"))) + .uri(uri)) .build(); } + @ControllerAdvice + public class GlobalExceptionHandler { + + @ExceptionHandler(IllegalStateException.class) + public ResponseEntity handleIllegalException(IllegalStateException ex) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); + } + + } + } } From 77dd818e00cd77f48418ae7bfd6e4fa58c448fb7 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Sat, 19 Apr 2025 17:41:53 +0900 Subject: [PATCH 45/85] Support for removing JSON attributes from response bodies in MVC Signed-off-by: raccoonback --- .../mvc/filter/AfterFilterFunctions.java | 47 +++- .../mvc/filter/AfterFilterFunctionsTests.java | 218 ++++++++++++++++++ 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java index 695d3fce..14795efa 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 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. @@ -24,6 +24,11 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.regex.Pattern; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + import org.springframework.cloud.gateway.server.mvc.common.HttpStatusHolder; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.cloud.gateway.server.mvc.handler.GatewayServerResponse; @@ -34,8 +39,16 @@ import org.springframework.util.StringUtils; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +/** + * @author raccoonback + */ public abstract class AfterFilterFunctions { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private AfterFilterFunctions() { } @@ -160,6 +173,38 @@ public abstract class AfterFilterFunctions { }; } + public static BiFunction removeJsonAttributesResponseBody( + List fieldList, boolean deleteRecursively) { + List immutableFieldList = List.copyOf(fieldList); + + return modifyResponseBody(String.class, String.class, APPLICATION_JSON_VALUE, (request, response, body) -> { + String responseBody = body; + if (APPLICATION_JSON.isCompatibleWith(response.headers().getContentType())) { + try { + JsonNode jsonBodyContent = OBJECT_MAPPER.readValue(responseBody, JsonNode.class); + + removeJsonAttributes(jsonBodyContent, immutableFieldList, deleteRecursively); + + responseBody = OBJECT_MAPPER.writeValueAsString(jsonBodyContent); + } + catch (JsonProcessingException exception) { + throw new IllegalStateException("Failed to process JSON of response body.", exception); + } + } + + return responseBody; + }); + } + + private static void removeJsonAttributes(JsonNode jsonNode, List fieldNames, boolean deleteRecursively) { + if (jsonNode instanceof ObjectNode objectNode) { + objectNode.remove(fieldNames); + } + if (deleteRecursively) { + jsonNode.forEach(childNode -> removeJsonAttributes(childNode, fieldNames, true)); + } + } + public enum DedupeStrategy { /** diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java new file mode 100644 index 00000000..a0ee50b8 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java @@ -0,0 +1,218 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.filter; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.modifyResponseBody; +import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.removeJsonAttributesResponseBody; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; + +/** + * @author raccoonback + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +class AfterFilterFunctionsTests { + + @Autowired + TestRestClient restClient; + + @Test + void doesNotRemoveJsonAttributes() { + restClient.get() + .uri("/anything/does_not/remove_json_attributes") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).containsEntry("foo", "bar"); + assertThat(res.getResponseBody()).containsEntry("baz", "qux"); + }); + } + + @Test + void removeJsonAttributesToAvoidBeingRecursive() { + restClient.get() + .uri("/anything/remove_json_attributes_to_avoid_being_recursive") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).doesNotContainKey("foo"); + assertThat(res.getResponseBody()).containsEntry("baz", "qux"); + }); + } + + @Test + void removeJsonAttributesRecursively() { + restClient.get() + .uri("/anything/remove_json_attributes_recursively") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).containsKey("foo"); + assertThat((Map) res.getResponseBody().get("foo")).containsEntry("bar", "A"); + assertThat(res.getResponseBody()).containsEntry("quux", "C"); + assertThat(res.getResponseBody()).doesNotContainKey("qux"); + }); + } + + @Test + void raisedErrorWhenRemoveJsonAttributes() { + restClient.get() + .uri("/anything/raised_error_when_remove_json_attributes") + .exchange() + .expectStatus() + .is5xxServerError() + .expectBody(String.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).isEqualTo("Failed to process JSON of response body."); + }); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + protected static class TestConfiguration { + + @Bean + public RouterFunction doesNotRemoveJsonAttributes() { + // @formatter:off + return route("does_not_remove_json_attributes") + .GET("/anything/does_not/remove_json_attributes", http()) + .before(new HttpbinUriResolver()) + .after( + removeJsonAttributesResponseBody(List.of("quux"), true) + ) + .after( + modifyResponseBody( + String.class, + String.class, + MediaType.APPLICATION_JSON_VALUE, + (request, response, s) -> "{\"foo\": \"bar\", \"baz\": \"qux\"}" + ) + ) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction removeJsonAttributesToAvoidBeingRecursively() { + // @formatter:off + return route("remove_json_attributes_to_avoid_being_recursive") + .GET("/anything/remove_json_attributes_to_avoid_being_recursive", http()) + .before(new HttpbinUriResolver()) + .after( + removeJsonAttributesResponseBody(List.of("foo"), false) + ) + .after( + modifyResponseBody( + String.class, + String.class, + MediaType.APPLICATION_JSON_VALUE, + (request, response, s) -> "{\"foo\": \"bar\", \"baz\": \"qux\"}" + ) + ) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction removeJsonAttributesRecursively() { + // @formatter:off + return route("remove_json_attributes_recursively") + .GET("/anything/remove_json_attributes_recursively", http()) + .before(new HttpbinUriResolver()) + .after( + removeJsonAttributesResponseBody(List.of("qux"), true) + ) + .after( + modifyResponseBody( + String.class, + String.class, + MediaType.APPLICATION_JSON_VALUE, + (request, response, s) -> "{\"foo\": { \"bar\": \"A\", \"qux\": \"B\"}, \"quux\": \"C\", \"qux\": {\"corge\": \"D\"}}" + ) + ) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction raisedErrorWhenRemoveJsonAttributes() { + // @formatter:off + return route("raised_error_when_remove_json_attributes") + .GET("/anything/raised_error_when_remove_json_attributes", http()) + .before(new HttpbinUriResolver()) + .after( + removeJsonAttributesResponseBody(List.of("qux"), true) + ) + .after( + modifyResponseBody( + String.class, + String.class, + MediaType.APPLICATION_JSON_VALUE, + (request, response, s) -> "{\"invalid_json\": 123" + ) + ) + .build(); + // @formatter:on + } + + @ControllerAdvice + public class GlobalExceptionHandler { + + @ExceptionHandler(IllegalStateException.class) + public ResponseEntity handleIllegalException(IllegalStateException ex) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); + } + + } + + } + +} From c70b671ed7044452b68ad50f5eec9db95575039e Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 24 Apr 2025 13:27:51 +0000 Subject: [PATCH 46/85] Bumping versions Signed-off-by: raccoonback --- .../cloud/gateway/filter/NettyRoutingFilterTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java index b96bb9fa..b071212d 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/NettyRoutingFilterTests.java @@ -113,7 +113,8 @@ class NettyRoutingFilterTests extends BaseWebClientTests { this.context.publishEvent(new EnvironmentChangeEvent(this.context, Collections.singleton("spring.cloud.gateway.httpclient.connect-timeout"))); Route route = routeLocator.getRoutes() - .filter(r -> r.getId().equals("refreshable_configuration_test")).blockLast(); + .filter(r -> r.getId().equals("refreshable_configuration_test")) + .blockLast(); assertThat(route).isNotNull(); HttpClient httpClient = nettyRoutingFilter.getHttpClient(route, null); HttpClientConfig configuration = httpClient.configuration(); From f1f49e092633af94307e4c1f7d4b43188472b32d Mon Sep 17 00:00:00 2001 From: raccoonback Date: Wed, 7 May 2025 23:00:14 +0900 Subject: [PATCH 47/85] Improve ProxyExchangeHandlerFunction to preserve original encoding of query parameters during proxy request ref. https://github.com/spring-cloud/spring-cloud-gateway/issues/3759 Signed-off-by: raccoonback --- .../handler/ProxyExchangeHandlerFunction.java | 21 +++- .../ProxyExchangeHandlerFunctionTest.java | 98 +++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java index 0ea445fc..94b78376 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 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. @@ -36,7 +36,11 @@ import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; +/** + * @author raccoonback + */ public class ProxyExchangeHandlerFunction implements HandlerFunction, ApplicationListener { @@ -84,14 +88,14 @@ public class ProxyExchangeHandlerFunction @Override public ServerResponse handle(ServerRequest serverRequest) { URI uri = uriResolver.apply(serverRequest); - boolean encoded = containsEncodedQuery(serverRequest.uri(), serverRequest.params()); + MultiValueMap params = ensureEncodedQueryParameters(serverRequest); // @formatter:off URI url = UriComponentsBuilder.fromUri(serverRequest.uri()) .scheme(uri.getScheme()) .host(uri.getHost()) .port(uri.getPort()) - .replaceQueryParams(serverRequest.params()) - .build(encoded) + .replaceQueryParams(params) + .build(true) .toUri(); // @formatter:on @@ -131,6 +135,15 @@ public class ProxyExchangeHandlerFunction return filtered; } + private static MultiValueMap ensureEncodedQueryParameters(ServerRequest serverRequest) { + boolean encoded = containsEncodedQuery(serverRequest.uri(), serverRequest.params()); + MultiValueMap params = serverRequest.params(); + if (!encoded) { + params = UriUtils.encodeQueryParams(serverRequest.params()); + } + return params; + } + private static boolean containsEncodedQuery(URI uri, MultiValueMap params) { String rawQuery = uri.getRawQuery(); boolean encoded = (rawQuery != null && rawQuery.contains("%")) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java new file mode 100644 index 00000000..713bcc20 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc.handler; + +import java.net.URI; +import java.util.Collections; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.gateway.server.mvc.common.AbstractProxyExchange; +import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; +import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; +import org.springframework.cloud.gateway.server.mvc.filter.HttpHeadersFilter.RequestHttpHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.HttpHeadersFilter.ResponseHttpHeadersFilter; +import org.springframework.http.HttpHeaders; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author raccoonback + */ +class ProxyExchangeHandlerFunctionTest { + + @Test + void keepOriginalEncodingOfQueryParameter() { + TestProxyExchange proxyExchange = new TestProxyExchange(); + ProxyExchangeHandlerFunction function = new ProxyExchangeHandlerFunction(proxyExchange, new ObjectProvider<>() { + @Override + public Stream stream() { + return Stream.of((httpHeaders, serverRequest) -> new HttpHeaders()); + } + }, new ObjectProvider<>() { + @Override + public Stream stream() { + return Stream.of((httpHeaders, serverRequest) -> new HttpHeaders()); + } + }); + + function.onApplicationEvent(null); + + MockHttpServletRequest servletRequest = MockMvcRequestBuilders + .get("http://localhost/é?foo=value1 value2&bar=value3=") + .buildRequest(null); + servletRequest.setAttribute(MvcUtils.GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost:8080")); + ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); + + function.handle(request); + + URI uri = proxyExchange.getRequest().getUri(); + + assertThat(uri).hasToString("http://localhost:8080/%C3%A9?foo=value1%20value2&bar=value3%3D") + .hasPath("/é") + .hasParameter("foo", "value1 value2") + .hasParameter("bar", "value3="); + } + + private class TestProxyExchange extends AbstractProxyExchange { + + private Request request; + + protected TestProxyExchange() { + super(new GatewayMvcProperties()); + } + + @Override + public ServerResponse exchange(Request request) { + this.request = request; + + return ServerResponse.ok().build(); + } + + public Request getRequest() { + return request; + } + + } + +} From 9217b373ae3373cd2422d8c8a185c6ae4a132e92 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Tue, 13 May 2025 09:44:05 +0900 Subject: [PATCH 48/85] Create the ObjectProvider instance to align with version 4.1.x. Signed-off-by: raccoonback --- .../ProxyExchangeHandlerFunctionTest.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java index 713bcc20..3edf7ad7 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java @@ -22,6 +22,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.server.mvc.common.AbstractProxyExchange; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; @@ -46,13 +47,56 @@ class ProxyExchangeHandlerFunctionTest { TestProxyExchange proxyExchange = new TestProxyExchange(); ProxyExchangeHandlerFunction function = new ProxyExchangeHandlerFunction(proxyExchange, new ObjectProvider<>() { @Override - public Stream stream() { + public RequestHttpHeadersFilter getObject() throws BeansException { + return null; + } + + @Override + public RequestHttpHeadersFilter getObject(Object... args) throws BeansException { + return null; + } + + @Override + public RequestHttpHeadersFilter getIfAvailable() throws BeansException { + return null; + } + + @Override + public RequestHttpHeadersFilter getIfUnique() throws BeansException { + return null; + } + + @Override + public Stream orderedStream() { return Stream.of((httpHeaders, serverRequest) -> new HttpHeaders()); } + }, new ObjectProvider<>() { + @Override - public Stream stream() { + public ResponseHttpHeadersFilter getObject() throws BeansException { + return null; + } + + @Override + public ResponseHttpHeadersFilter getObject(Object... args) throws BeansException { + return null; + } + + @Override + public ResponseHttpHeadersFilter getIfAvailable() throws BeansException { + return null; + } + + @Override + public ResponseHttpHeadersFilter getIfUnique() throws BeansException { + return null; + } + + @Override + public Stream orderedStream() { return Stream.of((httpHeaders, serverRequest) -> new HttpHeaders()); + } }); From 107e8d36bf763045954d0416155aafa026703f07 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Tue, 13 May 2025 16:29:35 +0900 Subject: [PATCH 49/85] Fix incorrect handling of '+' character in query parameter encoding Signed-off-by: raccoonback --- .../gateway/server/mvc/common/MvcUtils.java | 17 ++++++++++++++++- .../handler/ProxyExchangeHandlerFunction.java | 3 +-- .../ProxyExchangeHandlerFunctionTest.java | 7 ++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java index 05c073ed..ca81cc65 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 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. @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -40,11 +41,14 @@ import org.springframework.http.HttpInputMessage; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.util.StreamUtils; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.support.RequestContextUtils; import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; import static org.springframework.web.servlet.function.RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE; @@ -263,6 +267,17 @@ public abstract class MvcUtils { urls.add(url); } + public static MultiValueMap encodeQueryParams(MultiValueMap params) { + MultiValueMap encodedQueryParams = new LinkedMultiValueMap<>(params.size()); + for (Map.Entry> entry : params.entrySet()) { + for (String value : entry.getValue()) { + encodedQueryParams.add(UriUtils.encode(entry.getKey(), StandardCharsets.UTF_8), + UriUtils.encode(value, StandardCharsets.UTF_8)); + } + } + return CollectionUtils.unmodifiableMultiValueMap(encodedQueryParams); + } + private record ByteArrayInputMessage(ServerRequest request, ByteArrayInputStream body) implements HttpInputMessage { @Override diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java index 94b78376..5a724800 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java @@ -36,7 +36,6 @@ import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; /** * @author raccoonback @@ -139,7 +138,7 @@ public class ProxyExchangeHandlerFunction boolean encoded = containsEncodedQuery(serverRequest.uri(), serverRequest.params()); MultiValueMap params = serverRequest.params(); if (!encoded) { - params = UriUtils.encodeQueryParams(serverRequest.params()); + params = MvcUtils.encodeQueryParams(serverRequest.params()); } return params; } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java index 3edf7ad7..e8f650c7 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunctionTest.java @@ -103,7 +103,7 @@ class ProxyExchangeHandlerFunctionTest { function.onApplicationEvent(null); MockHttpServletRequest servletRequest = MockMvcRequestBuilders - .get("http://localhost/é?foo=value1 value2&bar=value3=") + .get("http://localhost/é?foo=value1 value2&bar=value3=&qux=value4+") .buildRequest(null); servletRequest.setAttribute(MvcUtils.GATEWAY_REQUEST_URL_ATTR, URI.create("http://localhost:8080")); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -112,10 +112,11 @@ class ProxyExchangeHandlerFunctionTest { URI uri = proxyExchange.getRequest().getUri(); - assertThat(uri).hasToString("http://localhost:8080/%C3%A9?foo=value1%20value2&bar=value3%3D") + assertThat(uri).hasToString("http://localhost:8080/%C3%A9?foo=value1%20value2&bar=value3%3D&qux=value4%2B") .hasPath("/é") .hasParameter("foo", "value1 value2") - .hasParameter("bar", "value3="); + .hasParameter("bar", "value3=") + .hasParameter("qux", "value4+"); } private class TestProxyExchange extends AbstractProxyExchange { From af2f0d6a3a5105dce162cecd1c9cedf736ac0d79 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 13 May 2025 12:33:10 -0400 Subject: [PATCH 50/85] Fixing GatewayServerMvcAutoConfiguration to align with correct Boot properties --- spring-cloud-gateway-server-mvc/pom.xml | 10 +++ .../GatewayServerMvcAutoConfiguration.java | 9 ++- ...atewayServerMvcAutoConfigurationTests.java | 9 +-- .../server/mvc/ServerMvcIntegrationTests.java | 3 +- .../mvc/filter/AfterFilterFunctionsTests.java | 74 +++++++++---------- 5 files changed, 56 insertions(+), 49 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index e9f6b80c..ad20bf03 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -107,6 +107,16 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit + + + io.projectreactor.netty + reactor-netty + + + org.springframework.boot + spring-boot-starter-webflux + + test diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index d515b906..37cd5245 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -216,18 +216,19 @@ public class GatewayServerMvcAutoConfiguration { static final boolean REACTOR_NETTY = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", null); static final boolean JDK = ClassUtils.isPresent("java.net.http.HttpClient", null); static final boolean HIGHER_PRIORITY = APACHE || JETTY || REACTOR_NETTY; + static final String SPRING_REDIRECTS_PROPERTY = "spring.http.client.redirects"; + static final String SPRING_HTTP_FACTORY_PROPERTY = "spring.http.client.factory"; @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - HttpRedirects redirects = environment.getProperty("spring.http.client.settings.redirects", - HttpRedirects.class); + HttpRedirects redirects = environment.getProperty(SPRING_REDIRECTS_PROPERTY, HttpRedirects.class); if (redirects == null) { // the user hasn't set anything, change the default environment.getPropertySources() .addFirst(new MapPropertySource("gatewayHttpClientProperties", - Map.of("spring.http.client.settings.redirects", HttpRedirects.DONT_FOLLOW))); + Map.of(SPRING_REDIRECTS_PROPERTY, HttpRedirects.DONT_FOLLOW))); } - Factory factory = environment.getProperty("spring.http.client.settings.factory", Factory.class); + Factory factory = environment.getProperty(SPRING_HTTP_FACTORY_PROPERTY, Factory.class); boolean setJdkHttpClientProperties = false; if (factory == null && !HIGHER_PRIORITY) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 886a7429..0eb0ff71 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -142,11 +142,8 @@ public class GatewayServerMvcAutoConfigurationTests { @Test void gatewayHttpClientPropertiesWork() { ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class) - .properties("spring.main.web-application-type=none", - "spring.cloud.gateway.mvc.http-client.connect-timeout=1s", - "spring.cloud.gateway.mvc.http-client.read-timeout=2s", - "spring.cloud.gateway.mvc.http-client.ssl-bundle=mybundle", - "spring.cloud.gateway.mvc.http-client.type=autodetect", + .properties("spring.main.web-application-type=none", "spring.http.client.connect-timeout=1s", + "spring.http.client.read-timeout=2s", "spring.http.client.ssl.bundle=mybundle", "spring.ssl.bundle.pem.mybundle.keystore.certificate=" + cert, "spring.ssl.bundle.pem.mybundle.keystore.key=" + key) .run(); @@ -201,7 +198,7 @@ public class GatewayServerMvcAutoConfigurationTests { @Test void settingHttpClientFactoryWorks() { ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class) - .properties("spring.main.web-application-type=none", "spring.http.client.settings.factory=simple") + .properties("spring.main.web-application-type=none", "spring.http.client.factory=simple") .run(); ClientHttpRequestFactoryBuilder builder = context.getBean(ClientHttpRequestFactoryBuilder.class); assertThat(builder).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index f72b1943..4efa9b8c 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -142,8 +142,7 @@ import static org.springframework.web.servlet.function.RequestPredicates.POST; import static org.springframework.web.servlet.function.RequestPredicates.path; @SuppressWarnings("unchecked") -@SpringBootTest( - properties = { "spring.cloud.gateway.mvc.http-client.type=jdk", "spring.cloud.gateway.function.enabled=false" }, +@SpringBootTest(properties = { "spring.http.client.factory=jdk", "spring.cloud.gateway.function.enabled=false" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) @ExtendWith(OutputCaptureExtension.class) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java index a0ee50b8..cbb6e0a6 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java @@ -60,58 +60,58 @@ class AfterFilterFunctionsTests { @Test void doesNotRemoveJsonAttributes() { restClient.get() - .uri("/anything/does_not/remove_json_attributes") - .exchange() - .expectStatus() - .isOk() - .expectBody(Map.class) - .consumeWith(res -> { - assertThat(res.getResponseBody()).containsEntry("foo", "bar"); - assertThat(res.getResponseBody()).containsEntry("baz", "qux"); - }); + .uri("/anything/does_not/remove_json_attributes") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).containsEntry("foo", "bar"); + assertThat(res.getResponseBody()).containsEntry("baz", "qux"); + }); } @Test void removeJsonAttributesToAvoidBeingRecursive() { restClient.get() - .uri("/anything/remove_json_attributes_to_avoid_being_recursive") - .exchange() - .expectStatus() - .isOk() - .expectBody(Map.class) - .consumeWith(res -> { - assertThat(res.getResponseBody()).doesNotContainKey("foo"); - assertThat(res.getResponseBody()).containsEntry("baz", "qux"); - }); + .uri("/anything/remove_json_attributes_to_avoid_being_recursive") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).doesNotContainKey("foo"); + assertThat(res.getResponseBody()).containsEntry("baz", "qux"); + }); } @Test void removeJsonAttributesRecursively() { restClient.get() - .uri("/anything/remove_json_attributes_recursively") - .exchange() - .expectStatus() - .isOk() - .expectBody(Map.class) - .consumeWith(res -> { - assertThat(res.getResponseBody()).containsKey("foo"); - assertThat((Map) res.getResponseBody().get("foo")).containsEntry("bar", "A"); - assertThat(res.getResponseBody()).containsEntry("quux", "C"); - assertThat(res.getResponseBody()).doesNotContainKey("qux"); - }); + .uri("/anything/remove_json_attributes_recursively") + .exchange() + .expectStatus() + .isOk() + .expectBody(Map.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).containsKey("foo"); + assertThat((Map) res.getResponseBody().get("foo")).containsEntry("bar", "A"); + assertThat(res.getResponseBody()).containsEntry("quux", "C"); + assertThat(res.getResponseBody()).doesNotContainKey("qux"); + }); } @Test void raisedErrorWhenRemoveJsonAttributes() { restClient.get() - .uri("/anything/raised_error_when_remove_json_attributes") - .exchange() - .expectStatus() - .is5xxServerError() - .expectBody(String.class) - .consumeWith(res -> { - assertThat(res.getResponseBody()).isEqualTo("Failed to process JSON of response body."); - }); + .uri("/anything/raised_error_when_remove_json_attributes") + .exchange() + .expectStatus() + .is5xxServerError() + .expectBody(String.class) + .consumeWith(res -> { + assertThat(res.getResponseBody()).isEqualTo("Failed to process JSON of response body."); + }); } @SpringBootConfiguration From a4a4002a5cb7474ea869a74485dbdb18135b25f7 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 13 May 2025 15:39:09 -0400 Subject: [PATCH 51/85] Merge pull request #3711 from qnnn/fix-generateId ensure generateId executes on the scheduler thread specified by publishOn --- .../cloud/gateway/route/CompositeRouteDefinitionLocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java index 8e54feb1..db116fa7 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/CompositeRouteDefinitionLocator.java @@ -65,7 +65,7 @@ public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator { } protected Mono randomId() { - return Mono.fromSupplier(idGenerator::generateId).map(UUID::toString).publishOn(Schedulers.boundedElastic()); + return Mono.fromSupplier(idGenerator::generateId).publishOn(Schedulers.boundedElastic()).map(UUID::toString); } } From 2a1d8318b858342b39e844ebc23c4ced86065774 Mon Sep 17 00:00:00 2001 From: Sebastien <5930188+SebHeuze@users.noreply.github.com> Date: Tue, 15 Apr 2025 22:12:06 +0200 Subject: [PATCH 52/85] Fix prefixPath double encoding Fixes gh-3769 Signed-off-by: Sebastien <5930188+SebHeuze@users.noreply.github.com> --- .../mvc/filter/BeforeFilterFunctions.java | 3 +- .../filter/BeforeFilterFunctionsTests.java | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 0e95bf82..6c7e6725 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -195,7 +195,8 @@ public abstract class BeforeFilterFunctions { String newPath = uri.getRawPath() + request.uri().getRawPath(); - URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).build().toUri(); + URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()) + .replacePath(newPath).build(true).toUri(); return ServerRequest.from(request).uri(prefixedUri).build(); }; } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index 8c8a12ee..42743b9b 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -243,4 +243,32 @@ class BeforeFilterFunctionsTests { .isEqualTo("/modified/path/with%E2%80%93en%E2%80%93dashes%20and%20spaces"); } + @Test + void prefixPath() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders + .get("http://localhost/get").buildRequest(null); + + ServerRequest request = ServerRequest.create(servletRequest, + Collections.emptyList()); + + ServerRequest modified = BeforeFilterFunctions.prefixPath("/prefix") + .apply(request); + + assertThat(modified.uri().getRawPath()).isEqualTo("/prefix/get"); + } + + @Test + void prefixEncodedPath() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders + .get("http://localhost/get/é").buildRequest(null); + + ServerRequest request = ServerRequest.create(servletRequest, + Collections.emptyList()); + + ServerRequest modified = BeforeFilterFunctions.prefixPath("/pre fix") + .apply(request); + + assertThat(modified.uri().getRawPath()).isEqualTo("/pre%20fix/get/%C3%A9"); + } + } From a9c80d7409145bec968fdf6e9c24b6013b3ee56b Mon Sep 17 00:00:00 2001 From: spring-builds Date: Wed, 14 May 2025 13:26:21 +0000 Subject: [PATCH 53/85] Bumping versions --- .../mvc/filter/BeforeFilterFunctions.java | 3 +-- .../mvc/filter/BeforeFilterFunctionsTests.java | 18 ++++++------------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 6c7e6725..3c86e394 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -195,8 +195,7 @@ public abstract class BeforeFilterFunctions { String newPath = uri.getRawPath() + request.uri().getRawPath(); - URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()) - .replacePath(newPath).build(true).toUri(); + URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).build(true).toUri(); return ServerRequest.from(request).uri(prefixedUri).build(); }; } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index 42743b9b..a8777c56 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -245,28 +245,22 @@ class BeforeFilterFunctionsTests { @Test void prefixPath() { - MockHttpServletRequest servletRequest = MockMvcRequestBuilders - .get("http://localhost/get").buildRequest(null); + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get").buildRequest(null); - ServerRequest request = ServerRequest.create(servletRequest, - Collections.emptyList()); + ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); - ServerRequest modified = BeforeFilterFunctions.prefixPath("/prefix") - .apply(request); + ServerRequest modified = BeforeFilterFunctions.prefixPath("/prefix").apply(request); assertThat(modified.uri().getRawPath()).isEqualTo("/prefix/get"); } @Test void prefixEncodedPath() { - MockHttpServletRequest servletRequest = MockMvcRequestBuilders - .get("http://localhost/get/é").buildRequest(null); + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/get/é").buildRequest(null); - ServerRequest request = ServerRequest.create(servletRequest, - Collections.emptyList()); + ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); - ServerRequest modified = BeforeFilterFunctions.prefixPath("/pre fix") - .apply(request); + ServerRequest modified = BeforeFilterFunctions.prefixPath("/pre fix").apply(request); assertThat(modified.uri().getRawPath()).isEqualTo("/pre%20fix/get/%C3%A9"); } From 5fe6ed55a966b512106b2ea3f81fa3fc9875c349 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Wed, 14 May 2025 23:57:21 +0900 Subject: [PATCH 54/85] Remove unnecessary query parameter encoding check by assuming decoded parameters from serverRequest Signed-off-by: raccoonback --- .../handler/ProxyExchangeHandlerFunction.java | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java index 5a724800..6923f2d6 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchangeHandlerFunction.java @@ -87,7 +87,7 @@ public class ProxyExchangeHandlerFunction @Override public ServerResponse handle(ServerRequest serverRequest) { URI uri = uriResolver.apply(serverRequest); - MultiValueMap params = ensureEncodedQueryParameters(serverRequest); + MultiValueMap params = MvcUtils.encodeQueryParams(serverRequest.params()); // @formatter:off URI url = UriComponentsBuilder.fromUri(serverRequest.uri()) .scheme(uri.getScheme()) @@ -134,38 +134,6 @@ public class ProxyExchangeHandlerFunction return filtered; } - private static MultiValueMap ensureEncodedQueryParameters(ServerRequest serverRequest) { - boolean encoded = containsEncodedQuery(serverRequest.uri(), serverRequest.params()); - MultiValueMap params = serverRequest.params(); - if (!encoded) { - params = MvcUtils.encodeQueryParams(serverRequest.params()); - } - return params; - } - - private static boolean containsEncodedQuery(URI uri, MultiValueMap params) { - String rawQuery = uri.getRawQuery(); - boolean encoded = (rawQuery != null && rawQuery.contains("%")) - || (uri.getRawPath() != null && uri.getRawPath().contains("%")); - - // Verify if it is really fully encoded. Treat partial encoded as unencoded. - if (encoded) { - try { - UriComponentsBuilder.fromUri(uri).replaceQueryParams(params).build(true); - return true; - } - catch (IllegalArgumentException ignored) { - if (log.isTraceEnabled()) { - log.trace("Error in containsEncodedParts", ignored); - } - } - - return false; - } - - return false; - } - public interface URIResolver extends Function { } From 8a9842103f25bf51735f2cd176821a7bd5ae55c1 Mon Sep 17 00:00:00 2001 From: PeterMue <3819198+PeterMue@users.noreply.github.com> Date: Tue, 22 Apr 2025 16:19:50 +0200 Subject: [PATCH 55/85] fixes gh-3774 Configure CORS after refresh routes completed on RefreshRoutesResultEvent Signed-off-by: PeterMue <3819198+PeterMue@users.noreply.github.com> --- .../CorsGatewayFilterApplicationListener.java | 8 +- ...wayControllerEndpointRedisRefreshTest.java | 148 ++++++++++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java index 337588b8..ebe3e148 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java @@ -25,7 +25,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import org.springframework.cloud.gateway.config.GlobalCorsProperties; -import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.event.RefreshRoutesResultEvent; import org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping; import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory; import org.springframework.cloud.gateway.route.Route; @@ -34,14 +34,14 @@ import org.springframework.context.ApplicationListener; import org.springframework.web.cors.CorsConfiguration; /** - * This class updates Cors configuration each time a {@link RefreshRoutesEvent} is + * This class updates Cors configuration each time a {@link RefreshRoutesResultEvent} is * consumed. The {@link Route}'s predicates are inspected for a * {@link PathRoutePredicateFactory} and the first pattern is used. * * @author Fredrich Ombico * @author Abel Salgado Romero */ -public class CorsGatewayFilterApplicationListener implements ApplicationListener { +public class CorsGatewayFilterApplicationListener implements ApplicationListener { private final GlobalCorsProperties globalCorsProperties; @@ -61,7 +61,7 @@ public class CorsGatewayFilterApplicationListener implements ApplicationListener } @Override - public void onApplicationEvent(RefreshRoutesEvent event) { + public void onApplicationEvent(RefreshRoutesResultEvent event) { routeLocator.getRoutes().collectList().subscribe(routes -> { // pre-populate with pre-existing global cors configurations to combine with. var corsConfigurations = new HashMap<>(globalCorsProperties.getCorsConfigurations()); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java new file mode 100644 index 00000000..1d630bac --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java @@ -0,0 +1,148 @@ +/* + * Copyright 2013-2024 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.actuate; + +import java.net.URI; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.BodyInserters; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Peter Müller + */ +@SpringBootTest(properties = {"management.endpoint.gateway.enabled=true", + "management.endpoints.web.exposure.include=*", "spring.cloud.gateway.actuator.verbose.enabled=true"}, + webEnvironment = RANDOM_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@ActiveProfiles("redis-route-repository") +@Testcontainers +@Tag("DockerRequired") +public class GatewayControllerEndpointRedisRefreshTest { + + @Container + public static GenericContainer redis = new GenericContainer<>("redis:5.0.14-alpine").withExposedPorts(6379); + + @BeforeAll + public static void startRedisContainer() { + redis.start(); + } + + @DynamicPropertySource + static void containerProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.redis.host", redis::getHost); + registry.add("spring.data.redis.port", redis::getFirstMappedPort); + } + + @Autowired + WebTestClient testClient; + + @LocalServerPort + int port; + + @Test + public void testCorsConfigurationAfterReload() { + Map cors = new HashMap<>(); + cors.put("allowCredentials", false); + cors.put("allowedOrigins", "*"); + cors.put("allowedMethods", "GET"); + + createOrUpdateRouteWithCors(cors); + + Awaitility.await().atMost(Duration.ofSeconds(3)).untilAsserted(() -> assertRouteHasCorsConfig(cors)); + Awaitility.await().atMost(Duration.ofSeconds(3)).untilAsserted(() -> assertPreflightAllowOrigin("*")); + + cors.put("allowedOrigins", "http://example.org"); + createOrUpdateRouteWithCors(cors); + + Awaitility.await().atMost(Duration.ofSeconds(3)).untilAsserted(() -> assertRouteHasCorsConfig(cors)); + Awaitility.await().atMost(Duration.ofSeconds(3)) + .untilAsserted(() -> assertPreflightAllowOrigin("http://example.org")); + } + + void createOrUpdateRouteWithCors(Map cors) { + RouteDefinition testRouteDefinition = new RouteDefinition(); + testRouteDefinition.setUri(URI.create("http://example.org")); + + PredicateDefinition methodRoutePredicateDefinition = new PredicateDefinition("Method=GET"); + testRouteDefinition.setPredicates(List.of(methodRoutePredicateDefinition)); + + testRouteDefinition.setMetadata(Map.of("cors", cors)); + + testClient.post() + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .accept(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(testRouteDefinition)) + .exchange() + .expectStatus() + .isCreated(); + + testClient.post() + .uri("http://localhost:" + port + "/actuator/gateway/refresh") + .exchange() + .expectStatus() + .isOk(); + } + + void assertRouteHasCorsConfig(Map cors) { + testClient.get() + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .exchange() + .expectStatus() + .isOk() + .expectBody() + .jsonPath("$.metadata") + .value(map -> assertThat((Map) map).hasSize(1) + .containsEntry("cors", cors)); + } + + void assertPreflightAllowOrigin(String origin) { + testClient.options() + .uri("http://localhost:" + port + "/") + .header("Origin", "http://example.org") + .header("Access-Control-Request-Method", "GET") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Access-Control-Allow-Origin", origin); + } +} From 365e3bae31fcc5e083d77080edb367c94f590245 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Wed, 14 May 2025 18:53:42 +0000 Subject: [PATCH 56/85] Bumping versions --- ...wayControllerEndpointRedisRefreshTest.java | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java index 1d630bac..b2b331bf 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java @@ -49,8 +49,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen /** * @author Peter Müller */ -@SpringBootTest(properties = {"management.endpoint.gateway.enabled=true", - "management.endpoints.web.exposure.include=*", "spring.cloud.gateway.actuator.verbose.enabled=true"}, +@SpringBootTest(properties = { "management.endpoint.gateway.enabled=true", + "management.endpoints.web.exposure.include=*", "spring.cloud.gateway.actuator.verbose.enabled=true" }, webEnvironment = RANDOM_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @ActiveProfiles("redis-route-repository") @@ -94,8 +94,9 @@ public class GatewayControllerEndpointRedisRefreshTest { createOrUpdateRouteWithCors(cors); Awaitility.await().atMost(Duration.ofSeconds(3)).untilAsserted(() -> assertRouteHasCorsConfig(cors)); - Awaitility.await().atMost(Duration.ofSeconds(3)) - .untilAsserted(() -> assertPreflightAllowOrigin("http://example.org")); + Awaitility.await() + .atMost(Duration.ofSeconds(3)) + .untilAsserted(() -> assertPreflightAllowOrigin("http://example.org")); } void createOrUpdateRouteWithCors(Map cors) { @@ -108,41 +109,41 @@ public class GatewayControllerEndpointRedisRefreshTest { testRouteDefinition.setMetadata(Map.of("cors", cors)); testClient.post() - .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") - .accept(MediaType.APPLICATION_JSON) - .body(BodyInserters.fromValue(testRouteDefinition)) - .exchange() - .expectStatus() - .isCreated(); + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .accept(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(testRouteDefinition)) + .exchange() + .expectStatus() + .isCreated(); testClient.post() - .uri("http://localhost:" + port + "/actuator/gateway/refresh") - .exchange() - .expectStatus() - .isOk(); + .uri("http://localhost:" + port + "/actuator/gateway/refresh") + .exchange() + .expectStatus() + .isOk(); } void assertRouteHasCorsConfig(Map cors) { testClient.get() - .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") - .exchange() - .expectStatus() - .isOk() - .expectBody() - .jsonPath("$.metadata") - .value(map -> assertThat((Map) map).hasSize(1) - .containsEntry("cors", cors)); + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .exchange() + .expectStatus() + .isOk() + .expectBody() + .jsonPath("$.metadata") + .value(map -> assertThat((Map) map).hasSize(1).containsEntry("cors", cors)); } void assertPreflightAllowOrigin(String origin) { testClient.options() - .uri("http://localhost:" + port + "/") - .header("Origin", "http://example.org") - .header("Access-Control-Request-Method", "GET") - .exchange() - .expectStatus() - .isOk() - .expectHeader() - .valueEquals("Access-Control-Allow-Origin", origin); + .uri("http://localhost:" + port + "/") + .header("Origin", "http://example.org") + .header("Access-Control-Request-Method", "GET") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Access-Control-Allow-Origin", origin); } + } From b3954c378c29eae12e6f03f94ef80b9830efd4a7 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Thu, 27 Mar 2025 14:51:48 +0800 Subject: [PATCH 57/85] fix RemoveResponseHeaderGatewayFilter remove header Signed-off-by: jiangyuan --- .../factory/RemoveResponseHeaderGatewayFilterFactory.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java index bf563fe0..84770879 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java @@ -48,7 +48,11 @@ public class RemoveResponseHeaderGatewayFilterFactory @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange) - .then(Mono.fromRunnable(() -> exchange.getResponse().getHeaders().remove(config.getName()))); + .then(Mono.fromRunnable(() -> { + if (!exchange.getResponse().isCommitted()) { + exchange.getResponse().getHeaders().remove(config.getName()); + } + })); } @Override From 54e151623f793dcd85444ac413bb57e113579699 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Thu, 27 Mar 2025 14:57:16 +0800 Subject: [PATCH 58/85] fix format Signed-off-by: jiangyuan --- .../RemoveResponseHeaderGatewayFilterFactory.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java index 84770879..e7cc8993 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java @@ -47,12 +47,11 @@ public class RemoveResponseHeaderGatewayFilterFactory return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - return chain.filter(exchange) - .then(Mono.fromRunnable(() -> { - if (!exchange.getResponse().isCommitted()) { - exchange.getResponse().getHeaders().remove(config.getName()); - } - })); + return chain.filter(exchange).then(Mono.fromRunnable(() -> { + if (!exchange.getResponse().isCommitted()) { + exchange.getResponse().getHeaders().remove(config.getName()); + } + })); } @Override From 7f6fcddc9ffedbd13af5c31e45ea500795fba7d4 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Mon, 17 Mar 2025 21:10:26 +0800 Subject: [PATCH 59/85] fix httpclient5.x connection leak Signed-off-by: jiangyuan --- .../server/mvc/filter/RetryFilterFunctions.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java index 272b1e6c..909aa74c 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.server.mvc.filter; import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -75,6 +76,7 @@ public abstract class RetryFilterFunctions { if (config.isCacheBody()) { MvcUtils.getOrCacheBody(request); } + reset(request); ServerResponse serverResponse = next.handle(request); if (isRetryableStatusCode(serverResponse.statusCode(), config) @@ -86,6 +88,20 @@ public abstract class RetryFilterFunctions { }); } + /** + * reset attribute + * + * @param request + * @throws IOException + */ + private static void reset(ServerRequest request) throws IOException { + InputStream inputStream = MvcUtils.getAttribute(request, MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR); + if (inputStream != null) { + inputStream.close(); + MvcUtils.putAttribute(request, MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, null); + } + } + private static boolean isRetryableStatusCode(HttpStatusCode httpStatus, RetryConfig config) { return config.getSeries().stream().anyMatch(series -> HttpStatus.Series.resolve(httpStatus.value()) == series); } From a261d17b4e594092d9f2234af975bf7fe947c01c Mon Sep 17 00:00:00 2001 From: joecqupt Date: Mon, 17 Mar 2025 22:47:18 +0800 Subject: [PATCH 60/85] fix format Signed-off-by: joecqupt Signed-off-by: jiangyuan --- .../gateway/server/mvc/filter/RetryFilterFunctions.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java index 909aa74c..9c421727 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java @@ -88,12 +88,6 @@ public abstract class RetryFilterFunctions { }); } - /** - * reset attribute - * - * @param request - * @throws IOException - */ private static void reset(ServerRequest request) throws IOException { InputStream inputStream = MvcUtils.getAttribute(request, MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR); if (inputStream != null) { From 7b79e181f2c19ab5f6837191fff5d10aab316644 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Mon, 31 Mar 2025 13:09:37 +0800 Subject: [PATCH 61/85] add client response attrs Signed-off-by: jiangyuan test ci build --- .../cloud/gateway/server/mvc/common/MvcUtils.java | 5 +++++ .../server/mvc/filter/RetryFilterFunctions.java | 10 +++++----- .../handler/ClientHttpRequestFactoryProxyExchange.java | 1 + .../server/mvc/handler/RestClientProxyExchange.java | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java index 05c073ed..27bfa1e1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java @@ -63,6 +63,11 @@ public abstract class MvcUtils { */ public static final String CLIENT_RESPONSE_INPUT_STREAM_ATTR = qualify("cachedClientResponseBody"); + /** + * Client response key. + */ + public static final String CLIENT_RESPONSE_ATTR = qualify("cachedClientResponse"); + /** * CircuitBreaker execution exception attribute name. */ diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java index 9c421727..4de07b1d 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctions.java @@ -17,7 +17,6 @@ package org.springframework.cloud.gateway.server.mvc.filter; import java.io.IOException; -import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -34,6 +33,7 @@ import org.springframework.core.NestedRuntimeException; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; +import org.springframework.http.client.ClientHttpResponse; import org.springframework.retry.RetryContext; import org.springframework.retry.RetryPolicy; import org.springframework.retry.policy.CompositeRetryPolicy; @@ -89,10 +89,10 @@ public abstract class RetryFilterFunctions { } private static void reset(ServerRequest request) throws IOException { - InputStream inputStream = MvcUtils.getAttribute(request, MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR); - if (inputStream != null) { - inputStream.close(); - MvcUtils.putAttribute(request, MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, null); + ClientHttpResponse clientHttpResponse = MvcUtils.getAttribute(request, MvcUtils.CLIENT_RESPONSE_ATTR); + if (clientHttpResponse != null) { + clientHttpResponse.close(); + MvcUtils.putAttribute(request, MvcUtils.CLIENT_RESPONSE_ATTR, null); } } diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java index 5c17dd2d..db1685d9 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java @@ -56,6 +56,7 @@ public class ClientHttpRequestFactoryProxyExchange extends AbstractProxyExchange InputStream body = clientHttpResponse.getBody(); // put the body input stream in a request attribute so filters can read it. MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, body); + MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_ATTR, clientHttpResponse); ServerResponse serverResponse = GatewayServerResponse.status(clientHttpResponse.getStatusCode()) .build((req, httpServletResponse) -> { try (clientHttpResponse) { diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java index 46e9d032..315a061f 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java @@ -72,6 +72,7 @@ public class RestClientProxyExchange extends AbstractProxyExchange { InputStream body = clientResponse.getBody(); // put the body input stream in a request attribute so filters can read it. MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR, body); + MvcUtils.putAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_ATTR, clientResponse); ServerResponse serverResponse = GatewayServerResponse.status(clientResponse.getStatusCode()) .build((req, httpServletResponse) -> { try (clientResponse) { From 7c9d43c0192e76cb94fe5be4edb66ca4e99cb4d5 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Wed, 2 Apr 2025 22:22:31 +0800 Subject: [PATCH 62/85] add unit-test Signed-off-by: jiangyuan --- .../mvc/filter/RetryFilterFunctionTests.java | 60 +++++++++++++++++++ .../src/test/resources/application.yml | 5 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java index edae11e4..430f3934 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java @@ -16,30 +16,41 @@ package org.springframework.cloud.gateway.server.mvc.filter; +import java.time.Duration; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; +import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchange; +import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction; +import org.springframework.cloud.gateway.server.mvc.handler.RestClientProxyExchange; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.LocalServerPortUriResolver; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.log.LogMessage; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -47,11 +58,14 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestClient; +import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.adaptCachedBody; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.prefixPath; +import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.setPath; import static org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.retry; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -93,6 +107,17 @@ public class RetryFilterFunctionTests { .isEqualTo("3"); } + @Test + public void retryWorksWithHttpComponentsClient() { + restClient.get() + .uri("/retrywithhttpcomponentsclient?key=retryWorksWithHttpComponentsClient") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("3"); + } + @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) @@ -110,6 +135,41 @@ public class RetryFilterFunctionTests { // @formatter:on } + @Bean + public RouterFunction gatewayRouterFunctionsRetryWithHttpComponentsClient( + GatewayMvcProperties properties, + ObjectProvider requestHttpHeadersFilters, + ObjectProvider responseHttpHeadersFilters, + ApplicationContext applicationContext) { + + // build httpComponents client factory + ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryBuilder.httpComponents() + .withConnectionManagerCustomizer(builder -> builder.setMaxConnTotal(2).setMaxConnPerRoute(2)) + .withDefaultRequestConfigCustomizer( + c -> c.setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(3000)))) + .build(); + + // build proxyExchange use httpComponents + RestClient.Builder restClientBuilder = RestClient.builder(); + restClientBuilder.requestFactory(clientHttpRequestFactory); + ProxyExchange proxyExchange = new RestClientProxyExchange(restClientBuilder.build(), properties); + + // build handler function use httpComponents + ProxyExchangeHandlerFunction function = new ProxyExchangeHandlerFunction(proxyExchange, + requestHttpHeadersFilters, responseHttpHeadersFilters); + function.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); + + // @formatter:off + return route("testretrywithhttpcomponentsclient") + .GET("/retrywithhttpcomponentsclient", function) + .before(new LocalServerPortUriResolver()) + .filter(retry(3)) + .filter(setPath("/retry")) + .filter(prefixPath("/do")) + .build(); + // @formatter:on + } + @Bean public RouterFunction gatewayRouterFunctionsRetryBody() { // @formatter:off diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application.yml index 9bc1759e..60537dfc 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application.yml @@ -6,4 +6,7 @@ logging: org.springframework.retry: TRACE spring: mvc: - log-request-details: true \ No newline at end of file + log-request-details: true + http: + client: + factory: REACTOR \ No newline at end of file From 5247da10f269a57fd88b2d6d11205ce144fe8545 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Thu, 3 Apr 2025 11:10:26 +0800 Subject: [PATCH 63/85] fix format Signed-off-by: jiangyuan --- .../gateway/server/mvc/filter/RetryFilterFunctionTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java index 430f3934..be2bfcba 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java @@ -59,7 +59,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestClient; -import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; From bcf26e8df34f2d8099d731ae30340d168dec482c Mon Sep 17 00:00:00 2001 From: joecqupt Date: Mon, 21 Apr 2025 01:49:18 +0800 Subject: [PATCH 64/85] add httpclint integration test module Signed-off-by: joecqupt --- .../httpclient/pom.xml | 77 +++++++++++ .../httpclient/HttpClientApplication.java | 121 ++++++++++++++++++ .../src/main/resources/application.yml | 3 + .../HttpClientApplicationTests.java | 42 ++++++ .../pom.xml | 1 + .../mvc/filter/RetryFilterFunctionTests.java | 59 --------- .../src/test/resources/application.yml | 5 +- 7 files changed, 245 insertions(+), 63 deletions(-) create mode 100644 spring-cloud-gateway-integration-tests/httpclient/pom.xml create mode 100644 spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java create mode 100644 spring-cloud-gateway-integration-tests/httpclient/src/main/resources/application.yml create mode 100644 spring-cloud-gateway-integration-tests/httpclient/src/test/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplicationTests.java diff --git a/spring-cloud-gateway-integration-tests/httpclient/pom.xml b/spring-cloud-gateway-integration-tests/httpclient/pom.xml new file mode 100644 index 00000000..54472f7b --- /dev/null +++ b/spring-cloud-gateway-integration-tests/httpclient/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + + httpclient + jar + + Spring Cloud Gateway HttpClient Integration Test + Spring Cloud Gateway HttpClient Integration Test + + + + + + org.springframework.cloud + spring-cloud-gateway-integration-tests + 4.3.0-SNAPSHOT + .. + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.cloud + spring-cloud-starter-gateway-server-webmvc + + + + org.springframework.retry + spring-retry + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.assertj + assertj-core + test + + + + + + + maven-deploy-plugin + + true + + + + + diff --git a/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java b/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java new file mode 100644 index 00000000..6e198797 --- /dev/null +++ b/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013-2025 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.tests.httpclient; + +import java.time.Duration; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hc.core5.util.Timeout; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; +import org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.prefixPath; +import static org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions.lb; +import static org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.retry; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; + +/** + * @author jiangyuan + */ +@SpringBootConfiguration +@EnableAutoConfiguration +@LoadBalancerClient(name = "myservice", configuration = MyServiceConf.class) +public class HttpClientApplication { + + public static void main(String[] args) { + SpringApplication.run(HttpClientApplication.class, args); + } + + @Bean + public HttpComponentsClientHttpRequestFactoryBuilder httpComponentsClientHttpRequestFactoryBuilder() { + return ClientHttpRequestFactoryBuilder.httpComponents() + .withConnectionManagerCustomizer(builder -> builder.setMaxConnTotal(2).setMaxConnPerRoute(2)) + .withDefaultRequestConfigCustomizer( + c -> c.setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(3000)))); + } + + @Bean + public RouterFunction gatewayRouterFunctionsRetry() { + return route("test-retry").GET("/retry", http()) + .filter(lb("myservice")) + .filter(prefixPath("/do")) + .filter(retry(3)) + .build(); + } + + @RestController + protected static class RetryController { + + Log log = LogFactory.getLog(getClass()); + + ConcurrentHashMap map = new ConcurrentHashMap<>(); + + @GetMapping("/do/retry") + public ResponseEntity retry(@RequestParam("key") String key, + @RequestParam(name = "count", defaultValue = "3") int count, + @RequestParam(name = "failStatus", required = false) Integer failStatus) { + AtomicInteger num = map.computeIfAbsent(key, s -> new AtomicInteger()); + int i = num.incrementAndGet(); + log.warn("Retry count: " + i); + String body = String.valueOf(i); + if (i < count) { + HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; + if (failStatus != null) { + httpStatus = HttpStatus.resolve(failStatus); + } + return ResponseEntity.status(httpStatus).header("X-Retry-Count", body).body("temporarily broken"); + } + return ResponseEntity.status(HttpStatus.OK).header("X-Retry-Count", body).body(body); + } + + } + +} + +class MyServiceConf { + + @Value("${local.server.port}") + private int port = 0; + + @Bean + public ServiceInstanceListSupplier staticServiceInstanceListSupplier() { + return ServiceInstanceListSuppliers.from("myservice", + new DefaultServiceInstance("myservice-1", "myservice", "localhost", port, false)); + } + +} diff --git a/spring-cloud-gateway-integration-tests/httpclient/src/main/resources/application.yml b/spring-cloud-gateway-integration-tests/httpclient/src/main/resources/application.yml new file mode 100644 index 00000000..106caafa --- /dev/null +++ b/spring-cloud-gateway-integration-tests/httpclient/src/main/resources/application.yml @@ -0,0 +1,3 @@ +logging: + level: + org.springframework.cloud.gateway: TRACE diff --git a/spring-cloud-gateway-integration-tests/httpclient/src/test/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplicationTests.java b/spring-cloud-gateway-integration-tests/httpclient/src/test/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplicationTests.java new file mode 100644 index 00000000..13269d41 --- /dev/null +++ b/spring-cloud-gateway-integration-tests/httpclient/src/test/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplicationTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2025 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.tests.httpclient; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.reactive.server.WebTestClient; + +/** + * @author jiangyuan + */ +@SpringBootTest(classes = HttpClientApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext +public class HttpClientApplicationTests { + + @LocalServerPort + private int port; + + @Test + public void retryWorks() { + WebTestClient client = WebTestClient.bindToServer().baseUrl("http://localhost:" + port).build(); + client.get().uri("/retry?key=get").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("3"); + } + +} diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 8fc43a9b..cab51af8 100644 --- a/spring-cloud-gateway-integration-tests/pom.xml +++ b/spring-cloud-gateway-integration-tests/pom.xml @@ -24,6 +24,7 @@ grpc http2 mvc-failure-analyzer + httpclient diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java index be2bfcba..edae11e4 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java @@ -16,41 +16,30 @@ package org.springframework.cloud.gateway.server.mvc.filter; -import java.time.Duration; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; -import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchange; -import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction; -import org.springframework.cloud.gateway.server.mvc.handler.RestClientProxyExchange; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.LocalServerPortUriResolver; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.log.LogMessage; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -58,13 +47,11 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestClient; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.adaptCachedBody; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.prefixPath; -import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.setPath; import static org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.retry; import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -106,17 +93,6 @@ public class RetryFilterFunctionTests { .isEqualTo("3"); } - @Test - public void retryWorksWithHttpComponentsClient() { - restClient.get() - .uri("/retrywithhttpcomponentsclient?key=retryWorksWithHttpComponentsClient") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo("3"); - } - @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) @@ -134,41 +110,6 @@ public class RetryFilterFunctionTests { // @formatter:on } - @Bean - public RouterFunction gatewayRouterFunctionsRetryWithHttpComponentsClient( - GatewayMvcProperties properties, - ObjectProvider requestHttpHeadersFilters, - ObjectProvider responseHttpHeadersFilters, - ApplicationContext applicationContext) { - - // build httpComponents client factory - ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryBuilder.httpComponents() - .withConnectionManagerCustomizer(builder -> builder.setMaxConnTotal(2).setMaxConnPerRoute(2)) - .withDefaultRequestConfigCustomizer( - c -> c.setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(3000)))) - .build(); - - // build proxyExchange use httpComponents - RestClient.Builder restClientBuilder = RestClient.builder(); - restClientBuilder.requestFactory(clientHttpRequestFactory); - ProxyExchange proxyExchange = new RestClientProxyExchange(restClientBuilder.build(), properties); - - // build handler function use httpComponents - ProxyExchangeHandlerFunction function = new ProxyExchangeHandlerFunction(proxyExchange, - requestHttpHeadersFilters, responseHttpHeadersFilters); - function.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); - - // @formatter:off - return route("testretrywithhttpcomponentsclient") - .GET("/retrywithhttpcomponentsclient", function) - .before(new LocalServerPortUriResolver()) - .filter(retry(3)) - .filter(setPath("/retry")) - .filter(prefixPath("/do")) - .build(); - // @formatter:on - } - @Bean public RouterFunction gatewayRouterFunctionsRetryBody() { // @formatter:off diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application.yml index 60537dfc..9bc1759e 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application.yml @@ -6,7 +6,4 @@ logging: org.springframework.retry: TRACE spring: mvc: - log-request-details: true - http: - client: - factory: REACTOR \ No newline at end of file + log-request-details: true \ No newline at end of file From 4ff93c591c2dfb6a70043e6392fa3575a67b841e Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Thu, 15 May 2025 14:53:21 +0800 Subject: [PATCH 65/85] update base branch to 4.1.x Signed-off-by: jiangyuan --- .../httpclient/pom.xml | 4 +-- .../httpclient/HttpClientApplication.java | 25 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/spring-cloud-gateway-integration-tests/httpclient/pom.xml b/spring-cloud-gateway-integration-tests/httpclient/pom.xml index 54472f7b..08178c87 100644 --- a/spring-cloud-gateway-integration-tests/httpclient/pom.xml +++ b/spring-cloud-gateway-integration-tests/httpclient/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.3.0-SNAPSHOT + 4.1.8-SNAPSHOT .. @@ -34,7 +34,7 @@ org.springframework.cloud - spring-cloud-starter-gateway-server-webmvc + spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java b/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java index 6e198797..9390e611 100644 --- a/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java +++ b/spring-cloud-gateway-integration-tests/httpclient/src/main/java/org/springframework/cloud/gateway/tests/httpclient/HttpClientApplication.java @@ -22,14 +22,16 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.core5.util.Timeout; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; -import org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; @@ -37,6 +39,7 @@ import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSupplie import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -62,11 +65,19 @@ public class HttpClientApplication { } @Bean - public HttpComponentsClientHttpRequestFactoryBuilder httpComponentsClientHttpRequestFactoryBuilder() { - return ClientHttpRequestFactoryBuilder.httpComponents() - .withConnectionManagerCustomizer(builder -> builder.setMaxConnTotal(2).setMaxConnPerRoute(2)) - .withDefaultRequestConfigCustomizer( - c -> c.setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(3000)))); + public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() { + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(2); + connectionManager.setDefaultMaxPerRoute(2); + + CloseableHttpClient httpClient = HttpClients.custom() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig( + RequestConfig.custom().setConnectionRequestTimeout(Timeout.of(Duration.ofMillis(3000))).build()) + .build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + return factory; } @Bean From de7f393e407d360deac2d89ac55013b3452bfc13 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 15 May 2025 10:41:06 -0400 Subject: [PATCH 66/85] Fix parent version --- spring-cloud-gateway-integration-tests/httpclient/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-integration-tests/httpclient/pom.xml b/spring-cloud-gateway-integration-tests/httpclient/pom.xml index 08178c87..798b2a41 100644 --- a/spring-cloud-gateway-integration-tests/httpclient/pom.xml +++ b/spring-cloud-gateway-integration-tests/httpclient/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.1.8-SNAPSHOT + 4.2.3-SNAPSHOT .. From 931232b96098ad51c707ec9b1a3b6be705996254 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 15 May 2025 10:42:34 -0400 Subject: [PATCH 67/85] Fix parent version --- spring-cloud-gateway-integration-tests/httpclient/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-integration-tests/httpclient/pom.xml b/spring-cloud-gateway-integration-tests/httpclient/pom.xml index 798b2a41..f10b23de 100644 --- a/spring-cloud-gateway-integration-tests/httpclient/pom.xml +++ b/spring-cloud-gateway-integration-tests/httpclient/pom.xml @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-gateway-integration-tests - 4.2.3-SNAPSHOT + 4.3.0-SNAPSHOT .. From 98021b54c1fe8c11c71f16111ac63e7b0c8fbda2 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Thu, 15 May 2025 00:08:42 +0900 Subject: [PATCH 68/85] Fix improper encoding of '+' in query parameter values in mvc Signed-off-by: raccoonback --- .../gateway/server/mvc/filter/BeforeFilterFunctions.java | 3 +-- .../gateway/server/mvc/filter/BeforeFilterFunctionsTests.java | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 3c86e394..98f0bbc8 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -45,7 +45,6 @@ import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriTemplate; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.server.mvc.common.MvcUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -216,7 +215,7 @@ public abstract class BeforeFilterFunctions { MultiValueMap queryParams = new LinkedMultiValueMap<>(request.params()); queryParams.remove(name); - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = MvcUtils.encodeQueryParams(queryParams); // remove from uri URI newUri = UriComponentsBuilder.fromUri(request.uri()) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index a8777c56..c90b256c 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -119,6 +119,7 @@ class BeforeFilterFunctionsTests { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") .queryParam("foo", "bar") .queryParam("baz[]", "qux[]") + .queryParam("quux", "corge+") .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -127,7 +128,8 @@ class BeforeFilterFunctionsTests { assertThat(result.param("foo")).isEmpty(); assertThat(result.param("baz[]")).isPresent().hasValue("qux[]"); - assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D"); + assertThat(result.param("quux")).isPresent().hasValue("corge+"); + assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&quux=corge%2B"); } @Test From 330a43d63185f60b879f70c4d9cff43b541607ed Mon Sep 17 00:00:00 2001 From: raccoonback Date: Thu, 15 May 2025 08:32:24 +0900 Subject: [PATCH 69/85] Fix improper encoding of '+' in query parameter values Signed-off-by: raccoonback --- ...eRequestParameterGatewayFilterFactory.java | 5 +++-- ...eRequestParameterGatewayFilterFactory.java | 5 +++-- .../support/ServerWebExchangeUtils.java | 17 ++++++++++++++++ ...estParameterGatewayFilterFactoryTests.java | 20 +++++++++++++++++++ ...estParameterGatewayFilterFactoryTests.java | 6 ++++++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java index 9d17f6ef..b8469337 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactory.java @@ -24,12 +24,12 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -59,7 +59,8 @@ public class RemoveRequestParameterGatewayFilterFactory queryParams.remove(config.getName()); try { - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = ServerWebExchangeUtils + .encodeQueryParams(queryParams); URI newUri = UriComponentsBuilder.fromUri(request.getURI()) .replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java index 02bccdaf..18f5e588 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java @@ -24,13 +24,13 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriUtils; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -71,7 +71,8 @@ public class RewriteRequestParameterGatewayFilterFactory } try { - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = ServerWebExchangeUtils + .encodeQueryParams(queryParams); URI uri = uriComponentsBuilder.replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) .toUri(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java index 7585a182..fd185504 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java @@ -17,9 +17,11 @@ package org.springframework.cloud.gateway.support; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -48,9 +50,13 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; /** * @author Spencer Gibb @@ -260,6 +266,17 @@ public final class ServerWebExchangeUtils { return encoded; } + public static MultiValueMap encodeQueryParams(MultiValueMap params) { + MultiValueMap encodedQueryParams = new LinkedMultiValueMap<>(params.size()); + for (Map.Entry> entry : params.entrySet()) { + for (String value : entry.getValue()) { + encodedQueryParams.add(UriUtils.encode(entry.getKey(), StandardCharsets.UTF_8), + UriUtils.encode(value, StandardCharsets.UTF_8)); + } + } + return CollectionUtils.unmodifiableMultiValueMap(encodedQueryParams); + } + public static HttpStatus parse(String statusString) { HttpStatus httpStatus; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java index a96aef38..2eb96bb6 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestParameterGatewayFilterFactoryTests.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.net.URI; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -24,6 +26,7 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig; +import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; @@ -123,6 +126,23 @@ class RemoveRequestParameterGatewayFilterFactoryTests { assertThat(actualRequest.getQueryParams()).containsEntry("ccc", singletonList(",xyz")); } + @Test + void removeRequestParameterFilterShouldHandleRemainingPlusSignParams() { + MockServerHttpRequest request = MockServerHttpRequest + .method(HttpMethod.GET, URI.create("http://localhost?foo=bar&aaa=%2Bxyz")) + .build(); + exchange = MockServerWebExchange.from(request); + NameConfig config = new NameConfig(); + config.setName("foo"); + GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory().apply(config); + + filter.filter(exchange, filterChain); + + ServerHttpRequest actualRequest = captor.getValue().getRequest(); + assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo"); + assertThat(actualRequest.getQueryParams()).containsEntry("aaa", singletonList("+xyz")); + } + @Test void removeRequestParameterFilterShouldHandleEncodedParameterName() { MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost") diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java index f7803861..24aa900b 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactoryTests.java @@ -88,6 +88,12 @@ class RewriteRequestParameterGatewayFilterFactoryTests { Map.of("campaign[]", List.of("blue"), "color", List.of("white"))); } + @Test + void rewriteRequestParameterFilterWithPlusSign() { + testRewriteRequestParameterFilter("color", "white+", "campaign=blue%2B&color=green", + Map.of("campaign", List.of("blue+"), "color", List.of("white+"))); + } + private void testRewriteRequestParameterFilter(String name, String replacement, String query, Map> expectedQueryParams) { GatewayFilter filter = new RewriteRequestParameterGatewayFilterFactory() From a840fca27b1f0e6f4b89734ee7c3a7b9d6956615 Mon Sep 17 00:00:00 2001 From: raccoonback Date: Thu, 15 May 2025 13:19:35 +0900 Subject: [PATCH 70/85] Fix improper encoding of '+' in query parameter values when rewrite query parameter Signed-off-by: raccoonback --- .../mvc/filter/BeforeFilterFunctions.java | 2 +- .../filter/BeforeFilterFunctionsTests.java | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 6fb71b8d..80e859ac 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -351,7 +351,7 @@ public abstract class BeforeFilterFunctions { queryParams.add(name, replacement); } - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = MvcUtils.encodeQueryParams(queryParams); URI rewrittenUri = UriComponentsBuilder.fromUri(request.uri()) .replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index 0608ca9a..1ef0b2c7 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -129,11 +129,27 @@ class BeforeFilterFunctionsTests { assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo%5B%5D=replacement%5B%5D"); } + @Test + void rewritePlusSignRequestParameter() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") + .param("foo", "bar") + .param("baz", "qux") + .buildRequest(null); + + ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); + + ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement+").apply(request); + + assertThat(result.param("foo")).isPresent().hasValue("replacement+"); + assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo=replacement%2B"); + } + @Test void rewriteRequestParameterWithEncodedRemainParameters() { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") .param("foo", "bar") .param("baz[]", "qux[]") + .param("quux", "corge+") .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -141,7 +157,8 @@ class BeforeFilterFunctionsTests { ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request); assertThat(result.param("foo")).isPresent().hasValue("replacement"); - assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&foo=replacement"); + assertThat(result.uri().toString()) + .hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&quux=corge%2B&foo=replacement"); } @Test From c09f3831a0177160c0760cabec5b541a06c58fcd Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 16 May 2025 13:26:02 +0000 Subject: [PATCH 71/85] Bumping versions --- ...wayControllerEndpointRedisRefreshTest.java | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java index 1d630bac..b2b331bf 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointRedisRefreshTest.java @@ -49,8 +49,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen /** * @author Peter Müller */ -@SpringBootTest(properties = {"management.endpoint.gateway.enabled=true", - "management.endpoints.web.exposure.include=*", "spring.cloud.gateway.actuator.verbose.enabled=true"}, +@SpringBootTest(properties = { "management.endpoint.gateway.enabled=true", + "management.endpoints.web.exposure.include=*", "spring.cloud.gateway.actuator.verbose.enabled=true" }, webEnvironment = RANDOM_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @ActiveProfiles("redis-route-repository") @@ -94,8 +94,9 @@ public class GatewayControllerEndpointRedisRefreshTest { createOrUpdateRouteWithCors(cors); Awaitility.await().atMost(Duration.ofSeconds(3)).untilAsserted(() -> assertRouteHasCorsConfig(cors)); - Awaitility.await().atMost(Duration.ofSeconds(3)) - .untilAsserted(() -> assertPreflightAllowOrigin("http://example.org")); + Awaitility.await() + .atMost(Duration.ofSeconds(3)) + .untilAsserted(() -> assertPreflightAllowOrigin("http://example.org")); } void createOrUpdateRouteWithCors(Map cors) { @@ -108,41 +109,41 @@ public class GatewayControllerEndpointRedisRefreshTest { testRouteDefinition.setMetadata(Map.of("cors", cors)); testClient.post() - .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") - .accept(MediaType.APPLICATION_JSON) - .body(BodyInserters.fromValue(testRouteDefinition)) - .exchange() - .expectStatus() - .isCreated(); + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .accept(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(testRouteDefinition)) + .exchange() + .expectStatus() + .isCreated(); testClient.post() - .uri("http://localhost:" + port + "/actuator/gateway/refresh") - .exchange() - .expectStatus() - .isOk(); + .uri("http://localhost:" + port + "/actuator/gateway/refresh") + .exchange() + .expectStatus() + .isOk(); } void assertRouteHasCorsConfig(Map cors) { testClient.get() - .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") - .exchange() - .expectStatus() - .isOk() - .expectBody() - .jsonPath("$.metadata") - .value(map -> assertThat((Map) map).hasSize(1) - .containsEntry("cors", cors)); + .uri("http://localhost:" + port + "/actuator/gateway/routes/cors-test-route") + .exchange() + .expectStatus() + .isOk() + .expectBody() + .jsonPath("$.metadata") + .value(map -> assertThat((Map) map).hasSize(1).containsEntry("cors", cors)); } void assertPreflightAllowOrigin(String origin) { testClient.options() - .uri("http://localhost:" + port + "/") - .header("Origin", "http://example.org") - .header("Access-Control-Request-Method", "GET") - .exchange() - .expectStatus() - .isOk() - .expectHeader() - .valueEquals("Access-Control-Allow-Origin", origin); + .uri("http://localhost:" + port + "/") + .header("Origin", "http://example.org") + .header("Access-Control-Request-Method", "GET") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Access-Control-Allow-Origin", origin); } + } From 7b4dd7cc285d7f46b5f020b83cd8b0d93537cd40 Mon Sep 17 00:00:00 2001 From: Stepan Mikhailiuk Date: Tue, 20 May 2025 09:07:54 +0800 Subject: [PATCH 72/85] fix(*): remove unnecessary exception according review comments Signed-off-by: Stepan Mikhailiuk --- .../filter/factory/SetRequestUriGatewayFilterFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java index 2910d88d..8f87428d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java @@ -84,7 +84,8 @@ public class SetRequestUriGatewayFilterFactory String url = getUri(exchange, config); URI uri = URI.create(url); if (!uri.isAbsolute()) { - throw new IllegalArgumentException("URI is not absolute"); + log.info("Request url is invalid: url={}, error=URI is not absolute", url); + return Optional.ofNullable(null); } return Optional.of(uri); } From f5076c41ef5ec7fa92bf635c2735894201edb813 Mon Sep 17 00:00:00 2001 From: Stepan Mikhailiuk Date: Tue, 20 May 2025 09:08:13 +0800 Subject: [PATCH 73/85] fix(*): remove unnecessary exception according review comments Signed-off-by: Stepan Mikhailiuk --- .../filter/factory/SetRequestUriGatewayFilterFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java index 8f87428d..1fbdfaed 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java @@ -90,7 +90,6 @@ public class SetRequestUriGatewayFilterFactory return Optional.of(uri); } catch (IllegalArgumentException e) { - log.info("Request url is invalid : url={}, error={}", config.getTemplate(), e.getMessage()); return Optional.ofNullable(null); } From b5afd8883d9baa4c4eee6f42577aa2bfcac87856 Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Tue, 20 May 2025 17:39:25 +0200 Subject: [PATCH 74/85] Add tests for LoadBalancerHandlerConfiguration (#3779) * Add autoconfiguration tests. Signed-off-by: Olga Maciaszek-Sharma --- ...atewayServerMvcAutoConfigurationTests.java | 25 +++++++- ...ServerMvcLoadBalancerIntegrationTests.java | 62 +++++++++++++++++++ .../src/test/resources/application-lb.yml | 11 ++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 0eb0ff71..71e3e638 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 the original author or authors. + * Copyright 2013-2025 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. @@ -34,6 +34,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; @@ -47,6 +48,7 @@ import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilte import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -204,6 +206,27 @@ public class GatewayServerMvcAutoConfigurationTests { assertThat(builder).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class); } + @Test + void loadBalancerFunctionHandlerAdded() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .run(context -> assertThat(context).hasBean("lbHandlerFunctionDefinition")); + } + + @Test + void loadBalancerFunctionHandlerNotAddedWhenNoLoadBalancerClientOnClasspath() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader(LoadBalancerClient.class)) + .run(context -> assertThat(context).doesNotHaveBean("lbHandlerFunctionDefinition")); + } + @SpringBootConfiguration @EnableAutoConfiguration static class TestConfig { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java new file mode 100644 index 00000000..f0b91066 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.gateway.server.mvc; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; + +/** + * Integration tests for {@link FilterAutoConfiguration.LoadBalancerHandlerConfiguration}. + * + * @author Olga Maciaszek-Sharma + * + */ +@SpringBootTest(classes = {ServerMvcLoadBalancerIntegrationTests.Config.class, FilterAutoConfiguration.class}, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +@ActiveProfiles("lb") +public class ServerMvcLoadBalancerIntegrationTests { + + @LocalServerPort + int port; + + @Autowired + TestRestClient testRestClient; + + @Test + void shouldUseLbHandlerFunctionDefinitionToResolveHost() { + testRestClient.get() + .uri("http://localhost:" + port + "/test") + .exchange().expectStatus().isOk(); + } + + @SpringBootApplication + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + static class Config { + } +} diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml new file mode 100644 index 00000000..9d0437b3 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-lb.yml @@ -0,0 +1,11 @@ +spring: + cloud: + gateway: + mvc: + routes: + - id: test + uri: lb://httpbin + predicates: + - Path=/test/** + filters: + - StripPrefix=1 \ No newline at end of file From b5f98411a91da0d5cf9cae41f628663dde186e0b Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 20 May 2025 13:28:20 -0400 Subject: [PATCH 75/85] Adds spring-boot-properties-migrator to server starters. This is temporary for backwards compatibility. --- spring-cloud-starter-gateway-mvc/pom.xml | 5 +++++ spring-cloud-starter-gateway-server-webflux/pom.xml | 5 +++++ spring-cloud-starter-gateway-server-webmvc/pom.xml | 5 +++++ spring-cloud-starter-gateway/pom.xml | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e86d2d1f..8e66ee4e 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -34,5 +34,10 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml index ab94fcc5..ed3b79c4 100644 --- a/spring-cloud-starter-gateway-server-webflux/pom.xml +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -33,5 +33,10 @@ org.springframework.boot spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml index 00420392..14b339e1 100644 --- a/spring-cloud-starter-gateway-server-webmvc/pom.xml +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -33,5 +33,10 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-properties-migrator + diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8de3f70e..9705acd7 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -34,5 +34,10 @@ org.springframework.boot spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-properties-migrator + From ec60c2e2a81d03c31aa67719347afa754080c191 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 20 May 2025 14:30:34 -0400 Subject: [PATCH 76/85] formatting --- ...atewayServerMvcAutoConfigurationTests.java | 22 +++++++++---------- ...ServerMvcLoadBalancerIntegrationTests.java | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index 71e3e638..01f8f9f4 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -209,22 +209,22 @@ public class GatewayServerMvcAutoConfigurationTests { @Test void loadBalancerFunctionHandlerAdded() { new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, - HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, - HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, - RestClientAutoConfiguration.class)) - .run(context -> assertThat(context).hasBean("lbHandlerFunctionDefinition")); + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .run(context -> assertThat(context).hasBean("lbHandlerFunctionDefinition")); } @Test void loadBalancerFunctionHandlerNotAddedWhenNoLoadBalancerClientOnClasspath() { new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, - HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, - HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, - RestClientAutoConfiguration.class)) - .withClassLoader(new FilteredClassLoader(LoadBalancerClient.class)) - .run(context -> assertThat(context).doesNotHaveBean("lbHandlerFunctionDefinition")); + .withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class, + HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class, + HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, + RestClientAutoConfiguration.class)) + .withClassLoader(new FilteredClassLoader(LoadBalancerClient.class)) + .run(context -> assertThat(context).doesNotHaveBean("lbHandlerFunctionDefinition")); } @SpringBootConfiguration diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java index f0b91066..d2e5889b 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcLoadBalancerIntegrationTests.java @@ -36,7 +36,7 @@ import org.springframework.test.context.ContextConfiguration; * @author Olga Maciaszek-Sharma * */ -@SpringBootTest(classes = {ServerMvcLoadBalancerIntegrationTests.Config.class, FilterAutoConfiguration.class}, +@SpringBootTest(classes = { ServerMvcLoadBalancerIntegrationTests.Config.class, FilterAutoConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) @ActiveProfiles("lb") @@ -50,13 +50,13 @@ public class ServerMvcLoadBalancerIntegrationTests { @Test void shouldUseLbHandlerFunctionDefinitionToResolveHost() { - testRestClient.get() - .uri("http://localhost:" + port + "/test") - .exchange().expectStatus().isOk(); + testRestClient.get().uri("http://localhost:" + port + "/test").exchange().expectStatus().isOk(); } @SpringBootApplication @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) static class Config { + } + } From 4fdf22e997153960cac3039e591033f1b76cb64d Mon Sep 17 00:00:00 2001 From: Stepan Mikhailiuk Date: Thu, 22 May 2025 12:38:10 +0800 Subject: [PATCH 77/85] fix(*): fix disable builtin filter Signed-off-by: Stepan Mikhailiuk --- .../gateway/config/conditional/DisableBuiltInFiltersTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java index b581dfa0..66eacd76 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/conditional/DisableBuiltInFiltersTests.java @@ -100,6 +100,7 @@ public class DisableBuiltInFiltersTests { "spring.cloud.gateway.server.webflux.filter.secure-headers.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-request-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-request-host-header.enabled=false", + "spring.cloud.gateway.server.webflux.filter.set-request-uri.enabled=false", "spring.cloud.gateway.server.webflux.filter.set-response-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.rewrite-response-header.enabled=false", "spring.cloud.gateway.server.webflux.filter.rewrite-location-response-header.enabled=false", From 03eb741d68849067facd45dbc312ae80fe9b2832 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 22 May 2025 15:30:30 -0400 Subject: [PATCH 78/85] Fixing tests after merge --- .../gateway/server/mvc/filter/BeforeFilterFunctions.java | 2 +- .../server/mvc/filter/BeforeFilterFunctionsTests.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 578d7c7c..ce2b2404 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -350,7 +350,7 @@ public abstract class BeforeFilterFunctions { queryParams.add(name, replacement); } - MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + MultiValueMap encodedQueryParams = MvcUtils.encodeQueryParams(queryParams); URI rewrittenUri = UriComponentsBuilder.fromUri(request.uri()) .replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) .build(true) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java index f6648063..db5a4b7a 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -117,9 +117,9 @@ class BeforeFilterFunctionsTests { @Test void rewriteEncodedRequestParameter() { MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") - .param("foo", "bar") - .param("baz[]", "qux[]") - .param("quux", "corge+") + .param("foo[]", "bar") + .param("baz", "qux") + .param("quux", "corge+") .buildRequest(null); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); @@ -128,7 +128,8 @@ class BeforeFilterFunctionsTests { assertThat(result.param("foo[]")).isPresent().hasValue("replacement[]"); assertThat(result.param("quux")).isPresent().hasValue("corge+"); - assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo%5B%5D=replacement%5B%5D&quux=corge%2B"); + assertThat(result.uri().toString()) + .hasToString("http://localhost/path?quux=corge%2B&baz=qux&foo%5B%5D=replacement%5B%5D"); } @Test From 0b03ee1d26ead45a9ad1a697bbdefb4c0ce9bbce Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 22 May 2025 15:58:45 -0400 Subject: [PATCH 79/85] Update maven.yml Changes java distribution to liberica Signed-off-by: Spencer Gibb --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index be248adf..801097a0 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -19,7 +19,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: 'liberica' java-version: '17' cache: 'maven' - name: Build with Maven From 6690c79a2dfa95f93f875a88b2c0326b369642a9 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 22 May 2025 16:22:29 -0400 Subject: [PATCH 80/85] Migrate server-webmvc properties to new namespace See gh-3647 --- .../spring-cloud-gateway-server-webmvc/starter.adoc | 2 +- .../GatewayMvcClassPathWarningAutoConfiguration.java | 3 ++- .../server/mvc/GatewayServerMvcAutoConfiguration.java | 2 +- .../gateway/server/mvc/VanillaRouterFunctionTests.java | 2 +- .../application-functionhandlerconfigtests.yml | 2 +- ...lication-propertiesbeandefinitionregistrartests.yml | 2 +- .../resources/application-streamhandlerconfigtests.yml | 2 +- .../resources/application-stripprefixstaticport.yml | 2 +- ...lication-weightrequestpredicateintegrationtests.yml | 2 +- .../additional-spring-configuration-metadata.json | 10 ---------- 10 files changed, 10 insertions(+), 19 deletions(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc index 6d3b7bd8..d8f759ce 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc @@ -5,7 +5,7 @@ To include Spring Cloud Gateway Server Web MVC in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway-server-webmvc`. See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train. -If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.mvc.enabled=false`. +If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.server.webmvc.enabled=false`. IMPORTANT: Spring Cloud Gateway Server MVC is built on https://spring.io/projects/spring-boot#learn[Spring Boot] and https://docs.spring.io/spring-framework/reference/web/webmvc-functional.html[Spring WebMvc.fn]. As a consequence, many of the asynchronous or reactive libraries may not apply when you use Spring Cloud Gateway Server MVC. diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java index 4fef7bc7..21173cf9 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java @@ -22,11 +22,12 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @AutoConfigureBefore(GatewayServerMvcAutoConfiguration.class) -@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayMvcProperties.PREFIX + ".enabled", matchIfMissing = true) public class GatewayMvcClassPathWarningAutoConfiguration { private static final Log log = LogFactory.getLog(GatewayMvcClassPathWarningAutoConfiguration.class); diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index 37cd5245..2aecabe1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -78,7 +78,7 @@ import org.springframework.web.client.RestClient; @AutoConfiguration(after = { HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class, FilterAutoConfiguration.class, HandlerFunctionAutoConfiguration.class, PredicateAutoConfiguration.class }) -@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) +@ConditionalOnProperty(name = GatewayMvcProperties.PREFIX + ".enabled", matchIfMissing = true) @Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class) @ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class) public class GatewayServerMvcAutoConfiguration { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java index fd96c938..81d1128c 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java @@ -43,7 +43,7 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @SuppressWarnings("unchecked") -@SpringBootTest(properties = { "spring.cloud.gateway.mvc.http-client.type=jdk" }, +@SpringBootTest(properties = { "spring.http.client.factory=jdk" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) public class VanillaRouterFunctionTests { diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml index c7430ca4..847e7057 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: testsimplefunction: uri: fn:upper diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml index a91fe14d..cd55ac63 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-propertiesbeandefinitionregistrartests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: route1: uri: https://example1.com diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml index 3e97fc80..00cfc6b9 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routesMap: testsimplestream: uri: stream:hello-out-0 diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml index c27795c3..184cfee5 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-stripprefixstaticport.yml @@ -1,5 +1,5 @@ strip.prefix.static.uri: http://${httpbin.host}:${httpbin.port} -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routes: - id: strip_prefix_static_port_config uri: ${strip.prefix.static.uri} diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml index 69d927b8..f4dc97ad 100644 --- a/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-weightrequestpredicateintegrationtests.yml @@ -1,4 +1,4 @@ -spring.cloud.gateway.mvc: +spring.cloud.gateway.server.webmvc: routes: - id: weight_high_test uri: https://examplel1.com diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1a646d71..13464a13 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1966,16 +1966,6 @@ "since": "4.3.0" } }, - { - "name": "spring.cloud.gateway.mvc.routes", - "type": "java.util.List", - "description": "List of Routes.", - "deprecated": true, - "deprecation": { - "replacement": "spring.cloud.gateway.server.webflux.mvc.routes", - "since": "4.3.0" - } - }, { "name": "spring.cloud.gateway.observability.enabled", "type": "java.lang.Boolean", From fb2a32bb81df0d28b906365d2ab620757bb7113b Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 22 May 2025 16:30:04 -0400 Subject: [PATCH 81/85] Attempt to get tests to pass in github actions --- spring-cloud-gateway-server-mvc/pom.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index ad20bf03..2e16c44c 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -146,4 +146,19 @@ test + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + host + + + + + From 5177890943e734bdf9a3f5d9f788ad3a6e629688 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 22 May 2025 18:25:47 -0400 Subject: [PATCH 82/85] Moves github action system property to a profile --- spring-cloud-gateway-server-mvc/pom.xml | 39 ++++++++++++++++--------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 2e16c44c..01c47d60 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -147,18 +147,29 @@ - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - host - - - - - + + + github_actions + + + + env.GITHUB_ACTIONS + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + host + + + + + + + From ca861ff4c837af19b0555fad795db8f4c888605f Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Mon, 19 May 2025 17:23:20 +0800 Subject: [PATCH 83/85] add new config for AddResponseHeaderGatewayFilterFactory Signed-off-by: jiangyuan --- ...AddResponseHeaderGatewayFilterFactory.java | 88 +++++++++++++++++-- .../route/builder/GatewayFilterSpec.java | 12 +++ ...sponseHeaderGatewayFilterFactoryTests.java | 68 ++++++++++++-- .../src/test/resources/application.yml | 1 + 4 files changed, 154 insertions(+), 15 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java index 937aa196..745c5807 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java @@ -16,12 +16,17 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Arrays; +import java.util.List; + import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.style.ToStringCreator; import org.springframework.http.HttpHeaders; +import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; @@ -29,10 +34,22 @@ import static org.springframework.cloud.gateway.support.GatewayToStringStyler.fi /** * @author Spencer Gibb */ -public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { +public class AddResponseHeaderGatewayFilterFactory + extends AbstractGatewayFilterFactory { + + private static final String OVERRIDE_KEY = "override"; + + public AddResponseHeaderGatewayFilterFactory() { + super(Config.class); + } @Override - public GatewayFilter apply(NameValueConfig config) { + public List shortcutFieldOrder() { + return Arrays.asList(GatewayFilter.NAME_KEY, GatewayFilter.VALUE_KEY, OVERRIDE_KEY); + } + + @Override + public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -42,19 +59,76 @@ public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGate @Override public String toString() { return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(GatewayFilter.NAME_KEY, config.getName()) + .append(GatewayFilter.VALUE_KEY, config.getValue()) + .append(OVERRIDE_KEY, config.isOverride()) .toString(); } }; } - void addHeader(ServerWebExchange exchange, NameValueConfig config) { - final String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); - HttpHeaders headers = exchange.getResponse().getHeaders(); + void addHeader(ServerWebExchange exchange, Config config) { // if response has been commited, no more response headers will bee added. if (!exchange.getResponse().isCommitted()) { - headers.add(config.getName(), value); + final String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + HttpHeaders headers = exchange.getResponse().getHeaders(); + if (config.override) { + headers.add(config.getName(), value); + } + else { + boolean headerIsMissingOrBlank = headers.getOrEmpty(config.getName()) + .stream() + .allMatch(h -> !StringUtils.hasText(h)); + if (headerIsMissingOrBlank) { + headers.add(config.getName(), value); + } + } } } + public static class Config { + + private String name; + + private String value; + + private boolean override = true; + + public String getName() { + return name; + } + + public Config setName(String name) { + this.name = name; + return this; + } + + public String getValue() { + return value; + } + + public Config setValue(String value) { + this.value = value; + return this; + } + + public boolean isOverride() { + return override; + } + + public Config setOverride(boolean override) { + this.override = override; + return this; + } + + @Override + public String toString() { + return new ToStringCreator(this).append(NAME_KEY, name) + .append(VALUE_KEY, value) + .append(OVERRIDE_KEY, override) + .toString(); + } + + } + } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index 47723b74..fdfec010 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -225,6 +225,18 @@ public class GatewayFilterSpec extends UriSpec { .apply(c -> c.setName(headerName).setValue(headerValue))); } + /** + * Adds a header to the response returned to the Gateway from the route. + * @param headerName the header name + * @param headerValue the header value + * @param override override or not + * @return a {@link GatewayFilterSpec} that can be used to apply additional filters + */ + public GatewayFilterSpec addResponseHeader(String headerName, String headerValue, boolean override) { + return filter(getBean(AddResponseHeaderGatewayFilterFactory.class) + .apply(c -> c.setName(headerName).setValue(headerValue).setOverride(override))); + } + /** * A filter that adds a local cache for storing response body for repeated requests. *

diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java index 4c3c002e..d42472bb 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java @@ -17,6 +17,8 @@ package org.springframework.cloud.gateway.filter.factory; import java.net.URI; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.Test; @@ -25,7 +27,6 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory.NameValueConfig; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.gateway.test.BaseWebClientTests; @@ -51,20 +52,71 @@ class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTests { .header("Host", host) .exchange() .expectHeader() - .valueEquals("X-Request-Foo", expectedValue); + .valueEquals("X-Request-Foo", expectedValue) + .expectHeader() + .valueEquals("X-Request-Example", "ValueA"); + } + + @Test + void testResponseHeaderFilterHeaderPresent() { + URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri(); + String host = "www.addresponseheader.org"; + String expectedValue = "Bar"; + + Map body = new HashMap<>(); + body.put("X-Request-Example", "ValueB"); + + testClient.patch() + .uri(uri) + .header("Host", host) + .bodyValue(body) + .exchange() + .expectHeader() + .valueEquals("X-Request-Foo", expectedValue) + .expectHeader() + .valueEquals("X-Request-Example", "ValueB"); } @Test void testResponseHeaderFilterJavaDsl() { - URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/get").build(true).toUri(); + URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri(); String host = "www.addresponseheaderjava.org"; String expectedValue = "myresponsevalue-www"; - testClient.get().uri(uri).header("Host", host).exchange().expectHeader().valueEquals("example", expectedValue); + testClient.get() + .uri(uri) + .header("Host", host) + .exchange() + .expectHeader() + .valueEquals("example", expectedValue) + .expectHeader() + .valueEquals("example2", "myresponsevalue2-www"); + } + + @Test + void testResponseHeaderFilterHeaderPresentJavaDsl() { + URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/headers").build(true).toUri(); + String host = "www.addresponseheaderjava.org"; + String expectedValue = "myresponsevalue-www"; + + Map body = new HashMap<>(); + body.put("example2", "myresponsevalue2"); + + testClient.patch() + .uri(uri) + .header("Host", host) + .bodyValue(body) + .exchange() + .expectHeader() + .valueEquals("example", expectedValue) + .expectHeader() + .valueEquals("example2", "myresponsevalue2"); } @Test void toStringFormat() { - NameValueConfig config = new NameValueConfig().setName("myname").setValue("myvalue"); + AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config() + .setName("myname") + .setValue("myvalue"); GatewayFilter filter = new AddResponseHeaderGatewayFilterFactory().apply(config); assertThat(filter.toString()).contains("myname").contains("myvalue"); } @@ -81,11 +133,11 @@ class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTests { public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("add_response_header_java_test", - r -> r.path("/get") + r -> r.path("/headers") .and() .host("{sub}.addresponseheaderjava.org") - .filters( - f -> f.prefixPath("/httpbin").addResponseHeader("example", "myresponsevalue-{sub}")) + .filters(f -> f.addResponseHeader("example", "myresponsevalue-{sub}") + .addResponseHeader("example2", "myresponsevalue2-{sub}", false)) .uri(uri)) .build(); } diff --git a/spring-cloud-gateway-server/src/test/resources/application.yml b/spring-cloud-gateway-server/src/test/resources/application.yml index a08f82da..1d34803b 100644 --- a/spring-cloud-gateway-server/src/test/resources/application.yml +++ b/spring-cloud-gateway-server/src/test/resources/application.yml @@ -72,6 +72,7 @@ spring: - Path=/headers filters: - AddResponseHeader=X-Request-Foo, Bar + - AddResponseHeader=X-Request-Example, ValueA, false - id: cache_request_body_test uri: ${test.uri} From 989dd6233a61e34bf7fe3d65f06a4804dcae9e7d Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Tue, 20 May 2025 12:28:50 +0800 Subject: [PATCH 84/85] update docs Signed-off-by: jiangyuan --- .../gatewayfilter-factories/addresponseheader-factory.adoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc index e15ea73c..f13de378 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc @@ -1,7 +1,7 @@ [[addresponseheader-gatewayfilter-factory]] = `AddResponseHeader` `GatewayFilter` Factory -The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter. +The `AddResponseHeader` `GatewayFilter` Factory takes three parameters: `name`, `value` and `override`(default value is `true`) . The following example configures an `AddResponseHeader` `GatewayFilter`: .application.yml @@ -15,9 +15,12 @@ spring: uri: https://example.org filters: - AddResponseHeader=X-Response-Red, Blue + - AddResponseHeader=X-Response-Black, White, false ---- This adds `X-Response-Red:Blue` header to the downstream response's headers for all matching requests. +and if the response already contains the `X-Response-Black` header, this will not add the `X-Response-Black: White` +header to the downstream response's headers for all matching requests. `AddResponseHeader` is aware of URI variables used to match a path or host. URI variables may be used in the value and are expanded at runtime. From c99e29009a1ec9727b562d052fc8f6eb5d35a926 Mon Sep 17 00:00:00 2001 From: jiangyuan Date: Fri, 23 May 2025 16:03:32 +0800 Subject: [PATCH 85/85] avoid breaking changes Signed-off-by: jiangyuan --- ...AddResponseHeaderGatewayFilterFactory.java | 60 +++++++++---------- .../route/builder/GatewayFilterSpec.java | 8 ++- ...sponseHeaderGatewayFilterFactoryTests.java | 5 +- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java index 745c5807..4e1d04d5 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java @@ -34,13 +34,18 @@ import static org.springframework.cloud.gateway.support.GatewayToStringStyler.fi /** * @author Spencer Gibb */ -public class AddResponseHeaderGatewayFilterFactory - extends AbstractGatewayFilterFactory { +public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { private static final String OVERRIDE_KEY = "override"; - public AddResponseHeaderGatewayFilterFactory() { - super(Config.class); + @Override + public Class getConfigClass() { + return Config.class; + } + + @Override + public NameValueConfig newConfig() { + return new Config(); } @Override @@ -49,7 +54,7 @@ public class AddResponseHeaderGatewayFilterFactory } @Override - public GatewayFilter apply(Config config) { + public GatewayFilter apply(NameValueConfig config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -58,21 +63,32 @@ public class AddResponseHeaderGatewayFilterFactory @Override public String toString() { + if (config instanceof Config) { + return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this) + .append(GatewayFilter.NAME_KEY, config.getName()) + .append(GatewayFilter.VALUE_KEY, config.getValue()) + .append(OVERRIDE_KEY, ((Config) config).isOverride()) + .toString(); + } return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this) - .append(GatewayFilter.NAME_KEY, config.getName()) - .append(GatewayFilter.VALUE_KEY, config.getValue()) - .append(OVERRIDE_KEY, config.isOverride()) + .append(config.getName(), config.getValue()) .toString(); } }; } - void addHeader(ServerWebExchange exchange, Config config) { + void addHeader(ServerWebExchange exchange, NameValueConfig config) { // if response has been commited, no more response headers will bee added. if (!exchange.getResponse().isCommitted()) { final String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); HttpHeaders headers = exchange.getResponse().getHeaders(); - if (config.override) { + + boolean override = true; // default is true + if (config instanceof Config) { + override = ((Config) config).isOverride(); + } + + if (override) { headers.add(config.getName(), value); } else { @@ -86,32 +102,10 @@ public class AddResponseHeaderGatewayFilterFactory } } - public static class Config { - - private String name; - - private String value; + public static class Config extends AbstractNameValueGatewayFilterFactory.NameValueConfig { private boolean override = true; - public String getName() { - return name; - } - - public Config setName(String name) { - this.name = name; - return this; - } - - public String getValue() { - return value; - } - - public Config setValue(String value) { - this.value = value; - return this; - } - public boolean isOverride() { return override; } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index fdfec010..5b1ed0c1 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -233,8 +233,12 @@ public class GatewayFilterSpec extends UriSpec { * @return a {@link GatewayFilterSpec} that can be used to apply additional filters */ public GatewayFilterSpec addResponseHeader(String headerName, String headerValue, boolean override) { - return filter(getBean(AddResponseHeaderGatewayFilterFactory.class) - .apply(c -> c.setName(headerName).setValue(headerValue).setOverride(override))); + AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config(); + config.setName(headerName); + config.setValue(headerValue); + config.setOverride(override); + + return filter(getBean(AddResponseHeaderGatewayFilterFactory.class).apply(config)); } /** diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java index d42472bb..1c58a88f 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactoryTests.java @@ -27,6 +27,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory.NameValueConfig; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.gateway.test.BaseWebClientTests; @@ -114,9 +115,7 @@ class AddResponseHeaderGatewayFilterFactoryTests extends BaseWebClientTests { @Test void toStringFormat() { - AddResponseHeaderGatewayFilterFactory.Config config = new AddResponseHeaderGatewayFilterFactory.Config() - .setName("myname") - .setValue("myvalue"); + NameValueConfig config = new NameValueConfig().setName("myname").setValue("myvalue"); GatewayFilter filter = new AddResponseHeaderGatewayFilterFactory().apply(config); assertThat(filter.toString()).contains("myname").contains("myvalue"); }