This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new c09f98953b fix(request): preserve values in identity key replacements 
(#7905)
c09f98953b is described below

commit c09f98953b969a66e0bd685b4299d8779f8e6b92
Author: cloudbase-ai <[email protected]>
AuthorDate: Wed Oct 21 14:04:41 2026 +0800

    fix(request): preserve values in identity key replacements (#7905)
    
    Signed-off-by: cloudbase-ai <[email protected]>
    Co-authored-by: cloudbase-ai 
<[email protected]>
---
 .../shenyu/plugin/request/RequestPlugin.java       |  6 +-
 .../shenyu/plugin/request/RequestPluginTest.java   | 77 ++++++++++++++++++++++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-request/src/main/java/org/apache/shenyu/plugin/request/RequestPlugin.java
 
b/shenyu-plugin/shenyu-plugin-request/src/main/java/org/apache/shenyu/plugin/request/RequestPlugin.java
index 43edfb3348..0a2c091239 100644
--- 
a/shenyu-plugin/shenyu-plugin-request/src/main/java/org/apache/shenyu/plugin/request/RequestPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-request/src/main/java/org/apache/shenyu/plugin/request/RequestPlugin.java
@@ -217,7 +217,7 @@ public class RequestPlugin extends AbstractShenyuPlugin {
 
     private void replaceParameterKey(final Map.Entry<String, String> 
shenyuParam, final MultiValueMap<String, String> queryParams) {
         List<String> values = queryParams.get(shenyuParam.getKey());
-        if (Objects.nonNull(values)) {
+        if (Objects.nonNull(values) && !Objects.equals(shenyuParam.getKey(), 
shenyuParam.getValue())) {
             queryParams.addAll(shenyuParam.getValue(), values);
             queryParams.remove(shenyuParam.getKey());
         }
@@ -250,9 +250,9 @@ public class RequestPlugin extends AbstractShenyuPlugin {
 
     private void replaceHeaderKey(final Map.Entry<String, String> 
shenyuHeader, final HttpHeaders headers) {
         List<String> values = headers.get(shenyuHeader.getKey());
-        if (Objects.nonNull(values)) {
-            headers.addAll(shenyuHeader.getValue(), values);
+        if (Objects.nonNull(values) && !Objects.equals(shenyuHeader.getKey(), 
shenyuHeader.getValue())) {
             headers.remove(shenyuHeader.getKey());
+            headers.addAll(shenyuHeader.getValue(), values);
         }
     }
 
diff --git 
a/shenyu-plugin/shenyu-plugin-request/src/test/java/org/apache/shenyu/plugin/request/RequestPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-request/src/test/java/org/apache/shenyu/plugin/request/RequestPluginTest.java
index fc5092573e..07990f028f 100644
--- 
a/shenyu-plugin/shenyu-plugin-request/src/test/java/org/apache/shenyu/plugin/request/RequestPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-request/src/test/java/org/apache/shenyu/plugin/request/RequestPluginTest.java
@@ -39,6 +39,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.EmptySource;
 import org.junit.jupiter.params.provider.ValueSource;
+import org.junit.jupiter.params.provider.CsvSource;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -331,6 +332,82 @@ public class RequestPluginTest {
         assertEquals("new=1", requestUri.getRawQuery());
     }
 
+    @ParameterizedTest
+    @CsvSource({"X-Id,X-Id", "X-Id,x-id", "x-id,X-ID"})
+    public void testHeaderRenamePreservesValuesForSameName(final String 
source, final String target) {
+        ruleData.setHandle("{\"header\":{\"replaceHeaderKeys\":{\"" + source + 
"\":\"" + target + "\"}}}");
+        new RequestPluginHandler().handlerRule(ruleData);
+        ServerWebExchange requestExchange = 
MockServerWebExchange.from(MockServerHttpRequest.get("/test")
+                .header("X-Id", "first", "second").build());
+        when(chain.execute(any())).thenReturn(Mono.empty());
+
+        StepVerifier.create(requestPlugin.doExecute(requestExchange, chain, 
new SelectorData(), ruleData)).verifyComplete();
+
+        ArgumentCaptor<ServerWebExchange> captor = 
ArgumentCaptor.forClass(ServerWebExchange.class);
+        Mockito.verify(chain).execute(captor.capture());
+        assertEquals(Arrays.asList("first", "second"), 
captor.getValue().getRequest().getHeaders().get(target));
+        assertEquals(Arrays.asList("first", "second"), 
requestExchange.getRequest().getHeaders().get("X-Id"));
+    }
+
+    @ParameterizedTest
+    @CsvSource({"token=first&token=second", "token&token=&token=second"})
+    public void testParameterIdentityRenamePreservesValuesAndOrder(final 
String query) {
+        
ruleData.setHandle("{\"parameter\":{\"replaceParameterKeys\":{\"token\":\"token\"}}}");
+        new RequestPluginHandler().handlerRule(ruleData);
+        ServerWebExchange requestExchange = 
MockServerWebExchange.from(MockServerHttpRequest
+                .method(HttpMethod.GET, 
URI.create("http://localhost/files/a%2Fb?"; + query + "&keep=1")).build());
+        when(chain.execute(any())).thenReturn(Mono.empty());
+
+        StepVerifier.create(requestPlugin.doExecute(requestExchange, chain, 
new SelectorData(), ruleData)).verifyComplete();
+
+        ArgumentCaptor<ServerWebExchange> captor = 
ArgumentCaptor.forClass(ServerWebExchange.class);
+        Mockito.verify(chain).execute(captor.capture());
+        URI result = captor.getValue().getRequest().getURI();
+        assertEquals(query + "&keep=1", result.getRawQuery());
+        assertEquals("/files/a%2Fb", result.getRawPath());
+    }
+
+    @ParameterizedTest
+    @CsvSource({"header,Old,New", "parameter,old,new", 
"parameter,Token,token"})
+    public void testRenameStillMergesIntoExistingTarget(final String type, 
final String source, final String target) {
+        String property = "header".equals(type) ? "replaceHeaderKeys" : 
"replaceParameterKeys";
+        ruleData.setHandle("{\"" + type + "\":{\"" + property + "\":{\"" + 
source + "\":\"" + target + "\"}}}");
+        new RequestPluginHandler().handlerRule(ruleData);
+        ServerWebExchange requestExchange = 
MockServerWebExchange.from(MockServerHttpRequest
+                .method(HttpMethod.GET, URI.create("http://localhost/test?"; + 
source + "=first&" + source + "=second&" + target + "=existing"))
+                .header(source, "first", "second").header(target, 
"existing").build());
+        when(chain.execute(any())).thenReturn(Mono.empty());
+
+        StepVerifier.create(requestPlugin.doExecute(requestExchange, chain, 
new SelectorData(), ruleData)).verifyComplete();
+
+        ArgumentCaptor<ServerWebExchange> captor = 
ArgumentCaptor.forClass(ServerWebExchange.class);
+        Mockito.verify(chain).execute(captor.capture());
+        ServerHttpRequest result = captor.getValue().getRequest();
+        MultiValueMap<String, String> values = "header".equals(type) ? 
result.getHeaders() : result.getQueryParams();
+        assertEquals(Arrays.asList("existing", "first", "second"), 
values.get(target));
+        assertFalse(values.containsKey(source));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {"header", "parameter"})
+    public void testMissingRenameSourcePreservesTarget(final String type) {
+        String property = "header".equals(type) ? "replaceHeaderKeys" : 
"replaceParameterKeys";
+        ruleData.setHandle("{\"" + type + "\":{\"" + property + 
"\":{\"missing\":\"target\"}}}");
+        new RequestPluginHandler().handlerRule(ruleData);
+        ServerWebExchange requestExchange = 
MockServerWebExchange.from(MockServerHttpRequest
+                .method(HttpMethod.GET, 
URI.create("http://localhost/test?target=kept";))
+                .header("target", "kept").build());
+        when(chain.execute(any())).thenReturn(Mono.empty());
+
+        StepVerifier.create(requestPlugin.doExecute(requestExchange, chain, 
new SelectorData(), ruleData)).verifyComplete();
+
+        ArgumentCaptor<ServerWebExchange> captor = 
ArgumentCaptor.forClass(ServerWebExchange.class);
+        Mockito.verify(chain).execute(captor.capture());
+        ServerHttpRequest result = captor.getValue().getRequest();
+        assertEquals("kept", result.getHeaders().getFirst("target"));
+        assertEquals("kept", result.getQueryParams().getFirst("target"));
+    }
+
     @Test
     public void testGetOrder() {
         assertEquals(this.requestPlugin.getOrder(), 
PluginEnum.REQUEST.getCode());

Reply via email to