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

wy471x 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 4e44c60bcd [ISSUE #7452] skip caching when cache rule handle is null 
(#7541)
4e44c60bcd is described below

commit 4e44c60bcd1ce8b38b41d6c22adc41926d5a74e8
Author: Emrys <[email protected]>
AuthorDate: Sun Oct 11 18:50:33 2026 +0800

    [ISSUE #7452] skip caching when cache rule handle is null (#7541)
    
    CachePluginDataHandler skips rules whose handle is null, so CachePlugin
    could not find a CacheRuleHandle for such a rule and CacheHttpResponse
    threw a NullPointerException on getTimeoutSeconds() while writing an
    otherwise successful downstream response.
    
    When no rule handle is cached, CachePlugin now passes the request to the
    rest of the chain without reading or writing the cache, the same way the
    Hystrix, Resilience4J, Sentinel and RateLimiter plugins handle a missing
    handle (#6877).
    
    Add regression tests for a rule without a handle and for a rule with a
    handle.
    
    Fixes #7452
---
 .../apache/shenyu/plugin/cache/CachePlugin.java    |  6 +-
 .../shenyu/plugin/cache/CachePluginTest.java       | 66 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/CachePlugin.java
 
b/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/CachePlugin.java
index d89fe42789..93f114ac38 100644
--- 
a/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/CachePlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/CachePlugin.java
@@ -52,6 +52,10 @@ public class CachePlugin extends AbstractShenyuPlugin {
     @Override
     public Mono<Void> doExecute(final ServerWebExchange exchange, final 
ShenyuPluginChain chain,
                                 final SelectorData selector, final RuleData 
rule) {
+        final CacheRuleHandle cacheRuleHandle = buildRuleHandle(rule);
+        if (Objects.isNull(cacheRuleHandle)) {
+            return chain.execute(exchange);
+        }
         CacheUpstream cacheUpstream = 
GsonUtils.getInstance().fromJson(selector.getHandle(), CacheUpstream.class);
         ICache cache = getCache(selector.getId(), cacheUpstream);
         if (Objects.nonNull(cache)) {
@@ -67,11 +71,9 @@ public class CachePlugin extends AbstractShenyuPlugin {
                             return 
exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes))
                                     .doOnNext(data -> 
exchange.getResponse().getHeaders().setContentLength(data.readableByteCount())));
                         }
-                        CacheRuleHandle cacheRuleHandle = 
buildRuleHandle(rule);
                         return chain.execute(exchange.mutate().response(new 
CacheHttpResponse(exchange, cacheRuleHandle, selector.getId())).build());
                     });
         }
-        CacheRuleHandle cacheRuleHandle = buildRuleHandle(rule);
         return chain.execute(exchange.mutate().response(new 
CacheHttpResponse(exchange, cacheRuleHandle, selector.getId())).build());
     }
 
diff --git 
a/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/test/java/org/apache/shenyu/plugin/cache/CachePluginTest.java
 
b/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/test/java/org/apache/shenyu/plugin/cache/CachePluginTest.java
index e2198a0414..0454ad33b1 100644
--- 
a/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/test/java/org/apache/shenyu/plugin/cache/CachePluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/test/java/org/apache/shenyu/plugin/cache/CachePluginTest.java
@@ -146,4 +146,70 @@ public class CachePluginTest {
         StepVerifier.create(result3).expectSubscription().verifyComplete();
     }
 
+    @Test
+    public void testDoExecuteSkipsCacheWhenRuleHandleIsNull() {
+        final ConfigurableApplicationContext context = 
mock(ConfigurableApplicationContext.class);
+        when(context.getBean(ShenyuResult.class)).thenReturn(new 
DefaultShenyuResult());
+        SpringBeanUtils.getInstance().setApplicationContext(context);
+        final MockServerWebExchange exchange = 
MockServerWebExchange.from(MockServerHttpRequest.get("/cache-null-handle-path").build());
+        final MemoryCache memoryCache = new MemoryCache();
+        Singleton.INST.single(ICache.class, memoryCache);
+        final RuleData ruleData = new RuleData();
+        ruleData.setSelectorId("cache-null-handle-selector");
+        ruleData.setId("cache-null-handle-rule");
+        final String key = CacheKeyUtils.INST.getKey(ruleData);
+        try {
+            CachePluginDataHandler.CACHED_HANDLE.get().removeHandle(key);
+            final SelectorData selectorData = new SelectorData();
+            selectorData.setId("cache-null-handle-selector");
+            final ShenyuPluginChain chain = mock(ShenyuPluginChain.class);
+            when(chain.execute(any())).thenAnswer(invocation -> {
+                final ServerWebExchange downstream = invocation.getArgument(0);
+                
downstream.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
+                return downstream.getResponse().writeWith(Mono.just(
+                        
downstream.getResponse().bufferFactory().wrap("body".getBytes(StandardCharsets.UTF_8))));
+            });
+            final Mono<Void> result = new CachePlugin().doExecute(exchange, 
chain, selectorData, ruleData);
+            StepVerifier.create(result).verifyComplete();
+            Assertions.assertEquals("body", 
exchange.getResponse().getBodyAsString().block());
+            
Assertions.assertNull(memoryCache.getData(CacheUtils.dataKey(exchange)).block());
+        } finally {
+            CachePluginDataHandler.CACHED_HANDLE.get().removeHandle(key);
+            memoryCache.close();
+        }
+    }
+
+    @Test
+    public void testDoExecuteCachesResponseWhenRuleHandleIsPresent() {
+        final ConfigurableApplicationContext context = 
mock(ConfigurableApplicationContext.class);
+        when(context.getBean(ShenyuResult.class)).thenReturn(new 
DefaultShenyuResult());
+        SpringBeanUtils.getInstance().setApplicationContext(context);
+        final MockServerWebExchange exchange = 
MockServerWebExchange.from(MockServerHttpRequest.get("/cache-with-handle-path").build());
+        final MemoryCache memoryCache = new MemoryCache();
+        Singleton.INST.single(ICache.class, memoryCache);
+        final RuleData ruleData = new RuleData();
+        ruleData.setSelectorId("cache-with-handle-selector");
+        ruleData.setId("cache-with-handle-rule");
+        final String key = CacheKeyUtils.INST.getKey(ruleData);
+        try {
+            CachePluginDataHandler.CACHED_HANDLE.get().cachedHandle(key, new 
CacheRuleHandle());
+            final SelectorData selectorData = new SelectorData();
+            selectorData.setId("cache-with-handle-selector");
+            final ShenyuPluginChain chain = mock(ShenyuPluginChain.class);
+            when(chain.execute(any())).thenAnswer(invocation -> {
+                final ServerWebExchange downstream = invocation.getArgument(0);
+                
downstream.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
+                return downstream.getResponse().writeWith(Mono.just(
+                        
downstream.getResponse().bufferFactory().wrap("body".getBytes(StandardCharsets.UTF_8))));
+            });
+            final Mono<Void> result = new CachePlugin().doExecute(exchange, 
chain, selectorData, ruleData);
+            StepVerifier.create(result).verifyComplete();
+            Assertions.assertEquals("body", 
exchange.getResponse().getBodyAsString().block());
+            
Assertions.assertArrayEquals("body".getBytes(StandardCharsets.UTF_8), 
memoryCache.getData(CacheUtils.dataKey(exchange)).block());
+        } finally {
+            CachePluginDataHandler.CACHED_HANDLE.get().removeHandle(key);
+            memoryCache.close();
+        }
+    }
+
 }

Reply via email to