Skip to content

Improve Netty4ClientHttpRequestFactory configurability and memory usage (SPR-12623) #719

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import java.util.concurrent.ExecutionException;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
Expand All @@ -51,21 +51,23 @@
* @since 4.1.2
*/
class Netty4ClientHttpRequest extends AbstractAsyncClientHttpRequest implements ClientHttpRequest {

public static final int INITIAL_REQUEST_BUFFER_SIZE = 512;

private final Bootstrap bootstrap;

private final URI uri;

private final HttpMethod method;

private final ByteBufOutputStream body;


public Netty4ClientHttpRequest(Bootstrap bootstrap, URI uri, HttpMethod method, int maxRequestSize) {
public Netty4ClientHttpRequest(Bootstrap bootstrap, ByteBufAllocator byteBufAllocator, URI uri, HttpMethod method, int maxRequestSize) {
this.bootstrap = bootstrap;
this.uri = uri;
this.method = method;
this.body = new ByteBufOutputStream(Unpooled.buffer(maxRequestSize));
this.body = new ByteBufOutputStream(byteBufAllocator.buffer(INITIAL_REQUEST_BUFFER_SIZE, maxRequestSize));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.net.URI;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
Expand Down Expand Up @@ -54,14 +57,48 @@ public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory,
*/
public static final int DEFAULT_MAX_REQUEST_SIZE = 1024 * 1024 * 10;

/**
* The default maximum header size
* @see #setMaxHeaderSize(int)
* @see HttpClientCodec#HttpClientCodec()
*/
public static final int DEFAULT_MAX_HEADER_SIZE = 8192;

/**
* The default initial line length.
* @see #setInitialLineLength(int)
* @see HttpClientCodec#HttpClientCodec()
*/
public static final int DEFAULT_INITIAL_LINE_LENGTH = 4096;

/**
* The default max chunk size.
* @see #setMaxChunkSize(int)
* @see HttpClientCodec#HttpClientCodec()
*/
public static final int DEFAULT_MAX_CHUNK_SIZE = 8192;

/**
* The default byte-buf allocator.
* @see UnpooledByteBufAllocator#DEFAULT
*/
public static final ByteBufAllocator DEFAULT_BYTE_BUF_ALLOCATOR = UnpooledByteBufAllocator.DEFAULT;

private final EventLoopGroup eventLoopGroup;

private final boolean defaultEventLoopGroup;

private int maxRequestSize = DEFAULT_MAX_REQUEST_SIZE;

private int maxHeaderSize = DEFAULT_MAX_HEADER_SIZE;

private int initialLineLength = DEFAULT_INITIAL_LINE_LENGTH;

private int maxChunkSize = DEFAULT_MAX_CHUNK_SIZE;

private SslContext sslContext;

private ByteBufAllocator byteBufAllocator = DEFAULT_BYTE_BUF_ALLOCATOR;

private volatile Bootstrap bootstrap;

Expand Down Expand Up @@ -91,13 +128,53 @@ public Netty4ClientHttpRequestFactory(EventLoopGroup eventLoopGroup) {


/**
* Set the default maximum request size.
* Set the maximum request size.
* <p>By default this is set to {@link #DEFAULT_MAX_REQUEST_SIZE}.
* @see HttpObjectAggregator#HttpObjectAggregator(int)
*/
public void setMaxRequestSize(int maxRequestSize) {
this.maxRequestSize = maxRequestSize;
}

/**
* Set the maximum header size.
* <p>By default this is set to {@link #DEFAULT_MAX_HEADER_SIZE}.
* @see HttpClientCodec#HttpClientCodec(int, int, int)
*/
public void setMaxHeaderSize(int maxHeaderSize) {
this.maxHeaderSize = maxHeaderSize;
}

/**
* Set the initial line length.
* <p>By default this is set to {@link #DEFAULT_INITIAL_LINE_LENGTH}.
* @see HttpClientCodec#HttpClientCodec(int, int, int)
*/
public void setInitialLineLength(int initialLineLength) {
this.initialLineLength = initialLineLength;
}

/**
* Set the maximum chunk size.
* <p>By default this is set to {@link #DEFAULT_MAX_CHUNK_SIZE}.
* @see HttpClientCodec#HttpClientCodec(int, int, int)
*/
public void setMaxChunkSize(int maxChunkSize) {
this.maxChunkSize = maxChunkSize;
}

/**
* Set the ByteBuf allocator used by the requests.
* @see ByteBufAllocator
*/
public void setByteBufAllocator(ByteBufAllocator byteBufAllocator) {
if(byteBufAllocator==null) {
this.byteBufAllocator = DEFAULT_BYTE_BUF_ALLOCATOR;
}
else {
this.byteBufAllocator = byteBufAllocator;
}
}

/**
* Set the SSL context. When configured it is used to create and insert an
Expand All @@ -111,6 +188,7 @@ public void setSslContext(SslContext sslContext) {
private Bootstrap getBootstrap() {
if (this.bootstrap == null) {
Bootstrap bootstrap = new Bootstrap();
bootstrap.option(ChannelOption.ALLOCATOR, byteBufAllocator);
bootstrap.group(this.eventLoopGroup).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
Expand All @@ -119,7 +197,7 @@ protected void initChannel(SocketChannel channel) throws Exception {
if (sslContext != null) {
pipeline.addLast(sslContext.newHandler(channel.alloc()));
}
pipeline.addLast(new HttpClientCodec());
pipeline.addLast(new HttpClientCodec(initialLineLength, maxHeaderSize, maxChunkSize));
pipeline.addLast(new HttpObjectAggregator(maxRequestSize));
}
});
Expand All @@ -145,7 +223,7 @@ public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod)
}

private Netty4ClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
return new Netty4ClientHttpRequest(getBootstrap(), uri, httpMethod, this.maxRequestSize);
return new Netty4ClientHttpRequest(getBootstrap(), byteBufAllocator, uri, httpMethod, this.maxRequestSize);
}


Expand Down