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 WebSocketParserD06 implements WebSocketParser
32 {
33 private static final Logger LOG = Log.getLogger(WebSocketParserD06.class);
34
35 public enum State {
36
37 START(0), MASK(4), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), 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
53 private final WebSocketBuffers _buffers;
54 private final EndPoint _endp;
55 private final FrameHandler _handler;
56 private final boolean _masked;
57 private State _state;
58 private Buffer _buffer;
59 private byte _flags;
60 private byte _opcode;
61 private int _bytesNeeded;
62 private long _length;
63 private final byte[] _mask = new byte[4];
64 private int _m;
65
66
67
68
69
70
71
72
73
74
75 public WebSocketParserD06(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean masked)
76 {
77 _buffers=buffers;
78 _endp=endp;
79 _handler=handler;
80 _masked=masked;
81 _state=State.START;
82 }
83
84
85 public boolean isBufferEmpty()
86 {
87 return _buffer==null || _buffer.length()==0;
88 }
89
90
91 public Buffer getBuffer()
92 {
93 return _buffer;
94 }
95
96
97
98
99
100
101
102
103
104 public int parseNext()
105 {
106 if (_buffer==null)
107 _buffer=_buffers.getBuffer();
108
109 int total_filled=0;
110 int events=0;
111
112
113 while(true)
114 {
115 int available=_buffer.length();
116
117
118 while (available<(_state==State.SKIP?1:_bytesNeeded))
119 {
120
121 _buffer.compact();
122
123
124 if (_buffer.space() == 0)
125 throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
126
127
128 try
129 {
130 int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
131 if (filled<=0)
132 return (total_filled+events)>0?(total_filled+events):filled;
133 total_filled+=filled;
134 available=_buffer.length();
135 }
136 catch(IOException e)
137 {
138 LOG.debug(e);
139 return (total_filled+events)>0?(total_filled+events):-1;
140 }
141 }
142
143
144
145
146 byte b;
147 while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
148 {
149 switch (_state)
150 {
151 case START:
152 _state=_masked?State.MASK:State.OPCODE;
153 _bytesNeeded=_state.getNeeds();
154 continue;
155
156 case MASK:
157 _buffer.get(_mask,0,4);
158 available-=4;
159 _state=State.OPCODE;
160 _bytesNeeded=_state.getNeeds();
161 _m=0;
162 continue;
163
164 case OPCODE:
165 b=_buffer.get();
166 available--;
167 if (_masked)
168 b^=_mask[_m++%4];
169 _opcode=(byte)(b&0xf);
170 _flags=(byte)(0xf&(b>>4));
171
172 if (WebSocketConnectionD06.isControlFrame(_opcode)&&!WebSocketConnectionD06.isLastFrame(_flags))
173 {
174 _state=State.SKIP;
175 events++;
176 _handler.close(WebSocketConnectionD06.CLOSE_PROTOCOL,"fragmented control");
177 }
178 else
179 _state=State.LENGTH_7;
180
181 _bytesNeeded=_state.getNeeds();
182 continue;
183
184 case LENGTH_7:
185 b=_buffer.get();
186 available--;
187 if (_masked)
188 b^=_mask[_m++%4];
189 switch(b)
190 {
191 case 127:
192 _length=0;
193 _state=State.LENGTH_63;
194 _bytesNeeded=_state.getNeeds();
195 break;
196 case 126:
197 _length=0;
198 _state=State.LENGTH_16;
199 _bytesNeeded=_state.getNeeds();
200 break;
201 default:
202 _length=(0x7f&b);
203 _bytesNeeded=(int)_length;
204 _state=State.DATA;
205 }
206 continue;
207
208 case LENGTH_16:
209 b=_buffer.get();
210 available--;
211 if (_masked)
212 b^=_mask[_m++%4];
213 _length = _length*0x100 + (0xff&b);
214 if (--_bytesNeeded==0)
215 {
216 _bytesNeeded=(int)_length;
217 if (_length>_buffer.capacity())
218 {
219 _state=State.SKIP;
220 events++;
221 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
222 }
223 else
224 {
225 _state=State.DATA;
226 }
227 }
228 continue;
229
230 case LENGTH_63:
231 b=_buffer.get();
232 available--;
233 if (_masked)
234 b^=_mask[_m++%4];
235 _length = _length*0x100 + (0xff&b);
236 if (--_bytesNeeded==0)
237 {
238 _bytesNeeded=(int)_length;
239 if (_length>=_buffer.capacity())
240 {
241 _state=State.SKIP;
242 events++;
243 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
244 }
245 else
246 {
247 _state=State.DATA;
248 }
249 }
250 continue;
251
252 case SKIP:
253 int skip=Math.min(available,_bytesNeeded);
254 _buffer.skip(skip);
255 available-=skip;
256 _bytesNeeded-=skip;
257 if (_bytesNeeded==0)
258 _state=State.START;
259
260 }
261 }
262
263 if (_state==State.DATA && available>=_bytesNeeded)
264 {
265 Buffer data =_buffer.get(_bytesNeeded);
266 if (_masked)
267 {
268 if (data.array()==null)
269 data=_buffer.asMutableBuffer();
270 byte[] array = data.array();
271 final int end=data.putIndex();
272 for (int i=data.getIndex();i<end;i++)
273 array[i]^=_mask[_m++%4];
274 }
275
276
277 events++;
278 _handler.onFrame(_flags, _opcode, data);
279 _bytesNeeded=0;
280 _state=State.START;
281
282 if (_buffer.length()==0)
283 {
284 _buffers.returnBuffer(_buffer);
285 _buffer=null;
286 }
287
288 return total_filled+events;
289 }
290 }
291 }
292
293
294 public void fill(Buffer buffer)
295 {
296 if (buffer!=null && buffer.length()>0)
297 {
298 if (_buffer==null)
299 _buffer=_buffers.getBuffer();
300 _buffer.put(buffer);
301 buffer.clear();
302 }
303 }
304
305 }