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