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