Skip to content

Commit 05943f5

Browse files
authored
Fix buffer leak regression in HttpClientCodec (#12762)
Motivation: #12709 changed HttpObjectEncoder to override the write method of MessageToMessageEncoder, with slightly changed semantics: The `msg` argument to `encode` is not released anymore. To accommodate this change, #12709 also update `HttpObjectEncoder.encode` to release the `msg`. However, `HttpClientCodec.Encoder` overrides `encode` and simply forwards the message if a HTTP upgrade has been completed. This code path was not updated to release the input message. This leads to a memory leak. Modifications: Changed the `encode` implementation to not retain the message that is forwarded. Added a test case to verify that the refCnt to the data passed through is unchanged. Result: The buffer retains its correct refCnt and will be released properly.
1 parent fcef0e4 commit 05943f5

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ protected void encode(
191191
ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
192192

193193
if (upgraded) {
194-
out.add(ReferenceCountUtil.retain(msg));
194+
// HttpObjectEncoder overrides .write and does not release msg, so we don't need to retain it here
195+
out.add(msg);
195196
return;
196197
}
197198

codec-http/src/test/java/io/netty/handler/codec/http/HttpClientCodecTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import io.netty.util.CharsetUtil;
3737
import io.netty.util.NetUtil;
3838
import org.hamcrest.CoreMatchers;
39+
import org.hamcrest.Matchers;
3940
import org.junit.jupiter.api.Test;
4041

4142
import java.net.InetSocketAddress;
@@ -423,4 +424,19 @@ public void testMultipleResponses() {
423424
assertTrue(ch.finishAndReleaseAll());
424425
}
425426

427+
@Test
428+
public void testWriteThroughAfterUpgrade() {
429+
HttpClientCodec codec = new HttpClientCodec();
430+
EmbeddedChannel ch = new EmbeddedChannel(codec);
431+
codec.prepareUpgradeFrom(null);
432+
433+
ByteBuf buffer = ch.alloc().buffer();
434+
assertThat(buffer.refCnt(), is(1));
435+
assertTrue(ch.writeOutbound(buffer));
436+
// buffer should pass through unchanged
437+
assertThat(ch.<ByteBuf>readOutbound(), sameInstance(buffer));
438+
assertThat(buffer.refCnt(), is(1));
439+
440+
buffer.release();
441+
}
426442
}

0 commit comments

Comments
 (0)