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"); } }