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 }