Add failImmediatelyOnTooLongFrameOption.
This commit is contained in:
parent
2fc18a00f6
commit
f474fc609a
@ -69,6 +69,7 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
|||||||
private final boolean stripDelimiter;
|
private final boolean stripDelimiter;
|
||||||
private boolean discardingTooLongFrame;
|
private boolean discardingTooLongFrame;
|
||||||
private int tooLongFrameLength;
|
private int tooLongFrameLength;
|
||||||
|
private boolean failImmediatelyOnTooLongFrame = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -169,11 +170,11 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
|||||||
discardingTooLongFrame = false;
|
discardingTooLongFrame = false;
|
||||||
buffer.skipBytes(minFrameLength + minDelimLength);
|
buffer.skipBytes(minFrameLength + minDelimLength);
|
||||||
|
|
||||||
// TODO Let user choose when the exception should be raised - early or late?
|
|
||||||
// If early, fail() should be called when discardingTooLongFrame is set to true.
|
|
||||||
int tooLongFrameLength = this.tooLongFrameLength;
|
int tooLongFrameLength = this.tooLongFrameLength;
|
||||||
this.tooLongFrameLength = 0;
|
this.tooLongFrameLength = 0;
|
||||||
fail(ctx, tooLongFrameLength);
|
if (!failImmediatelyOnTooLongFrame) {
|
||||||
|
fail(ctx, tooLongFrameLength);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +200,9 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
|||||||
tooLongFrameLength = buffer.readableBytes();
|
tooLongFrameLength = buffer.readableBytes();
|
||||||
buffer.skipBytes(buffer.readableBytes());
|
buffer.skipBytes(buffer.readableBytes());
|
||||||
discardingTooLongFrame = true;
|
discardingTooLongFrame = true;
|
||||||
|
if (failImmediatelyOnTooLongFrame) {
|
||||||
|
fail(ctx, tooLongFrameLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Still discarding the buffer since a delimiter is not found.
|
// Still discarding the buffer since a delimiter is not found.
|
||||||
@ -209,6 +213,23 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the behavior when a frame longer than maxFrameLength is encountered.
|
||||||
|
*
|
||||||
|
* @param failImmediatelyOnTooLongFrame If false (the default) a {@link TooLongFrameException}
|
||||||
|
* is thrown if the length of the frame exceeds maxFrameLength,
|
||||||
|
* after the delimiter has been read.
|
||||||
|
* If true a {@link TooLongFrameException} is thrown immediately
|
||||||
|
* when the length of the frame exceeds maxFrameLength,
|
||||||
|
* regardless of whether a delimiter has been found yet.
|
||||||
|
*/
|
||||||
|
public DelimiterBasedFrameDecoder setFailImmediatelyOnTooLongFrame(
|
||||||
|
boolean failImmediatelyOnTooLongFrame)
|
||||||
|
{
|
||||||
|
this.failImmediatelyOnTooLongFrame = failImmediatelyOnTooLongFrame;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private void fail(ChannelHandlerContext ctx, long frameLength) {
|
private void fail(ChannelHandlerContext ctx, long frameLength) {
|
||||||
if (frameLength > 0) {
|
if (frameLength > 0) {
|
||||||
Channels.fireExceptionCaught(
|
Channels.fireExceptionCaught(
|
||||||
|
@ -198,6 +198,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
private boolean discardingTooLongFrame;
|
private boolean discardingTooLongFrame;
|
||||||
private long tooLongFrameLength;
|
private long tooLongFrameLength;
|
||||||
private long bytesToDiscard;
|
private long bytesToDiscard;
|
||||||
|
private boolean failImmediatelyOnTooLongFrame = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -290,7 +291,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
buffer.skipBytes(localBytesToDiscard);
|
buffer.skipBytes(localBytesToDiscard);
|
||||||
bytesToDiscard -= localBytesToDiscard;
|
bytesToDiscard -= localBytesToDiscard;
|
||||||
this.bytesToDiscard = bytesToDiscard;
|
this.bytesToDiscard = bytesToDiscard;
|
||||||
failIfNecessary(ctx);
|
failIfNecessary(ctx, false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +341,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
tooLongFrameLength = frameLength;
|
tooLongFrameLength = frameLength;
|
||||||
bytesToDiscard = frameLength - buffer.readableBytes();
|
bytesToDiscard = frameLength - buffer.readableBytes();
|
||||||
buffer.skipBytes(buffer.readableBytes());
|
buffer.skipBytes(buffer.readableBytes());
|
||||||
failIfNecessary(ctx);
|
failIfNecessary(ctx, true);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,19 +367,25 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failIfNecessary(ChannelHandlerContext ctx) {
|
private void failIfNecessary(ChannelHandlerContext ctx, boolean firstDetectionOfTooLongFrame) {
|
||||||
if (bytesToDiscard == 0) {
|
if (bytesToDiscard == 0) {
|
||||||
// Reset to the initial state and tell the handlers that
|
// Reset to the initial state and tell the handlers that
|
||||||
// the frame was too large.
|
// the frame was too large.
|
||||||
// TODO Let user choose when the exception should be raised - early or late?
|
|
||||||
// If early, fail() should be called when discardingTooLongFrame is set to true.
|
|
||||||
long tooLongFrameLength = this.tooLongFrameLength;
|
long tooLongFrameLength = this.tooLongFrameLength;
|
||||||
this.tooLongFrameLength = 0;
|
this.tooLongFrameLength = 0;
|
||||||
discardingTooLongFrame = false;
|
discardingTooLongFrame = false;
|
||||||
fail(ctx, tooLongFrameLength);
|
if (!failImmediatelyOnTooLongFrame)
|
||||||
|
{
|
||||||
|
fail(ctx, tooLongFrameLength);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Keep discarding.
|
// Keep discarding.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (firstDetectionOfTooLongFrame && failImmediatelyOnTooLongFrame)
|
||||||
|
{
|
||||||
|
fail(ctx, tooLongFrameLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -402,6 +409,23 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the behavior when a frame longer than maxFrameLength is encountered.
|
||||||
|
*
|
||||||
|
* @param failImmediatelyOnTooLongFrame If false (the default) a {@link TooLongFrameException}
|
||||||
|
* is thrown if the length of the frame exceeds maxFrameLength,
|
||||||
|
* after the delimiter has been read.
|
||||||
|
* If true a {@link TooLongFrameException} is thrown immediately
|
||||||
|
* when the length of the frame exceeds maxFrameLength,
|
||||||
|
* regardless of whether a delimiter has been found yet.
|
||||||
|
*/
|
||||||
|
public LengthFieldBasedFrameDecoder setFailImmediatelyOnTooLongFrame(
|
||||||
|
boolean failImmediatelyOnTooLongFrame)
|
||||||
|
{
|
||||||
|
this.failImmediatelyOnTooLongFrame = failImmediatelyOnTooLongFrame;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private void fail(ChannelHandlerContext ctx, long frameLength) {
|
private void fail(ChannelHandlerContext ctx, long frameLength) {
|
||||||
if (frameLength > 0) {
|
if (frameLength > 0) {
|
||||||
Channels.fireExceptionCaught(
|
Channels.fireExceptionCaught(
|
||||||
|
@ -46,4 +46,25 @@ public class DelimiterBasedFrameDecoderTest {
|
|||||||
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailImmediatelyTooLongFrameRecovery() throws Exception {
|
||||||
|
DecoderEmbedder<ChannelBuffer> embedder = new DecoderEmbedder<ChannelBuffer>(
|
||||||
|
new DelimiterBasedFrameDecoder(1, Delimiters.nulDelimiter()).
|
||||||
|
setFailImmediatelyOnTooLongFrame(true));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i ++) {
|
||||||
|
try {
|
||||||
|
embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 1, 2 }));
|
||||||
|
Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised.");
|
||||||
|
} catch (CodecEmbedderException e) {
|
||||||
|
Assert.assertTrue(e.getCause() instanceof TooLongFrameException);
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 'A', 0 }));
|
||||||
|
ChannelBuffer buf = embedder.poll();
|
||||||
|
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,4 +46,25 @@ public class LengthFieldBasedFrameDecoderTest {
|
|||||||
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailImmediatelyTooLongFrameRecovery() throws Exception {
|
||||||
|
DecoderEmbedder<ChannelBuffer> embedder = new DecoderEmbedder<ChannelBuffer>(
|
||||||
|
new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4).
|
||||||
|
setFailImmediatelyOnTooLongFrame(true));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i ++) {
|
||||||
|
try {
|
||||||
|
embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 2 }));
|
||||||
|
Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised.");
|
||||||
|
} catch (CodecEmbedderException e) {
|
||||||
|
Assert.assertTrue(e.getCause() instanceof TooLongFrameException);
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 0, 0, 1, 'A' }));
|
||||||
|
ChannelBuffer buf = embedder.poll();
|
||||||
|
Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user