DraftHybi10Processor.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Threading;
  9. using SuperSocket.Common;
  10. using SuperSocket.SocketBase;
  11. using SuperSocket.SocketBase.Protocol;
  12. namespace SuperWebSocket.Protocol
  13. {
  14. /// <summary>
  15. /// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
  16. /// </summary>
  17. class DraftHybi10Processor : ProtocolProcessorBase
  18. {
  19. private const string m_Magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  20. protected DraftHybi10Processor(int version, ICloseStatusCode closeStatusCode)
  21. : base(version, closeStatusCode)
  22. {
  23. }
  24. public DraftHybi10Processor()
  25. : base(8, new CloseStatusCodeHybi10())
  26. {
  27. }
  28. private const string m_OriginKey = "Sec-WebSocket-Origin";
  29. protected virtual string OriginKey
  30. {
  31. get { return m_OriginKey; }
  32. }
  33. public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter<IWebSocketFragment> dataFrameReader)
  34. {
  35. if (!VersionTag.Equals(session.SecWebSocketVersion) && NextProcessor != null)
  36. {
  37. return NextProcessor.Handshake(session, previousFilter, out dataFrameReader);
  38. }
  39. dataFrameReader = null;
  40. session.ProtocolProcessor = this;
  41. if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue<string>(OriginKey, string.Empty)))
  42. return false;
  43. var secWebSocketKey = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey, string.Empty);
  44. if (string.IsNullOrEmpty(secWebSocketKey))
  45. {
  46. return false;
  47. }
  48. var responseBuilder = new StringBuilder();
  49. string secKeyAccept = string.Empty;
  50. try
  51. {
  52. secKeyAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secWebSocketKey + m_Magic)));
  53. }
  54. catch (Exception)
  55. {
  56. return false;
  57. }
  58. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine10);
  59. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine);
  60. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine);
  61. responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseAcceptLine, secKeyAccept);
  62. var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue<string>(WebSocketConstant.SecWebSocketProtocol, string.Empty));
  63. if (!string.IsNullOrEmpty(subProtocol))
  64. responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol);
  65. responseBuilder.AppendWithCrCf();
  66. byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString());
  67. session.SendRawData(data, 0, data.Length);
  68. dataFrameReader = new WebSocketDataFrameReceiveFilter();
  69. return true;
  70. }
  71. public override bool CanSendBinaryData
  72. {
  73. get { return true; }
  74. }
  75. public override void SendData(IWebSocketSession session, byte[] data, int offset, int length)
  76. {
  77. SendPackage(session, OpCode.Binary, data, offset, length);
  78. }
  79. public override void SendMessage(IWebSocketSession session, string message)
  80. {
  81. SendMessage(session, OpCode.Text, message);
  82. }
  83. public override void SendCloseHandshake(IWebSocketSession session, int statusCode, string closeReason)
  84. {
  85. byte[] playloadData = new byte[(string.IsNullOrEmpty(closeReason) ? 0 : Encoding.UTF8.GetMaxByteCount(closeReason.Length)) + 2];
  86. int highByte = statusCode / 256;
  87. int lowByte = statusCode % 256;
  88. playloadData[0] = (byte)highByte;
  89. playloadData[1] = (byte)lowByte;
  90. var playloadLength = playloadData.Length;
  91. if (!string.IsNullOrEmpty(closeReason))
  92. {
  93. int bytesCount = Encoding.UTF8.GetBytes(closeReason, 0, closeReason.Length, playloadData, 2);
  94. playloadLength = bytesCount + 2;
  95. }
  96. SendPackage(session, OpCode.Close, playloadData, 0, playloadLength);
  97. }
  98. public override void SendPong(IWebSocketSession session, byte[] pong)
  99. {
  100. SendPackage(session, OpCode.Pong, pong, 0, pong.Length);
  101. }
  102. public override void SendPing(IWebSocketSession session, byte[] ping)
  103. {
  104. SendPackage(session, OpCode.Ping, ping, 0, ping.Length);
  105. }
  106. public override IList<ArraySegment<byte>> GetEncodedPackage(int opCode, byte[] data, int offset, int length)
  107. {
  108. byte[] head;
  109. if (length < 126)
  110. {
  111. head = new byte[2];
  112. head[1] = (byte)length;
  113. }
  114. else if (length < 65536)
  115. {
  116. head = new byte[4];
  117. head[1] = (byte)126;
  118. head[2] = (byte)(length / 256);
  119. head[3] = (byte)(length % 256);
  120. }
  121. else
  122. {
  123. head = new byte[10];
  124. head[1] = (byte)127;
  125. int left = length;
  126. int unit = 256;
  127. for (int i = 9; i > 1; i--)
  128. {
  129. head[i] = (byte)(left % unit);
  130. left = left / unit;
  131. if (left == 0)
  132. break;
  133. }
  134. }
  135. head[0] = (byte)(opCode | 0x80); //No mask by default
  136. return new ArraySegment<byte>[] { new ArraySegment<byte>(head), new ArraySegment<byte>(data, offset, length) };
  137. }
  138. public override IList<ArraySegment<byte>> GetEncodedPackage(int opCode, string message)
  139. {
  140. byte[] playloadData = Encoding.UTF8.GetBytes(message);
  141. return GetEncodedPackage(opCode, playloadData, 0, playloadData.Length);
  142. }
  143. private byte[] GetPackageData(int opCode, byte[] data, int offset, int length)
  144. {
  145. byte[] fragment;
  146. if (length < 126)
  147. {
  148. fragment = new byte[2 + length];
  149. fragment[1] = (byte)length;
  150. }
  151. else if (length < 65536)
  152. {
  153. fragment = new byte[4 + length];
  154. fragment[1] = (byte)126;
  155. fragment[2] = (byte)(length / 256);
  156. fragment[3] = (byte)(length % 256);
  157. }
  158. else
  159. {
  160. fragment = new byte[10 + length];
  161. fragment[1] = (byte)127;
  162. int left = length;
  163. int unit = 256;
  164. for (int i = 9; i > 1; i--)
  165. {
  166. fragment[i] = (byte)(left % unit);
  167. left = left / unit;
  168. if (left == 0)
  169. break;
  170. }
  171. }
  172. fragment[0] = (byte)(opCode | 0x80);
  173. if (length > 0)
  174. {
  175. Buffer.BlockCopy(data, offset, fragment, fragment.Length - length, length);
  176. }
  177. return fragment;
  178. }
  179. private void SendPackage(IWebSocketSession session, int opCode, byte[] data, int offset, int length)
  180. {
  181. var fragment = GetPackageData(opCode, data, offset, length);
  182. session.SendRawData(fragment, 0, fragment.Length);
  183. }
  184. private bool TrySendPackage(IWebSocketSession session, int opCode, byte[] data, int offset, int length)
  185. {
  186. var fragment = GetPackageData(opCode, data, offset, length);
  187. return session.TrySendRawData(fragment, 0, fragment.Length);
  188. }
  189. private void SendMessage(IWebSocketSession session, int opCode, string message)
  190. {
  191. byte[] playloadData = Encoding.UTF8.GetBytes(message);
  192. SendPackage(session, opCode, playloadData, 0, playloadData.Length);
  193. }
  194. private bool TrySendMessage(IWebSocketSession session, int opCode, string message)
  195. {
  196. byte[] playloadData = Encoding.UTF8.GetBytes(message);
  197. return TrySendPackage(session, opCode, playloadData, 0, playloadData.Length);
  198. }
  199. public override bool IsValidCloseCode(int code)
  200. {
  201. var closeCode = this.CloseStatusClode;
  202. if (code >= 0 && code <= 999)
  203. return false;
  204. if (code >= 1000 && code <= 1999)
  205. {
  206. if (code == closeCode.NormalClosure
  207. || code == closeCode.GoingAway
  208. || code == closeCode.ProtocolError
  209. || code == closeCode.NotAcceptableData
  210. || code == closeCode.TooLargeFrame
  211. || code == closeCode.InvalidUTF8)
  212. {
  213. return true;
  214. }
  215. return false;
  216. }
  217. if (code >= 2000 && code <= 4999)
  218. return true;
  219. return false;
  220. }
  221. public override bool TrySendMessage(IWebSocketSession session, string message)
  222. {
  223. return TrySendMessage(session, OpCode.Text, message);
  224. }
  225. public override bool TrySendData(IWebSocketSession session, byte[] data, int offset, int length)
  226. {
  227. return TrySendPackage(session, OpCode.Binary, data, offset, length);
  228. }
  229. }
  230. }