1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.eclipse.jetty.websocket;
30
31 import java.io.IOException;
32
33 import org.eclipse.jetty.io.Buffer;
34 import org.eclipse.jetty.io.Buffers;
35 import org.eclipse.jetty.io.EndPoint;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38
39
40
41
42
43
44
45
46 public class WebSocketParserD08 implements WebSocketParser
47 {
48 private static final Logger LOG = Log.getLogger(WebSocketParserD08.class);
49
50 public enum State {
51
52 START(0), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), MASK(4), PAYLOAD(0), DATA(0), SKIP(1);
53
54 int _needs;
55
56 State(int needs)
57 {
58 _needs=needs;
59 }
60
61 int getNeeds()
62 {
63 return _needs;
64 }
65 }
66
67 private final WebSocketBuffers _buffers;
68 private final EndPoint _endp;
69 private final FrameHandler _handler;
70 private final boolean _shouldBeMasked;
71 private State _state;
72 private Buffer _buffer;
73 private byte _flags;
74 private byte _opcode;
75 private int _bytesNeeded;
76 private long _length;
77 private boolean _masked;
78 private final byte[] _mask = new byte[4];
79 private int _m;
80 private boolean _skip;
81 private boolean _fakeFragments=true;
82
83
84
85
86
87
88
89
90
91
92 public WebSocketParserD08(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean shouldBeMasked)
93 {
94 _buffers=buffers;
95 _endp=endp;
96 _handler=handler;
97 _shouldBeMasked=shouldBeMasked;
98 _state=State.START;
99 }
100
101
102
103
104
105 public boolean isFakeFragments()
106 {
107 return _fakeFragments;
108 }
109
110
111
112
113
114 public void setFakeFragments(boolean fakeFragments)
115 {
116 _fakeFragments = fakeFragments;
117 }
118
119
120 public boolean isBufferEmpty()
121 {
122 return _buffer==null || _buffer.length()==0;
123 }
124
125
126 public Buffer getBuffer()
127 {
128 return _buffer;
129 }
130
131
132
133
134
135
136
137
138
139 public int parseNext()
140 {
141 if (_buffer==null)
142 _buffer=_buffers.getBuffer();
143 int total_filled=0;
144 int events=0;
145
146
147 while(true)
148 {
149 int available=_buffer.length();
150
151
152 while (available<(_state==State.SKIP?1:_bytesNeeded))
153 {
154
155 _buffer.compact();
156
157
158 if (_buffer.space() == 0)
159 {
160
161 if (_fakeFragments && _state==State.DATA)
162 {
163 Buffer data =_buffer.get(4*(available/4));
164 _buffer.compact();
165 if (_masked)
166 {
167 if (data.array()==null)
168 data=_buffer.asMutableBuffer();
169 byte[] array = data.array();
170 final int end=data.putIndex();
171 for (int i=data.getIndex();i<end;i++)
172 array[i]^=_mask[_m++%4];
173 }
174
175
176 events++;
177 _bytesNeeded-=data.length();
178 _handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD08.FLAG_FIN)), _opcode, data);
179
180 _opcode=WebSocketConnectionD08.OP_CONTINUATION;
181 }
182
183 if (_buffer.space() == 0)
184 throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
185 }
186
187
188 try
189 {
190 int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
191 if (filled<=0)
192 return (total_filled+events)>0?(total_filled+events):filled;
193 total_filled+=filled;
194 available=_buffer.length();
195 }
196 catch(IOException e)
197 {
198 LOG.debug(e);
199 return (total_filled+events)>0?(total_filled+events):-1;
200 }
201 }
202
203
204
205
206 byte b;
207 while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
208 {
209 switch (_state)
210 {
211 case START:
212 _skip=false;
213 _state=State.OPCODE;
214 _bytesNeeded=_state.getNeeds();
215 continue;
216
217 case OPCODE:
218 b=_buffer.get();
219 available--;
220 _opcode=(byte)(b&0xf);
221 _flags=(byte)(0xf&(b>>4));
222
223 if (WebSocketConnectionD08.isControlFrame(_opcode)&&!WebSocketConnectionD08.isLastFrame(_flags))
224 {
225 events++;
226 LOG.warn("Fragmented Control from "+_endp);
227 _handler.close(WebSocketConnectionD08.CLOSE_PROTOCOL,"Fragmented control");
228 _skip=true;
229 }
230
231 _state=State.LENGTH_7;
232 _bytesNeeded=_state.getNeeds();
233
234 continue;
235
236 case LENGTH_7:
237 b=_buffer.get();
238 available--;
239 _masked=(b&0x80)!=0;
240 b=(byte)(0x7f&b);
241
242 switch(b)
243 {
244 case 0x7f:
245 _length=0;
246 _state=State.LENGTH_63;
247 break;
248 case 0x7e:
249 _length=0;
250 _state=State.LENGTH_16;
251 break;
252 default:
253 _length=(0x7f&b);
254 _state=_masked?State.MASK:State.PAYLOAD;
255 }
256 _bytesNeeded=_state.getNeeds();
257 continue;
258
259 case LENGTH_16:
260 b=_buffer.get();
261 available--;
262 _length = _length*0x100 + (0xff&b);
263 if (--_bytesNeeded==0)
264 {
265 if (_length>_buffer.capacity() && !_fakeFragments)
266 {
267 events++;
268 _handler.close(WebSocketConnectionD08.CLOSE_BADDATA,"frame size "+_length+">"+_buffer.capacity());
269 _skip=true;
270 }
271
272 _state=_masked?State.MASK:State.PAYLOAD;
273 _bytesNeeded=_state.getNeeds();
274 }
275 continue;
276
277 case LENGTH_63:
278 b=_buffer.get();
279 available--;
280 _length = _length*0x100 + (0xff&b);
281 if (--_bytesNeeded==0)
282 {
283 _bytesNeeded=(int)_length;
284 if (_length>=_buffer.capacity() && !_fakeFragments)
285 {
286 events++;
287 _handler.close(WebSocketConnectionD08.CLOSE_BADDATA,"frame size "+_length+">"+_buffer.capacity());
288 _skip=true;
289 }
290
291 _state=_masked?State.MASK:State.PAYLOAD;
292 _bytesNeeded=_state.getNeeds();
293 }
294 continue;
295
296 case MASK:
297 _buffer.get(_mask,0,4);
298 _m=0;
299 available-=4;
300 _state=State.PAYLOAD;
301 _bytesNeeded=_state.getNeeds();
302 break;
303
304 case PAYLOAD:
305 _bytesNeeded=(int)_length;
306 _state=_skip?State.SKIP:State.DATA;
307 break;
308
309 case DATA:
310 break;
311
312 case SKIP:
313 int skip=Math.min(available,_bytesNeeded);
314 _buffer.skip(skip);
315 available-=skip;
316 _bytesNeeded-=skip;
317 if (_bytesNeeded==0)
318 _state=State.START;
319
320 }
321 }
322
323 if (_state==State.DATA && available>=_bytesNeeded)
324 {
325 if ( _masked!=_shouldBeMasked)
326 {
327 _buffer.skip(_bytesNeeded);
328 _state=State.START;
329 events++;
330 _handler.close(WebSocketConnectionD08.CLOSE_PROTOCOL,"bad mask");
331 }
332 else
333 {
334 Buffer data =_buffer.get(_bytesNeeded);
335 if (_masked)
336 {
337 if (data.array()==null)
338 data=_buffer.asMutableBuffer();
339 byte[] array = data.array();
340 final int end=data.putIndex();
341 for (int i=data.getIndex();i<end;i++)
342 array[i]^=_mask[_m++%4];
343 }
344
345
346 events++;
347 _handler.onFrame(_flags, _opcode, data);
348 _bytesNeeded=0;
349 _state=State.START;
350 }
351
352 return total_filled+events;
353 }
354 }
355 }
356
357
358 public void fill(Buffer buffer)
359 {
360 if (buffer!=null && buffer.length()>0)
361 {
362 if (_buffer==null)
363 _buffer=_buffers.getBuffer();
364
365 _buffer.put(buffer);
366 buffer.clear();
367 }
368 }
369
370
371 public void returnBuffer()
372 {
373 if (_buffer!=null && _buffer.length()==0)
374 {
375 _buffers.returnBuffer(_buffer);
376 _buffer=null;
377 }
378 }
379
380
381 @Override
382 public String toString()
383 {
384 Buffer buffer=_buffer;
385 return WebSocketParserD08.class.getSimpleName()+"@"+ Integer.toHexString(hashCode())+"|"+_state+"|"+(buffer==null?"<>":buffer.toDetailString());
386 }
387
388 }