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);
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 int total_filled=0;
129 int events=0;
130
131
132 while(true)
133 {
134 int available=_buffer.length();
135
136
137 while (available<(_state==State.SKIP?1:_bytesNeeded))
138 {
139
140 _buffer.compact();
141
142
143 if (_buffer.space() == 0)
144 {
145
146 if (_fragmentFrames && _state==State.DATA)
147 {
148 Buffer data =_buffer.get(4*(available/4));
149 _buffer.compact();
150 if (_masked)
151 {
152 if (data.array()==null)
153 data=_buffer.asMutableBuffer();
154 byte[] array = data.array();
155 final int end=data.putIndex();
156 for (int i=data.getIndex();i<end;i++)
157 array[i]^=_mask[_m++%4];
158 }
159
160
161 events++;
162 _bytesNeeded-=data.length();
163 _handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD13.FLAG_FIN)), _opcode, data);
164
165 _opcode=WebSocketConnectionD13.OP_CONTINUATION;
166 }
167
168 if (_buffer.space() == 0)
169 throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
170 }
171
172
173 try
174 {
175 int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
176 if (filled<=0)
177 return (total_filled+events)>0?(total_filled+events):filled;
178 total_filled+=filled;
179 available=_buffer.length();
180 }
181 catch(IOException e)
182 {
183 LOG.debug(e);
184 return (total_filled+events)>0?(total_filled+events):-1;
185 }
186 }
187
188
189
190
191 byte b;
192 while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
193 {
194 switch (_state)
195 {
196 case START:
197 _skip=false;
198 _state=State.OPCODE;
199 _bytesNeeded=_state.getNeeds();
200 continue;
201
202 case OPCODE:
203 b=_buffer.get();
204 available--;
205 _opcode=(byte)(b&0xf);
206 _flags=(byte)(0xf&(b>>4));
207
208 if (WebSocketConnectionD13.isControlFrame(_opcode)&&!WebSocketConnectionD13.isLastFrame(_flags))
209 {
210 events++;
211 LOG.warn("Fragmented Control from "+_endp);
212 _handler.close(WebSocketConnectionD13.CLOSE_PROTOCOL,"Fragmented control");
213 _skip=true;
214 }
215
216 _state=State.LENGTH_7;
217 _bytesNeeded=_state.getNeeds();
218
219 continue;
220
221 case LENGTH_7:
222 b=_buffer.get();
223 available--;
224 _masked=(b&0x80)!=0;
225 b=(byte)(0x7f&b);
226
227 switch(b)
228 {
229 case 0x7f:
230 _length=0;
231 _state=State.LENGTH_63;
232 break;
233 case 0x7e:
234 _length=0;
235 _state=State.LENGTH_16;
236 break;
237 default:
238 _length=(0x7f&b);
239 _state=_masked?State.MASK:State.PAYLOAD;
240 }
241 _bytesNeeded=_state.getNeeds();
242 continue;
243
244 case LENGTH_16:
245 b=_buffer.get();
246 available--;
247 _length = _length*0x100 + (0xff&b);
248 if (--_bytesNeeded==0)
249 {
250 if (_length>_buffer.capacity() && !_fragmentFrames)
251 {
252 events++;
253 _handler.close(WebSocketConnectionD13.CLOSE_POLICY_VIOLATION,"frame size "+_length+">"+_buffer.capacity());
254 _skip=true;
255 }
256
257 _state=_masked?State.MASK:State.PAYLOAD;
258 _bytesNeeded=_state.getNeeds();
259 }
260 continue;
261
262 case LENGTH_63:
263 b=_buffer.get();
264 available--;
265 _length = _length*0x100 + (0xff&b);
266 if (--_bytesNeeded==0)
267 {
268 _bytesNeeded=(int)_length;
269 if (_length>=_buffer.capacity() && !_fragmentFrames)
270 {
271 events++;
272 _handler.close(WebSocketConnectionD13.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 MASK:
282 _buffer.get(_mask,0,4);
283 _m=0;
284 available-=4;
285 _state=State.PAYLOAD;
286 _bytesNeeded=_state.getNeeds();
287 break;
288
289 case PAYLOAD:
290 _bytesNeeded=(int)_length;
291 _state=_skip?State.SKIP:State.DATA;
292 break;
293
294 case DATA:
295 break;
296
297 case SKIP:
298 int skip=Math.min(available,_bytesNeeded);
299 _buffer.skip(skip);
300 available-=skip;
301 _bytesNeeded-=skip;
302 if (_bytesNeeded==0)
303 _state=State.START;
304
305 }
306 }
307
308 if (_state==State.DATA && available>=_bytesNeeded)
309 {
310 if ( _masked!=_shouldBeMasked)
311 {
312 _buffer.skip(_bytesNeeded);
313 _state=State.START;
314 events++;
315 _handler.close(WebSocketConnectionD13.CLOSE_PROTOCOL,"Not masked");
316 }
317 else
318 {
319 Buffer data =_buffer.get(_bytesNeeded);
320 if (_masked)
321 {
322 if (data.array()==null)
323 data=_buffer.asMutableBuffer();
324 byte[] array = data.array();
325 final int end=data.putIndex();
326 for (int i=data.getIndex();i<end;i++)
327 array[i]^=_mask[_m++%4];
328 }
329
330
331 events++;
332 _handler.onFrame(_flags, _opcode, data);
333 _bytesNeeded=0;
334 _state=State.START;
335 }
336
337 return total_filled+events;
338 }
339 }
340 }
341
342
343 public void fill(Buffer buffer)
344 {
345 if (buffer!=null && buffer.length()>0)
346 {
347 if (_buffer==null)
348 _buffer=_buffers.getBuffer();
349
350 _buffer.put(buffer);
351 buffer.clear();
352 }
353 }
354
355
356 public void returnBuffer()
357 {
358 if (_buffer!=null && _buffer.length()==0)
359 {
360 _buffers.returnBuffer(_buffer);
361 _buffer=null;
362 }
363 }
364
365
366 @Override
367 public String toString()
368 {
369 Buffer buffer=_buffer;
370 return WebSocketParserD13.class.getSimpleName()+"@"+ Integer.toHexString(hashCode())+"|"+_state+"|"+(buffer==null?"<>":buffer.toDetailString());
371 }
372
373 }