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.log.Log;
22  import org.eclipse.jetty.util.log.Logger;
23  
24  
25  
26  /* ------------------------------------------------------------ */
27  /**
28   * Parser the WebSocket protocol.
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       * @param buffers The buffers to use for parsing.  Only the {@link Buffers#getBuffer()} is used.
69       * This should be a direct buffer if binary data is mostly used or an indirect buffer if utf-8 data
70       * is mostly used.
71       * @param endp
72       * @param handler
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      /** Parse to next event.
97       * Parse to the next {@link WebSocketParser.FrameHandler} event or until no more data is
98       * available. Fill data from the {@link EndPoint} only as necessary.
99       * @return An indication of progress or otherwise. -1 indicates EOF, 0 indicates
100      * that no bytes were read and no messages parsed. A positive number indicates either
101      * the bytes filled or the messages parsed.
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         // Loop until an datagram call back or can't fill anymore
112         while(true)
113         {
114             int available=_buffer.length();
115 
116             // Fill buffer if we need a byte or need length
117             while (available<(_state==State.SKIP?1:_bytesNeeded))
118             {
119                 // compact to mark (set at start of data)
120                 _buffer.compact();
121 
122                 // if no space, then the data is too big for buffer
123                 if (_buffer.space() == 0)
124                     throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
125 
126                 // catch IOExceptions (probably EOF) and try to parse what we have
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             // if we are here, then we have sufficient bytes to process the current state.
143   
144             // Parse the buffer byte by byte (unless it is STATE_DATA)
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                 // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
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 }