From 8f3ce7666831575f8b0d537a43565614a7a4395d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Khan=20/=20=EC=9D=B4=EC=B0=BD=EB=AF=BC?= Date: Sat, 9 Nov 2024 00:24:42 +0900 Subject: [PATCH 01/56] Fix: incorrect link in configuration-properties --- .../pages/spring-cloud-gateway/configuration-properties.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc index 1aed5173..7d7642d2 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc @@ -2,4 +2,4 @@ = Configuration properties :page-section-summary-toc: 1 -To see the list of all Spring Cloud Gateway related configuration properties, see link:appendix.html[the appendix]. +To see the list of all Spring Cloud Gateway related configuration properties, see link:../appendix.html[the appendix]. From 4067254809fd5162df768d3c5c2107f11c0495d8 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Wed, 20 Nov 2024 13:30:57 +0000 Subject: [PATCH 02/56] Bumping versions --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index 32d1ae73..f980ffa7 100644 --- a/README.adoc +++ b/README.adoc @@ -52,9 +52,9 @@ given the ability to merge pull requests. [[code-of-conduct]] == Code of Conduct -This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/src/main/asciidoc/code-of-conduct.adoc[code of +This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/modules/ROOT/partials/code-of-conduct.adoc[code of conduct]. By participating, you are expected to uphold this code. Please report -unacceptable behavior to spring-code-of-conduct@pivotal.io. +unacceptable behavior to code-of-conduct@spring.io. [[code-conventions-and-housekeeping]] == Code Conventions and Housekeeping From 571c35bca5d41649a2411a23dfe40fa1775feece Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:18:37 +0000 Subject: [PATCH 03/56] Update SNAPSHOT to 4.1.6 --- 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 085bbd1d..687e2076 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6-SNAPSHOT + 4.1.6 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 008753e5..55b1f66b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6-SNAPSHOT + 4.1.6 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.4-SNAPSHOT + 4.1.4 @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.3-SNAPSHOT - 4.1.5-SNAPSHOT + 3.1.3 + 4.1.5 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index f82500bf..a4b233f8 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.4-SNAPSHOT + 4.1.4 spring-cloud-gateway-dependencies - 4.1.6-SNAPSHOT + 4.1.6 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 d7be74ae..cd7eb302 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 0b57feb5..ee5ab3dc 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.6-SNAPSHOT + 4.1.6 .. 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 4b6f30c2..2d988354 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index f89b909d..1e01e12f 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index ad39869a..67aefea0 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 8cd7a0c9..7ab9ce7d 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index b04f8739..58a8a192 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.6-SNAPSHOT + 4.1.6 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index a026b0f6..7942051b 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.6-SNAPSHOT + 4.1.6 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index f3f384aa..6a596348 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.6-SNAPSHOT + 4.1.6 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index c682053b..4c589ad4 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.6-SNAPSHOT + 4.1.6 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index a60b865b..1cb24e46 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.6-SNAPSHOT + 4.1.6 .. spring-cloud-starter-gateway From 21ad74985785ca32e72cd7c1398ce7a731da4c2d Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:20:53 +0000 Subject: [PATCH 04/56] 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 687e2076..085bbd1d 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6 + 4.1.6-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 55b1f66b..008753e5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6 + 4.1.6-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.4 + 4.1.4-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.3 - 4.1.5 + 3.1.3-SNAPSHOT + 4.1.5-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index a4b233f8..f82500bf 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.4 + 4.1.4-SNAPSHOT spring-cloud-gateway-dependencies - 4.1.6 + 4.1.6-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 cd7eb302..d7be74ae 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index ee5ab3dc..0b57feb5 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.6 + 4.1.6-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 2d988354..4b6f30c2 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 1e01e12f..f89b909d 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 67aefea0..ad39869a 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 7ab9ce7d..8cd7a0c9 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 58a8a192..b04f8739 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.6 + 4.1.6-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 7942051b..a026b0f6 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.6 + 4.1.6-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 6a596348..f3f384aa 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.6 + 4.1.6-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 4c589ad4..c682053b 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.6 + 4.1.6-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 1cb24e46..a60b865b 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.6 + 4.1.6-SNAPSHOT .. spring-cloud-starter-gateway From 92c59468a5affb7f8d4f63bfbcd744d4c07ea3d5 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:20:54 +0000 Subject: [PATCH 05/56] Bumping versions to 4.1.7-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 085bbd1d..4c71f5db 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6-SNAPSHOT + 4.1.7-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 008753e5..5a195f32 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6-SNAPSHOT + 4.1.7-SNAPSHOT pom Spring Cloud Gateway diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index f82500bf..2fa66a0f 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.6-SNAPSHOT + 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 d7be74ae..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.6-SNAPSHOT + 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 0b57feb5..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.6-SNAPSHOT + 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 4b6f30c2..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index f89b909d..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index ad39869a..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 8cd7a0c9..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index b04f8739..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.6-SNAPSHOT + 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 a026b0f6..f7bc1beb 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.6-SNAPSHOT + 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 f3f384aa..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index c682053b..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.6-SNAPSHOT + 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 a60b865b..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.6-SNAPSHOT + 4.1.7-SNAPSHOT .. spring-cloud-starter-gateway From 3487f61dc5177304b524359b7597e3fbcbb92963 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Tue, 26 Nov 2024 18:23:45 +0100 Subject: [PATCH 06/56] Update pom.xml --- docs/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pom.xml b/docs/pom.xml index 4c71f5db..58b6f5f2 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -25,6 +25,7 @@ .* ${maven.multiModuleProjectDirectory}/docs/modules/ROOT/partials/ + src/main/asciidoc From 908471d897c9526128a0c8878700b9504e7c9c7c Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:43:43 +0000 Subject: [PATCH 07/56] Update SNAPSHOT to 4.1.6 --- 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 58b6f5f2..2ed38261 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.6 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 5a195f32..55b1f66b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.7-SNAPSHOT + 4.1.6 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.4-SNAPSHOT + 4.1.4 @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.3-SNAPSHOT - 4.1.5-SNAPSHOT + 3.1.3 + 4.1.5 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 2fa66a0f..a4b233f8 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.4-SNAPSHOT + 4.1.4 spring-cloud-gateway-dependencies - 4.1.7-SNAPSHOT + 4.1.6 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..cd7eb302 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.6 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index f74bfb93..ee5ab3dc 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.6 .. 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..2d988354 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.6 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 121e9019..1e01e12f 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.6 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 6141755d..67aefea0 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.6 .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 2f7b6297..7ab9ce7d 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.6 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 9ecf0a73..58a8a192 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.6 .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index f7bc1beb..7942051b 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.6 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 2c529a28..6a596348 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.6 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index ccfa5c5f..4c589ad4 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.6 .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 614e9dd5..1cb24e46 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.6 .. spring-cloud-starter-gateway From 5c5ce6e8c80beaa82a9463e58d70efaa6f135817 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:46:48 +0000 Subject: [PATCH 08/56] 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 2ed38261..58b6f5f2 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6 + 4.1.7-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 55b1f66b..5a195f32 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.1.6 + 4.1.7-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.4 + 4.1.4-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.3 - 4.1.5 + 3.1.3-SNAPSHOT + 4.1.5-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index a4b233f8..2fa66a0f 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.4 + 4.1.4-SNAPSHOT spring-cloud-gateway-dependencies - 4.1.6 + 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 cd7eb302..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.6 + 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 ee5ab3dc..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.6 + 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 2d988354..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.6 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 1e01e12f..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.6 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 67aefea0..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.6 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 7ab9ce7d..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.6 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 58a8a192..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.6 + 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 7942051b..f7bc1beb 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.6 + 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 6a596348..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.6 + 4.1.7-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 4c589ad4..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.6 + 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 1cb24e46..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.6 + 4.1.7-SNAPSHOT .. spring-cloud-starter-gateway From 4cae649e57b52fc1df1be95e422f13be2d467943 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Tue, 26 Nov 2024 17:47:51 +0000 Subject: [PATCH 09/56] Bumping dependency versions after release --- pom.xml | 6 +++--- spring-cloud-gateway-dependencies/pom.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 5a195f32..17a0178f 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.4-SNAPSHOT + 4.1.5-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.3-SNAPSHOT - 4.1.5-SNAPSHOT + 3.1.4-SNAPSHOT + 4.1.6-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 2fa66a0f..5a721b66 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,7 +6,7 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.1.4-SNAPSHOT + 4.1.5-SNAPSHOT From 20a7c9079146ab992867b66ea513f92fdae9a9f4 Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Wed, 27 Nov 2024 18:09:13 +0100 Subject: [PATCH 10/56] Revert "Update pom.xml" This reverts commit 3487f61dc5177304b524359b7597e3fbcbb92963. --- docs/pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 58b6f5f2..4c71f5db 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -25,7 +25,6 @@ .* ${maven.multiModuleProjectDirectory}/docs/modules/ROOT/partials/ - src/main/asciidoc From 3419b41caa73134077f21bc4cad538521f783aa4 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 13 Dec 2024 12:39:12 -0500 Subject: [PATCH 11/56] Re-enables CustomBlockHoundIntegrationTest --- .../cloud/gateway/test/CustomBlockHoundIntegrationTest.java | 3 --- 1 file changed, 3 deletions(-) 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 69558c90..67ba0f7c 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 @@ -18,8 +18,6 @@ package org.springframework.cloud.gateway.test; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -29,7 +27,6 @@ import reactor.core.scheduler.Schedulers; public class CustomBlockHoundIntegrationTest { @Test - @DisabledForJreRange(min = JRE.JAVA_16) public void shouldThrowErrorForBlockingCallWithCustomBlockHoundIntegration() { Assertions.assertThrows(RuntimeException.class, () -> Mono.fromCallable(() -> { Thread.sleep(1); From dec24e02b9183c64d88a4d5efb511ef6ac8c0352 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 13 Dec 2024 14:35:39 -0500 Subject: [PATCH 12/56] Limits CustomBlockHoundIntegrationTest to java 17 --- .../cloud/gateway/test/CustomBlockHoundIntegrationTest.java | 3 +++ 1 file changed, 3 insertions(+) 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 67ba0f7c..228679ac 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 @@ -18,6 +18,8 @@ package org.springframework.cloud.gateway.test; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -27,6 +29,7 @@ import reactor.core.scheduler.Schedulers; public class CustomBlockHoundIntegrationTest { @Test + @DisabledForJreRange(min = JRE.JAVA_18) public void shouldThrowErrorForBlockingCallWithCustomBlockHoundIntegration() { Assertions.assertThrows(RuntimeException.class, () -> Mono.fromCallable(() -> { Thread.sleep(1); From 84009f2ee421e2191f8cc32ce3a84e7fc09e305e Mon Sep 17 00:00:00 2001 From: Dimitar Popov Date: Mon, 16 Dec 2024 20:18:33 +0100 Subject: [PATCH 13/56] Ssl bundles not working because of wrong condition (#3641) * Add test for ssl bundle configuration * Fix support of ssl bundles --------- Co-authored-by: Dimitar Popov --- .../gateway/config/AbstractSslConfigurer.java | 5 +-- .../ssl/ClientCertAuthSSLBundleTests.java | 33 ++++++++++++++ .../application-client-auth-ssl-bundle.yml | 43 +++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java create mode 100644 spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java index 3a32ecb1..1996abac 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java @@ -67,10 +67,7 @@ public abstract class AbstractSslConfigurer { } protected SslBundle getBundle() { - if (ssl.getSslBundle() == null || ssl.getSslBundle().length() > 0) { - return null; - } - if (bundles.getBundleNames().contains(ssl.getSslBundle())) { + if (ssl.getSslBundle() != null && ssl.getSslBundle().length() > 0 && bundles.getBundleNames().contains(ssl.getSslBundle())) { return bundles.getBundle(ssl.getSslBundle()); } return null; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java new file mode 100644 index 00000000..7219d97a --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java @@ -0,0 +1,33 @@ +package org.springframework.cloud.gateway.test.ssl; + +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ssl.SslBundles; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import reactor.netty.http.client.HttpClient; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +@ActiveProfiles("client-auth-ssl-bundle") +public class ClientCertAuthSSLBundleTests extends SingleCertSSLTests { + @Autowired + private SslBundles sslBundles; + + @BeforeEach + public void setup() throws Exception { + final var sslBundle = sslBundles.getBundle("scg-keystore-with-different-key-password"); + final var sslContext = SslContextBuilder.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .keyManager(sslBundle.getManagers().getKeyManagerFactory()) + .build(); + HttpClient httpClient = HttpClient.create().secure(ssl -> ssl.sslContext(sslContext)); + setup(new ReactorClientHttpConnector(httpClient), "https://localhost:" + port); + } +} 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 new file mode 100644 index 00000000..2ca408d5 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/resources/application-client-auth-ssl-bundle.yml @@ -0,0 +1,43 @@ +test: + uri: lb:https://testservice + +server: + ssl: + enabled: true + key-alias: scg + key-store-password: scg1234 + key-password: keyscg1234 + key-store: classpath:scg-keystore-with-different-key-password.jks + trust-store: classpath:scg-truststore.jks + trust-store-password: scg1234 + trust-store-type: JKS + key-store-type: JKS + client-auth: Need +spring: + cloud: + gateway: + httpclient: + ssl: + ssl-bundle: scg-keystore-with-different-key-password + trustedX509Certificates: + - src/test/resources/single-cert-for-different-key-password.pem + default-filters: + - PrefixPath=/httpbin + routes: + - id: default_path_to_httpbin + uri: ${test.uri} + order: 10000 + predicates: + - name: Path + args: + pattern: /** + ssl: + bundle: + jks: + scg-keystore-with-different-key-password: + key: + password: keyscg1234 + keystore: + type: JKS + location: classpath:scg-keystore-with-different-key-password.jks + password: scg1234 \ No newline at end of file From d087a97b5c31fdbe429fd7273766caf28311ef6c Mon Sep 17 00:00:00 2001 From: spencergibb Date: Mon, 16 Dec 2024 14:22:11 -0500 Subject: [PATCH 14/56] Formatting See gh-3641 --- .../gateway/config/AbstractSslConfigurer.java | 3 ++- .../ssl/ClientCertAuthSSLBundleTests.java | 27 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java index 1996abac..e1e27b66 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/AbstractSslConfigurer.java @@ -67,7 +67,8 @@ public abstract class AbstractSslConfigurer { } protected SslBundle getBundle() { - if (ssl.getSslBundle() != null && ssl.getSslBundle().length() > 0 && bundles.getBundleNames().contains(ssl.getSslBundle())) { + if (ssl.getSslBundle() != null && ssl.getSslBundle().length() > 0 + && bundles.getBundleNames().contains(ssl.getSslBundle())) { return bundles.getBundle(ssl.getSslBundle()); } return null; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java index 7219d97a..e3fa8567 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/ssl/ClientCertAuthSSLBundleTests.java @@ -1,15 +1,32 @@ +/* + * 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.test.ssl; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import org.junit.jupiter.api.BeforeEach; +import reactor.netty.http.client.HttpClient; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; -import reactor.netty.http.client.HttpClient; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -17,6 +34,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @DirtiesContext @ActiveProfiles("client-auth-ssl-bundle") public class ClientCertAuthSSLBundleTests extends SingleCertSSLTests { + @Autowired private SslBundles sslBundles; @@ -24,10 +42,11 @@ public class ClientCertAuthSSLBundleTests extends SingleCertSSLTests { public void setup() throws Exception { final var sslBundle = sslBundles.getBundle("scg-keystore-with-different-key-password"); final var sslContext = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .keyManager(sslBundle.getManagers().getKeyManagerFactory()) - .build(); + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .keyManager(sslBundle.getManagers().getKeyManagerFactory()) + .build(); HttpClient httpClient = HttpClient.create().secure(ssl -> ssl.sslContext(sslContext)); setup(new ReactorClientHttpConnector(httpClient), "https://localhost:" + port); } + } From 3ec77a2d8dedee23b50111797011f95960a40a08 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 17 Dec 2024 10:50:14 -0500 Subject: [PATCH 15/56] Add the ability to disable configuration properties in docs pom --- docs/antora.yml | 2 +- docs/pom.xml | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/antora.yml b/docs/antora.yml index fad926be..4bfa002b 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -6,7 +6,7 @@ nav: ext: collector: run: - command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests + command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests -DdisableConfigurationProperties local: true scan: dir: ./target/classes/antora-resources/ diff --git a/docs/pom.xml b/docs/pom.xml index 4c71f5db..0fed8431 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -25,20 +25,28 @@ .* ${maven.multiModuleProjectDirectory}/docs/modules/ROOT/partials/ - - - ${project.groupId} - spring-cloud-starter-gateway - - - ${project.groupId} - spring-cloud-starter-gateway-mvc - - src/main/asciidoc + + enable-configuration-properties + + + !disableConfigurationProperties + + + + + ${project.groupId} + spring-cloud-starter-gateway + + + ${project.groupId} + spring-cloud-starter-gateway-mvc + + + docs From 9da4abd50c99cabb313621a461a8f7a345caf07c Mon Sep 17 00:00:00 2001 From: spring-builds Date: Mon, 13 Jan 2025 22:11:00 +0000 Subject: [PATCH 16/56] Bumping versions --- pom.xml | 4 ++-- spring-cloud-gateway-dependencies/pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 17a0178f..353ccff7 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.1.5-SNAPSHOT + 4.1.6-SNAPSHOT @@ -55,7 +55,7 @@ 1.0.8.RELEASE 17 1.9.1 - 3.1.4-SNAPSHOT + 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 5a721b66..198369ec 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -6,7 +6,7 @@ spring-cloud-dependencies-parent org.springframework.cloud - 4.1.5-SNAPSHOT + 4.1.6-SNAPSHOT From 3da857d51ae7f4a58d83c0360169fcf674d97827 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 16 Jan 2025 18:46:56 +0000 Subject: [PATCH 17/56] Bumping versions --- README.adoc | 12 ++++-------- 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 +- 15 files changed, 22 insertions(+), 26 deletions(-) diff --git a/README.adoc b/README.adoc index f980ffa7..9d84e36e 100644 --- a/README.adoc +++ b/README.adoc @@ -40,15 +40,11 @@ tracker for issues and merging pull requests into main. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. -[[sign-the-contributor-license-agreement]] -== Sign the Contributor License Agreement +[[developer-certificate-of-origin]] +== Developer Certificate of Origin (DCO) -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. [[code-of-conduct]] == Code of Conduct diff --git a/docs/pom.xml b/docs/pom.xml index df489971..709dc57e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 87438173..c23ff6f3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 2.3.0 - 3.2.1-SNAPSHOT - 4.2.1-SNAPSHOT + 3.3.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 6d255037..2ee6b9a9 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-SNAPSHOT + 4.3.0-SNAPSHOT spring-cloud-gateway-dependencies - 4.2.1-SNAPSHOT + 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 606d6cf6..8c565d40 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.1-SNAPSHOT + 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 f833c541..6ac0d2fd 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.1-SNAPSHOT + 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 c79551c2..9302b3b5 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index e9bf2a3c..461e4c70 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index ed68626d..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.2.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 41884109..b32a638f 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index ba17bdf7..62d1f602 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index c365ed4b..0f07a777 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.1-SNAPSHOT + 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 fe8b8ece..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.2.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index a2c8eba8..dc37832b 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index f32a7980..b445822a 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway From 21caf96774b2db94aca3ed7da8fa0e2f4bf60ed9 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 16 Jan 2025 15:06:34 -0500 Subject: [PATCH 18/56] Adds dco.yml --- .github/dco.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/dco.yml diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 00000000..0c4b142e --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,2 @@ +require: + members: false From 92046f3fc489ca154b53f9c4c03253467ff24653 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 16 Jan 2025 15:07:27 -0500 Subject: [PATCH 19/56] Revert "Bumping versions" This reverts commit 3da857d51ae7f4a58d83c0360169fcf674d97827. --- README.adoc | 12 ++++++++---- 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 +- 15 files changed, 26 insertions(+), 22 deletions(-) diff --git a/README.adoc b/README.adoc index 9d84e36e..f980ffa7 100644 --- a/README.adoc +++ b/README.adoc @@ -40,11 +40,15 @@ tracker for issues and merging pull requests into main. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. -[[developer-certificate-of-origin]] -== Developer Certificate of Origin (DCO) +[[sign-the-contributor-license-agreement]] +== Sign the Contributor License Agreement -All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. -For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. +Before we accept a non-trivial patch or pull request we will need you to sign the +https://cla.pivotal.io/sign/spring[Contributor License Agreement]. +Signing the contributor's agreement does not grant anyone commit rights to the main +repository, but it does mean that we can accept your contributions, and you will get an +author credit if we do. Active contributors might be asked to join the core team, and +given the ability to merge pull requests. [[code-of-conduct]] == Code of Conduct diff --git a/docs/pom.xml b/docs/pom.xml index 709dc57e..df489971 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.2.1-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index c23ff6f3..87438173 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.2.1-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-SNAPSHOT + 4.2.1-SNAPSHOT @@ -55,8 +55,8 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-SNAPSHOT - 4.3.0-SNAPSHOT + 3.2.1-SNAPSHOT + 4.2.1-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 2ee6b9a9..6d255037 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.2.1-SNAPSHOT spring-cloud-gateway-dependencies - 4.3.0-SNAPSHOT + 4.2.1-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 8c565d40..606d6cf6 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 6ac0d2fd..f833c541 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.2.1-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 9302b3b5..c79551c2 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 461e4c70..e9bf2a3c 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 14d0d2aa..ed68626d 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index b32a638f..41884109 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 62d1f602..ba17bdf7 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.2.1-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 0f07a777..c365ed4b 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.2.1-SNAPSHOT .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..fe8b8ece 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.2.1-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index dc37832b..a2c8eba8 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.2.1-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index b445822a..f32a7980 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.2.1-SNAPSHOT .. spring-cloud-starter-gateway From d5f0f5cff7bee4e677b9dca06230160270fbae32 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 16 Jan 2025 15:10:39 -0500 Subject: [PATCH 20/56] Updates to version 4.3.0-SNAPSHOT --- docs/pom.xml | 2 +- pom.xml | 6 +++--- 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, 17 insertions(+), 17 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index df489971..709dc57e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 87438173..78269f86 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT @@ -56,7 +56,7 @@ 17 2.3.0 3.2.1-SNAPSHOT - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 6d255037..2ee6b9a9 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-SNAPSHOT + 4.3.0-SNAPSHOT spring-cloud-gateway-dependencies - 4.2.1-SNAPSHOT + 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 606d6cf6..8c565d40 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.1-SNAPSHOT + 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 f833c541..6ac0d2fd 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.1-SNAPSHOT + 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 c79551c2..9302b3b5 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index e9bf2a3c..461e4c70 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index ed68626d..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.2.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 41884109..b32a638f 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index ba17bdf7..62d1f602 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-gateway-server-mvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index c365ed4b..0f07a777 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.1-SNAPSHOT + 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 fe8b8ece..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.2.1-SNAPSHOT + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index a2c8eba8..dc37832b 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index f32a7980..b445822a 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.1-SNAPSHOT + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway From ab5e61d4d39f4465125a082f32a8aaf5628a8703 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 16 Jan 2025 21:13:46 -0500 Subject: [PATCH 21/56] Adds support for a Bucket4jRateLimiter in server webflux (#2955) * Adds support for a Bucket4jRateLimiter * Makes bucket4j-core optional and caffeine integration test scoped * Adds Bucket4jRateLimiter auto-configuration * Updates bucket4j to 8.14.0 * Adds customizable header and adapts to async build * Adds configuration for alternative RefillStyles * Adds documentation and refillTokens property --- .../requestratelimiter-factory.adoc | 88 +++++- pom.xml | 6 +- spring-cloud-gateway-server-mvc/pom.xml | 4 +- spring-cloud-gateway-server/pom.xml | 11 + .../config/GatewayAutoConfiguration.java | 16 ++ .../filter/ratelimit/Bucket4jRateLimiter.java | 266 ++++++++++++++++++ .../ratelimit/Bucket4jRateLimiterTests.java | 157 +++++++++++ .../ratelimit/RedisRateLimiterTests.java | 2 + 8 files changed, 540 insertions(+), 10 deletions(-) create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc index 6f0044d4..6a96ddc3 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc @@ -27,6 +27,17 @@ The default implementation of `KeyResolver` is the `PrincipalNameKeyResolver`, w By default, if the `KeyResolver` does not find a key, requests are denied. You can adjust this behavior by setting the `spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key` (`true` or `false`) and `spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code` properties. +The following example configures a `KeyResolver` in Java: + +.Config.java +[source,java] +---- +@Bean +KeyResolver userKeyResolver() { + return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); +} +---- + [NOTE] ===== The `RequestRateLimiter` is not configurable with the "shortcut" notation. The following example below is _invalid_: @@ -81,6 +92,7 @@ The following listing configures a `redis-rate-limiter`: Rate limits below `1 request/s` are accomplished by setting `replenishRate` to the wanted number of requests, `requestedTokens` to the timespan in seconds, and `burstCapacity` to the product of `replenishRate` and `requestedTokens`. For example, setting `replenishRate=1`, `requestedTokens=60`, and `burstCapacity=60` results in a limit of `1 request/min`. + .application.yml [source,yaml] ---- @@ -99,21 +111,87 @@ spring: ---- -The following example configures a `KeyResolver` in Java: +This defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available. +The `KeyResolver` is a simple one that gets the `user` request parameter +NOTE: This is not recommended for production + +[[bucket4j-ratelimiter]] +== Bucket4j `RateLimiter` + +This implementation is based on the https://bucket4j.com/[Bucket4j] Java library. +It requires the use of the `com.bucket4j:bucket4j_jdk17-core` dependency as well as one of the https://github.com/bucket4j/bucket4j?tab=readme-ov-file#bucket4j-distributed-features[distributed persistence options]. + +In this example, we will use the Caffeine integration, which is a local cache. This can be added by including the `com.github.ben-manes.caffeine:caffeine` artifact in your dependency management. The `com.bucket4j:bucket4j_jdk17-caffeine` artifact will need to be imported as well. + +.pom.xml +[source,xml] +---- + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + com.bucket4j + bucket4j_jdk17-caffeine + ${bucket4j.version} + +---- + +First a bean of type `io.github.bucket4j.distributed.proxy.AsyncProxyMananger` needs to be created. .Config.java [source,java] ---- @Bean -KeyResolver userKeyResolver() { - return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); +AsyncProxyManager caffeineProxyManager() { + Caffeine builder = (Caffeine) Caffeine.newBuilder().maximumSize(100); + return new CaffeineProxyManager<>(builder, Duration.ofMinutes(1)).asAsync(); } ---- -This defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available. -The `KeyResolver` is a simple one that gets the `user` request parameter +The `bucket4j-rate-limiter.capacity` property is the maximum number of requests a user is allowed in a single second (without any dropped requests). +This is the number of tokens the token bucket can hold. +Must be greater than zero. + +The `bucket4j-rate-limiter.refillPeriod` property defines the refill period. The bucket refills at a rate of `refillTokens` per `refillPeriod`. This is a required property and uses the https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.typesafe-configuration-properties.conversion.periods[Spring Boot Period format]. + +The `bucket4j-rate-limiter.refillTokens` property defines how many tokens are added to the bucket in during `refillPeriod`. +This defaults to `capacity` and must be greater than or equal to zero. + +The `bucket4j-rate-limiter.requestedTokens` property is how many tokens a request costs. +This is the number of tokens taken from the bucket for each request and defaults to `1`. Must be greater than zero. + +The `bucket4j-rate-limiter.refillStyle` property defines how the bucket is refilled. The 3 options are `GREEDY` (default), `INTERVALLY` and `INTERVALLY_ALIGNED`. +`GREEDY` tries to add the tokens to the bucket as soon as possible. `INTERVALLY`, in opposite to greedy, waits until the whole `refillPeriod` has elapsed before refilling tokens. `INTERVALLY_ALIGNED` is like `INTERVALLY`, but with a specified `timeOfFirstRefill`. + +The `bucket4j-rate-limiter.timeOfFirstRefill` property is an `Instant` only used when `refillStyle` is set to `INTERVALLY_ALIGNED`. + +The following example defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available. NOTE: This is not recommended for production +.application.yml +[source,yaml] +---- +spring: + cloud: + gateway: + routes: + - id: requestratelimiter_route + uri: https://example.org + filters: + - name: RequestRateLimiter + args: + bucket4j-rate-limiter.capacity: 20 + bucket4j-rate-limiter.refillTokens: 10 + bucket4j-rate-limiter.refillPeriod: 1s + bucket4j-rate-limiter.requestedTokens: 1 + +---- + +[[custom-ratelimiter]] +== Custom `RateLimiter` + You can also define a rate limiter as a bean that implements the `RateLimiter` interface. In configuration, you can reference the bean by name using SpEL. `#{@myRateLimiter}` is a SpEL expression that references a bean with named `myRateLimiter`. diff --git a/pom.xml b/pom.xml index 78269f86..4ca15e53 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ UTF-8 UTF-8 - 8.10.1 + 8.14.0 1.0.8.RELEASE 17 2.3.0 @@ -99,12 +99,12 @@ com.bucket4j - bucket4j-core + bucket4j_jdk17-core ${bucket4j.version} com.bucket4j - bucket4j-caffeine + bucket4j_jdk17-caffeine ${bucket4j.version} diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 62d1f602..62aa2075 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -75,7 +75,7 @@ com.bucket4j - bucket4j-core + bucket4j_jdk17-core true @@ -92,7 +92,7 @@ com.bucket4j - bucket4j-caffeine + bucket4j_jdk17-caffeine test diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 0f07a777..8ba0bd52 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -17,6 +17,7 @@ ${basedir}/.. 1.68.1 + 1.0.0 @@ -135,6 +136,16 @@ caffeine true + + com.bucket4j + bucket4j_jdk17-core + true + + + com.bucket4j + bucket4j_jdk17-caffeine + test + io.micrometer micrometer-observation-test 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 2b89cc0e..85767b84 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 @@ -25,6 +25,7 @@ import java.util.function.Supplier; import javax.net.ssl.TrustManagerFactory; +import io.github.bucket4j.distributed.proxy.AsyncProxyManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; @@ -123,6 +124,7 @@ import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter; import org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter; import org.springframework.cloud.gateway.filter.headers.TransferEncodingNormalizationHeadersFilter; import org.springframework.cloud.gateway.filter.headers.XForwardedHeadersFilter; +import org.springframework.cloud.gateway.filter.ratelimit.Bucket4jRateLimiter; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.cloud.gateway.filter.ratelimit.PrincipalNameKeyResolver; import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter; @@ -736,6 +738,20 @@ public class GatewayAutoConfiguration { return new ConfigurableHintsRegistrationProcessor(); } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(AsyncProxyManager.class) + protected static class Bucket4jConfiguration { + + @Bean + @ConditionalOnBean(AsyncProxyManager.class) + @ConditionalOnEnabledFilter(RequestRateLimiterGatewayFilterFactory.class) + public Bucket4jRateLimiter bucket4jRateLimiter(AsyncProxyManager proxyManager, + ConfigurationService configurationService) { + return new Bucket4jRateLimiter(proxyManager, configurationService); + } + + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(HttpClient.class) protected static class NettyConfiguration { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java new file mode 100644 index 00000000..b32a47c1 --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java @@ -0,0 +1,266 @@ +/* + * 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.filter.ratelimit; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Supplier; + +import io.github.bucket4j.Bandwidth; +import io.github.bucket4j.BandwidthBuilder.BandwidthBuilderBuildStage; +import io.github.bucket4j.BandwidthBuilder.BandwidthBuilderRefillStage; +import io.github.bucket4j.BucketConfiguration; +import io.github.bucket4j.ConsumptionProbe; +import io.github.bucket4j.distributed.AsyncBucketProxy; +import io.github.bucket4j.distributed.proxy.AsyncProxyManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator; +import org.springframework.cloud.gateway.support.ConfigurationService; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; + +public class Bucket4jRateLimiter extends AbstractRateLimiter { + + /** + * Default Header Name. + */ + public static final String DEFAULT_HEADER_NAME = "X-RateLimit-Remaining"; + + /** + * Redis Rate Limiter property name. + */ + public static final String CONFIGURATION_PROPERTY_NAME = "bucket4j-rate-limiter"; + + private final Log log = LogFactory.getLog(getClass()); + + private final AsyncProxyManager proxyManager; + + private Config defaultConfig = new Config(); + + public Bucket4jRateLimiter(AsyncProxyManager proxyManager, ConfigurationService configurationService) { + super(Config.class, CONFIGURATION_PROPERTY_NAME, configurationService); + this.proxyManager = proxyManager; + } + + @Override + public Mono isAllowed(String routeId, String id) { + Config routeConfig = loadRouteConfiguration(routeId); + + AsyncBucketProxy bucket = proxyManager.builder().build(id, routeConfig.getConfigurationSupplier()); + CompletableFuture bucketFuture = bucket + .tryConsumeAndReturnRemaining(routeConfig.getRequestedTokens()); + return Mono.fromFuture(bucketFuture).onErrorResume(throwable -> { + if (log.isDebugEnabled()) { + log.debug("Error calling Bucket4J rate limiter", throwable); + } + return Mono.just(ConsumptionProbe.rejected(-1, -1, -1)); + }).map(consumptionProbe -> { + boolean allowed = consumptionProbe.isConsumed(); + long remainingTokens = consumptionProbe.getRemainingTokens(); + Response response = new Response(allowed, getHeaders(routeConfig, remainingTokens)); + + if (log.isDebugEnabled()) { + log.debug("response: " + response); + } + return response; + }); + } + + protected Config loadRouteConfiguration(String routeId) { + Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig); + + if (routeConfig == null) { + routeConfig = getConfig().get(RouteDefinitionRouteLocator.DEFAULT_FILTERS); + } + + if (routeConfig == null) { + throw new IllegalArgumentException("No Configuration found for route " + routeId + " or defaultFilters"); + } + return routeConfig; + } + + public Map getHeaders(Config config, Long tokensLeft) { + Map headers = new HashMap<>(); + // TODO: configurable isIncludeHeaders? + // if (isIncludeHeaders()) { + headers.put(config.getHeaderName(), tokensLeft.toString()); + // } + return headers; + } + + public static class Config { + + private static final Function DEFAULT_CONFIGURATION_BUILDER = config -> { + BandwidthBuilderRefillStage bandwidth = Bandwidth.builder().capacity(config.getCapacity()); + + long refillTokens = config.getRefillTokens() == null ? config.getCapacity() : config.getRefillTokens(); + + BandwidthBuilderBuildStage refill = switch (config.getRefillStyle()) { + case GREEDY -> bandwidth.refillGreedy(refillTokens, config.getRefillPeriod()); + case INTERVALLY -> bandwidth.refillIntervally(refillTokens, config.getRefillPeriod()); + case INTERVALLY_ALIGNED -> bandwidth.refillIntervallyAligned(refillTokens, config.getRefillPeriod(), + config.getTimeOfFirstRefill()); + }; + + return BucketConfiguration.builder().addLimit(refill.build()).build(); + }; + + long capacity; + + Function configurationBuilder = DEFAULT_CONFIGURATION_BUILDER; + + Supplier> configurationSupplier; + + String headerName = DEFAULT_HEADER_NAME; + + Duration refillPeriod; + + RefillStyle refillStyle = RefillStyle.GREEDY; + + Long refillTokens; + + long requestedTokens = 1; + + // for RefillStyle.INTERVALLY_ALIGNED + Instant timeOfFirstRefill; + + public long getCapacity() { + return capacity; + } + + public Config setCapacity(long capacity) { + this.capacity = capacity; + return this; + } + + public Function getConfigurationBuilder() { + return configurationBuilder; + } + + public void setConfigurationBuilder(Function configurationBuilder) { + Assert.notNull(configurationBuilder, "configurationBuilder may not be null"); + this.configurationBuilder = configurationBuilder; + } + + public Supplier> getConfigurationSupplier() { + if (configurationSupplier != null) { + return configurationSupplier; + } + return () -> CompletableFuture.completedFuture(getConfigurationBuilder().apply(this)); + } + + public void setConfigurationSupplier(Function configurationBuilder) { + Assert.notNull(configurationBuilder, "configurationBuilder may not be null"); + this.configurationBuilder = configurationBuilder; + } + + public String getHeaderName() { + return headerName; + } + + public Config setHeaderName(String headerName) { + Assert.notNull(headerName, "headerName may not be null"); + this.headerName = headerName; + return this; + } + + public Duration getRefillPeriod() { + return refillPeriod; + } + + public Config setRefillPeriod(Duration refillPeriod) { + this.refillPeriod = refillPeriod; + return this; + } + + public RefillStyle getRefillStyle() { + return refillStyle; + } + + public Config setRefillStyle(RefillStyle refillStyle) { + this.refillStyle = refillStyle; + return this; + } + + public Long getRefillTokens() { + return refillTokens; + } + + public Config setRefillTokens(Long refillTokens) { + this.refillTokens = refillTokens; + return this; + } + + public long getRequestedTokens() { + return requestedTokens; + } + + public Config setRequestedTokens(long requestedTokens) { + this.requestedTokens = requestedTokens; + return this; + } + + public Instant getTimeOfFirstRefill() { + return timeOfFirstRefill; + } + + public Config setTimeOfFirstRefill(Instant timeOfFirstRefill) { + this.timeOfFirstRefill = timeOfFirstRefill; + return this; + } + + public String toString() { + return new ToStringCreator(this).append("capacity", capacity) + .append("headerName", headerName) + .append("refillPeriod", refillPeriod) + .append("refillStyle", refillStyle) + .append("refillTokens", refillTokens) + .append("requestedTokens", requestedTokens) + .append("timeOfFirstRefill", timeOfFirstRefill) + .toString(); + } + + } + + public enum RefillStyle { + + /** + * Greedy tries to add the tokens to the bucket as soon as possible. + */ + GREEDY, + + /** + * Intervally, in opposite to greedy, waits until the whole refillPeriod has elapsed + * before refilling tokens. + */ + INTERVALLY, + + /** + * IntervallyAligned, like Intervally, but with a specified first refill time. + */ + INTERVALLY_ALIGNED; + + } + +} 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 new file mode 100644 index 00000000..f262300b --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiterTests.java @@ -0,0 +1,157 @@ +/* + * 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.ratelimit; + +import java.time.Duration; +import java.util.UUID; + +import com.github.benmanes.caffeine.cache.Caffeine; +import io.github.bucket4j.caffeine.CaffeineProxyManager; +import io.github.bucket4j.distributed.proxy.AsyncProxyManager; +import io.github.bucket4j.distributed.remote.RemoteBucketState; +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.RetryingTest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.filter.ratelimit.Bucket4jRateLimiter.RefillStyle; +import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter.Response; +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.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Spencer Gibb + */ +@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.cloud.gateway.redis.enabled=false") +@DirtiesContext +public class Bucket4jRateLimiterTests extends BaseWebClientTests { + + @Autowired + private Bucket4jRateLimiter rateLimiter; + + @RetryingTest(3) + public void bucket4jRateLimiterGreedyWorks() throws Exception { + bucket4jRateLimiterWorks(RefillStyle.GREEDY); + } + + @RetryingTest(3) + public void bucket4jRateLimiterIntervallyWorks() throws Exception { + bucket4jRateLimiterWorks(RefillStyle.INTERVALLY); + } + + public void bucket4jRateLimiterWorks(RefillStyle refillStyle) throws Exception { + String id = UUID.randomUUID().toString(); + + long capacity = 10; + int requestedTokens = 1; + + String routeId = "myroute"; + rateLimiter.getConfig() + .put(routeId, + new Bucket4jRateLimiter.Config().setRefillStyle(refillStyle) + .setHeaderName("X-RateLimit-Custom") + .setCapacity(capacity) + .setRefillPeriod(Duration.ofSeconds(1))); + + checkLimitEnforced(id, capacity, requestedTokens, routeId); + } + + @Test + public void bucket4jRateLimiterIsAllowedFalseWorks() throws Exception { + String id = UUID.randomUUID().toString(); + + int capacity = 1; + int requestedTokens = 2; + + String routeId = "zero_capacity_route"; + rateLimiter.getConfig() + .put(routeId, + new Bucket4jRateLimiter.Config().setCapacity(capacity) + .setRefillPeriod(Duration.ofSeconds(1)) + .setRequestedTokens(requestedTokens)); + + Response response = rateLimiter.isAllowed(routeId, id).block(); + assertThat(response.isAllowed()).isFalse(); + } + + private void checkLimitEnforced(String id, long capacity, int requestedTokens, String routeId) + throws InterruptedException { + // Bursts work + simulateBurst(id, capacity, requestedTokens, routeId); + + checkLimitReached(id, routeId, capacity); + + Thread.sleep(Math.max(1, requestedTokens / capacity) * 1000); + + // # After the burst is done, check the steady state + checkSteadyState(id, capacity, routeId); + } + + private void simulateBurst(String id, long capacity, int requestedTokens, String routeId) { + long previousRemaining = capacity; + for (int i = 0; i < capacity / requestedTokens; i++) { + Response response = rateLimiter.isAllowed(routeId, id).block(); + assertThat(response.isAllowed()).as("Burst # %s is allowed", i).isTrue(); + assertThat(response.getHeaders()).containsKey("X-RateLimit-Custom"); + System.err.println("response headers: " + response.getHeaders()); + long remaining = Long.parseLong(response.getHeaders().get("X-RateLimit-Custom")); + assertThat(remaining).isLessThan(previousRemaining); + previousRemaining = remaining; + // TODO: assert additional headers + } + } + + private void checkLimitReached(String id, String routeId, long capacity) { + Response response = rateLimiter.isAllowed(routeId, id).block(); + if (response.isAllowed()) { // TODO: sometimes there is an off by one error + response = rateLimiter.isAllowed(routeId, id).block(); + } + assertThat(response.isAllowed()).as("capacity # %s is not allowed", capacity).isFalse(); + } + + private void checkSteadyState(String id, long capacity, String routeId) { + Response response; + for (int i = 0; i < capacity; i++) { + response = rateLimiter.isAllowed(routeId, id).block(); + assertThat(response.isAllowed()).as("steady state # %s is allowed", i).isTrue(); + } + + response = rateLimiter.isAllowed(routeId, id).block(); + assertThat(response.isAllowed()).as("steady state # %s is allowed", capacity).isFalse(); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + @Bean + public AsyncProxyManager caffeineProxyManager() { + Caffeine builder = (Caffeine) Caffeine.newBuilder().maximumSize(100); + return new CaffeineProxyManager<>(builder, Duration.ofMinutes(1)).asAsync(); + } + + } + +} 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 29a914dd..9181ce03 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 @@ -22,6 +22,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; import org.junitpioneer.jupiter.RetryingTest; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; @@ -100,6 +101,7 @@ public class RedisRateLimiterTests extends BaseWebClientTests { } @Test + @DisabledIfEnvironmentVariable(named = "GITHUB_ACTIONS", matches = "true") public void redisRateLimiterWorksForMultipleRoutes() throws Exception { String id = UUID.randomUUID().toString(); From af200a5c86ca0e20f9c609e096e2569eff24071b Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 16 Jan 2025 21:18:21 -0500 Subject: [PATCH 22/56] Adds support for spring-cloud-function and spring-cloud-stream handlers (#3646) * Add support for spring cloud function handler. * Add support for spring cloud stream handler. * Add support for path variable expansion in fn: and stream: URIs * Adds support for config based fn/stream HandlerFunctions * Starting support for webflux function support * Adds fn:functionName support for webflux server * Adds spring-cloud-starter-stream-rabbit to test scope * Adds StreamRoutingFilter to webflux server --- pom.xml | 16 ++ spring-cloud-gateway-server-mvc/pom.xml | 30 +++ .../handler/FunctionHandlerHeaderUtils.java | 116 ++++++++++ ...unctionHandlerRequestProcessingHelper.java | 130 ++++++++++++ .../server/mvc/handler/HandlerFunctions.java | 55 +++++ .../config/FunctionHandlerConfigTests.java | 77 +++++++ .../mvc/config/StreamHandlerConfigTests.java | 107 ++++++++++ .../mvc/handler/FunctionHandlerTests.java | 92 ++++++++ .../mvc/handler/StreamHandlerTests.java | 119 +++++++++++ ...application-functionhandlerconfigtests.yml | 16 ++ .../application-streamhandlerconfigtests.yml | 16 ++ spring-cloud-gateway-server/pom.xml | 36 +++- .../GatewayFunctionAutoConfiguration.java | 52 +++++ .../GatewayStreamAutoConfiguration.java | 48 +++++ .../gateway/filter/FunctionRoutingFilter.java | 198 ++++++++++++++++++ .../gateway/filter/StreamRoutingFilter.java | 103 +++++++++ .../gateway/support/MessageHeaderUtils.java | 116 ++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../filter/FunctionRoutingFilterTests.java | 80 +++++++ .../filter/StreamRoutingFilterTests.java | 106 ++++++++++ 20 files changed, 1512 insertions(+), 3 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerRequestProcessingHelper.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilter.java create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/StreamRoutingFilter.java create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/MessageHeaderUtils.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilterTests.java create mode 100644 spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/StreamRoutingFilterTests.java diff --git a/pom.xml b/pom.xml index 4ca15e53..d8937b9b 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,8 @@ 2.3.0 3.2.1-SNAPSHOT 4.3.0-SNAPSHOT + 4.2.1-SNAPSHOT + 4.2.1-SNAPSHOT @@ -75,6 +77,20 @@ pom import + + org.springframework.cloud + spring-cloud-function-dependencies + ${spring-cloud-function.version} + pom + import + + + org.springframework.cloud + spring-cloud-stream-dependencies + ${spring-cloud-stream.version} + pom + import + org.springframework.cloud spring-cloud-test-support diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 62aa2075..6f7ff6b3 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -52,6 +52,16 @@ org.springframework.cloud spring-cloud-commons + + org.springframework.cloud + spring-cloud-function-context + true + + + org.springframework.cloud + spring-cloud-stream + true + org.springframework.cloud spring-cloud-loadbalancer @@ -89,7 +99,22 @@ spring-boot-properties-migrator test + + org.springframework.boot + spring-boot-testcontainers + test + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + test + + + org.awaitility + awaitility + test + com.bucket4j bucket4j_jdk17-caffeine @@ -105,5 +130,10 @@ junit-jupiter test + + org.testcontainers + rabbitmq + test + \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java new file mode 100644 index 00000000..891f05c1 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java @@ -0,0 +1,116 @@ +/* + * Copyright 2012-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.server.mvc.handler; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.springframework.http.HttpHeaders; +import org.springframework.messaging.MessageHeaders; + +/** + * @author Dave Syer + * @author Oleg Zhurakousky + */ +public final class FunctionHandlerHeaderUtils { + + /** + * Message Header name which contains HTTP request parameters. + */ + public static final String HTTP_REQUEST_PARAM = "http_request_param"; + + private static HttpHeaders IGNORED = new HttpHeaders(); + + private static HttpHeaders REQUEST_ONLY = new HttpHeaders(); + + static { + IGNORED.add(MessageHeaders.ID, ""); + IGNORED.add(HttpHeaders.CONTENT_LENGTH, "0"); + // Headers that would typically be added by a downstream client + REQUEST_ONLY.add(HttpHeaders.ACCEPT, ""); + REQUEST_ONLY.add(HttpHeaders.CONTENT_LENGTH, ""); + REQUEST_ONLY.add(HttpHeaders.CONTENT_TYPE, ""); + REQUEST_ONLY.add(HttpHeaders.HOST, ""); + } + + private FunctionHandlerHeaderUtils() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + + public static HttpHeaders fromMessage(MessageHeaders headers, List ignoredHeders) { + HttpHeaders result = new HttpHeaders(); + for (String name : headers.keySet()) { + Object value = headers.get(name); + name = name.toLowerCase(Locale.ROOT); + if (!IGNORED.containsKey(name) && !ignoredHeders.contains(name)) { + Collection values = multi(value); + for (Object object : values) { + result.set(name, object.toString()); + } + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static HttpHeaders fromMessage(MessageHeaders headers) { + return fromMessage(headers, Collections.EMPTY_LIST); + } + + public static HttpHeaders sanitize(HttpHeaders request, List ignoredHeders, + List requestOnlyHeaders) { + HttpHeaders result = new HttpHeaders(); + for (String name : request.keySet()) { + List value = request.get(name); + name = name.toLowerCase(Locale.ROOT); + if (!IGNORED.containsKey(name) && !REQUEST_ONLY.containsKey(name) && !ignoredHeders.contains(name) + && !requestOnlyHeaders.contains(name)) { + result.put(name, value); + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static HttpHeaders sanitize(HttpHeaders request) { + return sanitize(request, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + } + + public static MessageHeaders fromHttp(HttpHeaders headers) { + Map map = new LinkedHashMap<>(); + for (String name : headers.keySet()) { + Collection values = multi(headers.get(name)); + name = name.toLowerCase(Locale.ROOT); + Object value = values == null ? null : (values.size() == 1 ? values.iterator().next() : values); + if (name.toLowerCase(Locale.ROOT).equals(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ROOT))) { + name = MessageHeaders.CONTENT_TYPE; + } + map.put(name, value); + } + return new MessageHeaders(map); + } + + private static Collection multi(Object value) { + return value instanceof Collection ? (Collection) value : Arrays.asList(value); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerRequestProcessingHelper.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerRequestProcessingHelper.java new file mode 100644 index 00000000..1990991b --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerRequestProcessingHelper.java @@ -0,0 +1,130 @@ +/* + * Copyright 2019-2021 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.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.CollectionUtils; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; +import org.springframework.web.servlet.function.ServerResponse.BodyBuilder; + +import static org.springframework.cloud.gateway.server.mvc.handler.FunctionHandlerHeaderUtils.fromMessage; +import static org.springframework.cloud.gateway.server.mvc.handler.FunctionHandlerHeaderUtils.sanitize; + +/** + * !INTERNAL USE ONLY! + * + * @author Oleg Zhurakousky + * + */ +final class FunctionHandlerRequestProcessingHelper { + + private static Log logger = LogFactory.getLog(FunctionHandlerRequestProcessingHelper.class); + + private FunctionHandlerRequestProcessingHelper() { + + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + static ServerResponse processRequest(ServerRequest request, FunctionInvocationWrapper function, Object argument, + boolean eventStream, List ignoredHeaders, List requestOnlyHeaders) { + if (argument == null) { + argument = ""; + } + + if (function == null) { + return ServerResponse.notFound().build(); + } + + HttpHeaders headers = request.headers().asHttpHeaders(); + + Message inputMessage = null; + + MessageBuilder builder = MessageBuilder.withPayload(argument); + if (!CollectionUtils.isEmpty(request.params())) { + builder = builder.setHeader(FunctionHandlerHeaderUtils.HTTP_REQUEST_PARAM, + request.params().toSingleValueMap()); + } + inputMessage = builder.copyHeaders(headers.toSingleValueMap()).build(); + + if (function.isRoutingFunction()) { + function.setSkipOutputConversion(true); + } + + Object result = function.apply(inputMessage); + if (function.isConsumer()) { + /* + * if (result instanceof Publisher) { Mono.from((Publisher) + * result).subscribe(); } + */ + return HttpMethod.DELETE.equals(request.method()) ? ServerResponse.ok().build() + : ServerResponse.accepted() + .headers(h -> h.addAll(sanitize(headers, ignoredHeaders, requestOnlyHeaders))) + .build(); + // Mono.empty() : + // Mono.just(ResponseEntity.accepted().headers(FunctionHandlerHeaderUtils.sanitize(headers, + // ignoredHeaders, requestOnlyHeaders)).build()); + } + + BodyBuilder responseOkBuilder = ServerResponse.ok() + .headers(h -> h.addAll(sanitize(headers, ignoredHeaders, requestOnlyHeaders))); + + // FIXME: Mono/Flux + /* + * Publisher pResult; if (result instanceof Publisher) { pResult = (Publisher) + * result; if (eventStream) { return Flux.from(pResult); } + * + * if (pResult instanceof Flux) { pResult = ((Flux) pResult).onErrorContinue((e, + * v) -> { logger.error("Failed to process value: " + v, (Throwable) e); + * }).collectList(); } pResult = Mono.from(pResult); } else { pResult = + * Mono.just(result); } + */ + + // return Mono.from(pResult).map(v -> { + if (result instanceof Iterable i) { + List aggregatedResult = (List) StreamSupport.stream(i.spliterator(), false).map(m -> { + return m instanceof Message ? processMessage(responseOkBuilder, (Message) m, ignoredHeaders) : m; + }).collect(Collectors.toList()); + return responseOkBuilder.header("content-type", "application/json").body(aggregatedResult); + } + else if (result instanceof Message message) { + return responseOkBuilder.body(processMessage(responseOkBuilder, message, ignoredHeaders)); + } + else { + return responseOkBuilder.body(result); + } + // }); + } + + private static Object processMessage(BodyBuilder responseOkBuilder, Message message, + List ignoredHeaders) { + responseOkBuilder.headers(h -> h.addAll(fromMessage(message.getHeaders(), ignoredHeaders))); + return message.getPayload(); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java index 9b3d118b..4b35cc44 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java @@ -21,22 +21,77 @@ import java.lang.reflect.Method; import java.net.URI; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; import jakarta.servlet.ServletException; +import org.springframework.cloud.function.context.FunctionCatalog; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; +import org.springframework.cloud.stream.function.StreamOperations; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.Assert; +import org.springframework.util.MimeType; import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; +import static org.springframework.cloud.gateway.server.mvc.handler.FunctionHandlerRequestProcessingHelper.processRequest; + public abstract class HandlerFunctions { private HandlerFunctions() { } + // for properties + public static HandlerFunction fn(RouteProperties routeProperties) { + // fn:fnName + return fn(routeProperties.getUri().getSchemeSpecificPart()); + } + + public static HandlerFunction fn(String functionName) { + Assert.hasText(functionName, "'functionName' must not be empty"); + return request -> { + String expandedFunctionName = MvcUtils.expand(request, functionName); + FunctionCatalog functionCatalog = MvcUtils.getApplicationContext(request).getBean(FunctionCatalog.class); + FunctionInvocationWrapper function = functionCatalog.lookup(expandedFunctionName, + request.headers().accept().stream().map(MimeType::toString).toArray(String[]::new)); + if (function != null) { + Object body = request.body(function.getRawInputType()); + return processRequest(request, function, body, false, Collections.emptyList(), Collections.emptyList()); + } + return ServerResponse.notFound().build(); + }; + } + + // for properties + public static HandlerFunction stream(RouteProperties routeProperties) { + // stream:bindingName + return stream(routeProperties.getUri().getSchemeSpecificPart()); + } + + public static HandlerFunction stream(String bindingName) { + Assert.hasText(bindingName, "'bindingName' must not be empty"); + // TODO: validate bindingName + return request -> { + String expandedBindingName = MvcUtils.expand(request, bindingName); + StreamOperations streamOps = MvcUtils.getApplicationContext(request).getBean(StreamOperations.class); + byte[] body = request.body(byte[].class); + MessageHeaders messageHeaders = FunctionHandlerHeaderUtils + .fromHttp(FunctionHandlerHeaderUtils.sanitize(request.headers().asHttpHeaders())); + boolean send = streamOps.send(expandedBindingName, MessageBuilder.createMessage(body, messageHeaders)); + if (send) { + return ServerResponse.accepted().build(); + } + return ServerResponse.badRequest().build(); + }; + } + + // for properties public static HandlerFunction forward(RouteProperties routeProperties) { return forward(routeProperties.getUri().getPath()); } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java new file mode 100644 index 00000000..21fe10f2 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java @@ -0,0 +1,77 @@ +/* + * 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.server.mvc.config; + +import java.util.Locale; +import java.util.function.Function; + +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.client.TestRestClient; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(properties = {}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("functionhandlerconfigtests") +public class FunctionHandlerConfigTests { + + @Autowired + private TestRestClient restClient; + + @Test + public void testSimpleFunctionWorks() { + restClient.post() + .uri("/simplefunction") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("HELLO"); + } + + @Test + public void testTemplatedFunctionWorks() { + restClient.post() + .uri("/templatedfunction/upper") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("HELLO"); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + @Bean + Function upper() { + return s -> s.toUpperCase(Locale.ROOT); + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java new file mode 100644 index 00000000..5227cc70 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java @@ -0,0 +1,107 @@ +/* + * 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.server.mvc.config; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.RabbitMQContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +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.testcontainers.service.connection.ServiceConnection; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest( + properties = { "spring.cloud.function.definition=consumeHello", + "spring.cloud.stream.bindings.consumeHello-in-0.destination=hello-out-0" }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("streamhandlerconfigtests") +@Testcontainers +public class StreamHandlerConfigTests { + + @Container + @ServiceConnection + public static RabbitMQContainer rabbitmq = new RabbitMQContainer("rabbitmq:3.7.25-management-alpine"); + + @Autowired + private TestRestClient restClient; + + @Autowired + private AtomicBoolean helloConsumed; + + @Test + public void testSimpleStreamWorks() { + helloConsumed.set(false); + restClient.post() + .uri("/simplestream") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isAccepted(); + + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> helloConsumed.get()); + assertThat(helloConsumed).isTrue(); + } + + @Test + public void testTemplatedStreamWorks() { + helloConsumed.set(false); + restClient.post() + .uri("/templatedstream/hello") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isAccepted(); + + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> helloConsumed.get()); + assertThat(helloConsumed).isTrue(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + @Bean + public AtomicBoolean helloConsumed() { + return new AtomicBoolean(false); + } + + @Bean + public Consumer consumeHello(AtomicBoolean helloConsumed) { + return message -> { + helloConsumed.compareAndSet(false, true); + }; + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java new file mode 100644 index 00000000..28d17153 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java @@ -0,0 +1,92 @@ +/* + * 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.server.mvc.handler; + +import java.util.Locale; +import java.util.function.Function; + +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.client.TestRestClient; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.fn; + +@SpringBootTest(properties = {}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class FunctionHandlerTests { + + @Autowired + private TestRestClient restClient; + + @Test + public void testSimpleFunctionWorks() { + restClient.post() + .uri("/simplefunction") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("HELLO"); + } + + @Test + public void testTemplatedFunctionWorks() { + restClient.post() + .uri("/templatedfunction/upper") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("HELLO"); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + @Bean + Function upper() { + return s -> s.toUpperCase(Locale.ROOT); + } + + @Bean + public RouterFunction gatewayRouterFunctionsSimpleFunction() { + // @formatter:off + return route("testsimplefunction") + .POST("/simplefunction", fn("upper")) + .build() + .and(route("testtemplatedfunction") + .POST("/templatedfunction/{fnName}", fn("{fnName}")) + .build()); + // @formatter:on + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java new file mode 100644 index 00000000..aa89417d --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java @@ -0,0 +1,119 @@ +/* + * 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.server.mvc.handler; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.RabbitMQContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +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.testcontainers.service.connection.ServiceConnection; +import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; +import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; +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.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.stream; + +@SpringBootTest( + properties = { "spring.cloud.function.definition=consumeHello", + "spring.cloud.stream.bindings.consumeHello-in-0.destination=hello-out-0" }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Testcontainers +public class StreamHandlerTests { + + @Container + @ServiceConnection + public static RabbitMQContainer rabbitmq = new RabbitMQContainer("rabbitmq:3.7.25-management-alpine"); + + @Autowired + private TestRestClient restClient; + + @Autowired + private AtomicBoolean helloConsumed; + + @Test + public void testSimpleStreamWorks() { + helloConsumed.set(false); + restClient.post() + .uri("/simplestream") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isAccepted(); + + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> helloConsumed.get()); + assertThat(helloConsumed).isTrue(); + } + + @Test + public void testTemplatedStreamWorks() { + helloConsumed.set(false); + restClient.post() + .uri("/templatedstream/hello") + .accept(MediaType.TEXT_PLAIN) + .bodyValue("hello") + .exchange() + .expectStatus() + .isAccepted(); + + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> helloConsumed.get()); + assertThat(helloConsumed).isTrue(); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfiguration { + + @Bean + public RouterFunction gatewayRouterFunctionsSimpleStream() { + // @formatter:off + return route("testsimplestream") + .POST("/simplestream", stream("hello-out-0")) + .build() + .and(route("testtemplatedstream") + .POST("/templatedstream/{name}", stream("{name}-out-0")) + .build()); + // @formatter:on + } + + @Bean + public AtomicBoolean helloConsumed() { + return new AtomicBoolean(false); + } + + @Bean + public Consumer consumeHello(AtomicBoolean helloConsumed) { + return message -> helloConsumed.compareAndSet(false, true); + } + + } + +} 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 new file mode 100644 index 00000000..0690e34b --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-functionhandlerconfigtests.yml @@ -0,0 +1,16 @@ +spring.cloud.gateway.mvc: + routesMap: + testsimplefunction: + uri: fn:upper + predicates: + - Path=/simplefunction + - Method=POST + testtemplatedfunction: + uri: fn:{fnName} + predicates: + - Path=/templatedfunction/{fnName} + - Method=POST + +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE 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 new file mode 100644 index 00000000..3e97fc80 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-streamhandlerconfigtests.yml @@ -0,0 +1,16 @@ +spring.cloud.gateway.mvc: + routesMap: + testsimplestream: + uri: stream:hello-out-0 + predicates: + - Path=/simplestream + - Method=POST + testtemplatedstream: + uri: stream:{name}-out-0 + predicates: + - Path=/templatedstream/{name} + - Method=POST + +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index 8ba0bd52..e405dd49 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -59,6 +59,16 @@ spring-cloud-loadbalancer true + + org.springframework.cloud + spring-cloud-function-context + true + + + org.springframework.cloud + spring-cloud-stream + true + org.springframework.boot spring-boot-devtools @@ -182,6 +192,16 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-testcontainers + test + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + test + org.junit-pioneer junit-pioneer @@ -192,6 +212,11 @@ spring-cloud-test-support test + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + test + io.projectreactor reactor-test @@ -217,12 +242,17 @@ junit-jupiter test + + org.testcontainers + rabbitmq + test + org.junit.platform junit-platform-launcher - test - - + test + + org.openjdk.jmh jmh-core 1.20 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 new file mode 100644 index 00000000..0afedfbe --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayFunctionAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * 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.config; + +import java.util.Set; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration; +import org.springframework.cloud.function.context.FunctionCatalog; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; +import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledGlobalFilter; +import org.springframework.cloud.gateway.filter.FunctionRoutingFilter; +import org.springframework.cloud.gateway.filter.factory.rewrite.MessageBodyEncoder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.web.reactive.DispatcherHandler; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(ContextFunctionCatalogAutoConfiguration.class) +@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, GatewayAutoConfiguration.class }) +@ConditionalOnClass({ FunctionCatalog.class, DispatcherHandler.class }) +@ConditionalOnProperty(name = "spring.cloud.gateway.function.enabled", matchIfMissing = true) +class GatewayFunctionAutoConfiguration { + + @Bean + @ConditionalOnEnabledGlobalFilter + @ConditionalOnBean(FunctionCatalog.class) + public FunctionRoutingFilter functionRoutingFilter(FunctionCatalog functionCatalog, + ServerCodecConfigurer codecConfigurer, Set messageBodyEncoders) { + return new FunctionRoutingFilter(functionCatalog, codecConfigurer.getReaders(), messageBodyEncoders); + } + +} 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 new file mode 100644 index 00000000..ba5dcbb4 --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayStreamAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * 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.config; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration; +import org.springframework.cloud.gateway.config.conditional.ConditionalOnEnabledGlobalFilter; +import org.springframework.cloud.gateway.filter.StreamRoutingFilter; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; +import org.springframework.cloud.stream.function.StreamBridge; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.web.reactive.DispatcherHandler; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(BindingServiceConfiguration.class) +@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, GatewayAutoConfiguration.class }) +@ConditionalOnClass({ StreamBridge.class, DispatcherHandler.class }) +@ConditionalOnProperty(name = "spring.cloud.gateway.stream.enabled", matchIfMissing = true) +class GatewayStreamAutoConfiguration { + + @Bean + @ConditionalOnEnabledGlobalFilter + @ConditionalOnBean(StreamBridge.class) + public StreamRoutingFilter streamRoutingFilter(StreamBridge streamBridge, ServerCodecConfigurer codecConfigurer) { + return new StreamRoutingFilter(streamBridge, codecConfigurer.getReaders()); + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilter.java new file mode 100644 index 00000000..e35227dd --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilter.java @@ -0,0 +1,198 @@ +/* + * 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.filter; + +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import org.springframework.cloud.function.context.FunctionCatalog; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.filter.factory.rewrite.MessageBodyEncoder; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.cloud.gateway.support.MessageHeaderUtils; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MimeType; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; + +import static java.util.function.Function.identity; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.isAlreadyRouted; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setAlreadyRouted; + +/** + * @author Spencer Gibb + */ +public class FunctionRoutingFilter implements GlobalFilter, Ordered { + + private static Log logger = LogFactory.getLog(FunctionRoutingFilter.class); + + private final FunctionCatalog functionCatalog; + + private final List> messageReaders; + + private final Map messageBodyEncoders; + + public FunctionRoutingFilter(FunctionCatalog functionCatalog, List> messageReaders, + Set messageBodyEncoders) { + this.functionCatalog = functionCatalog; + this.messageReaders = messageReaders; + this.messageBodyEncoders = messageBodyEncoders.stream() + .collect(Collectors.toMap(MessageBodyEncoder::encodingType, identity())); + } + + @Override + public int getOrder() { + return RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER + 10; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); + String scheme = requestUrl.getScheme(); + + if (isAlreadyRouted(exchange) || !"fn".equals(scheme)) { + return chain.filter(exchange); + } + setAlreadyRouted(exchange); + + FunctionInvocationWrapper function = functionCatalog.lookup(requestUrl.getHost(), + exchange.getRequest().getHeaders().getAccept().stream().map(MimeType::toString).toArray(String[]::new)); + if (function != null) { + return processRequest(exchange, function, messageReaders, messageBodyEncoders).then(chain.filter(exchange)); + } + + return Mono.error(new NotFoundException("No route for uri " + requestUrl)); + } + + protected Mono processRequest(ServerWebExchange exchange, FunctionInvocationWrapper function, + List> messageReaders, Map messageBodyEncoders) { + // 1- convert request body to function input type + // 2- call function + // 3- convert function return to raw data for response + ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders); + return serverRequest.bodyToMono(function.getRawInputType()).flatMap(requestBody -> { + ServerHttpRequest request = exchange.getRequest(); + HttpHeaders headers = request.getHeaders(); + + Message inputMessage = null; + + MessageBuilder builder = MessageBuilder.withPayload(requestBody); + if (!CollectionUtils.isEmpty(request.getQueryParams())) { + builder = builder.setHeader(MessageHeaderUtils.HTTP_REQUEST_PARAM, + request.getQueryParams().toSingleValueMap()); + } + inputMessage = builder.copyHeaders(headers.toSingleValueMap()).build(); + + if (function.isRoutingFunction()) { + function.setSkipOutputConversion(true); + } + + List ignoredHeaders = Collections.emptyList(); + HttpHeaders newResponseHeaders = new HttpHeaders(); + + Object functionResult = function.apply(inputMessage); + if (functionResult instanceof Message message) { + newResponseHeaders.addAll(MessageHeaderUtils.fromMessage(message.getHeaders(), ignoredHeaders)); + functionResult = message.getPayload(); + } + Publisher result; + if (functionResult instanceof Publisher publisher) { + // TODO: deal with eventStream + result = publisher; + } + else { + result = Mono.just(functionResult); + } + + Class outClass = byte[].class; + + BodyInserter bodyInserter = BodyInserters.fromPublisher(result, outClass); + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, + exchange.getResponse().getHeaders()); + + return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> { + ServerHttpResponse response = exchange.getResponse(); + Mono messageBody = writeBody(response, outputMessage, outClass); + HttpHeaders responseHeaders = response.getHeaders(); + if (!responseHeaders.containsKey(HttpHeaders.TRANSFER_ENCODING) + || responseHeaders.containsKey(HttpHeaders.CONTENT_LENGTH)) { + messageBody = messageBody.doOnNext(data -> headers.setContentLength(data.readableByteCount())); + } + responseHeaders.addAll(newResponseHeaders); + + // TODO: deal with content type + /* + * if (StringUtils.hasText(config.newContentType)) { + * headers.set(HttpHeaders.CONTENT_TYPE, config.newContentType); } + */ + + // TODO: fail if isStreamingMediaType? + return response.writeWith(messageBody); + })); + }); + } + + private Mono writeBody(ServerHttpResponse httpResponse, CachedBodyOutputMessage message, + Class outClass) { + Mono response = DataBufferUtils.join(message.getBody()); + if (byte[].class.isAssignableFrom(outClass)) { + return response; + } + + List encodingHeaders = httpResponse.getHeaders().getOrEmpty(HttpHeaders.CONTENT_ENCODING); + for (String encoding : encodingHeaders) { + MessageBodyEncoder encoder = messageBodyEncoders.get(encoding); + if (encoder != null) { + DataBufferFactory dataBufferFactory = httpResponse.bufferFactory(); + response = response.publishOn(Schedulers.parallel()).map(buffer -> { + byte[] encodedResponse = encoder.encode(buffer); + DataBufferUtils.release(buffer); + return encodedResponse; + }).map(dataBufferFactory::wrap); + break; + } + } + + return response; + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/StreamRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/StreamRoutingFilter.java new file mode 100644 index 00000000..8070ba05 --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/StreamRoutingFilter.java @@ -0,0 +1,103 @@ +/* + * 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.filter; + +import java.net.URI; +import java.util.List; + +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory; +import org.springframework.cloud.gateway.support.MessageHeaderUtils; +import org.springframework.cloud.stream.function.StreamBridge; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.CollectionUtils; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.isAlreadyRouted; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setAlreadyRouted; + +/** + * @author Spencer Gibb + */ +public class StreamRoutingFilter implements GlobalFilter, Ordered { + + private final StreamBridge streamBridge; + + private final List> messageReaders; + + private final SetStatusGatewayFilterFactory setStatusFilter; + + public StreamRoutingFilter(StreamBridge streamBridge, List> messageReaders) { + this.streamBridge = streamBridge; + this.messageReaders = messageReaders; + // TODO: is this the right place for this? + this.streamBridge.setAsync(true); + setStatusFilter = new SetStatusGatewayFilterFactory(); + } + + @Override + public int getOrder() { + return RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER + 10; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); + String scheme = requestUrl.getScheme(); + + if (isAlreadyRouted(exchange) || !"stream".equals(scheme)) { + return chain.filter(exchange); + } + setAlreadyRouted(exchange); + + ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders); + return serverRequest.bodyToMono(byte[].class).flatMap(requestBody -> { + ServerHttpRequest request = exchange.getRequest(); + HttpHeaders headers = request.getHeaders(); + + Message inputMessage = null; + + MessageBuilder builder = MessageBuilder.withPayload(requestBody); + if (!CollectionUtils.isEmpty(request.getQueryParams())) { + // TODO: move HeaderUtils + builder = builder.setHeader(MessageHeaderUtils.HTTP_REQUEST_PARAM, + request.getQueryParams().toSingleValueMap()); + // TODO: sanitize? + } + inputMessage = builder.copyHeaders(headers.toSingleValueMap()).build(); + + // TODO: output content type + boolean send = streamBridge.send(requestUrl.getHost(), inputMessage); + + HttpStatus responseStatus = (send) ? HttpStatus.OK : HttpStatus.BAD_REQUEST; + + SetStatusGatewayFilterFactory.Config config = new SetStatusGatewayFilterFactory.Config(); + config.setStatus(responseStatus.name()); + return setStatusFilter.apply(config).filter(exchange, chain); + }); + } + +} diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/MessageHeaderUtils.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/MessageHeaderUtils.java new file mode 100644 index 00000000..7916d77d --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/MessageHeaderUtils.java @@ -0,0 +1,116 @@ +/* + * 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.support; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.springframework.http.HttpHeaders; +import org.springframework.messaging.MessageHeaders; + +/** + * @author Dave Syer + * @author Oleg Zhurakousky + */ +public final class MessageHeaderUtils { + + /** + * Message Header name which contains HTTP request parameters. + */ + public static final String HTTP_REQUEST_PARAM = "http_request_param"; + + private static final HttpHeaders IGNORED = new HttpHeaders(); + + private static final HttpHeaders REQUEST_ONLY = new HttpHeaders(); + + static { + IGNORED.add(MessageHeaders.ID, ""); + IGNORED.add(HttpHeaders.CONTENT_LENGTH, "0"); + // Headers that would typically be added by a downstream client + REQUEST_ONLY.add(HttpHeaders.ACCEPT, ""); + REQUEST_ONLY.add(HttpHeaders.CONTENT_LENGTH, ""); + REQUEST_ONLY.add(HttpHeaders.CONTENT_TYPE, ""); + REQUEST_ONLY.add(HttpHeaders.HOST, ""); + } + + private MessageHeaderUtils() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + + public static HttpHeaders fromMessage(MessageHeaders headers, List ignoredHeders) { + HttpHeaders result = new HttpHeaders(); + for (String name : headers.keySet()) { + Object value = headers.get(name); + name = name.toLowerCase(Locale.ROOT); + if (!IGNORED.containsKey(name) && !ignoredHeders.contains(name)) { + Collection values = multi(value); + for (Object object : values) { + result.set(name, object.toString()); + } + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static HttpHeaders fromMessage(MessageHeaders headers) { + return fromMessage(headers, Collections.EMPTY_LIST); + } + + public static HttpHeaders sanitize(HttpHeaders request, List ignoredHeders, + List requestOnlyHeaders) { + HttpHeaders result = new HttpHeaders(); + for (String name : request.keySet()) { + List value = request.get(name); + name = name.toLowerCase(Locale.ROOT); + if (!IGNORED.containsKey(name) && !REQUEST_ONLY.containsKey(name) && !ignoredHeders.contains(name) + && !requestOnlyHeaders.contains(name)) { + result.put(name, value); + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static HttpHeaders sanitize(HttpHeaders request) { + return sanitize(request, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + } + + public static MessageHeaders fromHttp(HttpHeaders headers) { + Map map = new LinkedHashMap<>(); + for (String name : headers.keySet()) { + Collection values = multi(headers.get(name)); + name = name.toLowerCase(Locale.ROOT); + Object value = values == null ? null : (values.size() == 1 ? values.iterator().next() : values); + if (name.toLowerCase(Locale.ROOT).equals(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ROOT))) { + name = MessageHeaders.CONTENT_TYPE; + } + map.put(name, value); + } + return new MessageHeaders(map); + } + + private static Collection multi(Object value) { + return value instanceof Collection ? (Collection) value : Arrays.asList(value); + } + +} diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-gateway-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 51f1dfb4..ed8ffb9d 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -2,8 +2,10 @@ org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguratio org.springframework.cloud.gateway.config.GatewayAutoConfiguration org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration +org.springframework.cloud.gateway.config.GatewayFunctionAutoConfiguration org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration +org.springframework.cloud.gateway.config.GatewayStreamAutoConfiguration org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration org.springframework.cloud.gateway.config.SimpleUrlHandlerMappingGlobalCorsAutoConfiguration org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilterTests.java new file mode 100644 index 00000000..3e889c44 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/FunctionRoutingFilterTests.java @@ -0,0 +1,80 @@ +/* + * 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; + +import java.net.URI; +import java.util.Locale; +import java.util.function.Function; + +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.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.http.MediaType; +import org.springframework.web.util.UriComponentsBuilder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Spencer Gibb + */ +@SpringBootTest(webEnvironment = RANDOM_PORT, + properties = { "debug=false", "spring.cloud.function.definition=upper", "spring.codec.max-in-memory-size=40" }) +public class FunctionRoutingFilterTests extends BaseWebClientTests { + + @Test + public void functionRoutingFilterWorks() { + URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/").build(true).toUri(); + + testClient.post() + .uri(uri) + .bodyValue("hello") + .header("Host", "www.functionroutingfilterjava.org") + .accept(MediaType.TEXT_PLAIN) + .exchange() + .expectBody(String.class) + .consumeWith(res -> assertThat(res.getResponseBody()).isEqualTo("HELLO")); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + @Bean + Function upper() { + return s -> s.toUpperCase(Locale.ROOT); + } + + @Bean + public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("function_routing_filter_java_test", + r -> r.path("/").and().host("www.functionroutingfilterjava.org").uri("fn://upper")) + .build(); + } + + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/StreamRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/StreamRoutingFilterTests.java new file mode 100644 index 00000000..2c1abdf3 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/StreamRoutingFilterTests.java @@ -0,0 +1,106 @@ +/* + * 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.filter; + +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.RabbitMQContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +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.testcontainers.service.connection.ServiceConnection; +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.http.MediaType; +import org.springframework.web.util.UriComponentsBuilder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Spencer Gibb + */ +@SpringBootTest(webEnvironment = RANDOM_PORT, + properties = { "debug=false", "spring.cloud.function.definition=consumeHello", + "spring.cloud.stream.bindings.consumeHello-in-0.destination=hello-out-0" }) +@Testcontainers +public class StreamRoutingFilterTests extends BaseWebClientTests { + + @Container + @ServiceConnection + public static RabbitMQContainer rabbitmq = new RabbitMQContainer("rabbitmq:3.7.25-management-alpine"); + + @Autowired + private AtomicBoolean helloConsumed; + + @Test + public void streamRoutingFilterWorks() { + helloConsumed.set(false); + + URI uri = UriComponentsBuilder.fromUriString(this.baseUri + "/").build(true).toUri(); + + testClient.post() + .uri(uri) + .bodyValue("hello") + .header("Host", "www.streamroutingfilterjava.org") + .accept(MediaType.TEXT_PLAIN) + .exchange() + .expectStatus() + .isOk(); + + Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> helloConsumed.get()); + assertThat(helloConsumed).isTrue(); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + @Bean + public RouteLocator testRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("stream_routing_filter_java_test", + r -> r.path("/").and().host("www.streamroutingfilterjava.org").uri("stream://hello-out-0")) + .build(); + } + + @Bean + public AtomicBoolean helloConsumed() { + return new AtomicBoolean(false); + } + + @Bean + public Consumer consumeHello(AtomicBoolean helloConsumed) { + return message -> helloConsumed.compareAndSet(false, true); + } + + } + +} From 7a17e07cde6f22e68cb463a0aba6bef3d93d054a Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 16 Jan 2025 21:20:33 -0500 Subject: [PATCH 23/56] formatting --- .../cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java index b32a47c1..fcdc4076 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java @@ -251,8 +251,8 @@ public class Bucket4jRateLimiter extends AbstractRateLimiter Date: Thu, 16 Jan 2025 21:26:10 -0500 Subject: [PATCH 24/56] New module names (#3645) * New naming convention using webflux and webmvc The new suffixes are gateway-server-web{flux|mvc} and gateway-proxyexchange-web{flux|mvc}. This commit updates the starters to use gateway-server-web{flux|mvc} suffixes. * Adds new spring-cloud-gateway-server-web{flux|mvc} modules. These simply depend on the old ones. A warning is logged if not using the new module. * Adds s-c-g-proxyexchange-{webflux|webmvc} modules * Updates docs for s-c-g-{proxyexchange|server}-{webflux|webmvc} modules --- docs/modules/ROOT/nav.adoc | 208 +++++++++--------- docs/modules/ROOT/pages/intro.adoc | 5 +- .../spring-cloud-gateway-proxy-exchange.adoc | 6 +- .../spring-cloud-gateway-server-mvc.adoc | 5 - .../spring-cloud-gateway-server-webflux.adoc | 7 + .../actuator-api.adoc | 14 +- .../aot-and-native-image-support.adoc | 0 .../configuration-properties.adoc | 0 .../configuration.adoc | 0 ...dicate-factories-and-filter-factories.adoc | 0 .../cors-configuration.adoc | 0 .../developer-guide.adoc | 0 .../fluent-java-routes-api.adoc | 0 .../gatewayfilter-factories.adoc | 0 .../addrequestheader-factory.adoc | 0 ...addrequestheadersifnotpresent-factory.adoc | 0 .../addrequestparameter-factory.adoc | 0 .../addresponseheader-factory.adoc | 0 .../cacherequestbody-factory.adoc | 0 .../circuitbreaker-filter-factory.adoc | 2 +- .../deduperesponseheader-factory.adoc | 0 .../default-filters.adoc | 0 .../fallback-headers.adoc | 2 +- .../jsontogrpc-factory.adoc | 0 .../local-cache-response-filter.adoc | 2 +- .../maprequestheader-factory.adoc | 0 .../modifyrequestbody-factory.adoc | 0 .../modifyresponsebody-factory.adoc | 0 .../prefixpath-factory.adoc | 0 .../preservehostheader-factory.adoc | 0 .../redirectto-factory.adoc | 0 ...ovejsonattributesresponsebody-factory.adoc | 0 .../removerequestheader-factory.adoc | 0 .../removerequestparameter-factory.adoc | 0 .../removeresponseheader-factory.adoc | 0 .../requestheadersize-factory.adoc | 0 .../requestratelimiter-factory.adoc | 2 +- .../requestsize-factory.adoc | 0 .../retry-factory.adoc | 0 ...rewritelocationresponseheader-factory.adoc | 0 .../rewritepath-factory.adoc | 0 .../rewriterequestparameter-factory.adoc | 0 .../rewriteresponseheader-factory.adoc | 0 .../savesession-factory.adoc | 0 .../secureheaders-factory.adoc | 0 .../setpath-factory.adoc | 0 .../setrequestheader-factory.adoc | 0 .../setrequesthostheader-factory.adoc | 0 .../setresponseheader-factory.adoc | 0 .../setstatus-factory.adoc | 0 .../stripprefix-factory.adoc | 0 .../tokenrelay-factory.adoc | 0 .../global-filters.adoc | 4 +- .../glossary.adoc | 0 .../how-it-works.adoc | 0 .../http-client.adoc | 0 .../http-timeouts-configuration.adoc | 0 .../httpheadersfilters.adoc | 0 .../reactor-netty-access-logs.adoc | 0 .../request-predicates-factories.adoc | 0 .../route-metadata-configuration.adoc | 0 .../sharing-routes.adoc | 0 .../starter.adoc | 2 +- ...coveryclient-route-definition-locator.adoc | 0 .../tls-and-ssl.adoc | 0 .../troubleshooting.adoc | 0 .../spring-cloud-gateway-server-webmvc.adoc | 5 + .../filters/addrequestheader.adoc | 0 .../addrequestheadersifnotpresent.adoc | 0 .../filters/addrequestparameter.adoc | 0 .../filters/addresponseheader.adoc | 0 .../filters/circuitbreaker-filter.adoc | 2 +- .../filters/deduperesponseheader.adoc | 0 .../filters/fallback-headers.adoc | 2 +- .../filters/loadbalancer.adoc | 0 .../filters/local-cache-response-filter.adoc | 2 +- .../filters/maprequestheader.adoc | 0 .../filters/modifyrequestbody.adoc | 0 .../filters/modifyresponsebody.adoc | 0 .../filters/prefixpath.adoc | 0 .../filters/preservehostheader.adoc | 0 .../filters/ratelimiter.adoc | 0 .../filters/redirectto.adoc | 0 .../removejsonattributesresponsebody.adoc | 0 .../filters/removerequestheader.adoc | 0 .../filters/removerequestparameter.adoc | 0 .../filters/removeresponseheader.adoc | 0 .../filters/requestheadersize.adoc | 0 .../filters/requestsize.adoc | 0 .../filters/retry.adoc | 0 .../rewritelocationresponseheader.adoc | 0 .../filters/rewritepath.adoc | 0 .../filters/rewriterequestparameter.adoc | 0 .../filters/rewriteresponseheader.adoc | 0 .../filters/savesession.adoc | 0 .../filters/setpath.adoc | 0 .../filters/setrequestheader.adoc | 0 .../filters/setrequesthostheader.adoc | 0 .../filters/setresponseheader.adoc | 0 .../filters/setstatus.adoc | 0 .../filters/stripprefix.adoc | 0 .../filters/tokenrelay.adoc | 0 .../gateway-handler-filter-functions.adoc | 0 .../gateway-request-predicates.adoc | 0 .../glossary.adoc | 0 .../how-it-works.adoc | 0 .../java-routes-api.adoc | 0 .../starter.adoc | 4 +- .../working-with-servlets-and-filters.adoc | 0 ...writing-custom-predicates-and-filters.adoc | 0 .../ROOT/pages/spring-cloud-gateway.adoc | 7 - pom.xml | 12 + spring-cloud-gateway-dependencies/pom.xml | 36 +++ .../grpc/pom.xml | 2 +- .../http2/pom.xml | 2 +- .../mvc-failure-analyzer/pom.xml | 2 +- .../ProxyResponseAutoConfiguration.java | 20 ++ .../mvc/ProductionConfigurationTests.java | 9 + .../pom.xml | 30 +++ .../gateway/proxyexchange/webflux/Marker.java | 22 ++ .../pom.xml | 30 +++ .../gateway/proxyexchange/webmvc/Marker.java | 22 ++ spring-cloud-gateway-sample/pom.xml | 2 +- .../sample/GatewaySampleApplicationTests.java | 10 + ...yMvcClassPathWarningAutoConfiguration.java | 60 +++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../server/mvc/ServerMvcIntegrationTests.java | 9 + spring-cloud-gateway-server-webflux/pom.xml | 30 +++ .../cloud/gateway/server/webflux/Marker.java | 22 ++ spring-cloud-gateway-server-webmvc/pom.xml | 30 +++ .../cloud/gateway/server/webmvc/Marker.java | 22 ++ ...ewayClassPathWarningAutoConfiguration.java | 12 + .../gateway/test/GatewayIntegrationTests.java | 9 + .../ProxyResponseAutoConfiguration.java | 22 +- .../webflux/ProductionConfigurationTests.java | 9 + spring-cloud-starter-gateway-mvc/pom.xml | 3 +- .../StarterDeprecatedAutoConfiguration.java | 40 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../pom.xml | 37 ++++ .../pom.xml | 37 ++++ spring-cloud-starter-gateway/pom.xml | 3 +- .../StarterDeprecatedAutoConfiguration.java | 40 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + 143 files changed, 720 insertions(+), 148 deletions(-) delete mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc.adoc create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux.adoc rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/actuator-api.adoc (89%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/aot-and-native-image-support.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/configuration-properties.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/configuration.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/configuring-route-predicate-factories-and-filter-factories.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/cors-configuration.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/developer-guide.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/fluent-java-routes-api.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/addrequestheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/addrequestparameter-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/addresponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/cacherequestbody-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/circuitbreaker-filter-factory.adoc (98%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/deduperesponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/default-filters.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/fallback-headers.adoc (92%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/jsontogrpc-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/local-cache-response-filter.adoc (94%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/maprequestheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/modifyrequestbody-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/modifyresponsebody-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/prefixpath-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/preservehostheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/redirectto-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/removerequestheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/removerequestparameter-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/removeresponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/requestheadersize-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/requestratelimiter-factory.adoc (98%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/requestsize-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/retry-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/rewritepath-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/rewriterequestparameter-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/rewriteresponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/savesession-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/secureheaders-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/setpath-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/setrequestheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/setrequesthostheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/setresponseheader-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/setstatus-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/stripprefix-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/gatewayfilter-factories/tokenrelay-factory.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/global-filters.adoc (96%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/glossary.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/how-it-works.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/http-client.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/http-timeouts-configuration.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/httpheadersfilters.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/reactor-netty-access-logs.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/request-predicates-factories.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/route-metadata-configuration.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/sharing-routes.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/starter.adoc (96%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/the-discoveryclient-route-definition-locator.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/tls-and-ssl.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway => spring-cloud-gateway-server-webflux}/troubleshooting.adoc (100%) create mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc.adoc rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/addrequestheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/addrequestheadersifnotpresent.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/addrequestparameter.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/addresponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/circuitbreaker-filter.adoc (98%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/deduperesponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/fallback-headers.adoc (96%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/loadbalancer.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/local-cache-response-filter.adoc (94%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/maprequestheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/modifyrequestbody.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/modifyresponsebody.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/prefixpath.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/preservehostheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/ratelimiter.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/redirectto.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/removejsonattributesresponsebody.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/removerequestheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/removerequestparameter.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/removeresponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/requestheadersize.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/requestsize.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/retry.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/rewritelocationresponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/rewritepath.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/rewriterequestparameter.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/rewriteresponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/savesession.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/setpath.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/setrequestheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/setrequesthostheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/setresponseheader.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/setstatus.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/stripprefix.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/filters/tokenrelay.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/gateway-handler-filter-functions.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/gateway-request-predicates.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/glossary.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/how-it-works.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/java-routes-api.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/starter.adoc (76%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/working-with-servlets-and-filters.adoc (100%) rename docs/modules/ROOT/pages/{spring-cloud-gateway-server-mvc => spring-cloud-gateway-server-webmvc}/writing-custom-predicates-and-filters.adoc (100%) delete mode 100644 docs/modules/ROOT/pages/spring-cloud-gateway.adoc create mode 100644 spring-cloud-gateway-proxyexchange-webflux/pom.xml create mode 100644 spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/proxyexchange/webflux/Marker.java create mode 100644 spring-cloud-gateway-proxyexchange-webmvc/pom.xml create mode 100644 spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/proxyexchange/webmvc/Marker.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java create mode 100644 spring-cloud-gateway-server-webflux/pom.xml create mode 100644 spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/server/webflux/Marker.java create mode 100644 spring-cloud-gateway-server-webmvc/pom.xml create mode 100644 spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/Marker.java create mode 100644 spring-cloud-starter-gateway-mvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/starter/StarterDeprecatedAutoConfiguration.java create mode 100644 spring-cloud-starter-gateway-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 spring-cloud-starter-gateway-server-webflux/pom.xml create mode 100644 spring-cloud-starter-gateway-server-webmvc/pom.xml create mode 100644 spring-cloud-starter-gateway/src/main/java/org/springframework/cloud/gateway/server/webflux/starter/StarterDeprecatedAutoConfiguration.java create mode 100644 spring-cloud-starter-gateway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 947966c4..c8225ada 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,116 +1,116 @@ * xref:index.adoc[Introduction] -// begin Gateway Reactive Server +// begin Gateway Server WebFlux -* xref:spring-cloud-gateway.adoc[] -** xref:spring-cloud-gateway/starter.adoc[] -** xref:spring-cloud-gateway/glossary.adoc[] -** xref:spring-cloud-gateway/how-it-works.adoc[] -** xref:spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc[] -** xref:spring-cloud-gateway/request-predicates-factories.adoc[] -** xref:spring-cloud-gateway/gatewayfilter-factories.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/addrequestheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/addrequestparameter-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/cacherequestbody-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/deduperesponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/jsontogrpc-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/maprequestheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/modifyrequestbody-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/modifyresponsebody-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/prefixpath-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/preservehostheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/redirectto-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/removerequestheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/removerequestparameter-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/removeresponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/requestheadersize-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/rewritepath-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/rewriterequestparameter-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/rewriteresponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/savesession-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/secureheaders-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/setpath-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/setrequestheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/setresponseheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/setstatus-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/stripprefix-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/retry-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/requestsize-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/setrequesthostheader-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/tokenrelay-factory.adoc[] -*** xref:spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc[] -** xref:spring-cloud-gateway/global-filters.adoc[] -** xref:spring-cloud-gateway/httpheadersfilters.adoc[] -** xref:spring-cloud-gateway/tls-and-ssl.adoc[] -** xref:spring-cloud-gateway/http-client.adoc[] -** xref:spring-cloud-gateway/configuration.adoc[] -** xref:spring-cloud-gateway/route-metadata-configuration.adoc[] -** xref:spring-cloud-gateway/http-timeouts-configuration.adoc[] -** xref:spring-cloud-gateway/fluent-java-routes-api.adoc[] -** xref:spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc[] -** xref:spring-cloud-gateway/reactor-netty-access-logs.adoc[] -** xref:spring-cloud-gateway/cors-configuration.adoc[] -** xref:spring-cloud-gateway/actuator-api.adoc[] -** xref:spring-cloud-gateway/sharing-routes.adoc[] -** xref:spring-cloud-gateway/troubleshooting.adoc[] -** xref:spring-cloud-gateway/developer-guide.adoc[] -** xref:spring-cloud-gateway/aot-and-native-image-support.adoc[] -** xref:spring-cloud-gateway/configuration-properties.adoc[] +* xref:spring-cloud-gateway-server-webflux.adoc[] +** xref:spring-cloud-gateway-server-webflux/starter.adoc[] +** xref:spring-cloud-gateway-server-webflux/glossary.adoc[] +** xref:spring-cloud-gateway-server-webflux/how-it-works.adoc[] +** xref:spring-cloud-gateway-server-webflux/configuring-route-predicate-factories-and-filter-factories.adoc[] +** xref:spring-cloud-gateway-server-webflux/request-predicates-factories.adoc[] +** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestparameter-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/addresponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/circuitbreaker-filter-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/cacherequestbody-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/deduperesponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/fallback-headers.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/jsontogrpc-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/local-cache-response-filter.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/maprequestheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyrequestbody-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyresponsebody-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/prefixpath-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/preservehostheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/redirectto-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestparameter-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/removeresponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestheadersize-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestratelimiter-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritepath-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriterequestparameter-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriteresponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/savesession-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/setpath-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequestheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/setresponseheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/setstatus-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/stripprefix-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/retry-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestsize-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequesthostheader-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/tokenrelay-factory.adoc[] +*** xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/default-filters.adoc[] +** xref:spring-cloud-gateway-server-webflux/global-filters.adoc[] +** xref:spring-cloud-gateway-server-webflux/httpheadersfilters.adoc[] +** xref:spring-cloud-gateway-server-webflux/tls-and-ssl.adoc[] +** xref:spring-cloud-gateway-server-webflux/http-client.adoc[] +** xref:spring-cloud-gateway-server-webflux/configuration.adoc[] +** xref:spring-cloud-gateway-server-webflux/route-metadata-configuration.adoc[] +** xref:spring-cloud-gateway-server-webflux/http-timeouts-configuration.adoc[] +** xref:spring-cloud-gateway-server-webflux/fluent-java-routes-api.adoc[] +** xref:spring-cloud-gateway-server-webflux/the-discoveryclient-route-definition-locator.adoc[] +** xref:spring-cloud-gateway-server-webflux/reactor-netty-access-logs.adoc[] +** xref:spring-cloud-gateway-server-webflux/cors-configuration.adoc[] +** xref:spring-cloud-gateway-server-webflux/actuator-api.adoc[] +** xref:spring-cloud-gateway-server-webflux/sharing-routes.adoc[] +** xref:spring-cloud-gateway-server-webflux/troubleshooting.adoc[] +** xref:spring-cloud-gateway-server-webflux/developer-guide.adoc[] +** xref:spring-cloud-gateway-server-webflux/aot-and-native-image-support.adoc[] +** xref:spring-cloud-gateway-server-webflux/configuration-properties.adoc[] -// begin Gateway Server MVC +// begin Gateway Server Web MVC -* xref:spring-cloud-gateway-server-mvc.adoc[] -** xref:spring-cloud-gateway-server-mvc/starter.adoc[] -** xref:spring-cloud-gateway-server-mvc/glossary.adoc[] -** xref:spring-cloud-gateway-server-mvc/how-it-works.adoc[] -** xref:spring-cloud-gateway-server-mvc/java-routes-api.adoc[] -** xref:spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc[] -** xref:spring-cloud-gateway-server-mvc/gateway-handler-filter-functions.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/loadbalancer.adoc[] +* xref:spring-cloud-gateway-server-webmvc.adoc[] +** xref:spring-cloud-gateway-server-webmvc/starter.adoc[] +** xref:spring-cloud-gateway-server-webmvc/glossary.adoc[] +** xref:spring-cloud-gateway-server-webmvc/how-it-works.adoc[] +** xref:spring-cloud-gateway-server-webmvc/java-routes-api.adoc[] +** xref:spring-cloud-gateway-server-webmvc/gateway-request-predicates.adoc[] +** xref:spring-cloud-gateway-server-webmvc/gateway-handler-filter-functions.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/addrequestheadersifnotpresent.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/addrequestparameter.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/addresponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/circuitbreaker-filter.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/deduperesponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/fallback-headers.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/loadbalancer.adoc[] //*** xref:spring-cloud-gateway-server-mvc/filters/local-cache-response-filter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/prefixpath.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/redirectto.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/maprequestheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/modifyrequestbody.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/modifyresponsebody.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/prefixpath.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/preservehostheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/redirectto.adoc[] //*** xref:spring-cloud-gateway-server-mvc/filters/removejsonattributesresponsebody.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/rewritepath.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/removerequestheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/removerequestparameter.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/removeresponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/requestheadersize.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/ratelimiter.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/rewritepath.adoc[] //*** xref:spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/rewriteresponseheader.adoc[] //*** xref:spring-cloud-gateway-server-mvc/filters/savesession.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/setpath.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/setstatus.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/stripprefix.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/retry.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/requestsize.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc[] -*** xref:spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc[] -** xref:spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc[] -** xref:spring-cloud-gateway-server-mvc/working-with-servlets-and-filters.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/setpath.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/setrequestheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/setresponseheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/setstatus.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/stripprefix.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/retry.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/requestsize.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/setrequesthostheader.adoc[] +*** xref:spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc[] +** xref:spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc[] +** xref:spring-cloud-gateway-server-webmvc/working-with-servlets-and-filters.adoc[] // begin Gateway Proxy Exchange diff --git a/docs/modules/ROOT/pages/intro.adoc b/docs/modules/ROOT/pages/intro.adoc index 1f285ded..c5c70d56 100644 --- a/docs/modules/ROOT/pages/intro.adoc +++ b/docs/modules/ROOT/pages/intro.adoc @@ -1,10 +1,9 @@ [[introduction]] = Spring Cloud Gateway -// TODO: docs, rework intro for 4 modules This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 6, Spring Boot 3 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency. -There are two distinct flavors of Spring Cloud Gateway: *Server* and *Proxy Exchange*. Each flavor offers WebFlux and MVC compatibility. +There are two distinct flavors of Spring Cloud Gateway: *Server* and *Proxy Exchange*. Each flavor offers WebFlux and Web MVC compatibility. - The Server variant is a full-featured API gateway that can be standalone or embedded in a Spring Boot application. -- The Proxy Exchange variant is exclusively for use in annotation based WebFlux or MVC applications and allows the use of a special `ProxyExchange` object as a parameter to a web handler method. \ No newline at end of file +- The Proxy Exchange variant is exclusively for use in annotation based WebFlux or Web MVC applications and allows the use of a special `ProxyExchange` object as a parameter to a web handler method. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-proxy-exchange.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-proxy-exchange.adoc index 8e39d751..849ce240 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-proxy-exchange.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-proxy-exchange.adoc @@ -1,11 +1,11 @@ [[proxy-exchange-gateway]] -= Proxy Exchange Gateway with Spring MVC or Webflux += Proxy Exchange Gateway with Spring Web MVC or WebFlux WARNING: The following describes an alternative style gateway. None of the Spring Cloud Gateway Server documentation applies to what follows. == How to Include Spring Cloud Gateway Proxy Exchange -To include Spring Cloud Gateway Proxy Exchange in your project, use the artifact with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-gateway-mvc` for the MVC Proxy Exchange. For the WebFlux Proxy Exchange use artifact with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-gateway-webflux`. +To include Spring Cloud Gateway Proxy Exchange in your project, use the artifact with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-gateway-proxyexchange-webmvc` for the MVC Proxy Exchange. For the WebFlux Proxy Exchange use artifact with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-gateway-proxyexchange-webflux`. 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. @@ -15,7 +15,7 @@ Spring Cloud Gateway provides a utility object called `ProxyExchange`. You can use it inside a regular Spring web handler as a method parameter. It supports basic downstream HTTP exchanges through methods that mirror the HTTP verbs. With MVC, it also supports forwarding to a local handler through the `forward()` method. -To use the `ProxyExchange`, include the right module in your classpath (either `spring-cloud-gateway-mvc` or `spring-cloud-gateway-webflux`). +To use the `ProxyExchange`, include the right module in your classpath (either `spring-cloud-gateway-proxyexchange-webmvc` or `spring-cloud-gateway-proxyexchange-webflux`). The following MVC example proxies a request to `/test` downstream to a remote server: diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc.adoc deleted file mode 100644 index 24ce7b0f..00000000 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc.adoc +++ /dev/null @@ -1,5 +0,0 @@ -[[spring-cloud-gateway-server-mvc]] -= Spring Cloud Gateway Server MVC -:page-section-summary-toc: 1 - -// TODO: diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux.adoc new file mode 100644 index 00000000..abc3ec35 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux.adoc @@ -0,0 +1,7 @@ +[[spring-cloud-gateway-server-webflux]] += Spring Cloud Gateway Server WebFlux +:page-section-summary-toc: 1 + +*{spring-cloud-version}* + + diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/actuator-api.adoc similarity index 89% rename from docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/actuator-api.adoc index 1f8549cd..5188a214 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/actuator-api.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/actuator-api.adoc @@ -95,13 +95,13 @@ This will default to `true` in a future release. This section details how to retrieve route filters, including: -* xref:spring-cloud-gateway/actuator-api.adoc#gateway-global-filters[Global Filters] +* xref:spring-cloud-gateway-server-webflux/actuator-api.adoc#gateway-global-filters[Global Filters] * <> [[gateway-global-filters]] === Global Filters -To retrieve the xref:spring-cloud-gateway/global-filters.adoc[global filters] applied to all routes, make a `GET` request to `/actuator/gateway/globalfilters`. The resulting response is similar to the following: +To retrieve the xref:spring-cloud-gateway-server-webflux/global-filters.adoc[global filters] applied to all routes, make a `GET` request to `/actuator/gateway/globalfilters`. The resulting response is similar to the following: ---- { @@ -117,11 +117,11 @@ To retrieve the xref:spring-cloud-gateway/global-filters.adoc[global filters] ap ---- The response contains the details of the global filters that are in place. -For each global filter, there is a string representation of the filter object (for example, `org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5`) and the corresponding xref:spring-cloud-gateway/global-filters.adoc#gateway-combined-global-filter-and-gatewayfilter-ordering[order] in the filter chain. +For each global filter, there is a string representation of the filter object (for example, `org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@77856cc5`) and the corresponding xref:spring-cloud-gateway-server-webflux/global-filters.adoc#gateway-combined-global-filter-and-gatewayfilter-ordering[order] in the filter chain. [[gateway-route-filters]] === Route Filters -To retrieve the xref:spring-cloud-gateway/gatewayfilter-factories.adoc[`GatewayFilter` factories] applied to routes, make a `GET` request to `/actuator/gateway/routefilters`. +To retrieve the xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories.adoc[`GatewayFilter` factories] applied to routes, make a `GET` request to `/actuator/gateway/routefilters`. The resulting response is similar to the following: ---- @@ -215,7 +215,7 @@ The following table describes the structure of each element (each is a route) of |`route_object.filters` | Array -| The xref:spring-cloud-gateway/gatewayfilter-factories.adoc[`GatewayFilter` factories] applied to the route. +| The xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories.adoc[`GatewayFilter` factories] applied to the route. |`order` | Number @@ -273,14 +273,14 @@ The following table describes the structure of the response: [[creating-and-deleting-a-particular-route-definition]] == Creating and Deleting a Particular Route Definition -To create a route definition, make a `POST` request to `/gateway/routes/\{id_route_to_create}` with a JSON body that specifies the fields of the route (see xref:spring-cloud-gateway/actuator-api.adoc#gateway-retrieving-information-about-a-particular-route[Retrieving Information about a Particular Route]). +To create a route definition, make a `POST` request to `/gateway/routes/\{id_route_to_create}` with a JSON body that specifies the fields of the route (see xref:spring-cloud-gateway-server-webflux/actuator-api.adoc#gateway-retrieving-information-about-a-particular-route[Retrieving Information about a Particular Route]). To delete a route definition, make a `DELETE` request to `/gateway/routes/\{id_route_to_delete}`. [[creating-multiple-route-definitions]] == Creating multiple Route Definitions -To create multiple route definitions in a single request, make a `POST` request to `/gateway/routes` with a JSON body that specifies the fields of the route, including the route id (see xref:spring-cloud-gateway/actuator-api.adoc#gateway-retrieving-information-about-a-particular-route[Retrieving Information about a Particular Route]). +To create multiple route definitions in a single request, make a `POST` request to `/gateway/routes` with a JSON body that specifies the fields of the route, including the route id (see xref:spring-cloud-gateway-server-webflux/actuator-api.adoc#gateway-retrieving-information-about-a-particular-route[Retrieving Information about a Particular Route]). The route definitions will be discarded if any route raises an error during the creation of the routes. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/aot-and-native-image-support.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/aot-and-native-image-support.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/aot-and-native-image-support.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuration-properties.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/configuration-properties.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuration-properties.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuration.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/configuration.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuration.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuring-route-predicate-factories-and-filter-factories.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/configuring-route-predicate-factories-and-filter-factories.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/configuring-route-predicate-factories-and-filter-factories.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/cors-configuration.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/cors-configuration.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/cors-configuration.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/developer-guide.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/developer-guide.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/developer-guide.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/fluent-java-routes-api.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/fluent-java-routes-api.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/fluent-java-routes-api.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestheadersifnotpresent-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestparameter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestparameter-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addrequestparameter-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addrequestparameter-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addresponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/addresponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/addresponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/cacherequestbody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/cacherequestbody-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/cacherequestbody-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/cacherequestbody-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/circuitbreaker-filter-factory.adoc similarity index 98% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/circuitbreaker-filter-factory.adoc index 5ec70b95..9e50d713 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/circuitbreaker-filter-factory.adoc @@ -121,7 +121,7 @@ In case of the request being forwarded to fallback, the Spring Cloud CircuitBrea It is added to the `ServerWebExchange` as the `ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR` attribute that can be used when handling the fallback within the gateway application. For the external controller/handler scenario, headers can be added with exception details. -You can find more information on doing so in the xref:spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc[FallbackHeaders GatewayFilter Factory section]. +You can find more information on doing so in the xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/fallback-headers.adoc[FallbackHeaders GatewayFilter Factory section]. [[circuit-breaker-status-codes]] == Tripping The Circuit Breaker On Status Codes diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/deduperesponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/deduperesponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/deduperesponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/deduperesponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/default-filters.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/default-filters.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/default-filters.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/fallback-headers.adoc similarity index 92% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/fallback-headers.adoc index 02d7fcfb..f3832822 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/fallback-headers.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/fallback-headers.adoc @@ -39,5 +39,5 @@ You can overwrite the names of the headers in the configuration by setting the v * `rootCauseExceptionTypeHeaderName` (`"Root-Cause-Exception-Type"`) * `rootCauseExceptionMessageHeaderName` (`"Root-Cause-Exception-Message"`) -For more information on circuit breakers and the gateway see the xref:spring-cloud-gateway/gatewayfilter-factories/circuitbreaker-filter-factory.adoc[Spring Cloud CircuitBreaker Factory section]. +For more information on circuit breakers and the gateway see the xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/circuitbreaker-filter-factory.adoc[Spring Cloud CircuitBreaker Factory section]. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/jsontogrpc-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/jsontogrpc-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/jsontogrpc-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/jsontogrpc-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/local-cache-response-filter.adoc similarity index 94% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/local-cache-response-filter.adoc index 27fa083f..090132f4 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/local-cache-response-filter.adoc @@ -8,7 +8,7 @@ This filter allows caching the response body and headers to follow these rules: * Response data is not cached if `Cache-Control` header does not allow it (`no-store` present in the request or `no-store` or `private` present in the response). * If the response is already cached and a new request is performed with no-cache value in `Cache-Control` header, it returns a bodiless response with 304 (Not Modified). -This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a xref:spring-cloud-gateway/global-filters.adoc#local-cache-response-global-filter[local response cache configured globally] is also available as feature. +This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a xref:spring-cloud-gateway-server-webflux/global-filters.adoc#local-cache-response-global-filter[local response cache configured globally] is also available as feature. It accepts the first parameter to override the time to expire a cache entry (expressed in `s` for seconds, `m` for minutes, and `h` for hours) and a second parameter to set the maximum size of the cache to evict entries for this route (`KB`, `MB`, or `GB`). diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/maprequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/maprequestheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/maprequestheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/maprequestheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/modifyrequestbody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyrequestbody-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/modifyrequestbody-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyrequestbody-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/modifyresponsebody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyresponsebody-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/modifyresponsebody-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/modifyresponsebody-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/prefixpath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/prefixpath-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/prefixpath-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/prefixpath-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/preservehostheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/preservehostheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/preservehostheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/preservehostheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/redirectto-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/redirectto-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/redirectto-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/redirectto-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removejsonattributesresponsebody-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removerequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removerequestheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removerequestparameter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestparameter-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removerequestparameter-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removerequestparameter-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removeresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removeresponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/removeresponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/removeresponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestheadersize-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestheadersize-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestheadersize-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestheadersize-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestratelimiter-factory.adoc similarity index 98% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestratelimiter-factory.adoc index 6a96ddc3..9a4dd7d4 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestratelimiter-factory.adoc @@ -3,7 +3,7 @@ The `RequestRateLimiter` `GatewayFilter` factory uses a `RateLimiter` implementation to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned. -This filter takes an optional `keyResolver` parameter and parameters specific to the rate limiter (described xref:spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc#key-resolver-section[later in this section]). +This filter takes an optional `keyResolver` parameter and parameters specific to the rate limiter (described xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestratelimiter-factory.adoc#key-resolver-section[later in this section]). `keyResolver` is a bean that implements the `KeyResolver` interface. In configuration, reference the bean by name using SpEL. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestsize-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestsize-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/requestsize-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/requestsize-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/retry-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/retry-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/retry-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/retry-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritelocationresponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewritepath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritepath-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewritepath-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewritepath-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewriterequestparameter-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriterequestparameter-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewriterequestparameter-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriterequestparameter-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewriteresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriteresponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/rewriteresponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/rewriteresponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/savesession-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/savesession-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/savesession-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/savesession-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/secureheaders-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/secureheaders-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/secureheaders-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setpath-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setpath-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setpath-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setpath-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setrequestheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequestheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setrequestheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequestheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setrequesthostheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequesthostheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setrequesthostheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setrequesthostheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setresponseheader-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setresponseheader-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setresponseheader-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setresponseheader-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setstatus-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setstatus-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/setstatus-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/setstatus-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/stripprefix-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/stripprefix-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/stripprefix-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/stripprefix-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/tokenrelay-factory.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/tokenrelay-factory.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/gatewayfilter-factories/tokenrelay-factory.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/gatewayfilter-factories/tokenrelay-factory.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/global-filters.adoc similarity index 96% rename from docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/global-filters.adoc index 5bafd87b..5513a0a1 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/global-filters.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/global-filters.adoc @@ -12,7 +12,7 @@ NOTE: This interface and its usage are subject to change in future milestone rel When a request matches a route, the filtering web handler adds all instances of `GlobalFilter` and all route-specific instances of `GatewayFilter` to a filter chain. This combined filter chain is sorted by the `org.springframework.core.Ordered` interface, which you can set by implementing the `getOrder()` method. -As Spring Cloud Gateway distinguishes between "`pre`" and "`post`" phases for filter logic execution (see xref:spring-cloud-gateway/how-it-works.adoc[How it Works]), the filter with the highest precedence is the first in the "`pre`"-phase and the last in the "`post`"-phase. +As Spring Cloud Gateway distinguishes between "`pre`" and "`post`" phases for filter logic execution (see xref:spring-cloud-gateway-server-webflux/how-it-works.adoc[How it Works]), the filter with the highest precedence is the first in the "`pre`"-phase and the last in the "`post`"-phase. The following listing configures a filter chain: @@ -86,7 +86,7 @@ This filter also implements the automatic calculation of the `max-age` value in If `max-age` is present on the original response, the value is rewritten with the number of seconds set in the `timeToLive` configuration parameter. In subsequent calls, this value is recalculated with the number of seconds left until the response expires. -Setting `spring.cloud.gateway.global-filter.local-response-cache.enabled` to `false` deactivate the local response cache for all routes, the xref:spring-cloud-gateway/gatewayfilter-factories/local-cache-response-filter.adoc[LocalResponseCache filter] allows to use this functionality at route level. +Setting `spring.cloud.gateway.global-filter.local-response-cache.enabled` to `false` deactivate the local response cache for all routes, the xref:spring-cloud-gateway-server-webflux/gatewayfilter-factories/local-cache-response-filter.adoc[LocalResponseCache filter] allows to use this functionality at route level. NOTE: To enable this feature, add `com.github.ben-manes.caffeine:caffeine` and `spring-boot-starter-cache` as project dependencies. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/glossary.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/glossary.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/glossary.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/how-it-works.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/how-it-works.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/how-it-works.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/http-client.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/http-client.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/http-client.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/http-client.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/http-timeouts-configuration.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/http-timeouts-configuration.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/http-timeouts-configuration.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/httpheadersfilters.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/httpheadersfilters.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/httpheadersfilters.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/reactor-netty-access-logs.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/reactor-netty-access-logs.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/reactor-netty-access-logs.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/request-predicates-factories.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/request-predicates-factories.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/route-metadata-configuration.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/route-metadata-configuration.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/route-metadata-configuration.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/sharing-routes.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/sharing-routes.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/sharing-routes.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/sharing-routes.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/starter.adoc similarity index 96% rename from docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/starter.adoc index 7bc6f3f1..ee07b9e3 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway/starter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/starter.adoc @@ -2,7 +2,7 @@ = How to Include Spring Cloud Gateway :page-section-summary-toc: 1 -To include Spring Cloud Gateway in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway`. +To include Spring Cloud Gateway in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway-server-webflux`. 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.enabled=false`. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/the-discoveryclient-route-definition-locator.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/the-discoveryclient-route-definition-locator.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/the-discoveryclient-route-definition-locator.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/tls-and-ssl.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/tls-and-ssl.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/tls-and-ssl.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/troubleshooting.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway/troubleshooting.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webflux/troubleshooting.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc.adoc new file mode 100644 index 00000000..567955e0 --- /dev/null +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc.adoc @@ -0,0 +1,5 @@ +[[spring-cloud-gateway-server-webmvc]] += Spring Cloud Gateway Server Web MVC +:page-section-summary-toc: 1 + +// TODO: diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheadersifnotpresent.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestheadersifnotpresent.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheadersifnotpresent.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestparameter.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addrequestparameter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestparameter.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addresponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/addresponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addresponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/circuitbreaker-filter.adoc similarity index 98% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/circuitbreaker-filter.adoc index 8ec00ffd..8e16c8f3 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/circuitbreaker-filter.adoc @@ -155,7 +155,7 @@ In case of the request being forwarded to fallback, the Spring Cloud CircuitBrea It is added to the `ServerRequest` as the `MvcUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR` attribute that can be used when handling the fallback within the gateway application. For the external controller/handler scenario, headers can be added with exception details. -You can find more information on doing so in the xref:spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc[FallbackHeaders Filters section]. +You can find more information on doing so in the xref:spring-cloud-gateway-server-webmvc/filters/fallback-headers.adoc[FallbackHeaders Filters section]. [[circuit-breaker-status-codes]] == Tripping The Circuit Breaker On Status Codes diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/deduperesponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/deduperesponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/deduperesponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/fallback-headers.adoc similarity index 96% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/fallback-headers.adoc index 22f4114b..3b867001 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/fallback-headers.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/fallback-headers.adoc @@ -67,5 +67,5 @@ You can overwrite the names of the headers in the configuration by setting the v * `rootCauseExceptionTypeHeaderName` (`"Root-Cause-Exception-Type"`) * `rootCauseExceptionMessageHeaderName` (`"Root-Cause-Exception-Message"`) -For more information on circuit breakers and the gateway see the xref:spring-cloud-gateway-server-mvc/filters/circuitbreaker-filter.adoc[Spring Cloud CircuitBreaker Filter section]. +For more information on circuit breakers and the gateway see the xref:spring-cloud-gateway-server-webmvc/filters/circuitbreaker-filter.adoc[Spring Cloud CircuitBreaker Filter section]. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/loadbalancer.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/loadbalancer.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/loadbalancer.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/loadbalancer.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/local-cache-response-filter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/local-cache-response-filter.adoc similarity index 94% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/local-cache-response-filter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/local-cache-response-filter.adoc index 7cde3175..0929e94a 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/local-cache-response-filter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/local-cache-response-filter.adoc @@ -8,7 +8,7 @@ This filter allows caching the response body and headers to follow these rules: * Response data is not cached if `Cache-Control` header does not allow it (`no-store` present in the request or `no-store` or `private` present in the response). * If the response is already cached and a new request is performed with no-cache value in `Cache-Control` header, it returns a bodiless response with 304 (Not Modified). -This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a xref:spring-cloud-gateway/global-filters.adoc#local-cache-response-global-filter[local response cache configured globally] is also available as feature. +This filter configures the local response cache per route and is available only if the `spring.cloud.gateway.filter.local-response-cache.enabled` property is enabled. And a xref:spring-cloud-gateway-server-webflux/global-filters.adoc#local-cache-response-global-filter[local response cache configured globally] is also available as feature. It accepts the first parameter to override the time to expire a cache entry (expressed in `s` for seconds, `m` for minutes, and `h` for hours) and a second parameter to set the maximum size of the cache to evict entries for this route (`KB`, `MB`, or `GB`). diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/maprequestheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/maprequestheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/modifyrequestbody.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/modifyrequestbody.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/modifyresponsebody.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/modifyresponsebody.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/prefixpath.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/prefixpath.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/prefixpath.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/preservehostheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/preservehostheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/ratelimiter.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/ratelimiter.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/redirectto.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/redirectto.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/redirectto.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removejsonattributesresponsebody.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removejsonattributesresponsebody.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removejsonattributesresponsebody.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removejsonattributesresponsebody.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removerequestheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removerequestheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removerequestparameter.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removerequestparameter.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removeresponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/removeresponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/requestheadersize.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/requestheadersize.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/requestsize.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/requestsize.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/requestsize.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/retry.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/retry.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritepath.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewritepath.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritepath.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewriterequestparameter.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewriterequestparameter.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewriteresponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/rewriteresponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewriteresponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/savesession.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/savesession.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/savesession.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/savesession.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setpath.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setpath.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setpath.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setrequestheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequestheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setrequestheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setrequesthostheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setrequesthostheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setrequesthostheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setresponseheader.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setresponseheader.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setresponseheader.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setstatus.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/setstatus.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/setstatus.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/stripprefix.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/stripprefix.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/stripprefix.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/tokenrelay.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-handler-filter-functions.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/gateway-handler-filter-functions.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-handler-filter-functions.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/gateway-handler-filter-functions.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/gateway-request-predicates.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/gateway-request-predicates.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/gateway-request-predicates.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/glossary.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/glossary.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/glossary.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/glossary.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/how-it-works.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/how-it-works.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/how-it-works.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/how-it-works.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/java-routes-api.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/java-routes-api.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/java-routes-api.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/starter.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc similarity index 76% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/starter.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc index 3c081e91..6d3b7bd8 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/starter.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/starter.adoc @@ -1,8 +1,8 @@ [[gateway-starter]] -= How to Include Spring Cloud Gateway Server MVC += How to Include Spring Cloud Gateway Server Web MVC :page-section-summary-toc: 1 -To include Spring Cloud Gateway Server MVC in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway-mvc`. +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`. diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/working-with-servlets-and-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/working-with-servlets-and-filters.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/working-with-servlets-and-filters.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/working-with-servlets-and-filters.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc similarity index 100% rename from docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/writing-custom-predicates-and-filters.adoc rename to docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway.adoc deleted file mode 100644 index 1f896442..00000000 --- a/docs/modules/ROOT/pages/spring-cloud-gateway.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[spring-cloud-gateway]] -= Spring Cloud Gateway Reactive Server -:page-section-summary-toc: 1 - -*{spring-cloud-version}* - - diff --git a/pom.xml b/pom.xml index d8937b9b..9648f163 100644 --- a/pom.xml +++ b/pom.xml @@ -143,11 +143,23 @@ spring-cloud-gateway-dependencies + spring-cloud-gateway-mvc + spring-cloud-gateway-webflux + spring-cloud-gateway-server + spring-cloud-gateway-server-mvc + spring-cloud-gateway-proxyexchange-webflux + spring-cloud-gateway-proxyexchange-webmvc + spring-cloud-gateway-server-webflux + spring-cloud-gateway-server-webmvc + spring-cloud-starter-gateway-server-webflux + spring-cloud-starter-gateway-server-webmvc + spring-cloud-starter-gateway + spring-cloud-starter-gateway-mvc spring-cloud-gateway-sample spring-cloud-gateway-integration-tests diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 2ee6b9a9..66103cf7 100644 --- a/spring-cloud-gateway-dependencies/pom.xml +++ b/spring-cloud-gateway-dependencies/pom.xml @@ -22,31 +22,67 @@ + org.springframework.cloud spring-cloud-gateway-webflux ${project.version} + org.springframework.cloud spring-cloud-gateway-mvc ${project.version} + org.springframework.cloud spring-cloud-gateway-server ${project.version} + org.springframework.cloud spring-cloud-gateway-server-mvc ${project.version} + + org.springframework.cloud + spring-cloud-gateway-proxyexchange-webflux + ${project.version} + + + org.springframework.cloud + spring-cloud-gateway-proxyexchange-webmvc + ${project.version} + + + org.springframework.cloud + spring-cloud-gateway-server-webflux + ${project.version} + + + org.springframework.cloud + spring-cloud-gateway-server-webmvc + ${project.version} + + + org.springframework.cloud + spring-cloud-starter-gateway-server-webflux + ${project.version} + + + org.springframework.cloud + spring-cloud-starter-gateway-server-webmvc + ${project.version} + + org.springframework.cloud spring-cloud-starter-gateway ${project.version} + org.springframework.cloud spring-cloud-starter-gateway-mvc diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 8c565d40..553d0979 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -29,7 +29,7 @@ org.springframework.cloud - spring-cloud-starter-gateway + spring-cloud-starter-gateway-server-webflux org.springframework.boot diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 6ac0d2fd..49e2de46 100644 --- a/spring-cloud-gateway-integration-tests/http2/pom.xml +++ b/spring-cloud-gateway-integration-tests/http2/pom.xml @@ -27,7 +27,7 @@ org.springframework.cloud - spring-cloud-starter-gateway + spring-cloud-starter-gateway-server-webflux org.springframework.cloud 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 9302b3b5..810172ab 100644 --- a/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml +++ b/spring-cloud-gateway-integration-tests/mvc-failure-analyzer/pom.xml @@ -27,7 +27,7 @@ org.springframework.cloud - spring-cloud-starter-gateway + spring-cloud-starter-gateway-server-webflux org.springframework.cloud 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 ba462ba9..0a840d78 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 @@ -23,9 +23,13 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.client.RestTemplateBuilder; @@ -108,4 +112,20 @@ public class ProxyResponseAutoConfiguration implements WebMvcConfigurer { } + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingClass("org.springframework.cloud.gateway.proxyexchange.webmvc.Marker") + protected static class NewModuleConfiguration { + + private static final Log log = LogFactory.getLog(ProxyResponseAutoConfiguration.class); + + private static final String BORDER = "\n\n**********************************************************\n\n"; + + public NewModuleConfiguration() { + log.warn(BORDER + "The artifact spring-cloud-gateway-mvc is deprecated. " + + "It will be removed in the next major release. " + + "Please add spring-cloud-gateway-proxyexchange-webmvc dependency." + BORDER); + } + + } + } diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java index ddb6c6ba..d426f2d1 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java @@ -25,11 +25,14 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.gateway.mvc.ProductionConfigurationTests.TestApplication; @@ -59,6 +62,7 @@ import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = TestApplication.class) +@ExtendWith(OutputCaptureExtension.class) public class ProductionConfigurationTests { @Autowired @@ -325,6 +329,11 @@ public class ProductionConfigurationTests { assertThat(headers.get("forwarded").get(0)).isEqualTo("host=localhost:" + port); } + @Test + void logsArtifactDeprecatedWarning(CapturedOutput output) { + assertThat(output).contains("spring-cloud-gateway-mvc is deprecated"); + } + @SpringBootApplication static class TestApplication { diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml new file mode 100644 index 00000000..3243a645 --- /dev/null +++ b/spring-cloud-gateway-proxyexchange-webflux/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-gateway-proxyexchange-webflux + spring-cloud-gateway-proxyexchange-webflux + jar + Spring Cloud Gateway Proxy Exchange WebFlux + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-gateway-webflux + + + diff --git a/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/proxyexchange/webflux/Marker.java b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/proxyexchange/webflux/Marker.java new file mode 100644 index 00000000..f54110da --- /dev/null +++ b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/proxyexchange/webflux/Marker.java @@ -0,0 +1,22 @@ +/* + * 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.proxyexchange.webflux; + +@Deprecated +public class Marker { + +} diff --git a/spring-cloud-gateway-proxyexchange-webmvc/pom.xml b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml new file mode 100644 index 00000000..8d04d069 --- /dev/null +++ b/spring-cloud-gateway-proxyexchange-webmvc/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-gateway-proxyexchange-webmvc + spring-cloud-gateway-proxyexchange-webmvc + jar + Spring Cloud Gateway Proxy Exchange Web MVC + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-gateway-mvc + + + diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/proxyexchange/webmvc/Marker.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/proxyexchange/webmvc/Marker.java new file mode 100644 index 00000000..e9e2b4b5 --- /dev/null +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/proxyexchange/webmvc/Marker.java @@ -0,0 +1,22 @@ +/* + * 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.proxyexchange.webmvc; + +@Deprecated +public class Marker { + +} diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index b32a638f..20671002 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -31,7 +31,7 @@ org.springframework.cloud - spring-cloud-starter-gateway + spring-cloud-starter-gateway-server-webflux org.isomorphism diff --git a/spring-cloud-gateway-sample/src/test/java/org/springframework/cloud/gateway/sample/GatewaySampleApplicationTests.java b/spring-cloud-gateway-sample/src/test/java/org/springframework/cloud/gateway/sample/GatewaySampleApplicationTests.java index 6cc18e7f..f6dde871 100644 --- a/spring-cloud-gateway-sample/src/test/java/org/springframework/cloud/gateway/sample/GatewaySampleApplicationTests.java +++ b/spring-cloud-gateway-sample/src/test/java/org/springframework/cloud/gateway/sample/GatewaySampleApplicationTests.java @@ -26,10 +26,13 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.gateway.config.GatewayMetricsProperties; @@ -52,6 +55,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen */ @SpringBootTest(classes = { GatewaySampleApplicationTests.TestConfig.class }, webEnvironment = RANDOM_PORT, properties = { "management.endpoint.gateway.enabled=true", "management.server.port=${test.port}" }) +@ExtendWith(OutputCaptureExtension.class) public class GatewaySampleApplicationTests { protected static int managementPort; @@ -259,6 +263,12 @@ public class GatewaySampleApplicationTests { }); } + @Test + void usesNewStarter(CapturedOutput output) { + assertThat(output).doesNotContain("spring-cloud-starter-gateway is deprecated") + .doesNotContain("spring-cloud-gateway-server is deprecated"); + } + @Configuration(proxyBeanMethods = false) @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = LoadBalancerConfig.class) 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 new file mode 100644 index 00000000..4fef7bc7 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayMvcClassPathWarningAutoConfiguration.java @@ -0,0 +1,60 @@ +/* + * 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.server.mvc; + +import org.apache.commons.logging.Log; +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.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureBefore(GatewayServerMvcAutoConfiguration.class) +@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) +public class GatewayMvcClassPathWarningAutoConfiguration { + + private static final Log log = LogFactory.getLog(GatewayMvcClassPathWarningAutoConfiguration.class); + + private static final String BORDER = "\n\n**********************************************************\n\n"; + + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet") + protected static class WebMvcMissingFromClasspathConfiguration { + + public WebMvcMissingFromClasspathConfiguration() { + log.warn(BORDER + "Spring Web MVC is missing from the classpath, " + + "which is required for Spring Cloud Gateway Server Web MVC. " + + "Please add spring-boot-starter-web dependency." + BORDER); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingClass("org.springframework.cloud.gateway.server.webmvc.Marker") + protected static class NewModuleConfiguration { + + public NewModuleConfiguration() { + log.warn(BORDER + "The artifact spring-cloud-gateway-server-mvc is deprecated. " + + "It will be removed in the next major release. " + + "Please add spring-cloud-gateway-server-webmvc dependency." + BORDER); + } + + } + +} 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 bbc80f73..0b209bc3 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,3 +1,4 @@ org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration +org.springframework.cloud.gateway.server.mvc.GatewayMvcClassPathWarningAutoConfiguration org.springframework.cloud.gateway.server.mvc.handler.GatewayMultipartAutoConfiguration org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index d9a7dc7b..2b4ab69e 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 @@ -44,12 +44,15 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.web.servlet.FilterRegistrationBean; @@ -147,6 +150,7 @@ import static org.springframework.web.servlet.function.RequestPredicates.path; @SpringBootTest(properties = { "spring.cloud.gateway.mvc.http-client.type=jdk" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) +@ExtendWith(OutputCaptureExtension.class) public class ServerMvcIntegrationTests { static { @@ -981,6 +985,11 @@ public class ServerMvcIntegrationTests { }); } + @Test + void logsArtifactDeprecatedWarning(CapturedOutput output) { + assertThat(output).contains("spring-cloud-gateway-server-mvc is deprecated"); + } + @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) diff --git a/spring-cloud-gateway-server-webflux/pom.xml b/spring-cloud-gateway-server-webflux/pom.xml new file mode 100644 index 00000000..4f9f40e0 --- /dev/null +++ b/spring-cloud-gateway-server-webflux/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-gateway-server-webflux + spring-cloud-gateway-server-webflux + jar + Spring Cloud Gateway Server WebFlux + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-gateway-server + + + diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/server/webflux/Marker.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/server/webflux/Marker.java new file mode 100644 index 00000000..3b712903 --- /dev/null +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/server/webflux/Marker.java @@ -0,0 +1,22 @@ +/* + * 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.server.webflux; + +@Deprecated +public class Marker { + +} diff --git a/spring-cloud-gateway-server-webmvc/pom.xml b/spring-cloud-gateway-server-webmvc/pom.xml new file mode 100644 index 00000000..9792dfe9 --- /dev/null +++ b/spring-cloud-gateway-server-webmvc/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-gateway-server-webmvc + spring-cloud-gateway-server-webmvc + jar + Spring Cloud Gateway Server WebMvc + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-gateway-server-mvc + + + diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/Marker.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/Marker.java new file mode 100644 index 00000000..b749aa92 --- /dev/null +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/Marker.java @@ -0,0 +1,22 @@ +/* + * 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.server.webmvc; + +@Deprecated +public class Marker { + +} 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 2fd3e441..46507016 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 @@ -59,4 +59,16 @@ public class GatewayClassPathWarningAutoConfiguration { } + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingClass("org.springframework.cloud.gateway.server.webflux.Marker") + protected static class NewModuleConfiguration { + + public NewModuleConfiguration() { + log.warn(BORDER + "The artifact spring-cloud-gateway-server is deprecated. " + + "It will be removed in the next major release. " + + "Please add spring-cloud-gateway-server-webflux dependency." + BORDER); + } + + } + } 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 e79e8e0a..f998d8e0 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 @@ -26,12 +26,15 @@ import org.apache.commons.logging.LogFactory; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; 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.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.cloud.gateway.config.GatewayProperties; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter; @@ -62,6 +65,7 @@ import static org.springframework.cloud.gateway.test.TestUtils.getMap; @SpringBootTest(webEnvironment = RANDOM_PORT) @DirtiesContext @SuppressWarnings("unchecked") +@ExtendWith(OutputCaptureExtension.class) class GatewayIntegrationTests extends BaseWebClientTests { @Autowired @@ -209,6 +213,11 @@ class GatewayIntegrationTests extends BaseWebClientTests { testClient.get().uri("/nocontenttype").exchange().expectStatus().is2xxSuccessful(); } + @Test + void logsArtifactDeprecatedWarning(CapturedOutput output) { + assertThat(output).contains("spring-cloud-gateway-server is deprecated"); + } + @EnableAutoConfiguration @SpringBootConfiguration @Import(DefaultTestConfig.class) 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 d5f79dce..20ff720d 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 @@ -20,9 +20,13 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.gateway.webflux.ProxyExchange; @@ -43,7 +47,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve */ @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication -@ConditionalOnClass({ HandlerMethodReturnValueHandler.class }) +@ConditionalOnClass({ HandlerMethodReturnValueHandler.class, WebClient.class }) @EnableConfigurationProperties(ProxyProperties.class) public class ProxyResponseAutoConfiguration implements WebFluxConfigurer { @@ -76,4 +80,20 @@ public class ProxyResponseAutoConfiguration implements WebFluxConfigurer { configurer.addCustomResolver(context.getBean(ProxyExchangeArgumentResolver.class)); } + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingClass("org.springframework.cloud.gateway.proxyexchange.webflux.Marker") + protected static class NewModuleConfiguration { + + private static final Log log = LogFactory.getLog(ProxyResponseAutoConfiguration.class); + + private static final String BORDER = "\n\n**********************************************************\n\n"; + + public NewModuleConfiguration() { + log.warn(BORDER + "The artifact spring-cloud-gateway-webflux is deprecated. " + + "It will be removed in the next major release. " + + "Please add spring-cloud-gateway-proxyexchange-webflux dependency." + BORDER); + } + + } + } 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 e973a8aa..62b26201 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 @@ -25,6 +25,7 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -32,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.gateway.webflux.ProductionConfigurationTests.TestApplication; @@ -62,6 +65,7 @@ import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(properties = { "spring.cloud.gateway.proxy.skipped=host" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = TestApplication.class) @DirtiesContext +@ExtendWith(OutputCaptureExtension.class) public class ProductionConfigurationTests { @Autowired @@ -276,6 +280,11 @@ public class ProductionConfigurationTests { assertThat(deleteResponse.getBody().get("deleted")).usingRecursiveComparison().isEqualTo(foo); } + @Test + void logsArtifactDeprecatedWarning(CapturedOutput output) { + assertThat(output).contains("spring-cloud-gateway-webflux is deprecated"); + } + @SpringBootApplication static class TestApplication { diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index dc37832b..e86d2d1f 100644 --- a/spring-cloud-starter-gateway-mvc/pom.xml +++ b/spring-cloud-starter-gateway-mvc/pom.xml @@ -11,7 +11,8 @@ spring-cloud-starter-gateway-mvc spring-cloud-starter-gateway-mvc - Spring Cloud Gateway MVC + jar + Spring Cloud Gateway Starter MVC https://projects.spring.io/spring-cloud Pivotal Software, Inc. diff --git a/spring-cloud-starter-gateway-mvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/starter/StarterDeprecatedAutoConfiguration.java b/spring-cloud-starter-gateway-mvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/starter/StarterDeprecatedAutoConfiguration.java new file mode 100644 index 00000000..6d490391 --- /dev/null +++ b/spring-cloud-starter-gateway-mvc/src/main/java/org/springframework/cloud/gateway/server/webmvc/starter/StarterDeprecatedAutoConfiguration.java @@ -0,0 +1,40 @@ +/* + * 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.server.webmvc.starter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.annotation.Configuration; + +/** + * @author Spencer Gibb + */ +@Configuration(proxyBeanMethods = false) +public class StarterDeprecatedAutoConfiguration { + + private static final Log log = LogFactory.getLog(StarterDeprecatedAutoConfiguration.class); + + private static final String BORDER = "\n\n**********************************************************\n\n"; + + public StarterDeprecatedAutoConfiguration() { + log.warn(BORDER + "spring-cloud-starter-gateway-mvc is deprecated. " + + "It will be removed in the next major release. " + + "Please use spring-cloud-starter-gateway-server-webmvc instead." + BORDER); + } + +} diff --git a/spring-cloud-starter-gateway-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-starter-gateway-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..acc9b59a --- /dev/null +++ b/spring-cloud-starter-gateway-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.springframework.cloud.gateway.server.webmvc.starter.StarterDeprecatedAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-starter-gateway-server-webflux/pom.xml b/spring-cloud-starter-gateway-server-webflux/pom.xml new file mode 100644 index 00000000..ab94fcc5 --- /dev/null +++ b/spring-cloud-starter-gateway-server-webflux/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-starter-gateway-server-webflux + spring-cloud-starter-gateway-server-webflux + Spring Cloud Starter Gateway Server WebFlux + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-starter + + + org.springframework.cloud + spring-cloud-gateway-server-webflux + + + org.springframework.boot + spring-boot-starter-webflux + + + diff --git a/spring-cloud-starter-gateway-server-webmvc/pom.xml b/spring-cloud-starter-gateway-server-webmvc/pom.xml new file mode 100644 index 00000000..00420392 --- /dev/null +++ b/spring-cloud-starter-gateway-server-webmvc/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-gateway + 4.3.0-SNAPSHOT + .. + + spring-cloud-starter-gateway-server-webmvc + spring-cloud-starter-gateway-server-webmvc + Spring Cloud Gateway Server Web MVC + https://projects.spring.io/spring-cloud + + Pivotal Software, Inc. + https://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.cloud + spring-cloud-starter + + + org.springframework.cloud + spring-cloud-gateway-server-webmvc + + + org.springframework.boot + spring-boot-starter-web + + + diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index b445822a..8de3f70e 100644 --- a/spring-cloud-starter-gateway/pom.xml +++ b/spring-cloud-starter-gateway/pom.xml @@ -11,7 +11,8 @@ spring-cloud-starter-gateway spring-cloud-starter-gateway - Spring Cloud Starter + jar + Spring Cloud Starter Gateway https://projects.spring.io/spring-cloud Pivotal Software, Inc. diff --git a/spring-cloud-starter-gateway/src/main/java/org/springframework/cloud/gateway/server/webflux/starter/StarterDeprecatedAutoConfiguration.java b/spring-cloud-starter-gateway/src/main/java/org/springframework/cloud/gateway/server/webflux/starter/StarterDeprecatedAutoConfiguration.java new file mode 100644 index 00000000..7cff3218 --- /dev/null +++ b/spring-cloud-starter-gateway/src/main/java/org/springframework/cloud/gateway/server/webflux/starter/StarterDeprecatedAutoConfiguration.java @@ -0,0 +1,40 @@ +/* + * 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.server.webflux.starter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.annotation.Configuration; + +/** + * @author Spencer Gibb + */ +@Configuration(proxyBeanMethods = false) +public class StarterDeprecatedAutoConfiguration { + + private static final Log log = LogFactory.getLog(StarterDeprecatedAutoConfiguration.class); + + private static final String BORDER = "\n\n**********************************************************\n\n"; + + public StarterDeprecatedAutoConfiguration() { + log.warn(BORDER + "spring-cloud-starter-gateway is deprecated. " + + "It will be removed in the next major release. " + + "Please use spring-cloud-starter-gateway-server-webflux instead." + BORDER); + } + +} diff --git a/spring-cloud-starter-gateway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-starter-gateway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..4b340116 --- /dev/null +++ b/spring-cloud-starter-gateway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.springframework.cloud.gateway.server.webflux.starter.StarterDeprecatedAutoConfiguration \ No newline at end of file From 79c78f0baa8f35b08367780f031ee610f4a56409 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 17 Jan 2025 10:00:16 +0000 Subject: [PATCH 25/56] Bumping versions --- README.adoc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.adoc b/README.adoc index f980ffa7..9d84e36e 100644 --- a/README.adoc +++ b/README.adoc @@ -40,15 +40,11 @@ tracker for issues and merging pull requests into main. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. -[[sign-the-contributor-license-agreement]] -== Sign the Contributor License Agreement +[[developer-certificate-of-origin]] +== Developer Certificate of Origin (DCO) -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. [[code-of-conduct]] == Code of Conduct From 3802658b452edd67695a28af68fff65b7a49b37d Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 17 Jan 2025 13:30:00 +0000 Subject: [PATCH 26/56] Bumping versions --- README.adoc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.adoc b/README.adoc index f980ffa7..9d84e36e 100644 --- a/README.adoc +++ b/README.adoc @@ -40,15 +40,11 @@ tracker for issues and merging pull requests into main. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. -[[sign-the-contributor-license-agreement]] -== Sign the Contributor License Agreement +[[developer-certificate-of-origin]] +== Developer Certificate of Origin (DCO) -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. [[code-of-conduct]] == Code of Conduct From aebeae97dcaf42da0f01a440cba12a6ecb8d93c5 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 17 Jan 2025 12:47:42 -0500 Subject: [PATCH 27/56] Updates spring cloud deps to northfields versions --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9648f163..d1c8473c 100644 --- a/pom.xml +++ b/pom.xml @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.2.1-SNAPSHOT + 3.3.0-SNAPSHOT 4.3.0-SNAPSHOT - 4.2.1-SNAPSHOT - 4.2.1-SNAPSHOT + 4.3.0-SNAPSHOT + 4.3.0-SNAPSHOT From a905ee0b1bf20c2a87f8efa9321aa3ae19a4c518 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 17 Jan 2025 13:07:49 -0500 Subject: [PATCH 28/56] Adds fn and stream to disabled test --- .../config/conditional/DisableBuiltInGlobalFiltersTests.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 73e389e5..95217bab 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 @@ -49,7 +49,7 @@ public class DisableBuiltInGlobalFiltersTests { @Test public void shouldInjectBuiltInFilters() { - assertThat(globalFilters).hasSizeGreaterThanOrEqualTo(10); + assertThat(globalFilters).hasSizeGreaterThanOrEqualTo(12); } } @@ -86,6 +86,8 @@ public class DisableBuiltInGlobalFiltersTests { "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" }) @ActiveProfiles("disable-components") public class DisableAllGlobalFiltersByProperty { From d5f84f0237178e111cd98bbf5f3901ff0e8b272f Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 17 Jan 2025 18:47:46 +0000 Subject: [PATCH 29/56] Bumping versions --- README.adoc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.adoc b/README.adoc index f980ffa7..9d84e36e 100644 --- a/README.adoc +++ b/README.adoc @@ -40,15 +40,11 @@ tracker for issues and merging pull requests into main. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. -[[sign-the-contributor-license-agreement]] -== Sign the Contributor License Agreement +[[developer-certificate-of-origin]] +== Developer Certificate of Origin (DCO) -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. [[code-of-conduct]] == Code of Conduct From e2b3e728dd3a917614e9c4644900c2bb3d49478d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:10:47 -0500 Subject: [PATCH 30/56] Bump grpc.version from 1.68.1 to 1.70.0 (#3678) Bumps `grpc.version` from 1.68.1 to 1.70.0. Updates `io.grpc:grpc-netty` from 1.68.1 to 1.70.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.68.1...v1.70.0) Updates `io.grpc:grpc-protobuf` from 1.68.1 to 1.70.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.68.1...v1.70.0) Updates `io.grpc:grpc-stub` from 1.68.1 to 1.70.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.68.1...v1.70.0) --- updated-dependencies: - dependency-name: io.grpc:grpc-netty dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.grpc:grpc-protobuf dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.grpc:grpc-stub dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- 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 553d0979..39aefb18 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.68.1 + 1.70.0 diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index e405dd49..b893e88b 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.68.1 + 1.70.0 1.0.0 From 5abf0238e2aae2dc87f6ef790b84387e96f05a7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:12:07 -0500 Subject: [PATCH 31/56] Bump antora from 3.2.0-alpha.4 to 3.2.0-alpha.8 in /docs (#3628) Bumps [antora](https://gitlab.com/antora/antora) from 3.2.0-alpha.4 to 3.2.0-alpha.8. - [Changelog](https://gitlab.com/antora/antora/blob/main/CHANGELOG.adoc) - [Commits](https://gitlab.com/antora/antora/compare/v3.2.0-alpha.4...v3.2.0-alpha.8) --- updated-dependencies: - dependency-name: antora dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c3570e2f..4c4e3383 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "antora": "3.2.0-alpha.4", + "antora": "3.2.0-alpha.8", "@antora/atlas-extension": "1.0.0-alpha.2", "@antora/collector-extension": "1.0.0-alpha.3", "@asciidoctor/tabs": "1.0.0-beta.6", From 43f3408228d6ef99df884c66faabf3aabc4f2d57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:13:59 -0500 Subject: [PATCH 32/56] Bump org.jetbrains.kotlin:kotlin-maven-plugin from 1.9.23 to 1.9.25 (#3612) Bumps org.jetbrains.kotlin:kotlin-maven-plugin from 1.9.23 to 1.9.25. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- spring-cloud-gateway-server/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index f7bc1beb..52a624d7 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -235,7 +235,7 @@ kotlin-maven-plugin org.jetbrains.kotlin - 1.9.23 + 1.9.25 17 From f0c204bab7bbe43ba28c4adeea12a38f6e10efb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:16:10 -0500 Subject: [PATCH 33/56] Bump @antora/collector-extension from 1.0.0-alpha.3 to 1.0.1 in /docs (#3619) --- updated-dependencies: - dependency-name: "@antora/collector-extension" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 4c4e3383..b6c96a18 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,7 +2,7 @@ "dependencies": { "antora": "3.2.0-alpha.8", "@antora/atlas-extension": "1.0.0-alpha.2", - "@antora/collector-extension": "1.0.0-alpha.3", + "@antora/collector-extension": "1.0.1", "@asciidoctor/tabs": "1.0.0-beta.6", "@springio/antora-extensions": "1.11.1", "@springio/asciidoctor-extensions": "1.0.0-alpha.10" From c8da48150f868e42cb8dab9dd8098eb53c8fe494 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:16:57 -0500 Subject: [PATCH 34/56] Bump @springio/asciidoctor-extensions in /docs (#3622) Bumps [@springio/asciidoctor-extensions](https://github.com/spring-io/asciidoctor-extensions) from 1.0.0-alpha.10 to 1.0.0-alpha.14. - [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.10...v1.0.0-alpha.14) --- updated-dependencies: - dependency-name: "@springio/asciidoctor-extensions" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c3570e2f..0e4dcbc5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,6 @@ "@antora/collector-extension": "1.0.0-alpha.3", "@asciidoctor/tabs": "1.0.0-beta.6", "@springio/antora-extensions": "1.11.1", - "@springio/asciidoctor-extensions": "1.0.0-alpha.10" + "@springio/asciidoctor-extensions": "1.0.0-alpha.14" } } From cdf3e5b2bab948d6b9aa726ad7a59eb3a31da45b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:18:36 -0500 Subject: [PATCH 35/56] Bump @springio/asciidoctor-extensions in /docs (#3614) Bumps [@springio/asciidoctor-extensions](https://github.com/spring-io/asciidoctor-extensions) from 1.0.0-alpha.10 to 1.0.0-alpha.14. - [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.10...v1.0.0-alpha.14) --- updated-dependencies: - dependency-name: "@springio/asciidoctor-extensions" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index b6c96a18..35722055 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.11.1", - "@springio/asciidoctor-extensions": "1.0.0-alpha.10" + "@springio/asciidoctor-extensions": "1.0.0-alpha.14" } } From c12287390b32b69bdeb5f05260eb4ab7be98f695 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:20:27 -0500 Subject: [PATCH 36/56] Bump @springio/antora-extensions from 1.11.1 to 1.14.2 in /docs (#3623) Bumps [@springio/antora-extensions](https://github.com/spring-io/antora-extensions) from 1.11.1 to 1.14.2. - [Changelog](https://github.com/spring-io/antora-extensions/blob/main/CHANGELOG.adoc) - [Commits](https://github.com/spring-io/antora-extensions/compare/v1.11.1...v1.14.2) --- updated-dependencies: - dependency-name: "@springio/antora-extensions" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: Spencer Gibb Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Spencer Gibb --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 35722055..567c1f3a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,7 +4,7 @@ "@antora/atlas-extension": "1.0.0-alpha.2", "@antora/collector-extension": "1.0.1", "@asciidoctor/tabs": "1.0.0-beta.6", - "@springio/antora-extensions": "1.11.1", + "@springio/antora-extensions": "1.14.2", "@springio/asciidoctor-extensions": "1.0.0-alpha.14" } } From 805588953ed32f879afcf62febabd2237e8460b4 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 22 Jan 2025 16:20:50 -0500 Subject: [PATCH 37/56] Sets spring.servlet.multipart.enabled to false by default. Fixes gh-3527 --- .../MultipartEnvironmentPostProcessor.java | 44 +++++++++++++++ .../main/resources/META-INF/spring.factories | 20 +++++++ ...ultipartEnvironmentPostProcessorTests.java | 55 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java new file mode 100644 index 00000000..7558cf26 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -0,0 +1,44 @@ +/* + * Copyright 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.Map; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.util.StringUtils; + +public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcessor { + + /* for testing */ static final String MULTIPART_ENABLED_PROPERTY = "spring.servlet.multipart.enabled"; + /* for testing */ static final String MULTIPART_PROPERTY_SOURCE_NAME = "gatewayServerWebmvcMultipartPropertySource"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + String multipartEnabled = environment.getProperty(MULTIPART_ENABLED_PROPERTY); + if (!StringUtils.hasText(multipartEnabled)) { + // no user set property, set it to false. + MapPropertySource propertySource = new MapPropertySource(MULTIPART_PROPERTY_SOURCE_NAME, + Map.of(MULTIPART_ENABLED_PROPERTY, Boolean.FALSE)); + environment.getPropertySources().addFirst(propertySource); + } + } + +} 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 972cdb6d..4b1b5077 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 @@ -1,3 +1,20 @@ +# +# Copyright 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. +# +# + 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,\ @@ -12,3 +29,6 @@ org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier=\ 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.common.MultipartEnvironmentPostProcessor \ No newline at end of file diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java new file mode 100644 index 00000000..1815d9ca --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -0,0 +1,55 @@ +/* + * 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 org.junit.jupiter.api.Test; + +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.server.mvc.common.MultipartEnvironmentPostProcessor.MULTIPART_ENABLED_PROPERTY; +import static org.springframework.cloud.gateway.server.mvc.common.MultipartEnvironmentPostProcessor.MULTIPART_PROPERTY_SOURCE_NAME; + +public class MultipartEnvironmentPostProcessorTests { + + @Test + void multipartDisabledByDefault() { + MockEnvironment environment = new MockEnvironment(); + MultipartEnvironmentPostProcessor processor = new MultipartEnvironmentPostProcessor(); + processor.postProcessEnvironment(environment, null); + + assertThat(environment.getPropertySources().contains(MULTIPART_PROPERTY_SOURCE_NAME)).isTrue(); + + Boolean multipartEnabled = environment.getProperty(MULTIPART_ENABLED_PROPERTY, Boolean.class); + assertThat(multipartEnabled).isFalse(); + } + + @Test + void multipartEnabledByUser() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty(MULTIPART_ENABLED_PROPERTY, "true"); + MultipartEnvironmentPostProcessor processor = new MultipartEnvironmentPostProcessor(); + processor.postProcessEnvironment(environment, null); + + assertThat(environment.getPropertySources().contains(MULTIPART_PROPERTY_SOURCE_NAME)).isFalse(); + + Boolean multipartEnabled = environment.getProperty(MULTIPART_ENABLED_PROPERTY, Boolean.class); + assertThat(multipartEnabled).isTrue(); + } +} From 9d2575468ad1a62da5e26e3c0eab7c9d9801ff5e Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 23 Jan 2025 19:46:21 -0500 Subject: [PATCH 38/56] Formatting --- .../server/mvc/common/MultipartEnvironmentPostProcessor.java | 4 ++-- .../mvc/common/MultipartEnvironmentPostProcessorTests.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index 7558cf26..ce74a653 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 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. @@ -12,7 +12,6 @@ * 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; @@ -28,6 +27,7 @@ import org.springframework.util.StringUtils; public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcessor { /* for testing */ static final String MULTIPART_ENABLED_PROPERTY = "spring.servlet.multipart.enabled"; + /* for testing */ static final String MULTIPART_PROPERTY_SOURCE_NAME = "gatewayServerWebmvcMultipartPropertySource"; @Override diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index 1815d9ca..72dd1b3f 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -12,10 +12,8 @@ * 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 org.junit.jupiter.api.Test; @@ -52,4 +50,5 @@ public class MultipartEnvironmentPostProcessorTests { Boolean multipartEnabled = environment.getProperty(MULTIPART_ENABLED_PROPERTY, Boolean.class); assertThat(multipartEnabled).isTrue(); } + } From 7db891dec116683d44f120ca8b725e733e0e52c6 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Thu, 23 Jan 2025 19:46:55 -0500 Subject: [PATCH 39/56] Deprecate WebClientRouting infrastructure Fixes gh-3680 --- .../cloud/gateway/filter/WebClientHttpRoutingFilter.java | 2 ++ .../cloud/gateway/filter/WebClientWriteResponseFilter.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientHttpRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientHttpRoutingFilter.java index 02dcc349..10892d7d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientHttpRoutingFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientHttpRoutingFilter.java @@ -43,7 +43,9 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.s /** * @author Spencer Gibb + * @deprecated for removal in 5.0 */ +@Deprecated public class WebClientHttpRoutingFilter implements GlobalFilter, Ordered { private final WebClient webClient; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientWriteResponseFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientWriteResponseFilter.java index 8dab68e4..35009fd7 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientWriteResponseFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebClientWriteResponseFilter.java @@ -30,7 +30,9 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.C /** * @author Spencer Gibb + * @deprecated for removal in 5.0 */ +@Deprecated public class WebClientWriteResponseFilter implements GlobalFilter, Ordered { /** From 64c36c46b917cc6d0db8c7bdf015da88de89d185 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Mon, 27 Jan 2025 12:55:00 -0500 Subject: [PATCH 40/56] Formatting --- .../server/mvc/common/MultipartEnvironmentPostProcessor.java | 4 ++-- .../mvc/common/MultipartEnvironmentPostProcessorTests.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index 7558cf26..e06226f9 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 the original author or authors. + * Copyright 2012-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. @@ -12,7 +12,6 @@ * 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; @@ -28,6 +27,7 @@ import org.springframework.util.StringUtils; public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcessor { /* for testing */ static final String MULTIPART_ENABLED_PROPERTY = "spring.servlet.multipart.enabled"; + /* for testing */ static final String MULTIPART_PROPERTY_SOURCE_NAME = "gatewayServerWebmvcMultipartPropertySource"; @Override diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index 1815d9ca..72dd1b3f 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -12,10 +12,8 @@ * 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 org.junit.jupiter.api.Test; @@ -52,4 +50,5 @@ public class MultipartEnvironmentPostProcessorTests { Boolean multipartEnabled = environment.getProperty(MULTIPART_ENABLED_PROPERTY, Boolean.class); assertThat(multipartEnabled).isTrue(); } + } From cb404cf836e0590e78575a9b3e2d3245f85beca4 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Mon, 27 Jan 2025 16:16:17 -0500 Subject: [PATCH 41/56] Effectively disables MultipartEnvironmentPostProcessor --- .../server/mvc/common/MultipartEnvironmentPostProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index e06226f9..06b77e58 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -37,7 +37,7 @@ public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcess // no user set property, set it to false. MapPropertySource propertySource = new MapPropertySource(MULTIPART_PROPERTY_SOURCE_NAME, Map.of(MULTIPART_ENABLED_PROPERTY, Boolean.FALSE)); - environment.getPropertySources().addFirst(propertySource); + //environment.getPropertySources().addFirst(propertySource); } } From 92e8cfc0692842c33b12dd363427cd9005aa499f Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 28 Jan 2025 13:26:40 -0500 Subject: [PATCH 42/56] Effectively disables MultipartEnvironmentPostProcessor --- .../mvc/common/MultipartEnvironmentPostProcessorTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index 72dd1b3f..f62373ec 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -15,7 +15,7 @@ */ package org.springframework.cloud.gateway.server.mvc.common; - +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.mock.env.MockEnvironment; @@ -27,6 +27,7 @@ import static org.springframework.cloud.gateway.server.mvc.common.MultipartEnvir public class MultipartEnvironmentPostProcessorTests { @Test + @Disabled void multipartDisabledByDefault() { MockEnvironment environment = new MockEnvironment(); MultipartEnvironmentPostProcessor processor = new MultipartEnvironmentPostProcessor(); From ff2c7e7ae83c5dc7b49025a9de88a304aa05f609 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 28 Jan 2025 13:29:58 -0500 Subject: [PATCH 43/56] Effectively disables MultipartEnvironmentPostProcessor --- .../server/mvc/common/MultipartEnvironmentPostProcessor.java | 2 +- .../mvc/common/MultipartEnvironmentPostProcessorTests.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index 06b77e58..1ac9abdc 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -37,7 +37,7 @@ public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcess // no user set property, set it to false. MapPropertySource propertySource = new MapPropertySource(MULTIPART_PROPERTY_SOURCE_NAME, Map.of(MULTIPART_ENABLED_PROPERTY, Boolean.FALSE)); - //environment.getPropertySources().addFirst(propertySource); + // environment.getPropertySources().addFirst(propertySource); } } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index f62373ec..638bb86e 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -15,6 +15,7 @@ */ package org.springframework.cloud.gateway.server.mvc.common; + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; From cf958b361b240690e1e8816b82a4c0808cd22a78 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 30 Jan 2025 11:56:23 +0000 Subject: [PATCH 44/56] Update SNAPSHOT to 4.3.0-M1 --- 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..c03c5177 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-M1 spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index d1c8473c..5492b390 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-SNAPSHOT + 4.3.0-M1 pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-SNAPSHOT + 4.3.0-M1 @@ -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-M1 + 4.3.0-M1 + 4.3.0-M1 + 4.3.0-M1 diff --git a/spring-cloud-gateway-dependencies/pom.xml b/spring-cloud-gateway-dependencies/pom.xml index 66103cf7..e631a8ab 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-M1 spring-cloud-gateway-dependencies - 4.3.0-SNAPSHOT + 4.3.0-M1 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 39aefb18..41921a98 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-M1 .. diff --git a/spring-cloud-gateway-integration-tests/http2/pom.xml b/spring-cloud-gateway-integration-tests/http2/pom.xml index 49e2de46..79df8f3a 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-M1 .. 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..0e4eb167 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-M1 .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 461e4c70..688997ee 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-M1 .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 14d0d2aa..7d871fd7 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-M1 .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index 3243a645..8799e7bd 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-M1 .. 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..9de8957b 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-M1 .. spring-cloud-gateway-proxyexchange-webmvc diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 20671002..3c1a7dc3 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-M1 .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 6f7ff6b3..1e522f49 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-M1 .. 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..f18e93ba 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-M1 .. 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..25cfadef 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-M1 .. spring-cloud-gateway-server-webmvc diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index b893e88b..d4af4d84 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-M1 .. spring-cloud-gateway-server diff --git a/spring-cloud-gateway-webflux/pom.xml b/spring-cloud-gateway-webflux/pom.xml index 5859d52d..b32798bf 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-M1 .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index e86d2d1f..52692740 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-M1 .. 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..242435b1 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-M1 .. 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..3d76dbdb 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-M1 .. spring-cloud-starter-gateway-server-webmvc diff --git a/spring-cloud-starter-gateway/pom.xml b/spring-cloud-starter-gateway/pom.xml index 8de3f70e..fc88a166 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-M1 .. spring-cloud-starter-gateway From 7f638fbcaea0938a5cc3c7e6160bf04c3f0eb0c6 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Thu, 30 Jan 2025 11:59:00 +0000 Subject: [PATCH 45/56] 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 c03c5177..709dc57e 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M1 + 4.3.0-SNAPSHOT spring-cloud-gateway-docs jar diff --git a/pom.xml b/pom.xml index 5492b390..d1c8473c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-gateway - 4.3.0-M1 + 4.3.0-SNAPSHOT pom Spring Cloud Gateway @@ -15,7 +15,7 @@ org.springframework.cloud spring-cloud-build - 4.3.0-M1 + 4.3.0-SNAPSHOT @@ -55,10 +55,10 @@ 1.0.8.RELEASE 17 2.3.0 - 3.3.0-M1 - 4.3.0-M1 - 4.3.0-M1 - 4.3.0-M1 + 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 e631a8ab..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-M1 + 4.3.0-SNAPSHOT spring-cloud-gateway-dependencies - 4.3.0-M1 + 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 41921a98..39aefb18 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-M1 + 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 79df8f3a..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-M1 + 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 0e4eb167..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-M1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-integration-tests/pom.xml b/spring-cloud-gateway-integration-tests/pom.xml index 688997ee..461e4c70 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-M1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-mvc/pom.xml b/spring-cloud-gateway-mvc/pom.xml index 7d871fd7..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-M1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-proxyexchange-webflux/pom.xml b/spring-cloud-gateway-proxyexchange-webflux/pom.xml index 8799e7bd..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-M1 + 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 9de8957b..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-M1 + 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 3c1a7dc3..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-M1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 1e522f49..6f7ff6b3 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-M1 + 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 f18e93ba..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-M1 + 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 25cfadef..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-M1 + 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 d4af4d84..b893e88b 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-M1 + 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 b32798bf..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-M1 + 4.3.0-SNAPSHOT .. diff --git a/spring-cloud-starter-gateway-mvc/pom.xml b/spring-cloud-starter-gateway-mvc/pom.xml index 52692740..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-M1 + 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 242435b1..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-M1 + 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 3d76dbdb..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-M1 + 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 fc88a166..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-M1 + 4.3.0-SNAPSHOT .. spring-cloud-starter-gateway From f76397df192e9ab1ff1735edd2f181d1cb308ca8 Mon Sep 17 00:00:00 2001 From: KOSEUNGBIN Date: Sat, 1 Feb 2025 01:04:02 +0900 Subject: [PATCH 46/56] Support rewriting request parameters (#3669) Introduced a method to modify or replace request parameters during request processing, providing greater flexibility for parameter handling in routing. Signed-off-by: raccoonback --- .../mvc/filter/BeforeFilterFunctions.java | 25 ++++ .../filter/BeforeFilterFunctionsTests.java | 110 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java 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 93a3eb7c..bfd77c2c 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,6 +45,7 @@ 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; @@ -337,6 +338,30 @@ public abstract class BeforeFilterFunctions { }; } + public static Function rewriteRequestParameter(String name, String replacement) { + return request -> { + MultiValueMap queryParams = new LinkedMultiValueMap<>(request.params()); + if (queryParams.containsKey(name)) { + queryParams.remove(name); + queryParams.add(name, replacement); + } + + MultiValueMap encodedQueryParams = UriUtils.encodeQueryParams(queryParams); + URI rewrittenUri = UriComponentsBuilder.fromUri(request.uri()) + .replaceQueryParams(unmodifiableMultiValueMap(encodedQueryParams)) + .build(true) + .toUri(); + + return ServerRequest.from(request) + .params(params -> { + params.remove(name); + params.add(name, replacement); + }) + .uri(rewrittenUri) + .build(); + }; + } + public static Function routeId(String routeId) { return request -> { MvcUtils.setRouteId(request, routeId); 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 new file mode 100644 index 00000000..47101449 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctionsTests.java @@ -0,0 +1,110 @@ +/* + * 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 org.junit.jupiter.api.Test; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.servlet.function.ServerRequest; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author raccoonback + */ +class BeforeFilterFunctionsTests { + + @Test + void rewriteRequestParameter() { + 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"); + } + + @Test + void rewriteOnlyFirstRequestParameter() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path") + .param("foo", "bar_1") + .param("foo", "bar_2") + .param("foo", "bar_3") + .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"); + } + + @Test + void rewriteEncodedRequestParameter() { + 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%5B%5D=replacement%5B%5D"); + } + + @Test + void rewriteRequestParameterWithEncodedRemainParameters() { + 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%5B%5D=qux%5B%5D&foo=replacement"); + } + + @Test + void rewriteRequestParameterWithEncodedPath() { + MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path/é/last") + .param("foo", "bar") + .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/%C3%A9/last?foo=replacement"); + } + +} From 3a6267ce8972acbb2edf905b27e0c9a6ac06db98 Mon Sep 17 00:00:00 2001 From: spring-builds Date: Fri, 31 Jan 2025 19:00:50 +0000 Subject: [PATCH 47/56] Bumping versions --- .../server/mvc/filter/BeforeFilterFunctions.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 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 bfd77c2c..806bdaa4 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 @@ -352,13 +352,10 @@ public abstract class BeforeFilterFunctions { .build(true) .toUri(); - return ServerRequest.from(request) - .params(params -> { - params.remove(name); - params.add(name, replacement); - }) - .uri(rewrittenUri) - .build(); + return ServerRequest.from(request).params(params -> { + params.remove(name); + params.add(name, replacement); + }).uri(rewrittenUri).build(); }; } From d83e890cd1b9ff7cd3f6d07ccef11e0c56d3ec70 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 4 Feb 2025 16:27:42 -0500 Subject: [PATCH 48/56] Removed var --- .../server/mvc/handler/ProxyExchangeHandlerFunction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 84ce2018..0ea445fc 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 @@ -123,9 +123,9 @@ public class ProxyExchangeHandlerFunction private HttpHeaders filterHeaders(List filters, HttpHeaders original, REQUEST_OR_RESPONSE requestOrResponse) { HttpHeaders filtered = original; - for (var filter : filters) { + for (Object filter : filters) { @SuppressWarnings("unchecked") - var typed = ((HttpHeadersFilter) filter); + HttpHeadersFilter typed = ((HttpHeadersFilter) filter); filtered = typed.apply(filtered, requestOrResponse); } return filtered; From eef10abba3967ce93463bdcc0b6e0af21b791e32 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 4 Feb 2025 16:29:12 -0500 Subject: [PATCH 49/56] Re-enables MultipartEnvironmentPostProcessor Closes gh-3527 --- .../MultipartEnvironmentPostProcessor.java | 2 +- .../server/mvc/ServerMvcIntegrationTests.java | 23 +++++++++--- ...ultipartEnvironmentPostProcessorTests.java | 2 -- .../server/mvc/test/TestController.java | 36 +------------------ 4 files changed, 20 insertions(+), 43 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index 1ac9abdc..e06226f9 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -37,7 +37,7 @@ public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcess // no user set property, set it to false. MapPropertySource propertySource = new MapPropertySource(MULTIPART_PROPERTY_SOURCE_NAME, Map.of(MULTIPART_ENABLED_PROPERTY, Boolean.FALSE)); - // environment.getPropertySources().addFirst(propertySource); + environment.getPropertySources().addFirst(propertySource); } } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index d9a7dc7b..4af00c8b 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 @@ -22,6 +22,7 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -484,7 +485,7 @@ public class ServerMvcIntegrationTests { @Test public void rewritePathPostLocalWorks() { restClient.post() - .uri("/baz/post") + .uri("/baz/localpost") .bodyValue("hello") .header("Host", "www.rewritepathpostlocal.org") .exchange() @@ -636,8 +637,21 @@ public class ServerMvcIntegrationTests { private void assertMultipartData(Map responseBody) { Map files = (Map) responseBody.get("files"); assertThat(files).containsKey("imgpart"); - String file = (String) files.get("imgpart"); - assertThat(file).startsWith("data:").contains(";base64,"); + Object imgpart = files.get("imgpart"); + if (imgpart instanceof List l) { + String file = (String) l.get(0); + assertThat(isPNG(file.getBytes())); + } + else { + String file = (String) imgpart; + assertThat(file).startsWith("data:").contains(";base64,"); + } + } + + private static boolean isPNG(byte[] bytes) { + byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + byte[] header = Arrays.copyOf(bytes, pngSignature.length); + return Arrays.equals(pngSignature, header); } @Test @@ -1279,8 +1293,7 @@ public class ServerMvcIntegrationTests { // @formatter:off return route("testform") .POST("/post", host("**.testform.org"), http()) - .before(new LocalServerPortUriResolver()) - .filter(prefixPath("/test")) + .filter(new HttpbinUriResolver()) .filter(addRequestHeader("X-Test", "form")) .build(); // @formatter:on diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index 638bb86e..72dd1b3f 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -16,7 +16,6 @@ package org.springframework.cloud.gateway.server.mvc.common; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.mock.env.MockEnvironment; @@ -28,7 +27,6 @@ import static org.springframework.cloud.gateway.server.mvc.common.MultipartEnvir public class MultipartEnvironmentPostProcessorTests { @Test - @Disabled void multipartDisabledByDefault() { MockEnvironment environment = new MockEnvironment(); MultipartEnvironmentPostProcessor processor = new MultipartEnvironmentPostProcessor(); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java index d65d50f9..5048c042 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java @@ -16,27 +16,21 @@ package org.springframework.cloud.gateway.server.mvc.test; -import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Map; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ServerWebExchange; @RestController @@ -58,35 +52,7 @@ public class TestController { return result; } - @PostMapping(value = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public Map postFormData(HttpServletRequest request, - @RequestParam MultiValueMap parts) throws ServletException, IOException { - HashMap ret = new HashMap<>(); - ret.put("headers", getHeaders(request)); - HashMap files = new HashMap<>(); - ret.put("files", files); - - parts.values().stream().flatMap(List::stream).forEach(part -> { - String contentType = part.getContentType(); - long contentLength = part.getSize(); - // TODO: get part data - files.put(part.getName(), "data:" + contentType + ";base64," + contentLength); - }); - return ret; - } - - @PostMapping(path = "/post", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public Map postUrlEncoded(HttpServletRequest request, - @RequestBody(required = false) MultiValueMap form) throws IOException { - HashMap ret = new HashMap<>(); - ret.put("headers", getHeaders(request)); - ret.put("form", form); - return ret; - } - - @PostMapping(path = "/post", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(path = "/localpost", produces = MediaType.APPLICATION_JSON_VALUE) public Map post(HttpServletRequest request, @RequestBody(required = false) String body) { HashMap ret = new HashMap<>(); ret.put("headers", getHeaders(request)); From 64fedc0fae1984f9db833d237b0837e99d27458f Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 4 Feb 2025 16:27:42 -0500 Subject: [PATCH 50/56] Removed var --- .../server/mvc/handler/ProxyExchangeHandlerFunction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 84ce2018..0ea445fc 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 @@ -123,9 +123,9 @@ public class ProxyExchangeHandlerFunction private HttpHeaders filterHeaders(List filters, HttpHeaders original, REQUEST_OR_RESPONSE requestOrResponse) { HttpHeaders filtered = original; - for (var filter : filters) { + for (Object filter : filters) { @SuppressWarnings("unchecked") - var typed = ((HttpHeadersFilter) filter); + HttpHeadersFilter typed = ((HttpHeadersFilter) filter); filtered = typed.apply(filtered, requestOrResponse); } return filtered; From adf32f641cdc4b19356ce253de02e54a35c45712 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 4 Feb 2025 16:29:12 -0500 Subject: [PATCH 51/56] Re-enables MultipartEnvironmentPostProcessor Closes gh-3527 --- .../MultipartEnvironmentPostProcessor.java | 2 +- .../server/mvc/ServerMvcIntegrationTests.java | 23 +++++++++--- ...ultipartEnvironmentPostProcessorTests.java | 2 -- .../server/mvc/test/TestController.java | 36 +------------------ 4 files changed, 20 insertions(+), 43 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java index d896037c..ce74a653 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessor.java @@ -37,7 +37,7 @@ public class MultipartEnvironmentPostProcessor implements EnvironmentPostProcess // no user set property, set it to false. MapPropertySource propertySource = new MapPropertySource(MULTIPART_PROPERTY_SOURCE_NAME, Map.of(MULTIPART_ENABLED_PROPERTY, Boolean.FALSE)); - // environment.getPropertySources().addFirst(propertySource); + environment.getPropertySources().addFirst(propertySource); } } 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 2b4ab69e..3f744881 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 @@ -22,6 +22,7 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -488,7 +489,7 @@ public class ServerMvcIntegrationTests { @Test public void rewritePathPostLocalWorks() { restClient.post() - .uri("/baz/post") + .uri("/baz/localpost") .bodyValue("hello") .header("Host", "www.rewritepathpostlocal.org") .exchange() @@ -640,8 +641,21 @@ public class ServerMvcIntegrationTests { private void assertMultipartData(Map responseBody) { Map files = (Map) responseBody.get("files"); assertThat(files).containsKey("imgpart"); - String file = (String) files.get("imgpart"); - assertThat(file).startsWith("data:").contains(";base64,"); + Object imgpart = files.get("imgpart"); + if (imgpart instanceof List l) { + String file = (String) l.get(0); + assertThat(isPNG(file.getBytes())); + } + else { + String file = (String) imgpart; + assertThat(file).startsWith("data:").contains(";base64,"); + } + } + + private static boolean isPNG(byte[] bytes) { + byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + byte[] header = Arrays.copyOf(bytes, pngSignature.length); + return Arrays.equals(pngSignature, header); } @Test @@ -1288,8 +1302,7 @@ public class ServerMvcIntegrationTests { // @formatter:off return route("testform") .POST("/post", host("**.testform.org"), http()) - .before(new LocalServerPortUriResolver()) - .filter(prefixPath("/test")) + .filter(new HttpbinUriResolver()) .filter(addRequestHeader("X-Test", "form")) .build(); // @formatter:on diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java index 638bb86e..72dd1b3f 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/common/MultipartEnvironmentPostProcessorTests.java @@ -16,7 +16,6 @@ package org.springframework.cloud.gateway.server.mvc.common; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.mock.env.MockEnvironment; @@ -28,7 +27,6 @@ import static org.springframework.cloud.gateway.server.mvc.common.MultipartEnvir public class MultipartEnvironmentPostProcessorTests { @Test - @Disabled void multipartDisabledByDefault() { MockEnvironment environment = new MockEnvironment(); MultipartEnvironmentPostProcessor processor = new MultipartEnvironmentPostProcessor(); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java index d65d50f9..5048c042 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/TestController.java @@ -16,27 +16,21 @@ package org.springframework.cloud.gateway.server.mvc.test; -import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Map; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ServerWebExchange; @RestController @@ -58,35 +52,7 @@ public class TestController { return result; } - @PostMapping(value = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public Map postFormData(HttpServletRequest request, - @RequestParam MultiValueMap parts) throws ServletException, IOException { - HashMap ret = new HashMap<>(); - ret.put("headers", getHeaders(request)); - HashMap files = new HashMap<>(); - ret.put("files", files); - - parts.values().stream().flatMap(List::stream).forEach(part -> { - String contentType = part.getContentType(); - long contentLength = part.getSize(); - // TODO: get part data - files.put(part.getName(), "data:" + contentType + ";base64," + contentLength); - }); - return ret; - } - - @PostMapping(path = "/post", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - public Map postUrlEncoded(HttpServletRequest request, - @RequestBody(required = false) MultiValueMap form) throws IOException { - HashMap ret = new HashMap<>(); - ret.put("headers", getHeaders(request)); - ret.put("form", form); - return ret; - } - - @PostMapping(path = "/post", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(path = "/localpost", produces = MediaType.APPLICATION_JSON_VALUE) public Map post(HttpServletRequest request, @RequestBody(required = false) String body) { HashMap ret = new HashMap<>(); ret.put("headers", getHeaders(request)); From 41606b757658460f39b1ab0cb83f28d7474fdd23 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 5 Feb 2025 11:15:37 -0500 Subject: [PATCH 52/56] Initial support for Supplier functions in server-webmvc See gh-3646 --- .../server/mvc/handler/HandlerFunctions.java | 2 +- .../mvc/handler/FunctionHandlerTests.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java index 4b35cc44..04cfc1a0 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java @@ -61,7 +61,7 @@ public abstract class HandlerFunctions { FunctionInvocationWrapper function = functionCatalog.lookup(expandedFunctionName, request.headers().accept().stream().map(MimeType::toString).toArray(String[]::new)); if (function != null) { - Object body = request.body(function.getRawInputType()); + Object body = function.isSupplier() ? null : request.body(function.getRawInputType()); return processRequest(request, function, body, false, Collections.emptyList(), Collections.emptyList()); } return ServerResponse.notFound().build(); diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java index 28d17153..73de8492 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java @@ -18,7 +18,9 @@ package org.springframework.cloud.gateway.server.mvc.handler; import java.util.Locale; import java.util.function.Function; +import java.util.function.Supplier; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -66,6 +68,19 @@ public class FunctionHandlerTests { .isEqualTo("HELLO"); } + @Disabled + @Test + public void testSupplierFunctionWorks() { + restClient.get() + .uri("/supplierfunction") + .accept(MediaType.TEXT_PLAIN) + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("hello"); + } + @SpringBootConfiguration @EnableAutoConfiguration protected static class TestConfiguration { @@ -75,6 +90,11 @@ public class FunctionHandlerTests { return s -> s.toUpperCase(Locale.ROOT); } + @Bean + Supplier hello() { + return () -> "hello"; + } + @Bean public RouterFunction gatewayRouterFunctionsSimpleFunction() { // @formatter:off @@ -83,6 +103,9 @@ public class FunctionHandlerTests { .build() .and(route("testtemplatedfunction") .POST("/templatedfunction/{fnName}", fn("{fnName}")) + .build()) + .and(route("testsupplierfunction") + .POST("/supplierfunction", fn("hello")) .build()); // @formatter:on } From 6e6ceb5dffb46d1130bb07e32692e6224b4f0132 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 5 Feb 2025 11:35:10 -0500 Subject: [PATCH 53/56] Fixed supplier function test config to GET See gh-3646 --- .../gateway/server/mvc/handler/FunctionHandlerTests.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java index 73de8492..c2090807 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java @@ -20,7 +20,6 @@ import java.util.Locale; import java.util.function.Function; import java.util.function.Supplier; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -68,7 +67,6 @@ public class FunctionHandlerTests { .isEqualTo("HELLO"); } - @Disabled @Test public void testSupplierFunctionWorks() { restClient.get() @@ -105,7 +103,7 @@ public class FunctionHandlerTests { .POST("/templatedfunction/{fnName}", fn("{fnName}")) .build()) .and(route("testsupplierfunction") - .POST("/supplierfunction", fn("hello")) + .GET("/supplierfunction", fn("hello")) .build()); // @formatter:on } From f469733d9fc55e42e0eba089e9fdca90e4f42b11 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 5 Feb 2025 11:39:57 -0500 Subject: [PATCH 54/56] Adds test for Supplier functions via config in server-webmvc See gh-3646 --- .../mvc/config/FunctionHandlerConfigTests.java | 18 ++++++++++++++++++ .../application-functionhandlerconfigtests.yml | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java index 21fe10f2..779bc5bd 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java @@ -18,6 +18,7 @@ package org.springframework.cloud.gateway.server.mvc.config; import java.util.Locale; import java.util.function.Function; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; @@ -63,6 +64,18 @@ public class FunctionHandlerConfigTests { .isEqualTo("HELLO"); } + @Test + public void testSupplierFunctionWorks() { + restClient.get() + .uri("/supplierfunction") + .accept(MediaType.TEXT_PLAIN) + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("hello"); + } + @SpringBootConfiguration @EnableAutoConfiguration protected static class TestConfiguration { @@ -72,6 +85,11 @@ public class FunctionHandlerConfigTests { return s -> s.toUpperCase(Locale.ROOT); } + @Bean + Supplier hello() { + return () -> "hello"; + } + } } 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 0690e34b..c7430ca4 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 @@ -10,7 +10,11 @@ spring.cloud.gateway.mvc: predicates: - Path=/templatedfunction/{fnName} - Method=POST - + testsupplierfunction: + uri: fn:hello + predicates: + - Path=/supplierfunction + - Method=GET logging: level: org.springframework.cloud.gateway.server.mvc: TRACE From a8f9212d01048caca2bf4304fd591fcf2c124f48 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 5 Feb 2025 15:29:44 -0500 Subject: [PATCH 55/56] Disables test for jdk 23 and up --- .../server/mvc/GatewayServerMvcAutoConfigurationTests.java | 3 +++ 1 file changed, 3 insertions(+) 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 95526486..7eb56405 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 @@ -19,6 +19,8 @@ package org.springframework.cloud.gateway.server.mvc; import java.time.Duration; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -132,6 +134,7 @@ public class GatewayServerMvcAutoConfigurationTests { }); } + @DisabledForJreRange(min = JRE.JAVA_23) @Test void gatewayHttpClientPropertiesWork() { ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class) From 159ce34abe4887efd1eee974d180ba291ac6bc64 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 11 Feb 2025 19:39:39 -0500 Subject: [PATCH 56/56] Adds support for retry with request body. Adds MvcUtils.getOrCacheBody() used by RetryFilterFunctions.retry(). Moves retry tests into RetryFilterFunctionTests.java Fixes gh-3336 --- .../filters/retry.adoc | 10 +- .../gateway/server/mvc/common/MvcUtils.java | 8 + .../mvc/filter/RetryFilterFunctions.java | 15 ++ .../server/mvc/ServerMvcIntegrationTests.java | 71 ------- .../mvc/filter/RetryFilterFunctionTests.java | 180 ++++++++++++++++++ 5 files changed, 212 insertions(+), 72 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc index fa6529fa..96165f0d 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-mvc/filters/retry.adoc @@ -9,6 +9,7 @@ The `Retry` filter supports the following parameters: * `methods`: The HTTP methods that should be retried, represented by using `org.springframework.http.HttpMethod`. * `series`: The series of status codes to be retried, represented by using `org.springframework.http.HttpStatus.Series`. * `exceptions`: A list of thrown exceptions that should be retried. +* `cacheBody`: A flag to signal if the request body should be cached. If set to `true`, the `adaptCacheBody` filter must be used to send the cached body downstream. //* `backoff`: The configured exponential backoff for the retries. //Retries are performed after a backoff interval of `firstBackoff * (factor ^ n)`, where `n` is the iteration. //If `maxBackoff` is configured, the maximum backoff applied is limited to `maxBackoff`. @@ -20,8 +21,11 @@ The following defaults are configured for `Retry` filter, if enabled: * `series`: 5XX series * `methods`: GET method * `exceptions`: `IOException`, `TimeoutException` and `RetryException` +* `cacheBody`: `false` //* `backoff`: disabled +WARNING: Setting `cacheBody` to `true` causes the gateway to read the whole body into memory. This should be used with caution. + The following listing configures a Retry filter: .application.yml @@ -42,11 +46,14 @@ spring: retries: 3 series: SERVER_ERROR methods: GET,POST + cacheBody: true + - name: AdaptCachedBody ---- .GatewaySampleApplication.java [source,java] ---- +import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.adaptCachedBody; 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; @@ -59,7 +66,8 @@ class RouteConfiguration { public RouterFunction gatewayRouterFunctionsAddReqHeader() { return route("add_request_parameter_route") .route(host("*.retry.com"), http("https://example.org")) - .filter(retry(config -> config.setRetries(3).setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)).setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)))) + .filter(retry(config -> config.setRetries(3).setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)).setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)).setCacheBody(true))) + .filter(adaptCachedBody()) .build(); } } 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 5e635b71..72f30289 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 @@ -116,6 +116,14 @@ public abstract class MvcUtils { } } + public static ByteArrayInputStream getOrCacheBody(ServerRequest request) { + ByteArrayInputStream body = getAttribute(request, MvcUtils.CACHED_REQUEST_BODY_ATTR); + if (body != null) { + return body; + } + return cacheBody(request); + } + public static String expand(ServerRequest request, String template) { Assert.notNull(request, "request may not be null"); Assert.notNull(template, "template may not be null"); 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 8a550ce2..272b1e6c 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 @@ -27,6 +27,7 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; 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.common.Shortcut; import org.springframework.core.NestedRuntimeException; import org.springframework.http.HttpMethod; @@ -71,6 +72,9 @@ public abstract class RetryFilterFunctions { .setPolicies(Arrays.asList(simpleRetryPolicy, new HttpRetryPolicy(config)).toArray(new RetryPolicy[0])); RetryTemplate retryTemplate = retryTemplateBuilder.customPolicy(compositeRetryPolicy).build(); return (request, next) -> retryTemplate.execute(context -> { + if (config.isCacheBody()) { + MvcUtils.getOrCacheBody(request); + } ServerResponse serverResponse = next.handle(request); if (isRetryableStatusCode(serverResponse.statusCode(), config) @@ -121,6 +125,8 @@ public abstract class RetryFilterFunctions { private Set methods = new HashSet<>(List.of(HttpMethod.GET)); + private boolean cacheBody = false; + // TODO: individual statuses // TODO: backoff // TODO: support more Spring Retry policies @@ -176,6 +182,15 @@ public abstract class RetryFilterFunctions { return this; } + public boolean isCacheBody() { + return cacheBody; + } + + public RetryConfig setCacheBody(boolean cacheBody) { + this.cacheBody = cacheBody; + return this; + } + } private static class RetryException extends NestedRuntimeException { 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 4af00c8b..9deff0ed 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 @@ -27,8 +27,6 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import com.github.benmanes.caffeine.cache.Caffeine; @@ -41,8 +39,6 @@ import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -80,10 +76,8 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StreamUtils; -import org.springframework.web.bind.annotation.GetMapping; 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.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.RouterFunction; @@ -118,7 +112,6 @@ import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreaker import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.addRequestHeader; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.addRequestHeadersIfNotPresent; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.addRequestParameter; -import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.prefixPath; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.redirectTo; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.removeRequestHeader; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.rewritePath; @@ -127,7 +120,6 @@ import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunction import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.setRequestHostHeader; import static org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.stripPrefix; 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.forward; import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; @@ -394,20 +386,6 @@ public class ServerMvcIntegrationTests { // @formatter:on } - @Test - public void retryWorks() { - restClient.get().uri("/retry?key=get").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("3"); - // test for: java.lang.IllegalArgumentException: You have already selected another - // retry policy - restClient.get() - .uri("/retry?key=get2") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo("3"); - } - @Test public void rateLimitWorks() { restClient.get().uri("/anything/ratelimit").exchange().expectStatus().isOk(); @@ -1005,11 +983,6 @@ public class ServerMvcIntegrationTests { return new TestHandler(); } - @Bean - RetryController retryController() { - return new RetryController(); - } - @Bean EventController eventController() { return new EventController(); @@ -1194,19 +1167,6 @@ public class ServerMvcIntegrationTests { // @formatter:on } - @Bean - public RouterFunction gatewayRouterFunctionsRetry() { - // @formatter:off - return route("testretry") - .route(path("/retry"), http()) - .before(new LocalServerPortUriResolver()) - .filter(retry(3)) - //.filter(retry(config -> config.setRetries(3).setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)).setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)))) - .filter(prefixPath("/do")) - .build(); - // @formatter:on - } - @Bean public RouterFunction gatewayRouterFunctionsRateLimit() { // @formatter:off @@ -1690,37 +1650,6 @@ public class ServerMvcIntegrationTests { } - @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 = getCount(key); - 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); - } - - AtomicInteger getCount(String key) { - return map.computeIfAbsent(key, s -> new AtomicInteger()); - } - - } - protected static class TestHandler implements HandlerFunction { @Override 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 new file mode 100644 index 00000000..edae11e4 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java @@ -0,0 +1,180 @@ +/* + * 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.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.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.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.annotation.Bean; +import org.springframework.core.log.LogMessage; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +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.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.RetryFilterFunctions.retry; +import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; +import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; + +@SuppressWarnings("unchecked") +@SpringBootTest(properties = {}, webEnvironment = WebEnvironment.RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +public class RetryFilterFunctionTests { + + @LocalServerPort + int port; + + @Autowired + TestRestClient restClient; + + @Test + public void retryWorks() { + restClient.get().uri("/retry?key=get").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("3"); + // test for: java.lang.IllegalArgumentException: You have already selected another + // retry policy + restClient.get() + .uri("/retry?key=get2") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("3"); + } + + @Test + public void retryBodyWorks() { + restClient.post() + .uri("/retrybody?key=post") + .bodyValue("thebody") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("3"); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + protected static class TestConfiguration { + + @Bean + public RouterFunction gatewayRouterFunctionsRetry() { + // @formatter:off + return route("testretry") + .GET("/retry", http()) + .before(new LocalServerPortUriResolver()) + .filter(retry(3)) + .filter(prefixPath("/do")) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction gatewayRouterFunctionsRetryBody() { + // @formatter:off + return route("testretrybody") + .POST("/retrybody", http()) + .before(new LocalServerPortUriResolver()) + .filter(retry(config -> config.setRetries(3).setSeries(Set.of(HttpStatus.Series.SERVER_ERROR)) + .setMethods(Set.of(HttpMethod.GET, HttpMethod.POST)).setCacheBody(true))) + .filter(adaptCachedBody()) + .filter(prefixPath("/do")) + .build(); + // @formatter:on + } + + @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 = getCount(key); + 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); + } + + @PostMapping("/do/retrybody") + public ResponseEntity retryBody(@RequestParam("key") String key, + @RequestParam(name = "count", defaultValue = "3") int count, @RequestBody String requestBody) { + AtomicInteger num = getCount(key); + int i = num.incrementAndGet(); + log.warn(LogMessage.format("Retry count: %s, body: %s", i, requestBody)); + String body = String.valueOf(i); + if (!StringUtils.hasText(requestBody)) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .header("X-Retry-Count", body) + .body("missing body"); + } + if (i < count) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .header("X-Retry-Count", body) + .body("temporarily broken"); + } + return ResponseEntity.status(HttpStatus.OK).header("X-Retry-Count", body).body(body); + } + + AtomicInteger getCount(String key) { + return map.computeIfAbsent(key, s -> new AtomicInteger()); + } + + } + + } + +}