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

albumenj pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new b9a2f194f0 Fix memory leak in HttpPostRequestDecoder (#14741)
b9a2f194f0 is described below

commit b9a2f194f044c07532715e212ab2e72155be9bad
Author: Sean Yang <[email protected]>
AuthorDate: Wed Oct 2 10:16:24 2024 +0800

    Fix memory leak in HttpPostRequestDecoder (#14741)
---
 .../java/org/apache/dubbo/remoting/http12/HttpUtils.java | 12 +++++++++++-
 .../tri/h12/AbstractServerTransportListener.java         | 16 +++++++++++++++-
 .../tri/rest/support/basic/RestProtocolTest.groovy       | 14 ++++++++++++++
 3 files changed, 40 insertions(+), 2 deletions(-)

diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
index 22e16fb20f..488242d921 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
@@ -29,8 +29,11 @@ import java.util.List;
 import java.util.Locale;
 
 import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
 import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.ByteBufOutputStream;
 import io.netty.buffer.Unpooled;
+import io.netty.buffer.UnpooledByteBufAllocator;
 import io.netty.handler.codec.http.DefaultFullHttpRequest;
 import io.netty.handler.codec.http.DefaultHttpHeaders;
 import io.netty.handler.codec.http.HttpHeaders;
@@ -51,6 +54,7 @@ import 
io.netty.handler.codec.http.multipart.InterfaceHttpData;
 
 public final class HttpUtils {
 
+    public static final ByteBufAllocator HEAP_ALLOC = new 
UnpooledByteBufAllocator(false, false);
     public static final HttpDataFactory DATA_FACTORY = new 
DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
     public static final String CHARSET_PREFIX = "charset=";
 
@@ -164,7 +168,13 @@ public final class HttpUtils {
             if (canMark) {
                 inputStream.mark(Integer.MAX_VALUE);
             }
-            data = Unpooled.wrappedBuffer(StreamUtils.readBytes(inputStream));
+            if (inputStream.available() == 0) {
+                data = Unpooled.EMPTY_BUFFER;
+            } else {
+                data = HEAP_ALLOC.buffer();
+                ByteBufOutputStream os = new ByteBufOutputStream(data);
+                StreamUtils.copy(inputStream, os);
+            }
         } catch (IOException e) {
             throw new DecodeException("Error while reading post data: " + 
e.getMessage(), e);
         } finally {
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
index 871b9aa46b..a6944a3510 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.common.logger.FluentLogger;
 import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
 import org.apache.dubbo.common.threadpool.serial.SerializingExecutor;
 import org.apache.dubbo.common.utils.MethodUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.remoting.http12.HttpChannel;
 import org.apache.dubbo.remoting.http12.HttpInputMessage;
 import org.apache.dubbo.remoting.http12.HttpStatus;
@@ -278,14 +279,27 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
         if (consumerAppName != null) {
             inv.put(TripleHeaderEnum.CONSUMER_APP_NAME_KEY, consumerAppName);
         }
+
         // customizer RpcInvocation
-        headerFilters.forEach(f -> f.invoke(invoker, inv));
+        HeaderFilter[] headerFilters =
+                UrlUtils.computeServiceAttribute(invoker.getUrl(), 
HEADER_FILTERS_CACHE, this::loadHeaderFilters);
+        for (HeaderFilter headerFilter : headerFilters) {
+            headerFilter.invoke(invoker, inv);
+        }
 
         initializeAltSvc(url);
 
         return onBuildRpcInvocationCompletion(inv);
     }
 
+    private HeaderFilter[] loadHeaderFilters(URL url) {
+        List<HeaderFilter> headerFilters = frameworkModel
+                .getExtensionLoader(HeaderFilter.class)
+                .getActivateExtension(url, CommonConstants.HEADER_FILTER_KEY);
+        LOGGER.info("Header filters for [{}] loaded: {}", url, headerFilters);
+        return headerFilters.toArray(new HeaderFilter[0]);
+    }
+
     protected RpcInvocation onBuildRpcInvocationCompletion(RpcInvocation 
invocation) {
         String timeoutString = 
httpMetadata.header(TripleHeaderEnum.SERVICE_TIMEOUT.getKey());
         try {
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
 
b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
index 4a2da172b9..430a646d01 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
@@ -174,6 +174,20 @@ class RestProtocolTest extends BaseServiceTest {
             '/argTest' | 'Sam is 8 years old'
     }
 
+    def "urlEncodeForm body test"() {
+        given:
+            def request = new TestRequest(
+                path: path,
+                contentType: MediaType.APPLICATION_FROM_URLENCODED,
+                body: body
+            )
+        expect:
+            runner.post(request) == output
+        where:
+            path       | body             | output
+            '/argTest' | 'name=Sam&age=8' | 'Sam is 8 years old'
+    }
+
     def "override mapping test"() {
         expect:
             runner.get(path) == output

Reply via email to