View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.handler.codec.http.websocket;
    17
    18  import org.jboss.netty.buffer.ChannelBuffer;
    19  import org.jboss.netty.channel.Channel;
    20  import org.jboss.netty.channel.ChannelHandlerContext;
    21  import org.jboss.netty.handler.codec.frame.TooLongFrameException;
    22  import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
    23  import org.jboss.netty.handler.codec.replay.VoidEnum;
    24
    25  /**
    26   * @deprecated Use <tt>org.jboss.netty.handler.codec.http.websocketx</tt> instead.
    27   *
    28   * Decodes {@link ChannelBuffer}s into {@link WebSocketFrame}s.
    29   * <p>
    30   * For the detailed instruction on adding add Web Socket support to your HTTP
    31   * server, take a look into the <tt>WebSocketServer</tt> example located in the
    32   * {@code org.jboss.netty.example.http.websocket} package.
    33   * @apiviz.landmark
    34   * @apiviz.uses org.jboss.netty.handler.codec.http.websocket.WebSocketFrame
    35   */
    36  @Deprecated
    37  public class WebSocketFrameDecoder extends ReplayingDecoder<VoidEnum> {
    38
    39      public static final int DEFAULT_MAX_FRAME_SIZE = 16384;
    40
    41      private final int maxFrameSize;
    42      private boolean receivedClosingHandshake;
    43
    44      public WebSocketFrameDecoder() {
    45          this(DEFAULT_MAX_FRAME_SIZE);
    46      }
    47
    48      /**
    49       * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}.  If the client
    50       * sends a frame size larger than {@code maxFrameSize}, the channel will be closed.
    51       *
    52       * @param maxFrameSize  the maximum frame size to decode
    53       */
    54      public WebSocketFrameDecoder(int maxFrameSize) {
    55          this.maxFrameSize = maxFrameSize;
    56      }
    57
    58      @Override
    59      protected Object decode(ChannelHandlerContext ctx, Channel channel,
    60              ChannelBuffer buffer, VoidEnum state) throws Exception {
    61
    62          // Discard all data received if closing handshake was received before.
    63          if (receivedClosingHandshake) {
    64              buffer.skipBytes(actualReadableBytes());
    65              return null;
    66          }
    67
    68          // Decode a frame otherwise.
    69          byte type = buffer.readByte();
    70          if ((type & 0x80) == 0x80) {
    71              // If the MSB on type is set, decode the frame length
    72              return decodeBinaryFrame(type, buffer);
    73          } else {
    74              // Decode a 0xff terminated UTF-8 string
    75              return decodeTextFrame(type, buffer);
    76          }
    77      }
    78
    79      private WebSocketFrame decodeBinaryFrame(int type, ChannelBuffer buffer) throws TooLongFrameException {
    80          long frameSize = 0;
    81          int lengthFieldSize = 0;
    82          byte b;
    83          do {
    84              b = buffer.readByte();
    85              frameSize <<= 7;
    86              frameSize |= b & 0x7f;
    87              if (frameSize > maxFrameSize) {
    88                  throw new TooLongFrameException();
    89              }
    90              lengthFieldSize ++;
    91              if (lengthFieldSize > 8) {
    92                  // Perhaps a malicious peer?
    93                  throw new TooLongFrameException();
    94              }
    95          } while ((b & 0x80) == 0x80);
    96
    97          if (type == 0xFF && frameSize == 0) {
    98              receivedClosingHandshake = true;
    99          }
    100
    101         return new DefaultWebSocketFrame(
    102                 type, buffer.readBytes((int) frameSize));
    103     }
    104
    105     private WebSocketFrame decodeTextFrame(int type, ChannelBuffer buffer) throws TooLongFrameException {
    106         int ridx = buffer.readerIndex();
    107         int rbytes = actualReadableBytes();
    108         int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF);
    109         if (delimPos == -1) {
    110             // Frame delimiter (0xFF) not found
    111             if (rbytes > maxFrameSize) {
    112                 // Frame length exceeded the maximum
    113                 throw new TooLongFrameException();
    114             } else {
    115                 // Wait until more data is received
    116                 return null;
    117             }
    118         }
    119
    120         int frameSize = delimPos - ridx;
    121         if (frameSize > maxFrameSize) {
    122             throw new TooLongFrameException();
    123         }
    124
    125         ChannelBuffer binaryData = buffer.readBytes(frameSize);
    126         buffer.skipBytes(1);
    127         return new DefaultWebSocketFrame(type, binaryData);
    128     }
    129 }