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