From 0d7caac88374324f28360c2b002d82737e0a846a Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sun, 29 Nov 2015 13:36:32 +0900 Subject: [PATCH] Fix IllegalReferenceCountException caused by HttpClientCodec.upgradeFrom() Motivation: On a successful protocol upgrade in HTTP, HttpClientUpgradeHandler calls HttpClientCodec.upgradeFrom(), which removed both the HTTP encoder and decoder from the pipeline immediately. However, because the decoder is in the middle of the decode loop, removing it from the pipeline immediately will cause the cumulation buffer to be released prematurely. This often leads to an IllegalReferenceCountException or missing first response after the upgrade response. Modifications: - Remove the decoder *after* the decode loop is done Result: Fixes #4504 --- .../netty/handler/codec/http/HttpClientCodec.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java index e781a49d94..2ba67dc903 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java @@ -19,7 +19,9 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerAppender; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.PrematureChannelClosureException; +import io.netty.util.internal.OneTimeTask; import java.util.ArrayDeque; import java.util.List; @@ -93,8 +95,15 @@ public final class HttpClientCodec extends ChannelHandlerAppender implements */ @Override public void upgradeFrom(ChannelHandlerContext ctx) { - ctx.pipeline().remove(Decoder.class); - ctx.pipeline().remove(Encoder.class); + final ChannelPipeline p = ctx.pipeline(); + // Remove the decoder later so that the decoder can enter the 'UPGRADED' state and forward the remaining data. + ctx.executor().execute(new OneTimeTask() { + @Override + public void run() { + p.remove(decoder()); + } + }); + p.remove(encoder()); } /**