Allow a user specify the byte order of the length field for LengthFieldBasedFrameDecoder

- Fixes #1164
This commit is contained in:
Trustin Lee 2013-03-18 13:58:48 +09:00
parent 660e6f4afe
commit 97f2fa7341

View File

@ -20,6 +20,8 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.serialization.ObjectDecoder;
import java.nio.ByteOrder;
/**
* A decoder that splits the received {@link ByteBuf}s dynamically by the
* value of the length field in the message. It is particularly useful when you
@ -181,6 +183,7 @@ import io.netty.handler.codec.serialization.ObjectDecoder;
*/
public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
private final ByteOrder byteOrder;
private final int maxFrameLength;
private final int lengthFieldOffset;
private final int lengthFieldLength;
@ -260,9 +263,45 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
* has been read.
*/
public LengthFieldBasedFrameDecoder(
int maxFrameLength,
int lengthFieldOffset, int lengthFieldLength,
int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
this(
ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength,
lengthAdjustment, initialBytesToStrip, failFast);
}
/**
* Creates a new instance.
*
* @param byteOrder
* the {@link ByteOrder} of the length field
* @param maxFrameLength
* the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset
* the offset of the length field
* @param lengthFieldLength
* the length of the length field
* @param lengthAdjustment
* the compensation value to add to the value of the length field
* @param initialBytesToStrip
* the number of first bytes to strip out from the decoded frame
* @param failFast
* If <tt>true</tt>, a {@link TooLongFrameException} is thrown as
* soon as the decoder notices the length of the frame will exceed
* <tt>maxFrameLength</tt> regardless of whether the entire frame
* has been read. If <tt>false</tt>, a {@link TooLongFrameException}
* is thrown after the entire frame that exceeds <tt>maxFrameLength</tt>
* has been read.
*/
public LengthFieldBasedFrameDecoder(
ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
if (byteOrder == null) {
throw new NullPointerException("byteOrder");
}
if (maxFrameLength <= 0) {
throw new IllegalArgumentException(
"maxFrameLength must be a positive integer: " +
@ -297,6 +336,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
"lengthFieldLength (" + lengthFieldLength + ").");
}
this.byteOrder = byteOrder;
this.maxFrameLength = maxFrameLength;
this.lengthFieldOffset = lengthFieldOffset;
this.lengthFieldLength = lengthFieldLength;
@ -323,26 +363,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
}
int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
long frameLength;
switch (lengthFieldLength) {
case 1:
frameLength = in.getUnsignedByte(actualLengthFieldOffset);
break;
case 2:
frameLength = in.getUnsignedShort(actualLengthFieldOffset);
break;
case 3:
frameLength = in.getUnsignedMedium(actualLengthFieldOffset);
break;
case 4:
frameLength = in.getUnsignedInt(actualLengthFieldOffset);
break;
case 8:
frameLength = in.getLong(actualLengthFieldOffset);
break;
default:
throw new Error("should not reach here");
}
long frameLength = getFrameLength(in, actualLengthFieldOffset);
if (frameLength < 0) {
in.skipBytes(lengthFieldEndOffset);
@ -391,6 +412,31 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
return frame;
}
private long getFrameLength(ByteBuf in, int actualLengthFieldOffset) {
in = in.order(byteOrder);
long frameLength;
switch (lengthFieldLength) {
case 1:
frameLength = in.getUnsignedByte(actualLengthFieldOffset);
break;
case 2:
frameLength = in.getUnsignedShort(actualLengthFieldOffset);
break;
case 3:
frameLength = in.getUnsignedMedium(actualLengthFieldOffset);
break;
case 4:
frameLength = in.getUnsignedInt(actualLengthFieldOffset);
break;
case 8:
frameLength = in.getLong(actualLengthFieldOffset);
break;
default:
throw new Error("should not reach here");
}
return frameLength;
}
private void failIfNecessary(ChannelHandlerContext ctx, boolean firstDetectionOfTooLongFrame) {
if (bytesToDiscard == 0) {
// Reset to the initial state and tell the handlers that