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 ba9d884deb fix(sign): avoid per-request String.format in 
ComposableSignService#skipSignExchange (#7214)
ba9d884deb is described below

commit ba9d884debe8f5d1dafa2142fcf89f28cddcfe66
Author: Sean-Walker0 <[email protected]>
AuthorDate: Thu Sep 24 14:24:16 2026 +0800

    fix(sign): avoid per-request String.format in 
ComposableSignService#skipSignExchange (#7214)
    
    skipSignExchange is evaluated on every signed request, and each call
    parsed the "%s-%s" format string three times via String.format. The
    expected module pattern 'pluginName-rpcType' is fixed for the three
    http-forwarding plugins, so precompute their names in a constant and
    match with a single suffix comparison instead.
    
    Adds unit tests covering supported plugins, mismatched rpc types,
    unsupported plugins and malformed modules.
    
    Fixes #6804
    
    Co-authored-by: Sean-Walker0 
<[email protected]>
    Co-authored-by: aias00 <[email protected]>
---
 .../plugin/sign/service/ComposableSignService.java | 20 +++++-
 .../sign/service/ComposableSignServiceTest.java    | 81 ++++++++++++++++++++++
 2 files changed, 98 insertions(+), 3 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
 
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
index f4142c7604..96abc1cbaa 100644
--- 
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
+++ 
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
@@ -43,6 +43,8 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.server.ServerWebExchange;
 
 import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -77,6 +79,13 @@ public class ComposableSignService implements SignService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ComposableSignService.class);
 
+    /**
+     * Plugins whose module attribute is built as {@code pluginName + "-" + 
rpcType};
+     * for these the app name is taken from the request context path instead 
of the module.
+     */
+    private static final List<String> SKIP_SIGN_PLUGIN_NAMES = 
Collections.unmodifiableList(Arrays.asList(
+            PluginEnum.SPRING_CLOUD.getName(), PluginEnum.DIVIDE.getName(), 
PluginEnum.WEB_SOCKET.getName()));
+
     @Value("${shenyu.sign.delay:5}")
     private int delay;
 
@@ -231,8 +240,13 @@ public class ComposableSignService implements SignService {
     }
 
     private boolean skipSignExchange(final ShenyuContext context) {
-        return StringUtils.equals(String.format("%s-%s", 
PluginEnum.SPRING_CLOUD.getName(), context.getRpcType()), context.getModule())
-                || StringUtils.equals(String.format("%s-%s", 
PluginEnum.DIVIDE.getName(), context.getRpcType()), context.getModule())
-                || StringUtils.equals(String.format("%s-%s", 
PluginEnum.WEB_SOCKET.getName(), context.getRpcType()), context.getModule());
+        final String module = context.getModule();
+        final String rpcType = context.getRpcType();
+        if (StringUtils.isAnyBlank(module, rpcType)) {
+            return false;
+        }
+        final String rpcTypeSuffix = "-" + rpcType;
+        return module.endsWith(rpcTypeSuffix)
+                && SKIP_SIGN_PLUGIN_NAMES.contains(module.substring(0, 
module.length() - rpcTypeSuffix.length()));
     }
 }
diff --git 
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/ComposableSignServiceTest.java
 
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/ComposableSignServiceTest.java
new file mode 100644
index 0000000000..8303df163a
--- /dev/null
+++ 
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/ComposableSignServiceTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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.apache.shenyu.plugin.sign.service;
+
+import org.apache.shenyu.plugin.api.context.ShenyuContext;
+import org.apache.shenyu.plugin.sign.extractor.DefaultExtractor;
+import org.apache.shenyu.plugin.sign.provider.DefaultSignProvider;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test for ComposableSignService#skipSignExchange.
+ */
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+public final class ComposableSignServiceTest {
+
+    private ComposableSignService signService;
+
+    @BeforeEach
+    public void setUp() {
+        this.signService = new ComposableSignService(new DefaultExtractor(), 
new DefaultSignProvider());
+    }
+
+    private boolean skipSignExchange(final String module, final String 
rpcType) {
+        ShenyuContext context = new ShenyuContext();
+        context.setModule(module);
+        context.setRpcType(rpcType);
+        return 
Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(this.signService, 
"skipSignExchange", context));
+    }
+
+    @Test
+    public void testSkipSignExchangeForSupportedPlugins() {
+        assertTrue(skipSignExchange("divide-http", "http"));
+        assertTrue(skipSignExchange("springCloud-http", "http"));
+        assertTrue(skipSignExchange("websocket-ws", "ws"));
+    }
+
+    @Test
+    public void testSkipSignExchangeWithMismatchedRpcType() {
+        assertFalse(skipSignExchange("divide-http", "grpc"));
+        assertFalse(skipSignExchange("springCloud-grpc", "http"));
+    }
+
+    @Test
+    public void testSkipSignExchangeForUnsupportedPlugin() {
+        assertFalse(skipSignExchange("dubbo-http", "http"));
+        assertFalse(skipSignExchange("grpc-http", "http"));
+    }
+
+    @Test
+    public void testSkipSignExchangeWithMalformedModule() {
+        assertFalse(skipSignExchange("http", "http"));
+        assertFalse(skipSignExchange("divide-", ""));
+        assertFalse(skipSignExchange("", "http"));
+        assertFalse(skipSignExchange("divide-springCloud-http", "http"));
+    }
+}

Reply via email to