1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.websocket;
15
16 import java.io.IOException;
17
18 import org.eclipse.jetty.io.Buffer;
19 import org.eclipse.jetty.io.Buffers;
20 import org.eclipse.jetty.io.EndPoint;
21 import org.eclipse.jetty.util.TypeUtil;
22 import org.eclipse.jetty.util.Utf8StringBuilder;
23 import org.eclipse.jetty.util.log.Log;
24
25
26
27
28
29
30
31
32 public class WebSocketParserD06 implements WebSocketParser
33 {
34 public enum State {
35
36 START(0), MASK(4), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), DATA(0), SKIP(1);
37
38 int _needs;
39
40 State(int needs)
41 {
42 _needs=needs;
43 }
44
45 int getNeeds()
46 {
47 return _needs;
48 }
49 };
50
51
52 private final WebSocketBuffers _buffers;
53 private final EndPoint _endp;
54 private final FrameHandler _handler;
55 private final boolean _masked;
56 private State _state;
57 private Buffer _buffer;
58 private byte _flags;
59 private byte _opcode;
60 private int _bytesNeeded;
61 private long _length;
62 private final byte[] _mask = new byte[4];
63 private int _m;
64
65
66
67
68
69
70
71
72
73 public WebSocketParserD06(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean masked)
74 {
75 _buffers=buffers;
76 _endp=endp;
77 _handler=handler;
78 _masked=masked;
79 _state=State.START;
80 }
81
82
83 public boolean isBufferEmpty()
84 {
85 return _buffer==null || _buffer.length()==0;
86 }
87
88
89 public Buffer getBuffer()
90 {
91 return _buffer;
92 }
93
94
95
96
97
98
99
100
101
102 public int parseNext()
103 {
104 if (_buffer==null)
105 _buffer=_buffers.getBuffer();
106
107 int total_filled=0;
108 int events=0;
109
110
111 while(true)
112 {
113 int available=_buffer.length();
114
115
116 while (available<(_state==State.SKIP?1:_bytesNeeded))
117 {
118
119 _buffer.compact();
120
121
122 if (_buffer.space() == 0)
123 throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
124
125
126 try
127 {
128 int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
129 if (filled<=0)
130 return (total_filled+events)>0?(total_filled+events):filled;
131 total_filled+=filled;
132 available=_buffer.length();
133 }
134 catch(IOException e)
135 {
136 Log.debug(e);
137 return (total_filled+events)>0?(total_filled+events):-1;
138 }
139 }
140
141
142
143
144 byte b;
145 while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
146 {
147 switch (_state)
148 {
149 case START:
150 _state=_masked?State.MASK:State.OPCODE;
151 _bytesNeeded=_state.getNeeds();
152 continue;
153
154 case MASK:
155 _buffer.get(_mask,0,4);
156 available-=4;
157 _state=State.OPCODE;
158 _bytesNeeded=_state.getNeeds();
159 _m=0;
160 continue;
161
162 case OPCODE:
163 b=_buffer.get();
164 available--;
165 if (_masked)
166 b^=_mask[_m++%4];
167 _opcode=(byte)(b&0xf);
168 _flags=(byte)(0xf&(b>>4));
169
170 if (WebSocketConnectionD06.isControlFrame(_opcode)&&!WebSocketConnectionD06.isLastFrame(_flags))
171 {
172 _state=State.SKIP;
173 events++;
174 _handler.close(WebSocketConnectionD06.CLOSE_PROTOCOL,"fragmented control");
175 }
176 else
177 _state=State.LENGTH_7;
178
179 _bytesNeeded=_state.getNeeds();
180 continue;
181
182 case LENGTH_7:
183 b=_buffer.get();
184 available--;
185 if (_masked)
186 b^=_mask[_m++%4];
187 switch(b)
188 {
189 case 127:
190 _length=0;
191 _state=State.LENGTH_63;
192 _bytesNeeded=_state.getNeeds();
193 break;
194 case 126:
195 _length=0;
196 _state=State.LENGTH_16;
197 _bytesNeeded=_state.getNeeds();
198 break;
199 default:
200 _length=(0x7f&b);
201 _bytesNeeded=(int)_length;
202 _state=State.DATA;
203 }
204 continue;
205
206 case LENGTH_16:
207 b=_buffer.get();
208 available--;
209 if (_masked)
210 b^=_mask[_m++%4];
211 _length = _length*0x100 + (0xff&b);
212 if (--_bytesNeeded==0)
213 {
214 _bytesNeeded=(int)_length;
215 if (_length>_buffer.capacity())
216 {
217 _state=State.SKIP;
218 events++;
219 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
220 }
221 else
222 {
223 _state=State.DATA;
224 }
225 }
226 continue;
227
228 case LENGTH_63:
229 b=_buffer.get();
230 available--;
231 if (_masked)
232 b^=_mask[_m++%4];
233 _length = _length*0x100 + (0xff&b);
234 if (--_bytesNeeded==0)
235 {
236 _bytesNeeded=(int)_length;
237 if (_length>=_buffer.capacity())
238 {
239 _state=State.SKIP;
240 events++;
241 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
242 }
243 else
244 {
245 _state=State.DATA;
246 }
247 }
248 continue;
249
250 case SKIP:
251 int skip=Math.min(available,_bytesNeeded);
252 _buffer.skip(skip);
253 available-=skip;
254 _bytesNeeded-=skip;
255 if (_bytesNeeded==0)
256 _state=State.START;
257
258 }
259 }
260
261 if (_state==State.DATA && available>=_bytesNeeded)
262 {
263 Buffer data =_buffer.get(_bytesNeeded);
264 if (_masked)
265 {
266 if (data.array()==null)
267 data=_buffer.asMutableBuffer();
268 byte[] array = data.array();
269 final int end=data.putIndex();
270 for (int i=data.getIndex();i<end;i++)
271 array[i]^=_mask[_m++%4];
272 }
273
274
275 events++;
276 _handler.onFrame(_flags, _opcode, data);
277 _bytesNeeded=0;
278 _state=State.START;
279
280 if (_buffer.length()==0)
281 {
282 _buffers.returnBuffer(_buffer);
283 _buffer=null;
284 }
285
286 return total_filled+events;
287 }
288 }
289 }
290
291
292 public void fill(Buffer buffer)
293 {
294 if (buffer!=null && buffer.length()>0)
295 {
296 if (_buffer==null)
297 _buffer=_buffers.getBuffer();
298 _buffer.put(buffer);
299 buffer.clear();
300 }
301 }
302
303 }