More robust exception handling for incorrect length and too large frames
This commit is contained in:
parent
7fa20dcb07
commit
247251420a
@ -43,6 +43,9 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
private final int lengthFieldLength;
|
private final int lengthFieldLength;
|
||||||
private final int lengthFieldEndOffset;
|
private final int lengthFieldEndOffset;
|
||||||
private final int lengthAdjustment;
|
private final int lengthAdjustment;
|
||||||
|
private volatile boolean discardingTooLongFrame;
|
||||||
|
private volatile long tooLongFrameLength;
|
||||||
|
private volatile long bytesToDiscard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -97,6 +100,28 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
@Override
|
@Override
|
||||||
protected Object decode(
|
protected Object decode(
|
||||||
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
|
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
|
||||||
|
|
||||||
|
if (discardingTooLongFrame) {
|
||||||
|
long bytesToDiscard = this.bytesToDiscard;
|
||||||
|
int localBytesToDiscard = (int) Math.min(bytesToDiscard, buffer.readableBytes());
|
||||||
|
buffer.skipBytes(localBytesToDiscard);
|
||||||
|
bytesToDiscard -= localBytesToDiscard;
|
||||||
|
this.bytesToDiscard = bytesToDiscard;
|
||||||
|
if (bytesToDiscard == 0) {
|
||||||
|
// Reset to the initial state and tell the handlers that
|
||||||
|
// the frame was too large.
|
||||||
|
discardingTooLongFrame = false;
|
||||||
|
long tooLongFrameLength = this.tooLongFrameLength;
|
||||||
|
this.tooLongFrameLength = 0;
|
||||||
|
throw new TooLongFrameException(
|
||||||
|
"Adjusted frame length exceeds " + maxFrameLength +
|
||||||
|
": " + tooLongFrameLength);
|
||||||
|
} else {
|
||||||
|
// Keep discarding.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer.readableBytes() < lengthFieldEndOffset) {
|
if (buffer.readableBytes() < lengthFieldEndOffset) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -124,21 +149,24 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frameLength < 0) {
|
if (frameLength < 0) {
|
||||||
buffer.skipBytes(actualLengthFieldOffset + lengthFieldLength);
|
buffer.skipBytes(lengthFieldEndOffset);
|
||||||
throw new CorruptedFrameException(
|
throw new CorruptedFrameException(
|
||||||
"negative pre-adjustment length field: " + frameLength);
|
"negative pre-adjustment length field: " + frameLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameLength += lengthAdjustment + lengthFieldEndOffset;
|
frameLength += lengthAdjustment + lengthFieldEndOffset;
|
||||||
if (frameLength < lengthFieldEndOffset) {
|
if (frameLength < lengthFieldEndOffset) {
|
||||||
buffer.skipBytes(actualLengthFieldOffset + lengthFieldLength);
|
buffer.skipBytes(lengthFieldEndOffset);
|
||||||
throw new CorruptedFrameException(
|
throw new CorruptedFrameException(
|
||||||
"Adjusted length (" + frameLength + ") is less than " +
|
"Adjusted length (" + frameLength + ") is less than " +
|
||||||
lengthFieldEndOffset);
|
lengthFieldEndOffset);
|
||||||
} else if (frameLength > maxFrameLength) {
|
} else if (frameLength > maxFrameLength) {
|
||||||
throw new TooLongFrameException(
|
// Enter the discard mode and discard everything received so far.
|
||||||
"Adjusted length exceeds " + maxFrameLength + ": " +
|
discardingTooLongFrame = true;
|
||||||
frameLength);
|
tooLongFrameLength = frameLength;
|
||||||
|
bytesToDiscard = frameLength - buffer.readableBytes();
|
||||||
|
buffer.skipBytes(buffer.readableBytes());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// never overflows because it's less than maxFrameLength
|
// never overflows because it's less than maxFrameLength
|
||||||
|
Loading…
Reference in New Issue
Block a user