diff --git a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java index 0bfd23759f..4076e07dee 100644 --- a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java +++ b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java @@ -18,7 +18,9 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; +import io.netty.util.internal.ObjectUtil; +import java.nio.ByteOrder; import java.util.List; @@ -51,6 +53,7 @@ import java.util.List; @Sharable public class LengthFieldPrepender extends MessageToMessageEncoder { + private final ByteOrder byteOrder; private final int lengthFieldLength; private final boolean lengthIncludesLengthFieldLength; private final int lengthAdjustment; @@ -116,6 +119,28 @@ public class LengthFieldPrepender extends MessageToMessageEncoder { * if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8 */ public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) { + this(ByteOrder.BIG_ENDIAN, lengthFieldLength, lengthAdjustment, lengthIncludesLengthFieldLength); + } + + /** + * Creates a new instance. + * + * @param byteOrder the {@link ByteOrder} of the length field + * @param lengthFieldLength the length of the prepended length field. + * Only 1, 2, 3, 4, and 8 are allowed. + * @param lengthAdjustment the compensation value to add to the value + * of the length field + * @param lengthIncludesLengthFieldLength + * if {@code true}, the length of the prepended + * length field is added to the value of the + * prepended length field. + * + * @throws IllegalArgumentException + * if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8 + */ + public LengthFieldPrepender( + ByteOrder byteOrder, int lengthFieldLength, + int lengthAdjustment, boolean lengthIncludesLengthFieldLength) { if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 3 && lengthFieldLength != 4 && lengthFieldLength != 8) { @@ -123,7 +148,9 @@ public class LengthFieldPrepender extends MessageToMessageEncoder { "lengthFieldLength must be either 1, 2, 3, 4, or 8: " + lengthFieldLength); } + ObjectUtil.checkNotNull(byteOrder, "byteOrder"); + this.byteOrder = byteOrder; this.lengthFieldLength = lengthFieldLength; this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; this.lengthAdjustment = lengthAdjustment; @@ -147,27 +174,27 @@ public class LengthFieldPrepender extends MessageToMessageEncoder { throw new IllegalArgumentException( "length does not fit into a byte: " + length); } - out.add(ctx.alloc().buffer(1).writeByte((byte) length)); + out.add(ctx.alloc().buffer(1).order(byteOrder).writeByte((byte) length)); break; case 2: if (length >= 65536) { throw new IllegalArgumentException( "length does not fit into a short integer: " + length); } - out.add(ctx.alloc().buffer(2).writeShort((short) length)); + out.add(ctx.alloc().buffer(2).order(byteOrder).writeShort((short) length)); break; case 3: if (length >= 16777216) { throw new IllegalArgumentException( "length does not fit into a medium integer: " + length); } - out.add(ctx.alloc().buffer(3).writeMedium(length)); + out.add(ctx.alloc().buffer(3).order(byteOrder).writeMedium(length)); break; case 4: - out.add(ctx.alloc().buffer(4).writeInt(length)); + out.add(ctx.alloc().buffer(4).order(byteOrder).writeInt(length)); break; case 8: - out.add(ctx.alloc().buffer(8).writeLong(length)); + out.add(ctx.alloc().buffer(8).order(byteOrder).writeLong(length)); break; default: throw new Error("should not reach here"); diff --git a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java index 57b12a81e6..1e18273d1a 100644 --- a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java +++ b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java @@ -24,6 +24,8 @@ import org.junit.Before; import org.junit.Test; import static io.netty.buffer.Unpooled.*; +import java.nio.ByteOrder; + import static org.junit.Assert.*; public class LengthFieldPrependerTest { @@ -87,4 +89,25 @@ public class LengthFieldPrependerTest { // Expected } } + + @Test + public void testPrependLengthInLittleEndian() throws Exception { + final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(ByteOrder.LITTLE_ENDIAN, 4, 0, false)); + ch.writeOutbound(msg); + ByteBuf buf = ch.readOutbound(); + assertEquals(4, buf.readableBytes()); + byte[] writtenBytes = new byte[buf.readableBytes()]; + buf.getBytes(0, writtenBytes); + assertEquals(1, writtenBytes[0]); + assertEquals(0, writtenBytes[1]); + assertEquals(0, writtenBytes[2]); + assertEquals(0, writtenBytes[3]); + buf.release(); + + buf = ch.readOutbound(); + assertSame(buf, msg); + buf.release(); + assertFalse("The channel must have been completely read", ch.finish()); + } + }