From ccd5542f0c668b569f27b16a33286416eacdf687 Mon Sep 17 00:00:00 2001 From: JongJun Kim <195850@jnu.ac.kr> Date: Thu, 14 Aug 2025 12:35:41 +0900 Subject: [PATCH] Fix #3729: Add overloaded methods for RewriteLocationResponseHeader filter - Add 1, 2, 3 parameter overloads in FilterFunctions and AfterFilterFunctions - Support flexible YAML configuration: RewriteLocationResponseHeader=AS_IN_REQUEST - Add comprehensive tests for all parameter combinations - Update documentation with multiple configuration examples - Maintain full backward compatibility with existing 4-parameter method Resolves spring-cloud/spring-cloud-gateway#3729 Signed-off-by: JongJun Kim <195850@jnu.ac.kr> --- .../rewritelocationresponseheader.adoc | 20 ++++- .../mvc/filter/AfterFilterFunctions.java | 29 +++++++ .../server/mvc/filter/FilterFunctions.java | 22 ++++++ .../server/mvc/ServerMvcIntegrationTests.java | 75 +++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc index 6af573a193..dd25f2d34a 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/rewritelocationresponseheader.adoc @@ -18,7 +18,14 @@ spring: predicates: - Path=/** filters: - - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , + # Minimal configuration - only stripVersion + - RewriteLocationResponseHeader=AS_IN_REQUEST + # Specify header name + - RewriteLocationResponseHeader=AS_IN_REQUEST, Location + # Specify custom host value + - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, api.example.com + # Full configuration with protocols regex + - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, api.example.com, https?|ftps? ---- .GatewaySampleApplication.java @@ -62,3 +69,14 @@ The `protocolsRegex` parameter must be a valid regex `String`, against which the If it is not matched, the filter does nothing. The default is `http|https|ftp|ftps`. +== Multiple Configuration Options + +The `RewriteLocationResponseHeader` filter supports multiple configuration formats for different use cases: + +* **Minimal configuration**: `RewriteLocationResponseHeader=AS_IN_REQUEST` - Uses default values for all other parameters +* **With header name**: `RewriteLocationResponseHeader=AS_IN_REQUEST, Location` - Specifies custom header name (default is `Location`) +* **With host value**: `RewriteLocationResponseHeader=AS_IN_REQUEST, Location, api.example.com` - Uses custom host instead of request Host header +* **Full configuration**: `RewriteLocationResponseHeader=AS_IN_REQUEST, Location, api.example.com, https?|ftps?` - Specifies all parameters including protocols regex + +All parameters after `stripVersionMode` are optional and use sensible defaults when not provided. + diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java index d0abf60256..7a3daf02c6 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java @@ -123,6 +123,35 @@ public static BiFunction rewriteL }); } + public static BiFunction rewriteLocationResponseHeader( + String stripVersion) { + return RewriteLocationResponseHeaderFilterFunctions + .rewriteLocationResponseHeader(config -> config.setStripVersion(stripVersion)); + } + + public static BiFunction rewriteLocationResponseHeader( + String stripVersion, String locationHeaderName) { + return RewriteLocationResponseHeaderFilterFunctions.rewriteLocationResponseHeader( + config -> config.setStripVersion(stripVersion).setLocationHeaderName(locationHeaderName)); + } + + public static BiFunction rewriteLocationResponseHeader( + String stripVersion, String locationHeaderName, String hostValue) { + return RewriteLocationResponseHeaderFilterFunctions + .rewriteLocationResponseHeader(config -> config.setStripVersion(stripVersion) + .setLocationHeaderName(locationHeaderName) + .setHostValue(hostValue)); + } + + public static BiFunction rewriteLocationResponseHeader( + String stripVersion, String locationHeaderName, String hostValue, String protocolsRegex) { + return RewriteLocationResponseHeaderFilterFunctions + .rewriteLocationResponseHeader(config -> config.setStripVersion(stripVersion) + .setLocationHeaderName(locationHeaderName) + .setHostValue(hostValue) + .setProtocolsRegex(protocolsRegex)); + } + public static BiFunction rewriteLocationResponseHeader( Consumer configConsumer) { return RewriteLocationResponseHeaderFilterFunctions.rewriteLocationResponseHeader(configConsumer); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java index 55b6602cc0..a3c93452f2 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterFunctions.java @@ -160,6 +160,28 @@ static HandlerFilterFunction requestSize(DataSiz return ofRequestProcessor(BeforeFilterFunctions.requestSize(maxSize)); } + @Shortcut + static HandlerFilterFunction rewriteLocationResponseHeader(String stripVersion) { + return ofResponseProcessor(RewriteLocationResponseHeaderFilterFunctions + .rewriteLocationResponseHeader(config -> config.setStripVersion(stripVersion))); + } + + @Shortcut + static HandlerFilterFunction rewriteLocationResponseHeader(String stripVersion, + String locationHeaderName) { + return ofResponseProcessor(RewriteLocationResponseHeaderFilterFunctions.rewriteLocationResponseHeader( + config -> config.setStripVersion(stripVersion).setLocationHeaderName(locationHeaderName))); + } + + @Shortcut + static HandlerFilterFunction rewriteLocationResponseHeader(String stripVersion, + String locationHeaderName, String hostValue) { + return ofResponseProcessor(RewriteLocationResponseHeaderFilterFunctions + .rewriteLocationResponseHeader(config -> config.setStripVersion(stripVersion) + .setLocationHeaderName(locationHeaderName) + .setHostValue(hostValue))); + } + @Shortcut static HandlerFilterFunction rewriteLocationResponseHeader(String stripVersion, String locationHeaderName, String hostValue, String protocolsRegex) { diff --git a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 43013908f6..e1baceb364 100644 --- a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -899,6 +899,42 @@ public void rewriteLocationResponseHeaderWorks() { .valueEquals("Location", "https://test1.rewritelocationresponseheader.org/some/object/id"); } + @Test + public void rewriteLocationResponseHeaderWithMinimalArgsWorks() { + restClient.get() + .uri("/anything/rewritelocationresponseheader-minimal") + .header("Host", "test2.rewritelocationresponseheader.org") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Location", "https://test2.rewritelocationresponseheader.org/some/object/id"); + } + + @Test + public void rewriteLocationResponseHeaderWithTwoArgsWorks() { + restClient.get() + .uri("/anything/rewritelocationresponseheader-twoargs") + .header("Host", "test3.rewritelocationresponseheader.org") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Location", "https://test3.rewritelocationresponseheader.org/some/object/id"); + } + + @Test + public void rewriteLocationResponseHeaderWithThreeArgsWorks() { + restClient.get() + .uri("/anything/rewritelocationresponseheader-threeargs") + .header("Host", "test4.rewritelocationresponseheader.org") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals("Location", "https://custom.host.example.com/some/object/id"); + } + @Test public void readBodyWorks() { Event messageEvent = new Event("message", "bar"); @@ -1578,6 +1614,45 @@ public RouterFunction gatewayRouterFunctionsRewriteLocationRespo // @formatter:on } + @Bean + public RouterFunction gatewayRouterFunctionsRewriteLocationResponseHeaderMinimal() { + // @formatter:off + return route("testrewritelocationresponseheaderminimal") + .GET("/anything/rewritelocationresponseheader-minimal", host("**.rewritelocationresponseheader.org"), http()) + .before(new HttpbinUriResolver()) + // reverse order for "post" filters + .after(rewriteLocationResponseHeader("AS_IN_REQUEST")) + .after(addResponseHeader("Location", "https://backend.org:443/v1/some/object/id")) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction gatewayRouterFunctionsRewriteLocationResponseHeaderTwoArgs() { + // @formatter:off + return route("testrewritelocationresponseheadertwoargs") + .GET("/anything/rewritelocationresponseheader-twoargs", host("**.rewritelocationresponseheader.org"), http()) + .before(new HttpbinUriResolver()) + // reverse order for "post" filters + .after(rewriteLocationResponseHeader("AS_IN_REQUEST", "Location")) + .after(addResponseHeader("Location", "https://backend.org:443/v1/some/object/id")) + .build(); + // @formatter:on + } + + @Bean + public RouterFunction gatewayRouterFunctionsRewriteLocationResponseHeaderThreeArgs() { + // @formatter:off + return route("testrewritelocationresponseheaderthreeargs") + .GET("/anything/rewritelocationresponseheader-threeargs", host("**.rewritelocationresponseheader.org"), http()) + .before(new HttpbinUriResolver()) + // reverse order for "post" filters + .after(rewriteLocationResponseHeader("AS_IN_REQUEST", "Location", "custom.host.example.com")) + .after(addResponseHeader("Location", "https://backend.org:443/v1/some/object/id")) + .build(); + // @formatter:on + } + @Bean public RouterFunction gatewayRouterFunctionsReadBodyPredicate() { // @formatter:off