PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParserD12.java

https://github.com/dekellum/jetty
Java | 373 lines | 266 code | 50 blank | 57 comment | 35 complexity | 7888aef04000c7c68fd3664ffd6fb461 MD5 | raw file
  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. package org.eclipse.jetty.websocket;
  14. import java.io.IOException;
  15. import org.eclipse.jetty.io.Buffer;
  16. import org.eclipse.jetty.io.Buffers;
  17. import org.eclipse.jetty.io.EndPoint;
  18. import org.eclipse.jetty.util.log.Log;
  19. import org.eclipse.jetty.util.log.Logger;
  20. /* ------------------------------------------------------------ */
  21. /**
  22. * Parser the WebSocket protocol.
  23. *
  24. */
  25. public class WebSocketParserD12 implements WebSocketParser
  26. {
  27. private static final Logger LOG = Log.getLogger(WebSocketParserD12.class);
  28. public enum State {
  29. START(0), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), MASK(4), PAYLOAD(0), DATA(0), SKIP(1);
  30. int _needs;
  31. State(int needs)
  32. {
  33. _needs=needs;
  34. }
  35. int getNeeds()
  36. {
  37. return _needs;
  38. }
  39. }
  40. private final WebSocketBuffers _buffers;
  41. private final EndPoint _endp;
  42. private final FrameHandler _handler;
  43. private final boolean _shouldBeMasked;
  44. private State _state;
  45. private Buffer _buffer;
  46. private byte _flags;
  47. private byte _opcode;
  48. private int _bytesNeeded;
  49. private long _length;
  50. private boolean _masked;
  51. private final byte[] _mask = new byte[4];
  52. private int _m;
  53. private boolean _skip;
  54. private boolean _fakeFragments=true;
  55. /* ------------------------------------------------------------ */
  56. /**
  57. * @param buffers The buffers to use for parsing. Only the {@link Buffers#getBuffer()} is used.
  58. * This should be a direct buffer if binary data is mostly used or an indirect buffer if utf-8 data
  59. * is mostly used.
  60. * @param endp the endpoint
  61. * @param handler the handler to notify when a parse event occurs
  62. * @param shouldBeMasked whether masking should be handled
  63. */
  64. public WebSocketParserD12(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean shouldBeMasked)
  65. {
  66. _buffers=buffers;
  67. _endp=endp;
  68. _handler=handler;
  69. _shouldBeMasked=shouldBeMasked;
  70. _state=State.START;
  71. }
  72. /* ------------------------------------------------------------ */
  73. /**
  74. * @return True if fake fragments should be created for frames larger than the buffer.
  75. */
  76. public boolean isFakeFragments()
  77. {
  78. return _fakeFragments;
  79. }
  80. /* ------------------------------------------------------------ */
  81. /**
  82. * @param fakeFragments True if fake fragments should be created for frames larger than the buffer.
  83. */
  84. public void setFakeFragments(boolean fakeFragments)
  85. {
  86. _fakeFragments = fakeFragments;
  87. }
  88. /* ------------------------------------------------------------ */
  89. public boolean isBufferEmpty()
  90. {
  91. return _buffer==null || _buffer.length()==0;
  92. }
  93. /* ------------------------------------------------------------ */
  94. public Buffer getBuffer()
  95. {
  96. return _buffer;
  97. }
  98. /* ------------------------------------------------------------ */
  99. /** Parse to next event.
  100. * Parse to the next {@link WebSocketParser.FrameHandler} event or until no more data is
  101. * available. Fill data from the {@link EndPoint} only as necessary.
  102. * @return An indication of progress or otherwise. -1 indicates EOF, 0 indicates
  103. * that no bytes were read and no messages parsed. A positive number indicates either
  104. * the bytes filled or the messages parsed.
  105. */
  106. public int parseNext()
  107. {
  108. if (_buffer==null)
  109. _buffer=_buffers.getBuffer();
  110. int total_filled=0;
  111. int events=0;
  112. // Loop until a datagram call back or can't fill anymore
  113. while(true)
  114. {
  115. int available=_buffer.length();
  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. // if no space, then the data is too big for buffer
  122. if (_buffer.space() == 0)
  123. {
  124. // Can we send a fake frame?
  125. if (_fakeFragments && _state==State.DATA)
  126. {
  127. Buffer data =_buffer.get(4*(available/4));
  128. _buffer.compact();
  129. if (_masked)
  130. {
  131. if (data.array()==null)
  132. data=_buffer.asMutableBuffer();
  133. byte[] array = data.array();
  134. final int end=data.putIndex();
  135. for (int i=data.getIndex();i<end;i++)
  136. array[i]^=_mask[_m++%4];
  137. }
  138. // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
  139. events++;
  140. _bytesNeeded-=data.length();
  141. _handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD12.FLAG_FIN)), _opcode, data);
  142. _opcode=WebSocketConnectionD12.OP_CONTINUATION;
  143. }
  144. if (_buffer.space() == 0)
  145. throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
  146. }
  147. // catch IOExceptions (probably EOF) and try to parse what we have
  148. try
  149. {
  150. int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
  151. if (filled<=0)
  152. return (total_filled+events)>0?(total_filled+events):filled;
  153. total_filled+=filled;
  154. available=_buffer.length();
  155. }
  156. catch(IOException e)
  157. {
  158. LOG.debug(e);
  159. return (total_filled+events)>0?(total_filled+events):-1;
  160. }
  161. }
  162. // if we are here, then we have sufficient bytes to process the current state.
  163. // Parse the buffer byte by byte (unless it is STATE_DATA)
  164. byte b;
  165. while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded))
  166. {
  167. switch (_state)
  168. {
  169. case START:
  170. _skip=false;
  171. _state=State.OPCODE;
  172. _bytesNeeded=_state.getNeeds();
  173. continue;
  174. case OPCODE:
  175. b=_buffer.get();
  176. available--;
  177. _opcode=(byte)(b&0xf);
  178. _flags=(byte)(0xf&(b>>4));
  179. if (WebSocketConnectionD12.isControlFrame(_opcode)&&!WebSocketConnectionD12.isLastFrame(_flags))
  180. {
  181. events++;
  182. LOG.warn("Fragmented Control from "+_endp);
  183. _handler.close(WebSocketConnectionD12.CLOSE_PROTOCOL,"Fragmented control");
  184. _skip=true;
  185. }
  186. _state=State.LENGTH_7;
  187. _bytesNeeded=_state.getNeeds();
  188. continue;
  189. case LENGTH_7:
  190. b=_buffer.get();
  191. available--;
  192. _masked=(b&0x80)!=0;
  193. b=(byte)(0x7f&b);
  194. switch(b)
  195. {
  196. case 0x7f:
  197. _length=0;
  198. _state=State.LENGTH_63;
  199. break;
  200. case 0x7e:
  201. _length=0;
  202. _state=State.LENGTH_16;
  203. break;
  204. default:
  205. _length=(0x7f&b);
  206. _state=_masked?State.MASK:State.PAYLOAD;
  207. }
  208. _bytesNeeded=_state.getNeeds();
  209. continue;
  210. case LENGTH_16:
  211. b=_buffer.get();
  212. available--;
  213. _length = _length*0x100 + (0xff&b);
  214. if (--_bytesNeeded==0)
  215. {
  216. if (_length>_buffer.capacity() && !_fakeFragments)
  217. {
  218. events++;
  219. _handler.close(WebSocketConnectionD12.CLOSE_BADDATA,"frame size "+_length+">"+_buffer.capacity());
  220. _skip=true;
  221. }
  222. _state=_masked?State.MASK:State.PAYLOAD;
  223. _bytesNeeded=_state.getNeeds();
  224. }
  225. continue;
  226. case LENGTH_63:
  227. b=_buffer.get();
  228. available--;
  229. _length = _length*0x100 + (0xff&b);
  230. if (--_bytesNeeded==0)
  231. {
  232. _bytesNeeded=(int)_length;
  233. if (_length>=_buffer.capacity() && !_fakeFragments)
  234. {
  235. events++;
  236. _handler.close(WebSocketConnectionD12.CLOSE_BADDATA,"frame size "+_length+">"+_buffer.capacity());
  237. _skip=true;
  238. }
  239. _state=_masked?State.MASK:State.PAYLOAD;
  240. _bytesNeeded=_state.getNeeds();
  241. }
  242. continue;
  243. case MASK:
  244. _buffer.get(_mask,0,4);
  245. _m=0;
  246. available-=4;
  247. _state=State.PAYLOAD;
  248. _bytesNeeded=_state.getNeeds();
  249. break;
  250. case PAYLOAD:
  251. _bytesNeeded=(int)_length;
  252. _state=_skip?State.SKIP:State.DATA;
  253. break;
  254. case DATA:
  255. break;
  256. case SKIP:
  257. int skip=Math.min(available,_bytesNeeded);
  258. _buffer.skip(skip);
  259. available-=skip;
  260. _bytesNeeded-=skip;
  261. if (_bytesNeeded==0)
  262. _state=State.START;
  263. }
  264. }
  265. if (_state==State.DATA && available>=_bytesNeeded)
  266. {
  267. if ( _masked!=_shouldBeMasked)
  268. {
  269. _buffer.skip(_bytesNeeded);
  270. _state=State.START;
  271. events++;
  272. _handler.close(WebSocketConnectionD12.CLOSE_PROTOCOL,"bad mask");
  273. }
  274. else
  275. {
  276. Buffer data =_buffer.get(_bytesNeeded);
  277. if (_masked)
  278. {
  279. if (data.array()==null)
  280. data=_buffer.asMutableBuffer();
  281. byte[] array = data.array();
  282. final int end=data.putIndex();
  283. for (int i=data.getIndex();i<end;i++)
  284. array[i]^=_mask[_m++%4];
  285. }
  286. // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
  287. events++;
  288. _handler.onFrame(_flags, _opcode, data);
  289. _bytesNeeded=0;
  290. _state=State.START;
  291. }
  292. return total_filled+events;
  293. }
  294. }
  295. }
  296. /* ------------------------------------------------------------ */
  297. public void fill(Buffer buffer)
  298. {
  299. if (buffer!=null && buffer.length()>0)
  300. {
  301. if (_buffer==null)
  302. _buffer=_buffers.getBuffer();
  303. _buffer.put(buffer);
  304. buffer.clear();
  305. }
  306. }
  307. /* ------------------------------------------------------------ */
  308. public void returnBuffer()
  309. {
  310. if (_buffer!=null && _buffer.length()==0)
  311. {
  312. _buffers.returnBuffer(_buffer);
  313. _buffer=null;
  314. }
  315. }
  316. /* ------------------------------------------------------------ */
  317. @Override
  318. public String toString()
  319. {
  320. Buffer buffer=_buffer;
  321. return WebSocketParserD12.class.getSimpleName()+"@"+ Integer.toHexString(hashCode())+"|"+_state+"|"+(buffer==null?"<>":buffer.toDetailString());
  322. }
  323. }