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