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"));
+ }
+}