Merge pull request #25 from aaronriekenberg/master
Add failImmediatelyOnTooLongFrame option to DelimiterBasedFrameDecoder and LengthFieldBasedFrameDecoder
This commit is contained in:
commit
193acdb36c
@ -69,6 +69,7 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
||||
private final boolean stripDelimiter;
|
||||
private boolean discardingTooLongFrame;
|
||||
private int tooLongFrameLength;
|
||||
private boolean failImmediatelyOnTooLongFrame = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@ -169,11 +170,11 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
||||
discardingTooLongFrame = false;
|
||||
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;
|
||||
this.tooLongFrameLength = 0;
|
||||
fail(ctx, tooLongFrameLength);
|
||||
if (!failImmediatelyOnTooLongFrame) {
|
||||
fail(ctx, tooLongFrameLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -199,6 +200,9 @@ public class DelimiterBasedFrameDecoder extends FrameDecoder {
|
||||
tooLongFrameLength = buffer.readableBytes();
|
||||
buffer.skipBytes(buffer.readableBytes());
|
||||
discardingTooLongFrame = true;
|
||||
if (failImmediatelyOnTooLongFrame) {
|
||||
fail(ctx, tooLongFrameLength);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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) {
|
||||
if (frameLength > 0) {
|
||||
Channels.fireExceptionCaught(
|
||||
|
@ -199,6 +199,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
||||
private boolean discardingTooLongFrame;
|
||||
private long tooLongFrameLength;
|
||||
private long bytesToDiscard;
|
||||
private boolean failImmediatelyOnTooLongFrame = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@ -318,7 +319,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
||||
buffer.skipBytes(localBytesToDiscard);
|
||||
bytesToDiscard -= localBytesToDiscard;
|
||||
this.bytesToDiscard = bytesToDiscard;
|
||||
failIfNecessary(ctx);
|
||||
failIfNecessary(ctx, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -370,7 +371,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
||||
tooLongFrameLength = frameLength;
|
||||
bytesToDiscard = frameLength - buffer.readableBytes();
|
||||
buffer.skipBytes(buffer.readableBytes());
|
||||
failIfNecessary(ctx);
|
||||
failIfNecessary(ctx, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -396,19 +397,26 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
||||
return frame;
|
||||
}
|
||||
|
||||
private void failIfNecessary(ChannelHandlerContext ctx) {
|
||||
private void failIfNecessary(ChannelHandlerContext ctx, boolean firstDetectionOfTooLongFrame) {
|
||||
if (bytesToDiscard == 0) {
|
||||
// Reset to the initial state and tell the handlers that
|
||||
// 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;
|
||||
this.tooLongFrameLength = 0;
|
||||
discardingTooLongFrame = false;
|
||||
fail(ctx, tooLongFrameLength);
|
||||
if ((!failImmediatelyOnTooLongFrame) ||
|
||||
(failImmediatelyOnTooLongFrame && firstDetectionOfTooLongFrame))
|
||||
{
|
||||
fail(ctx, tooLongFrameLength);
|
||||
}
|
||||
} else {
|
||||
// Keep discarding.
|
||||
// Keep discarding and notify handlers if necessary.
|
||||
if (failImmediatelyOnTooLongFrame && firstDetectionOfTooLongFrame)
|
||||
{
|
||||
fail(ctx, this.tooLongFrameLength);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -432,6 +440,23 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
|
||||
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 entire frame has been read.
|
||||
* If true a {@link TooLongFrameException} is thrown immediately
|
||||
* when the length of the frame exceeds maxFrameLength,
|
||||
* regardless of whether the entire frame has been read.
|
||||
*/
|
||||
public LengthFieldBasedFrameDecoder setFailImmediatelyOnTooLongFrame(
|
||||
boolean failImmediatelyOnTooLongFrame)
|
||||
{
|
||||
this.failImmediatelyOnTooLongFrame = failImmediatelyOnTooLongFrame;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void fail(ChannelHandlerContext ctx, long frameLength) {
|
||||
if (frameLength > 0) {
|
||||
Channels.fireExceptionCaught(
|
||||
|
@ -46,4 +46,25 @@ public class DelimiterBasedFrameDecoderTest {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@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