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 ef6f32b429 fix(plugin): prevent corruption of URL-encoded RPC query 
and form parameters (#7757)
ef6f32b429 is described below

commit ef6f32b42999a7cccaed85844e9372573a16e145
Author: lymerin <[email protected]>
AuthorDate: Mon Oct 19 09:33:23 2026 +0800

    fix(plugin): prevent corruption of URL-encoded RPC query and form 
parameters (#7757)
---
 .../shenyu/plugin/api/utils/BodyParamUtils.java    |  6 +++--
 .../plugin/transform/RpcParamTransformPlugin.java  |  5 ++--
 .../transform/RpcParamTransformPluginTest.java     | 30 +++++++++++++++++++++-
 3 files changed, 35 insertions(+), 6 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/BodyParamUtils.java
 
b/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/BodyParamUtils.java
index 7951a527d8..83b278da57 100644
--- 
a/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/BodyParamUtils.java
+++ 
b/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/BodyParamUtils.java
@@ -17,6 +17,8 @@
 
 package org.apache.shenyu.plugin.api.utils;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -63,10 +65,10 @@ public final class BodyParamUtils {
         LinkedMultiValueMap<String, String> params = new 
LinkedMultiValueMap<>();
         Matcher matcher = QUERY_PARAM_PATTERN.matcher(param);
         while (matcher.find()) {
-            String name = matcher.group(1);
+            String name = URLDecoder.decode(matcher.group(1), 
StandardCharsets.UTF_8);
             String eq = matcher.group(2);
             String value = matcher.group(3);
-            params.add(name, Objects.nonNull(value) ? value : 
(StringUtils.isNotBlank(eq) ? "" : null));
+            params.add(name, Objects.nonNull(value) ? URLDecoder.decode(value, 
StandardCharsets.UTF_8) : (StringUtils.isNotBlank(eq) ? "" : null));
         }
         return params;
     }
diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/main/java/org/apache/shenyu/plugin/transform/RpcParamTransformPlugin.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/main/java/org/apache/shenyu/plugin/transform/RpcParamTransformPlugin.java
index 81ad86b99b..6611e7d0ed 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/main/java/org/apache/shenyu/plugin/transform/RpcParamTransformPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/main/java/org/apache/shenyu/plugin/transform/RpcParamTransformPlugin.java
@@ -34,7 +34,6 @@ import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 
-import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import java.util.Optional;
@@ -89,7 +88,7 @@ public class RpcParamTransformPlugin implements ShenyuPlugin {
                     if (map.isPresent()) {
                         String param = resolveBodyFromRequest(map.get());
                         LinkedMultiValueMap<String, String> 
linkedMultiValueMap;
-                        linkedMultiValueMap = 
BodyParamUtils.buildBodyParams(URLDecoder.decode(param, 
StandardCharsets.UTF_8));
+                        linkedMultiValueMap = 
BodyParamUtils.buildBodyParams(param);
                         
exchange.getAttributes().put(Constants.PARAM_TRANSFORM, 
HttpParamConverter.toMap(() -> linkedMultiValueMap));
                     }
                     return chain.execute(exchange);
@@ -97,7 +96,7 @@ public class RpcParamTransformPlugin implements ShenyuPlugin {
     }
 
     private Mono<Void> query(final ServerWebExchange exchange, final 
ServerHttpRequest serverHttpRequest, final ShenyuPluginChain chain) {
-        exchange.getAttributes().put(Constants.PARAM_TRANSFORM, 
HttpParamConverter.ofString(() -> serverHttpRequest.getURI().getQuery()));
+        exchange.getAttributes().put(Constants.PARAM_TRANSFORM, 
HttpParamConverter.ofString(() -> serverHttpRequest.getURI().getRawQuery()));
         return chain.execute(exchange);
     }
 
diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/test/java/org/apache/shenyu/plugin/transform/RpcParamTransformPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/test/java/org/apache/shenyu/plugin/transform/RpcParamTransformPluginTest.java
index 4402461a36..cc9440ca2a 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/test/java/org/apache/shenyu/plugin/transform/RpcParamTransformPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-transform/src/test/java/org/apache/shenyu/plugin/transform/RpcParamTransformPluginTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shenyu.plugin.transform;
 
+import com.google.gson.JsonParser;
 import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.enums.PluginEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
@@ -28,6 +29,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
 import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
 import org.springframework.mock.web.server.MockServerWebExchange;
@@ -35,6 +37,8 @@ import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
+import java.net.URI;
+
 import static org.mockito.Mockito.mock;
 
 /**
@@ -42,6 +46,9 @@ import static org.mockito.Mockito.mock;
  */
 @ExtendWith(MockitoExtension.class)
 public final class RpcParamTransformPluginTest {
+
+    private static final String ENCODED_PARAMS = 
"value=a%26b%3Dc&plus=a%2Bb&space=a+b&encoded=%2526"
+            + "&empty=&repeat=first&repeat=second";
     
     private ShenyuPluginChain chain;
     
@@ -95,13 +102,34 @@ public final class RpcParamTransformPluginTest {
     @Test
     public void testFormatBody() {
         final ServerWebExchange exchange = MockServerWebExchange.from(
-                
MockServerHttpRequest.post("localhost").contentType(MediaType.APPLICATION_FORM_URLENCODED).body("test=test"));
+                
MockServerHttpRequest.post("localhost").contentType(MediaType.APPLICATION_FORM_URLENCODED).body(ENCODED_PARAMS));
+        Mockito.when(chain.execute(exchange)).thenReturn(Mono.empty());
+        ShenyuContext context = new ShenyuContext();
+        context.setRpcType(RpcTypeEnum.DUBBO.getName());
+        exchange.getAttributes().put(Constants.CONTEXT, context);
+        Mono<Void> result = rpcParamTransformPlugin.execute(exchange, chain);
+        StepVerifier.create(result).expectSubscription().verifyComplete();
+        
Assertions.assertEquals(JsonParser.parseString("{\"value\":\"a&b=c\",\"plus\":\"a+b\",\"space\":\"a
 b\","
+                        + 
"\"encoded\":\"%26\",\"empty\":\"\",\"repeat\":\"first\"}"),
+                
JsonParser.parseString(exchange.getAttribute(Constants.PARAM_TRANSFORM)));
+    }
+
+    /**
+     * Test query parameters.
+     */
+    @Test
+    public void testQueryParams() {
+        ServerWebExchange exchange = MockServerWebExchange.from(
+                MockServerHttpRequest.method(HttpMethod.GET, 
URI.create("http://localhost/?"; + ENCODED_PARAMS)).build());
         Mockito.when(chain.execute(exchange)).thenReturn(Mono.empty());
         ShenyuContext context = new ShenyuContext();
         context.setRpcType(RpcTypeEnum.DUBBO.getName());
         exchange.getAttributes().put(Constants.CONTEXT, context);
         Mono<Void> result = rpcParamTransformPlugin.execute(exchange, chain);
         StepVerifier.create(result).expectSubscription().verifyComplete();
+        
Assertions.assertEquals(JsonParser.parseString("{\"value\":\"a&b=c\",\"plus\":\"a+b\",\"space\":\"a
 b\","
+                        + 
"\"encoded\":\"%26\",\"empty\":\"\",\"repeat\":\"second\"}"),
+                
JsonParser.parseString(exchange.getAttribute(Constants.PARAM_TRANSFORM)));
     }
     
     /**

Reply via email to