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