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 21fa6f31a8 [type:fix] guard the tars plugin against an empty proxy
list (#6652) (#7211)
21fa6f31a8 is described below
commit 21fa6f31a8d2a3692c7217b24d473f6986602c04
Author: HY-love-sleep <[email protected]>
AuthorDate: Sat Sep 26 11:32:35 2026 +0800
[type:fix] guard the tars plugin against an empty proxy list (#6652) (#7211)
---
.../org/apache/shenyu/plugin/tars/TarsPlugin.java | 8 ++++
.../apache/shenyu/plugin/tars/TarsPluginTest.java | 43 +++++++++++++++++++---
2 files changed, 45 insertions(+), 6 deletions(-)
diff --git
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/TarsPlugin.java
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/TarsPlugin.java
index 01593e07f7..1f142bdc9f 100644
---
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/TarsPlugin.java
+++
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/main/java/org/apache/shenyu/plugin/tars/TarsPlugin.java
@@ -17,6 +17,7 @@
package org.apache.shenyu.plugin.tars;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.common.constant.Constants;
import org.apache.shenyu.common.dto.MetaData;
@@ -79,6 +80,13 @@ public class TarsPlugin extends AbstractShenyuPlugin {
return WebFluxResultUtils.result(exchange, error);
}
TarsInvokePrxList tarsInvokePrxList =
ApplicationConfigCache.getInstance().get(metaData.getPath());
+ // the cache loader returns an empty proxy list when the path was
never initialized
+ if (CollectionUtils.isEmpty(tarsInvokePrxList.getTarsInvokePrxList()))
{
+ LOG.error("tars upstream configuration error: {}",
metaData.getPath());
+
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
+ Object error = ShenyuResultWrap.error(exchange,
ShenyuResultEnum.CANNOT_FIND_HEALTHY_UPSTREAM_URL);
+ return WebFluxResultUtils.result(exchange, error);
+ }
int index =
ThreadLocalRandom.current().nextInt(tarsInvokePrxList.getTarsInvokePrxList().size());
Object prx =
tarsInvokePrxList.getTarsInvokePrxList().get(index).getInvokePrx();
Method method = tarsInvokePrxList.getMethod();
diff --git
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/TarsPluginTest.java
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/TarsPluginTest.java
index 33bcff2972..5af88f9b4a 100644
---
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/TarsPluginTest.java
+++
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-tars/src/test/java/org/apache/shenyu/plugin/tars/TarsPluginTest.java
@@ -30,6 +30,7 @@ import
org.apache.shenyu.plugin.api.result.DefaultShenyuResult;
import org.apache.shenyu.plugin.api.result.ShenyuResult;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
import org.apache.shenyu.plugin.tars.cache.ApplicationConfigCache;
+import org.apache.shenyu.plugin.tars.proxy.TarsInvokePrx;
import org.apache.shenyu.plugin.tars.proxy.TarsInvokePrxList;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -38,6 +39,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
+import org.springframework.http.HttpStatus;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
@@ -53,7 +55,6 @@ import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -120,9 +121,14 @@ public class TarsPluginTest {
exchange.getAttributes().put(Constants.META_DATA, metaData);
exchange.getAttributes().put(Constants.PARAM_TRANSFORM,
"{\"param1\":1,\"param2\":2}");
when(chain.execute(exchange)).thenReturn(Mono.empty());
+ // the plugin needs an upstream in the cache, otherwise it answers
with a "no upstream" error
+
ApplicationConfigCache.getInstance().get(metaData.getPath()).getTarsInvokePrxList()
+ .add(new TarsInvokePrx(mock(Object.class), "127.0.0.1:8080"));
RuleData data = mock(RuleData.class);
SelectorData selectorData = mock(SelectorData.class);
- assertThrows(IllegalArgumentException.class, () ->
StepVerifier.create(tarsPluginUnderTest.doExecute(exchange, chain,
selectorData, data)).expectSubscription().verifyComplete());
+ StepVerifier.create(tarsPluginUnderTest.doExecute(exchange, chain,
selectorData, data))
+ .expectSubscription().verifyComplete();
+ assertEquals(HttpStatus.INTERNAL_SERVER_ERROR,
exchange.getResponse().getStatusCode());
}
@Test
@@ -132,16 +138,25 @@ public class TarsPluginTest {
exchange.getAttributes().put(Constants.META_DATA, metaData);
exchange.getAttributes().put(Constants.PARAM_TRANSFORM,
"{\"param1\":\"1\",\"param2\":\"1\"}");
when(chain.execute(exchange)).thenReturn(Mono.empty());
- RuleData data = mock(RuleData.class);
- SelectorData selectorData = mock(SelectorData.class);
TarsInvokePrxList tarsInvokePrxList =
ApplicationConfigCache.getInstance().get(metaData.getPath());
Method method = mock(Method.class);
ExecutorService executorService = Executors.newFixedThreadPool(1,
ShenyuThreadFactory.create("long-polling", true));
CompletableFuture<String> stringCompletableFuture =
CompletableFuture.supplyAsync(() -> "", executorService);
- when(method.invoke(any(), any())).thenReturn(stringCompletableFuture);
+ // Method#invoke is varargs: the arguments array must be matched as a
whole,
+ // otherwise the stub never applies and invoke() returns null
+ when(method.invoke(any(),
any(Object[].class))).thenReturn(stringCompletableFuture);
tarsInvokePrxList.setMethod(method);
- assertThrows(IllegalArgumentException.class, () ->
StepVerifier.create(tarsPluginUnderTest.doExecute(exchange, chain,
selectorData, data)).expectSubscription().verifyComplete());
+ tarsInvokePrxList.setParamTypes(new Class<?>[]{String.class,
String.class});
+ tarsInvokePrxList.setParamNames(new String[]{"param1", "param2"});
+ // the plugin needs an upstream in the cache, otherwise it answers
with a "no upstream" error
+
ApplicationConfigCache.getInstance().get(metaData.getPath()).getTarsInvokePrxList()
+ .add(new TarsInvokePrx(mock(Object.class), "127.0.0.1:8080"));
+ RuleData data = mock(RuleData.class);
+ SelectorData selectorData = mock(SelectorData.class);
+ StepVerifier.create(tarsPluginUnderTest.doExecute(exchange, chain,
selectorData, data))
+ .expectSubscription().verifyComplete();
+ assertEquals("", exchange.getAttributes().get(Constants.RPC_RESULT));
}
@Test
@@ -164,4 +179,20 @@ public class TarsPluginTest {
boolean result = tarsPluginUnderTest.skip(exchange);
assertFalse(result);
}
+
+ @Test
+ public void testTarsPluginWithEmptyProxyList() {
+ ShenyuContext context = mock(ShenyuContext.class);
+ exchange.getAttributes().put(Constants.CONTEXT, context);
+ MetaData uninitialized = new MetaData("id", "127.0.0.1:8080",
"contextPath",
+ "uninitializedPath", RpcTypeEnum.TARS.getName(),
"serviceName", "method1",
+ metaData.getParameterTypes(), metaData.getRpcExt(), false,
Constants.SYS_DEFAULT_NAMESPACE_ID);
+ exchange.getAttributes().put(Constants.META_DATA, uninitialized);
+ exchange.getAttributes().put(Constants.PARAM_TRANSFORM,
"{\"param1\":\"1\",\"param2\":\"1\"}");
+ RuleData data = mock(RuleData.class);
+ SelectorData selectorData = mock(SelectorData.class);
+ StepVerifier.create(tarsPluginUnderTest.doExecute(exchange, chain,
selectorData, data))
+ .expectSubscription().verifyComplete();
+ assertEquals(HttpStatus.INTERNAL_SERVER_ERROR,
exchange.getResponse().getStatusCode());
+ }
}