1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.websocketx;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.handler.codec.ReplayingDecoder;
21 import io.netty.handler.codec.TooLongFrameException;
22
23 import java.util.List;
24
25
26
27
28
29
30
31 public class WebSocket00FrameDecoder extends ReplayingDecoder<Void> implements WebSocketFrameDecoder {
32
33 static final int DEFAULT_MAX_FRAME_SIZE = 16384;
34
35 private final long maxFrameSize;
36 private boolean receivedClosingHandshake;
37
38 public WebSocket00FrameDecoder() {
39 this(DEFAULT_MAX_FRAME_SIZE);
40 }
41
42
43
44
45
46
47
48
49 public WebSocket00FrameDecoder(int maxFrameSize) {
50 this.maxFrameSize = maxFrameSize;
51 }
52
53 @Override
54 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
55
56 if (receivedClosingHandshake) {
57 in.skipBytes(actualReadableBytes());
58 return;
59 }
60
61
62 byte type = in.readByte();
63 WebSocketFrame frame;
64 if ((type & 0x80) == 0x80) {
65
66 frame = decodeBinaryFrame(ctx, type, in);
67 } else {
68
69 frame = decodeTextFrame(ctx, in);
70 }
71
72 if (frame != null) {
73 out.add(frame);
74 }
75 }
76
77 private WebSocketFrame decodeBinaryFrame(ChannelHandlerContext ctx, byte type, ByteBuf buffer) {
78 long frameSize = 0;
79 int lengthFieldSize = 0;
80 byte b;
81 do {
82 b = buffer.readByte();
83 frameSize <<= 7;
84 frameSize |= b & 0x7f;
85 if (frameSize > maxFrameSize) {
86 throw new TooLongFrameException();
87 }
88 lengthFieldSize++;
89 if (lengthFieldSize > 8) {
90
91 throw new TooLongFrameException();
92 }
93 } while ((b & 0x80) == 0x80);
94
95 if (type == (byte) 0xFF && frameSize == 0) {
96 receivedClosingHandshake = true;
97 return new CloseWebSocketFrame();
98 }
99 ByteBuf payload = ctx.alloc().buffer((int) frameSize);
100 buffer.readBytes(payload);
101 return new BinaryWebSocketFrame(payload);
102 }
103
104 private WebSocketFrame decodeTextFrame(ChannelHandlerContext ctx, ByteBuf buffer) {
105 int ridx = buffer.readerIndex();
106 int rbytes = actualReadableBytes();
107 int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF);
108 if (delimPos == -1) {
109
110 if (rbytes > maxFrameSize) {
111
112 throw new TooLongFrameException();
113 } else {
114
115 return null;
116 }
117 }
118
119 int frameSize = delimPos - ridx;
120 if (frameSize > maxFrameSize) {
121 throw new TooLongFrameException();
122 }
123
124 ByteBuf binaryData = ctx.alloc().buffer(frameSize);
125 buffer.readBytes(binaryData);
126 buffer.skipBytes(1);
127
128 int ffDelimPos = binaryData.indexOf(binaryData.readerIndex(), binaryData.writerIndex(), (byte) 0xFF);
129 if (ffDelimPos >= 0) {
130 throw new IllegalArgumentException("a text frame should not contain 0xFF.");
131 }
132
133 return new TextWebSocketFrame(binaryData);
134 }
135 }