View Javadoc

1   // ========================================================================
2   // Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
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.TypeUtil;
22  import org.eclipse.jetty.util.Utf8StringBuilder;
23  import org.eclipse.jetty.util.log.Log;
24  
25  
26  
27  /* ------------------------------------------------------------ */
28  /**
29   * Parser the WebSocket protocol.
30   *
31   */
32  public class WebSocketParserD06 implements WebSocketParser
33  {    
34      public enum State { 
35          
36          START(0), MASK(4), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), DATA(0), SKIP(1);
37  
38          int _needs;
39  
40          State(int needs)
41          {
42              _needs=needs;
43          }
44  
45          int getNeeds()
46          {
47              return _needs;
48          }
49      };
50  
51  
52      private final WebSocketBuffers _buffers;
53      private final EndPoint _endp;
54      private final FrameHandler _handler;
55      private final boolean _masked;
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 final byte[] _mask = new byte[4];
63      private int _m;
64  
65      /* ------------------------------------------------------------ */
66      /**
67       * @param buffers The buffers to use for parsing.  Only the {@link Buffers#getBuffer()} is used.
68       * This should be a direct buffer if binary data is mostly used or an indirect buffer if utf-8 data
69       * is mostly used.
70       * @param endp
71       * @param handler
72       */
73      public WebSocketParserD06(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean masked)
74      {
75          _buffers=buffers;
76          _endp=endp;
77          _handler=handler;
78          _masked=masked;
79          _state=State.START;
80      }
81  
82      /* ------------------------------------------------------------ */
83      public boolean isBufferEmpty()
84      {
85          return _buffer==null || _buffer.length()==0;
86      }
87  
88      /* ------------------------------------------------------------ */
89      public Buffer getBuffer()
90      {
91          return _buffer;
92      }
93  
94      /* ------------------------------------------------------------ */
95      /** Parse to next event.
96       * Parse to the next {@link WebSocketParser.FrameHandler} event or until no more data is
97       * available. Fill data from the {@link EndPoint} only as necessary.
98       * @return An indication of progress or otherwise. -1 indicates EOF, 0 indicates
99       * that no bytes were read and no messages parsed. A positive number indicates either
100      * the bytes filled or the messages parsed.
101      */
102     public int parseNext()
103     {
104         if (_buffer==null)
105             _buffer=_buffers.getBuffer();
106 
107         int total_filled=0;
108         int events=0;
109 
110         // Loop until an datagram call back or can't fill anymore
111         while(true)
112         {
113             int available=_buffer.length();
114 
115             // Fill buffer if we need a byte or need length
116             while (available<(_state==State.SKIP?1:_bytesNeeded))
117             {
118                 // compact to mark (set at start of data)
119                 _buffer.compact();
120 
121                 // if no space, then the data is too big for buffer
122                 if (_buffer.space() == 0)
123                     throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
124 
125                 // catch IOExceptions (probably EOF) and try to parse what we have
126                 try
127                 {
128                     int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
129                     if (filled<=0)
130                         return (total_filled+events)>0?(total_filled+events):filled;
131                     total_filled+=filled;
132                     available=_buffer.length();
133                 }
134                 catch(IOException e)
135                 {
136                     Log.debug(e);
137                     return (total_filled+events)>0?(total_filled+events):-1;
138                 }
139             }
140 
141             // if we are here, then we have sufficient bytes to process the current state.
142   
143             // Parse the buffer byte by byte (unless it is STATE_DATA)
144             byte b;
145             while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
146             {
147                 switch (_state)
148                 {
149                     case START:
150                         _state=_masked?State.MASK:State.OPCODE;
151                         _bytesNeeded=_state.getNeeds();
152                         continue;
153                     
154                     case MASK:
155                         _buffer.get(_mask,0,4);
156                         available-=4;
157                         _state=State.OPCODE;
158                         _bytesNeeded=_state.getNeeds();
159                         _m=0;
160                         continue;
161                         
162                     case OPCODE:
163                         b=_buffer.get();
164                         available--;
165                         if (_masked)
166                             b^=_mask[_m++%4];
167                         _opcode=(byte)(b&0xf);
168                         _flags=(byte)(0xf&(b>>4));
169                         
170                         if (WebSocketConnectionD06.isControlFrame(_opcode)&&!WebSocketConnectionD06.isLastFrame(_flags))
171                         {
172                             _state=State.SKIP;
173                             events++;
174                             _handler.close(WebSocketConnectionD06.CLOSE_PROTOCOL,"fragmented control");
175                         }
176                         else
177                             _state=State.LENGTH_7;
178 
179                         _bytesNeeded=_state.getNeeds();
180                         continue;
181 
182                     case LENGTH_7:
183                         b=_buffer.get();
184                         available--;
185                         if (_masked)
186                             b^=_mask[_m++%4];
187                         switch(b)
188                         {
189                             case 127:
190                                 _length=0;
191                                 _state=State.LENGTH_63;
192                                 _bytesNeeded=_state.getNeeds();
193                                 break;
194                             case 126:
195                                 _length=0;
196                                 _state=State.LENGTH_16;
197                                 _bytesNeeded=_state.getNeeds();
198                                 break;
199                             default:
200                                 _length=(0x7f&b);
201                                 _bytesNeeded=(int)_length;
202                                 _state=State.DATA; 
203                         }
204                         continue;
205 
206                     case LENGTH_16:
207                         b=_buffer.get();
208                         available--;
209                         if (_masked)
210                             b^=_mask[_m++%4];
211                         _length = _length*0x100 + (0xff&b);
212                         if (--_bytesNeeded==0)
213                         {
214                             _bytesNeeded=(int)_length;
215                             if (_length>_buffer.capacity())
216                             {
217                                 _state=State.SKIP;
218                                 events++;
219                                 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
220                             }
221                             else
222                             {
223                                 _state=State.DATA;
224                             }
225                         }
226                         continue;
227 
228                     case LENGTH_63:
229                         b=_buffer.get();
230                         available--;
231                         if (_masked)
232                             b^=_mask[_m++%4];
233                         _length = _length*0x100 + (0xff&b);
234                         if (--_bytesNeeded==0)
235                         {
236                             _bytesNeeded=(int)_length;
237                             if (_length>=_buffer.capacity())
238                             {
239                                 _state=State.SKIP;
240                                 events++;
241                                 _handler.close(WebSocketConnectionD06.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
242                             }
243                             else
244                             {
245                                 _state=State.DATA;
246                             }
247                         }
248                         continue;
249                         
250                     case SKIP:
251                         int skip=Math.min(available,_bytesNeeded);
252                         _buffer.skip(skip);
253                         available-=skip;
254                         _bytesNeeded-=skip;
255                         if (_bytesNeeded==0)
256                             _state=State.START;
257                         
258                 }
259             }
260 
261             if (_state==State.DATA && available>=_bytesNeeded)
262             {
263                 Buffer data =_buffer.get(_bytesNeeded);
264                 if (_masked)
265                 {
266                     if (data.array()==null)
267                         data=_buffer.asMutableBuffer();
268                     byte[] array = data.array();
269                     final int end=data.putIndex();
270                     for (int i=data.getIndex();i<end;i++)
271                         array[i]^=_mask[_m++%4];
272                 }
273 
274                 // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
275                 events++;
276                 _handler.onFrame(_flags, _opcode, data);
277                 _bytesNeeded=0;
278                 _state=State.START;
279 
280                 if (_buffer.length()==0)
281                 {
282                     _buffers.returnBuffer(_buffer);
283                     _buffer=null;
284                 }
285 
286                 return total_filled+events;
287             }
288         }
289     }
290 
291     /* ------------------------------------------------------------ */
292     public void fill(Buffer buffer)
293     {
294         if (buffer!=null && buffer.length()>0)
295         {
296             if (_buffer==null)
297                 _buffer=_buffers.getBuffer();
298             _buffer.put(buffer);
299             buffer.clear();
300         }
301     }
302 
303 }