diff --git a/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java b/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java index ecf752aaaa..36bd3c609a 100644 --- a/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java @@ -211,7 +211,10 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler { * * @param ctx the context of this handler * @param channel the current channel - * @param buffer the cumulative buffer of received packets so far + * @param buffer the cumulative buffer of received packets so far. + * Note that the buffer might be empty, which means you + * should not make an assumption that the buffer contains + * at least one byte in your decoder implementation. * * @return the decoded frame if a full frame was received and decoded. * {@code null} if there's not enough data in the buffer to decode a frame. @@ -225,7 +228,10 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler { * * @param ctx the context of this handler * @param channel the current channel - * @param buffer the cumulative buffer of received packets so far + * @param buffer the cumulative buffer of received packets so far. + * Note that the buffer might be empty, which means you + * should not make an assumption that the buffer contains + * at least one byte in your decoder implementation. * * @return the decoded frame if a full frame was received and decoded. * {@code null} if there's not enough data in the buffer to decode a frame. @@ -292,13 +298,14 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler { if (cumulation.readable()) { // Make sure all frames are read before notifying a closed channel. callDecode(ctx, ctx.getChannel(), cumulation, null); - if (cumulation.readable()) { - // and send the remainders too if necessary. - Object partialFrame = decodeLast(ctx, ctx.getChannel(), cumulation); - if (partialFrame != null) { - fireMessageReceived(ctx, null, partialFrame); - } - } + } + + // Call decodeLast() finally. Please note that decodeLast() is + // called even if there's nothing more to read from the buffer to + // notify a user that the connection was closed explicitly. + Object partialFrame = decodeLast(ctx, ctx.getChannel(), cumulation); + if (partialFrame != null) { + fireMessageReceived(ctx, null, partialFrame); } } finally { ctx.sendUpstream(e); diff --git a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoder.java b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoder.java index 2bc6696ab6..5f8d2f4f86 100644 --- a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoder.java @@ -326,7 +326,10 @@ public abstract class ReplayingDecoder> * * @param ctx the context of this handler * @param channel the current channel - * @param buffer the cumulative buffer of received packets so far\ + * @param buffer the cumulative buffer of received packets so far. + * Note that the buffer might be empty, which means you + * should not make an assumption that the buffer contains + * at least one byte in your decoder implementation. * @param state the current decoder state ({@code null} if unused) * * @return the decoded frame @@ -340,7 +343,10 @@ public abstract class ReplayingDecoder> * * @param ctx the context of this handler * @param channel the current channel - * @param buffer the cumulative buffer of received packets so far + * @param buffer the cumulative buffer of received packets so far. + * Note that the buffer might be empty, which means you + * should not make an assumption that the buffer contains + * at least one byte in your decoder implementation. * @param state the current decoder state ({@code null} if unused) * * @return the decoded frame @@ -460,13 +466,14 @@ public abstract class ReplayingDecoder> if (cumulation.readable()) { // Make sure all data was read before notifying a closed channel. callDecode(ctx, e.getChannel(), cumulation, null); - if (cumulation.readable()) { - // and send the remainders too if necessary. - Object partiallyDecoded = decodeLast(ctx, e.getChannel(), replayable, state); - if (partiallyDecoded != null) { - unfoldAndfireMessageReceived(ctx, partiallyDecoded, null); - } - } + } + + // Call decodeLast() finally. Please note that decodeLast() is + // called even if there's nothing more to read from the buffer to + // notify a user that the connection was closed explicitly. + Object partiallyDecoded = decodeLast(ctx, e.getChannel(), replayable, state); + if (partiallyDecoded != null) { + unfoldAndfireMessageReceived(ctx, partiallyDecoded, null); } } catch (ReplayError replay) { // Ignore