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 478dcfe4cf refactor: use try-with-resources for GZIP decompression in 
AiResponseTransformerPlugin and add unit test for resource cleanup (#6915)
478dcfe4cf is described below

commit 478dcfe4cfa99670cf2f7556f3c346378f421691
Author: Limbo <[email protected]>
AuthorDate: Fri Aug 14 14:48:50 2026 +0800

    refactor: use try-with-resources for GZIP decompression in 
AiResponseTransformerPlugin and add unit test for resource cleanup (#6915)
    
    Co-authored-by: aias00 <[email protected]>
---
 .../response/AiResponseTransformerPlugin.java      | 11 ++++----
 .../response/AiResponseTransformerPluginTest.java  | 30 ++++++++++++++++++++++
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/main/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPlugin.java
 
b/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/main/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPlugin.java
index 033ee402fd..6dfea7c12d 100644
--- 
a/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/main/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/main/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPlugin.java
@@ -48,6 +48,8 @@ import reactor.core.publisher.Mono;
 import org.reactivestreams.Publisher;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
@@ -57,6 +59,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.zip.GZIPInputStream;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -309,17 +312,13 @@ public class AiResponseTransformerPlugin extends 
AbstractShenyuPlugin {
                 String contentEncoding = 
exchange.getResponse().getHeaders().getFirst("Content-Encoding");
                 if ("gzip".equalsIgnoreCase(contentEncoding)) {
                     LOG.debug("Detected gzip encoding, attempting to 
decompress");
-                    try {
-                        java.io.ByteArrayInputStream bis = new 
java.io.ByteArrayInputStream(bytes);
-                        java.util.zip.GZIPInputStream gis = new 
java.util.zip.GZIPInputStream(bis);
-                        java.io.ByteArrayOutputStream bos = new 
java.io.ByteArrayOutputStream();
+                    try (GZIPInputStream gis = new GZIPInputStream(new 
ByteArrayInputStream(bytes));
+                         ByteArrayOutputStream bos = new 
ByteArrayOutputStream()) {
                         byte[] buffer = new byte[1024];
                         int len;
                         while ((len = gis.read(buffer)) > 0) {
                             bos.write(buffer, 0, len);
                         }
-                        gis.close();
-                        bos.close();
                         originalResponseBody = 
bos.toString(StandardCharsets.UTF_8.name());
                         LOG.debug("Decompressed response body: {}", 
originalResponseBody);
                     } catch (Exception e) {
diff --git 
a/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/test/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/test/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPluginTest.java
index fcaa60beb1..aa9d4d50fb 100644
--- 
a/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/test/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-response-transformer/src/test/java/org/apache/shenyu/plugin/ai/transformer/response/AiResponseTransformerPluginTest.java
@@ -26,13 +26,17 @@ import org.apache.shenyu.common.utils.Singleton;
 import org.apache.shenyu.plugin.ai.common.config.AiCommonConfig;
 import org.apache.shenyu.plugin.ai.common.spring.ai.AiModelFactory;
 import 
org.apache.shenyu.plugin.ai.common.spring.ai.registry.AiModelFactoryRegistry;
+import 
org.apache.shenyu.plugin.ai.transformer.response.template.AiResponseTransformerTemplate;
 import org.apache.shenyu.plugin.api.ShenyuPluginChain;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
+import org.mockito.MockedConstruction;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.core.io.buffer.DataBuffer;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
@@ -43,13 +47,18 @@ import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.Collections;
+import java.util.zip.GZIPInputStream;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.lenient;
 
@@ -139,6 +148,27 @@ class AiResponseTransformerPluginTest {
                 .verifyComplete();
     }
 
+    @Test
+    void testGzipInputStreamClosedWhenDecompressionFails() throws IOException {
+        MockServerHttpResponse response = (MockServerHttpResponse) 
exchange.getResponse();
+        response.getHeaders().set(HttpHeaders.CONTENT_ENCODING, "gzip");
+        AiResponseTransformerTemplate template = 
mock(AiResponseTransformerTemplate.class);
+        ChatClient chatClient = mock(ChatClient.class);
+        when(template.assembleMessage(exchange)).thenReturn(Mono.empty());
+        AiResponseTransformerPlugin.AiResponseTransformerDecorator decorator =
+                new 
AiResponseTransformerPlugin.AiResponseTransformerDecorator(exchange, template, 
chatClient);
+        DataBuffer responseBody = 
response.bufferFactory().wrap("gzip".getBytes(StandardCharsets.UTF_8));
+
+        try (MockedConstruction<GZIPInputStream> gzipStreams = 
mockConstruction(GZIPInputStream.class,
+                (gzipInputStream, context) -> 
when(gzipInputStream.read(any(byte[].class))).thenThrow(new IOException()))) {
+            StepVerifier.create(decorator.writeWith(Mono.just(responseBody)))
+                    .verifyComplete();
+
+            assertEquals(1, gzipStreams.constructed().size());
+            verify(gzipStreams.constructed().get(0)).close();
+        }
+    }
+
     @Test
     void testExtractBodyFromAiResponse() {
         String aiResponse = "HTTP/1.1 200 OK\nContent-Type: 
application/json\n\n{\"status\":\"success\"}";

Reply via email to