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

acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new 4094279  CAMEL-13545: fix netty4-http memory issues
     new 9bf74a5  Merge pull request #2929 from zregvart/CAMEL-13545
4094279 is described below

commit 409427932593ac2003a487435fe9cd9682326b2b
Author: Zoran Regvart <zregv...@apache.org>
AuthorDate: Sun May 19 19:38:54 2019 +0200

    CAMEL-13545: fix netty4-http memory issues
    
    `DefaultNettyHttpBinding::toNettyRequest` could allocate a new Netty
    `ByteBuf` (e.g. via `NettyConverter::toByteBuffer`) which in turn might
    or might not be passed to the `FullHttpRequest` depending on the
    resulting buffer size: if it's 0 it will not be set as content of the
    request. In that case this causes a memory leak.
    
    The buffer having the size of 0 is quite common for `GET` or `OPTIONS`
    HTTP method requests, so releasing the buffer if the incoming request is
    received when acting as a proxy will cause the any downstream Netty
    requests (say in a scenario
    `from("netty-http:proxy:...").toD("netty-http:...")`) to block.
    
    So additional optimization was added to store the proxy HTTP request in
    the `Exchange` property and to check if the current request in the
    `NettyHttpMessage` has the same reference; and in that case the proxy
    HTTP request will be reused, only changes to the HTTP method, protocol
    or request URL will be applied.
---
 .../netty4/http/DefaultNettyHttpBinding.java       | 81 +++++++++++++++-------
 .../component/netty4/http/NettyHttpConstants.java  |  1 +
 .../http/handlers/HttpServerChannelHandler.java    |  2 +
 3 files changed, 59 insertions(+), 25 deletions(-)

diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
index a626c0e..e51f65f 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/DefaultNettyHttpBinding.java
@@ -509,37 +509,68 @@ public class DefaultNettyHttpBinding implements 
NettyHttpBinding, Cloneable {
             httpMethod = HttpMethod.valueOf(headerMethod);
         }
 
-        FullHttpRequest request = new DefaultFullHttpRequest(protocol, 
httpMethod, uriForRequest);
-        if (body != null) {
-            // support bodies as native Netty
-            ByteBuf buffer;
-            if (body instanceof ByteBuf) {
-                buffer = (ByteBuf) body;
-            } else {
-                // try to convert to buffer first
-                buffer = message.getBody(ByteBuf.class);
-                if (buffer == null) {
-                    // fallback to byte array as last resort
-                    byte[] data = message.getMandatoryBody(byte[].class);
-
-                    if (data.length > 0) {
-                        buffer = NettyConverter.toByteBuffer(data);
+        final Exchange exchange = message.getExchange();
+        final Object proxyRequest;
+        if (exchange != null) {
+            proxyRequest = 
exchange.getProperty(NettyHttpConstants.PROXY_REQUEST);
+        } else {
+            proxyRequest = null;
+        }
+
+        FullHttpRequest request = null;
+        if (message instanceof NettyHttpMessage) {
+            // if the request is already given we should set the values
+            // from message headers and pass on the same request
+            final FullHttpRequest givenRequest = ((NettyHttpMessage) 
message).getHttpRequest();
+            // we need to make sure that the givenRequest is the original
+            // request received by the proxy
+            if (givenRequest != null && proxyRequest == givenRequest) {
+                request = givenRequest
+                        .setProtocolVersion(protocol)
+                        .setMethod(httpMethod)
+                        .setUri(uriForRequest);
+            }
+        }
+
+        if (request == null) {
+            request = new DefaultFullHttpRequest(protocol, httpMethod, 
uriForRequest);
+
+            if (body != null) {
+                // support bodies as native Netty
+                ByteBuf buffer;
+                if (body instanceof ByteBuf) {
+                    buffer = (ByteBuf) body;
+                } else {
+                    // try to convert to buffer first
+                    buffer = message.getBody(ByteBuf.class);
+                    if (buffer == null) {
+                        // fallback to byte array as last resort
+                        byte[] data = message.getMandatoryBody(byte[].class);
+    
+                        if (data.length > 0) {
+                            buffer = NettyConverter.toByteBuffer(data);
+                        }
+                    }
+                }
+    
+                if (buffer != null) {
+                    if (buffer.readableBytes() > 0) {
+                        request = request.replace(buffer);
+                        int len = buffer.readableBytes();
+                        // set content-length
+                        
request.headers().set(HttpHeaderNames.CONTENT_LENGTH.toString(), len);
+                        LOG.trace("Content-Length: {}", len);
+                    } else {
+                        buffer.release();
                     }
                 }
             }
 
-            if (buffer != null && buffer.readableBytes() > 0) {
-                request = request.replace(buffer);
-                int len = buffer.readableBytes();
-                // set content-length
-                
request.headers().set(HttpHeaderNames.CONTENT_LENGTH.toString(), len);
-                LOG.trace("Content-Length: {}", len);
-            }
+            // update HTTP method accordingly as we know if we have a body or 
not
+            HttpMethod method = NettyHttpHelper.createMethod(message, body != 
null);
+            request.setMethod(method);
         }
 
-        // update HTTP method accordingly as we know if we have a body or not
-        HttpMethod method = NettyHttpHelper.createMethod(message, body != 
null);
-        request.setMethod(method);
 
         TypeConverter tc = 
message.getExchange().getContext().getTypeConverter();
 
diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpConstants.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpConstants.java
index c243b40..b3024ed 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpConstants.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpConstants.java
@@ -28,6 +28,7 @@ public final class NettyHttpConstants {
     @Deprecated
     public static final String HTTP_RESPONSE_TEXT = 
Exchange.HTTP_RESPONSE_TEXT;
     public static final String HTTP_AUTHENTICATION = "CamelHttpAuthentication";
+    public static final String PROXY_REQUEST = "NettyHttpProxyRequest";
 
     private NettyHttpConstants() {
     }
diff --git 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpServerChannelHandler.java
 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpServerChannelHandler.java
index 211d0c2..8c0b38c 100644
--- 
a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpServerChannelHandler.java
+++ 
b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/handlers/HttpServerChannelHandler.java
@@ -41,6 +41,7 @@ import org.apache.camel.component.netty4.NettyHelper;
 import org.apache.camel.component.netty4.handlers.ServerChannelHandler;
 import org.apache.camel.component.netty4.http.HttpPrincipal;
 import org.apache.camel.component.netty4.http.NettyHttpConfiguration;
+import org.apache.camel.component.netty4.http.NettyHttpConstants;
 import org.apache.camel.component.netty4.http.NettyHttpConsumer;
 import org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration;
 import org.apache.camel.component.netty4.http.SecurityAuthenticator;
@@ -282,6 +283,7 @@ public class HttpServerChannelHandler extends 
ServerChannelHandler {
 
         final Message in = exchange.getIn();
         if (configuration.isHttpProxy()) {
+            exchange.setProperty(NettyHttpConstants.PROXY_REQUEST, request);
             in.removeHeader("Proxy-Connection");
         }
     }

Reply via email to