From afcd2b83154828878a6c2a13a6b3c53f4f10d5a4 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 17 Dec 2008 11:39:45 +0000 Subject: [PATCH] Resolved issue: NETTY-95 Length-prefixed frame decoder * Added LengthFieldBasedFrameDecoder * Added CorruptedFrameException --- .../codec/frame/CorruptedFrameException.java | 67 ++++++++ .../frame/LengthFieldBasedFrameDecoder.java | 150 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 src/main/java/org/jboss/netty/handler/codec/frame/CorruptedFrameException.java create mode 100644 src/main/java/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java diff --git a/src/main/java/org/jboss/netty/handler/codec/frame/CorruptedFrameException.java b/src/main/java/org/jboss/netty/handler/codec/frame/CorruptedFrameException.java new file mode 100644 index 0000000000..5bc3ea75b4 --- /dev/null +++ b/src/main/java/org/jboss/netty/handler/codec/frame/CorruptedFrameException.java @@ -0,0 +1,67 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * by the @author tags. See the COPYRIGHT.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.netty.handler.codec.frame; + +/** + * An {@link Exception} which is thrown when the received frame data can not + * be decoded by a {@link FrameDecoder} implementation. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev:231 $, $Date:2008-06-12 16:44:50 +0900 (목, 12 6월 2008) $ + * + * @apiviz.hidden + */ +public class CorruptedFrameException extends Exception { + + private static final long serialVersionUID = 3918052232492988408L; + + /** + * Creates a new instance. + */ + public CorruptedFrameException() { + super(); + } + + /** + * Creates a new instance. + */ + public CorruptedFrameException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new instance. + */ + public CorruptedFrameException(String message) { + super(message); + } + + /** + * Creates a new instance. + */ + public CorruptedFrameException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java b/src/main/java/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java new file mode 100644 index 0000000000..f6499275fa --- /dev/null +++ b/src/main/java/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java @@ -0,0 +1,150 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2008, Red Hat Middleware LLC, and individual contributors + * by the @author tags. See the COPYRIGHT.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.netty.handler.codec.frame; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; + +/** + * TODO Documentation + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev:231 $, $Date:2008-06-12 16:44:50 +0900 (목, 12 6월 2008) $ + * + * @apiviz.landmark + */ +public class LengthFieldBasedFrameDecoder extends FrameDecoder { + + private final int maxFrameLength; + private final int lengthFieldOffset; + private final int lengthFieldLength; + private final int lengthFieldEndOffset; + private final int lengthAdjustment; + + /** + * Creates a new instance. + */ + public LengthFieldBasedFrameDecoder( + int maxFrameLength, + int lengthFieldOffset, int lengthFieldLength) { + this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0); + } + + /** + * Creates a new instance. + */ + public LengthFieldBasedFrameDecoder( + int maxFrameLength, + int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment) { + if (maxFrameLength <= 0) { + throw new IllegalArgumentException( + "maxFrameLength must be a positive integer: " + + maxFrameLength); + } + + if (lengthFieldOffset < 0) { + throw new IllegalArgumentException( + "lengthFieldOffset must be a non-negative integer: " + + lengthFieldOffset); + } + + if (lengthFieldLength != 1 && lengthFieldLength != 2 && + lengthFieldLength != 3 && lengthFieldLength != 4 && + lengthFieldLength != 8) { + throw new IllegalArgumentException( + "lengthFieldLength must be either 1, 2, 3, 4, or 8: " + + lengthFieldLength); + } + + if (lengthFieldOffset > maxFrameLength - lengthFieldLength) { + throw new IllegalArgumentException( + "maxFrameLength (" + maxFrameLength + ") " + + "must be equal to or greater than " + + "lengthFieldOffset (" + lengthFieldOffset + ") + " + + "lengthFieldLength (" + lengthFieldLength + ")."); + } + + this.maxFrameLength = maxFrameLength; + this.lengthFieldOffset = lengthFieldOffset; + this.lengthFieldLength = lengthFieldLength; + this.lengthAdjustment = lengthAdjustment; + lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { + if (buffer.readableBytes() < lengthFieldEndOffset) { + return null; + } + + int actualLengthFieldOffset = buffer.readerIndex() + lengthFieldOffset; + long frameLength; + switch (lengthFieldLength) { + case 1: + frameLength = buffer.getUnsignedByte(actualLengthFieldOffset); + break; + case 2: + frameLength = buffer.getUnsignedShort(actualLengthFieldOffset); + break; + case 3: + frameLength = buffer.getUnsignedMedium(actualLengthFieldOffset); + break; + case 4: + frameLength = buffer.getUnsignedInt(actualLengthFieldOffset); + break; + case 8: + frameLength = buffer.getLong(actualLengthFieldOffset); + break; + default: + throw new Error("should not reach here"); + } + + if (frameLength < 0) { + throw new CorruptedFrameException( + "negative pre-adjustment length field: " + frameLength); + } + + frameLength += lengthAdjustment + lengthFieldEndOffset; + if (frameLength < lengthFieldEndOffset) { + throw new CorruptedFrameException( + "Adjusted length (" + frameLength + ") is less than " + + lengthFieldEndOffset); + } else if (frameLength > maxFrameLength) { + throw new TooLongFrameException( + "Adjusted length exceeds " + maxFrameLength + ": " + + frameLength); + } + + // never overflows because it's less than maxFrameLength + int frameLengthInt = (int) frameLength; + if (buffer.readableBytes() < frameLengthInt) { + return null; + } else { + return buffer.readBytes(frameLengthInt); + } + } +}