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 WebSocketParserRFC6455 implements WebSocketParser
47 {
48 private static final Logger LOG = Log.getLogger(WebSocketParserRFC6455.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), SEEK_EOF(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 _fragmentFrames=true;
82
83
84
85
86
87
88
89
90
91
92 public WebSocketParserRFC6455(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 _fragmentFrames;
108 }
109
110
111
112
113
114 public void setFakeFragments(boolean fakeFragments)
115 {
116 _fragmentFrames = 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
144 boolean progress=false;
145 int filled=-1;
146
147
148 while(!progress && (!_endp.isInputShutdown()||_buffer.length()>0))
149 {
150 int available=_buffer.length();
151
152
153 while (available<(_state==State.SKIP?1:_bytesNeeded))
154 {
155
156 _buffer.compact();
157
158
159 if (_buffer.space() == 0)
160 {
161
162 if (_fragmentFrames && _state==State.DATA)
163 {
164 Buffer data =_buffer.get(4*(available/4));
165 _buffer.compact();
166 if (_masked)
167 {
168 if (data.array()==null)
169 data=_buffer.asMutableBuffer();
170 byte[] array = data.array();
171 final int end=data.putIndex();
172 for (int i=data.getIndex();i<end;i++)
173 array[i]^=_mask[_m++%4];
174 }
175
176
177 _bytesNeeded-=data.length();
178 progress=true;
179 _handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionRFC6455.FLAG_FIN)), _opcode, data);
180
181 _opcode=WebSocketConnectionRFC6455.OP_CONTINUATION;
182 }
183
184 if (_buffer.space() == 0)
185 throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
186 }
187
188
189 try
190 {
191 filled=_endp.isInputShutdown()?-1:_endp.fill(_buffer);
192 available=_buffer.length();
193
194 if (filled<=0)
195 break;
196 }
197 catch(IOException e)
198 {
199 LOG.debug(e);
200 filled=-1;
201 break;
202 }
203 }
204
205 if (available<(_state==State.SKIP?1:_bytesNeeded))
206 break;
207
208
209
210 byte b;
211 while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
212 {
213 switch (_state)
214 {
215 case START:
216 _skip=false;
217 _state=_opcode==WebSocketConnectionRFC6455.OP_CLOSE?State.SEEK_EOF:State.OPCODE;
218 _bytesNeeded=_state.getNeeds();
219 continue;
220
221 case OPCODE:
222 b=_buffer.get();
223 available--;
224 _opcode=(byte)(b&0xf);
225 _flags=(byte)(0xf&(b>>4));
226
227 if (WebSocketConnectionRFC6455.isControlFrame(_opcode)&&!WebSocketConnectionRFC6455.isLastFrame(_flags))
228 {
229 LOG.warn("Fragmented Control from "+_endp);
230 _handler.close(WebSocketConnectionRFC6455.CLOSE_PROTOCOL,"Fragmented control");
231 progress=true;
232 _skip=true;
233 }
234
235 _state=State.LENGTH_7;
236 _bytesNeeded=_state.getNeeds();
237
238 continue;
239
240 case LENGTH_7:
241 b=_buffer.get();
242 available--;
243 _masked=(b&0x80)!=0;
244 b=(byte)(0x7f&b);
245
246 switch(b)
247 {
248 case 0x7f:
249 _length=0;
250 _state=State.LENGTH_63;
251 break;
252 case 0x7e:
253 _length=0;
254 _state=State.LENGTH_16;
255 break;
256 default:
257 _length=(0x7f&b);
258 _state=_masked?State.MASK:State.PAYLOAD;
259 }
260 _bytesNeeded=_state.getNeeds();
261 continue;
262
263 case LENGTH_16:
264 b=_buffer.get();
265 available--;
266 _length = _length*0x100 + (0xff&b);
267 if (--_bytesNeeded==0)
268 {
269 if (_length>_buffer.capacity() && !_fragmentFrames)
270 {
271 progress=true;
272 _handler.close(WebSocketConnectionRFC6455.CLOSE_POLICY_VIOLATION,"frame size "+_length+">"+_buffer.capacity());
273 _skip=true;
274 }
275
276 _state=_masked?State.MASK:State.PAYLOAD;
277 _bytesNeeded=_state.getNeeds();
278 }
279 continue;
280
281 case LENGTH_63:
282 b=_buffer.get();
283 available--;
284 _length = _length*0x100 + (0xff&b);
285 if (--_bytesNeeded==0)
286 {
287 _bytesNeeded=(int)_length;
288 if (_length>=_buffer.capacity() && !_fragmentFrames)
289 {
290 progress=true;
291 _handler.close(WebSocketConnectionRFC6455.CLOSE_POLICY_VIOLATION,"frame size "+_length+">"+_buffer.capacity());
292 _skip=true;
293 }
294
295 _state=_masked?State.MASK:State.PAYLOAD;
296 _bytesNeeded=_state.getNeeds();
297 }
298 continue;
299
300 case MASK:
301 _buffer.get(_mask,0,4);
302 _m=0;
303 available-=4;
304 _state=State.PAYLOAD;
305 _bytesNeeded=_state.getNeeds();
306 break;
307
308 case PAYLOAD:
309 _bytesNeeded=(int)_length;
310 _state=_skip?State.SKIP:State.DATA;
311 break;
312
313 case DATA:
314 break;
315
316 case SKIP:
317 int skip=Math.min(available,_bytesNeeded);
318 progress=true;
319 _buffer.skip(skip);
320 available-=skip;
321 _bytesNeeded-=skip;
322 if (_bytesNeeded==0)
323 _state=State.START;
324 break;
325
326 case SEEK_EOF:
327 progress=true;
328 _buffer.skip(available);
329 available=0;
330 break;
331 }
332 }
333
334 if (_state==State.DATA && available>=_bytesNeeded)
335 {
336 if ( _masked!=_shouldBeMasked)
337 {
338 _buffer.skip(_bytesNeeded);
339 _state=State.START;
340 progress=true;
341 _handler.close(WebSocketConnectionRFC6455.CLOSE_PROTOCOL,"Not masked");
342 }
343 else
344 {
345 Buffer data =_buffer.get(_bytesNeeded);
346 if (_masked)
347 {
348 if (data.array()==null)
349 data=_buffer.asMutableBuffer();
350 byte[] array = data.array();
351 final int end=data.putIndex();
352 for (int i=data.getIndex();i<end;i++)
353 array[i]^=_mask[_m++%4];
354 }
355
356
357
358 progress=true;
359 _handler.onFrame(_flags, _opcode, data);
360 _bytesNeeded=0;
361 _state=State.START;
362 }
363
364 break;
365 }
366 }
367
368 return progress?1:filled;
369 }
370
371
372 public void fill(Buffer buffer)
373 {
374 if (buffer!=null && buffer.length()>0)
375 {
376 if (_buffer==null)
377 _buffer=_buffers.getBuffer();
378
379 _buffer.put(buffer);
380 buffer.clear();
381 }
382 }
383
384
385 public void returnBuffer()
386 {
387 if (_buffer!=null && _buffer.length()==0)
388 {
389 _buffers.returnBuffer(_buffer);
390 _buffer=null;
391 }
392 }
393
394
395 @Override
396 public String toString()
397 {
398 return String.format("%s@%x state=%s buffer=%s",
399 getClass().getSimpleName(),
400 hashCode(),
401 _state,
402 _buffer);
403 }
404 }