public bool Handshake(WebSocketContext context) { Context = context; var handshakeValidator = context.Channel as IHandshakeValidator; var request = context.HandshakeRequest; var channel = context.Channel; if (handshakeValidator != null) { if (!handshakeValidator.ValidateHandshake(channel, context.HandshakeRequest)) { //TODO: do something like send error code? channel.Close(); return(false); } } var secWebSocketKey = request.Get(WebSocketConstant.SecWebSocketKey); if (string.IsNullOrEmpty(secWebSocketKey)) { //TODO: do something like send error code? channel.Close(); return(false); } var responseBuilder = new StringBuilder(); string secKeyAccept = string.Empty; try { secKeyAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secWebSocketKey + m_Magic))); } catch (Exception) { //TODO: do something like send error code? channel.Close(); return(false); } responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine10); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseAcceptLine, secKeyAccept); ///TODO: get available sub protocols //var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue<string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); //if (!string.IsNullOrEmpty(subProtocol)) // responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); channel.Send(new ArraySegment <byte>(data)); return(true); }
public override StringPackageInfo ResolvePackage(IList <ArraySegment <byte> > packageData) { var session = AppContext.CurrentSession; var bufferManager = session.AppServer.BufferManager; var context = WebSocketContext.Get(session); var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); if (!string.IsNullOrEmpty(context.Origin)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, context.Origin); } responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, context.UriScheme, context.Host, context.Path); var subProtocol = context.GetAvailableSubProtocol(); if (!string.IsNullOrEmpty(subProtocol)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); } responseBuilder.AppendWithCrCf(); var response = responseBuilder.ToString(); var encoding = Encoding.UTF8; var data = bufferManager.GetBuffer(encoding.GetMaxByteCount(response.Length)); var length = encoding.GetBytes(response, 0, response.Length, data, 0); var secKey1 = context.HandshakeRequest.Get(WebSocketConstant.SecWebSocketKey1); var secKey2 = context.HandshakeRequest.Get(WebSocketConstant.SecWebSocketKey2); byte[] secret; if (packageData.Count == 1) { secret = GetResponseSecurityKey(secKey1, secKey2, packageData[0]); } else { var secKey3 = bufferManager.GetBuffer(8); try { secret = GetResponseSecurityKey(secKey1, secKey2, new ArraySegment <byte>(secKey3)); } finally { bufferManager.ReturnBuffer(secKey3); } } session.SocketSession.TrySend(new ArraySegment <byte>(secret)); NextReceiveFilter = new DraftHybi00DataReceiveFilter(); return(null); }
public override WebSocketPackageInfo ResolvePackage(IList <ArraySegment <byte> > packageData) { var context = Context; var bufferManager = context.BufferManager; var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); if (!string.IsNullOrEmpty(context.Origin)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, context.Origin); } responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, context.UriScheme, context.Host, context.Path); ///TODO: get available sub protocols //var subProtocol = context.GetAvailableSubProtocol(); //if (!string.IsNullOrEmpty(subProtocol)) // responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); responseBuilder.AppendWithCrCf(); var response = responseBuilder.ToString(); var encoding = Encoding.UTF8; byte[] data = encoding.GetBytes(response); context.Channel.Send(new ArraySegment <byte>(data)); var secKey1 = context.HandshakeRequest.Get(WebSocketConstant.SecWebSocketKey1); var secKey2 = context.HandshakeRequest.Get(WebSocketConstant.SecWebSocketKey2); byte[] secret; using (var stream = this.GetBufferStream(packageData)) { var secKey3 = bufferManager.GetBuffer(c_Key3Len); try { stream.Read(secKey3, 0, c_Key3Len); secret = GetResponseSecurityKey(secKey1, secKey2, new ArraySegment <byte>(secKey3, 0, c_Key3Len)); } finally { bufferManager.ReturnBuffer(secKey3); } } context.Channel.Send(new ArraySegment <byte>(secret)); NextReceiveFilter = new DraftHybi00DataReceiveFilter(context); return(null); }
public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter <IWebSocketFragment> dataFrameReader) { if (!VersionTag.Equals(session.SecWebSocketVersion) && NextProcessor != null) { return(NextProcessor.Handshake(session, previousFilter, out dataFrameReader)); } dataFrameReader = null; session.ProtocolProcessor = this; if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue <string>(OriginKey, string.Empty))) { return(false); } var secWebSocketKey = session.Items.GetValue <string>(WebSocketConstant.SecWebSocketKey, string.Empty); if (string.IsNullOrEmpty(secWebSocketKey)) { return(false); } var responseBuilder = new StringBuilder(); string secKeyAccept = string.Empty; try { secKeyAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secWebSocketKey + m_Magic))); } catch (Exception) { return(false); } responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine10); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseAcceptLine, secKeyAccept); var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue <string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); if (!string.IsNullOrEmpty(subProtocol)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); } responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); session.SendRawData(data, 0, data.Length); dataFrameReader = new WebSocketDataFrameReceiveFilter(); return(true); }
// Token: 0x060005C0 RID: 1472 RVA: 0x00019580 File Offset: 0x00017780 public override void SendHandshake(WebSocket websocket) { string text = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); string value = (text + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").CalculateChallenge(); websocket.Items[this.m_ExpectedAcceptKey] = value; StringBuilder stringBuilder = new StringBuilder(); if (websocket.HttpConnectProxy == null) { stringBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.PathAndQuery); } else { stringBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.ToString()); } stringBuilder.Append("Host: "); stringBuilder.AppendWithCrCf(websocket.HandshakeHost); stringBuilder.AppendWithCrCf("Upgrade: websocket"); stringBuilder.AppendWithCrCf("Connection: Upgrade"); stringBuilder.Append("Sec-WebSocket-Version: "); stringBuilder.AppendWithCrCf(base.VersionTag); stringBuilder.Append("Sec-WebSocket-Key: "); stringBuilder.AppendWithCrCf(text); stringBuilder.Append(string.Format("{0}: ", this.m_OriginHeaderName)); stringBuilder.AppendWithCrCf(websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { stringBuilder.Append("Sec-WebSocket-Protocol: "); stringBuilder.AppendWithCrCf(websocket.SubProtocol); } List <KeyValuePair <string, string> > cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] array = new string[cookies.Count]; for (int i = 0; i < cookies.Count; i++) { KeyValuePair <string, string> keyValuePair = cookies[i]; array[i] = keyValuePair.Key + "=" + Uri.EscapeUriString(keyValuePair.Value); } stringBuilder.Append("Cookie: "); stringBuilder.AppendWithCrCf(string.Join(";", array)); } if (websocket.CustomHeaderItems != null) { for (int j = 0; j < websocket.CustomHeaderItems.Count; j++) { KeyValuePair <string, string> keyValuePair2 = websocket.CustomHeaderItems[j]; stringBuilder.AppendFormatWithCrCf("{0}: {1}", new object[] { keyValuePair2.Key, keyValuePair2.Value }); } } stringBuilder.AppendWithCrCf(); byte[] bytes = Encoding.UTF8.GetBytes(stringBuilder.ToString()); websocket.Client.Send(bytes, 0, bytes.Length); }
public MultipleProtocolSwitchProcessor(int[] availableVersions) { var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf("HTTP/1.1 400 Bad Request"); responseBuilder.AppendWithCrCf("Upgrade: WebSocket"); responseBuilder.AppendWithCrCf("Connection: Upgrade"); responseBuilder.AppendWithCrCf("Sec-WebSocket-Version: " + string.Join(", ", availableVersions.Select(i => i.ToString()).ToArray())); responseBuilder.AppendWithCrCf(); m_SwitchResponse = Encoding.UTF8.GetBytes(responseBuilder.ToString()); }
public override void SendHandshake(WebSocket websocket) { string @string = Encoding.UTF8.GetString(GenerateSecKey()); string string2 = Encoding.UTF8.GetString(GenerateSecKey()); byte[] array = GenerateSecKey(8); m_ExpectedChallenge = GetResponseSecurityKey(@string, string2, array); StringBuilder stringBuilder = new StringBuilder(); if (websocket.HttpConnectProxy == null) { stringBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.PathAndQuery); } else { stringBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.ToString()); } stringBuilder.Append("Host: "); stringBuilder.AppendWithCrCf(websocket.TargetUri.Host); stringBuilder.AppendWithCrCf("Upgrade: WebSocket"); stringBuilder.AppendWithCrCf("Connection: Upgrade"); stringBuilder.Append("Sec-WebSocket-Key1: "); stringBuilder.AppendWithCrCf(@string); stringBuilder.Append("Sec-WebSocket-Key2: "); stringBuilder.AppendWithCrCf(string2); stringBuilder.Append("Origin: "); stringBuilder.AppendWithCrCf(string.IsNullOrEmpty(websocket.Origin) ? websocket.TargetUri.Host : websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { stringBuilder.Append("Sec-WebSocket-Protocol: "); stringBuilder.AppendWithCrCf(websocket.SubProtocol); } List <KeyValuePair <string, string> > cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] array2 = new string[cookies.Count]; for (int i = 0; i < cookies.Count; i++) { KeyValuePair <string, string> keyValuePair = cookies[i]; array2[i] = keyValuePair.Key + "=" + Uri.EscapeUriString(keyValuePair.Value); } stringBuilder.Append("Cookie: "); stringBuilder.AppendWithCrCf(string.Join(";", array2)); } if (websocket.CustomHeaderItems != null) { for (int j = 0; j < websocket.CustomHeaderItems.Count; j++) { KeyValuePair <string, string> keyValuePair2 = websocket.CustomHeaderItems[j]; stringBuilder.AppendFormatWithCrCf("{0}: {1}", keyValuePair2.Key, keyValuePair2.Value); } } stringBuilder.AppendWithCrCf(); stringBuilder.Append(Encoding.UTF8.GetString(array, 0, array.Length)); byte[] bytes = Encoding.UTF8.GetBytes(stringBuilder.ToString()); websocket.Client.Send(bytes, 0, bytes.Length); }
public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter<IWebSocketFragment> dataFrameReader) { if (!VersionTag.Equals(session.SecWebSocketVersion) && NextProcessor != null) { return NextProcessor.Handshake(session, previousFilter, out dataFrameReader); } dataFrameReader = null; session.ProtocolProcessor = this; if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue<string>(OriginKey, string.Empty))) return false; var secWebSocketKey = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey, string.Empty); if (string.IsNullOrEmpty(secWebSocketKey)) { return false; } var responseBuilder = new StringBuilder(); string secKeyAccept = string.Empty; try { secKeyAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secWebSocketKey + m_Magic))); } catch (Exception) { return false; } responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine10); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseAcceptLine, secKeyAccept); var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue<string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); if (!string.IsNullOrEmpty(subProtocol)) responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); session.SendRawData(data, 0, data.Length); dataFrameReader = new WebSocketDataFrameReceiveFilter(); return true; }
public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter <IWebSocketFragment> dataFrameReader) { var secKey1 = session.Items.GetValue <string>(WebSocketConstant.SecWebSocketKey1, string.Empty); var secKey2 = session.Items.GetValue <string>(WebSocketConstant.SecWebSocketKey2, string.Empty); dataFrameReader = null; if (string.IsNullOrEmpty(secKey1) && string.IsNullOrEmpty(secKey2) && NextProcessor != null) { return(NextProcessor.Handshake(session, previousFilter, out dataFrameReader)); } session.ProtocolProcessor = this; if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue <string>(WebSocketConstant.Origin, string.Empty))) { return(false); } var secKey3 = session.Items.GetValue <byte[]>(WebSocketConstant.SecWebSocketKey3, m_ZeroKeyBytes); var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); if (!string.IsNullOrEmpty(session.Origin)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, session.Origin); } responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, session.UriScheme, session.Host, session.Path); var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue <string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); if (!string.IsNullOrEmpty(subProtocol)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); } responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); session.SendRawData(data, 0, data.Length); //Encrypt message byte[] secret = GetResponseSecurityKey(secKey1, secKey2, secKey3); session.SendRawData(secret, 0, secret.Length); dataFrameReader = new WebSocketDataReceiveFilter(previousFilter); return(true); }
internal static byte[] CreateOpenningHandshakeBadRequestResponse(AsyncWebSocketSession session) { var sb = new StringBuilder(); // HTTP/1.1 400 Bad Request sb.AppendFormatWithCrCf("HTTP/{0} {1} {2}", Consts.HttpVersion, (int)HttpStatusCode.BadRequest, @"Bad Request"); // Upgrade: websocket sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // Connection: Upgrade sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // Sec-WebSocket-Version: 13 sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketVersion, Consts.WebSocketVersion); sb.AppendWithCrCf(); var response = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", session.RemoteEndPoint, Environment.NewLine, response); #endif return(Encoding.UTF8.GetBytes(response)); }
public bool TryHandshake(WebSocketContext context, out IWebSocketReceiveFilter filter) { var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf("HTTP/1.1 400 Bad Request"); responseBuilder.AppendWithCrCf("Upgrade: WebSocket"); responseBuilder.AppendWithCrCf("Connection: Upgrade"); responseBuilder.AppendWithCrCf("Sec-WebSocket-Version: " + string.Join(", ", m_Versions.Select(i => i.ToString()).ToArray())); responseBuilder.AppendWithCrCf(); var switchResponse = Encoding.UTF8.GetBytes(responseBuilder.ToString()); filter = new MultipleProtocolSwitchReceiveFilter(switchResponse); return(true); }
public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter<IWebSocketFragment> dataFrameReader) { var secKey1 = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey1, string.Empty); var secKey2 = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey2, string.Empty); dataFrameReader = null; if (string.IsNullOrEmpty(secKey1) && string.IsNullOrEmpty(secKey2) && NextProcessor != null) { return NextProcessor.Handshake(session, previousFilter, out dataFrameReader); } session.ProtocolProcessor = this; if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue<string>(WebSocketConstant.Origin, string.Empty))) return false; var secKey3 = session.Items.GetValue<byte[]>(WebSocketConstant.SecWebSocketKey3, m_ZeroKeyBytes); var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); if (!string.IsNullOrEmpty(session.Origin)) responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, session.Origin); responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, session.UriScheme, session.Host, session.Path); var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue<string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); if (!string.IsNullOrEmpty(subProtocol)) responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); session.SendRawData(data, 0, data.Length); //Encrypt message byte[] secret = GetResponseSecurityKey(secKey1, secKey2, secKey3); session.SendRawData(secret, 0, secret.Length); dataFrameReader = new WebSocketDataReceiveFilter(previousFilter); return true; }
private async Task <bool> HandleHandshake(IAppSession session, WebSocketPackage p) { const string requiredVersion = "13"; var version = p.HttpHeader.Items[WebSocketConstant.SecWebSocketVersion]; if (!requiredVersion.Equals(version)) { return(false); } var secWebSocketKey = p.HttpHeader.Items[WebSocketConstant.SecWebSocketKey]; if (string.IsNullOrEmpty(secWebSocketKey)) { return(false); } var responseBuilder = new StringBuilder(); string secKeyAccept = string.Empty; try { secKeyAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secWebSocketKey + _magic))); } catch (Exception) { return(false); } responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine10); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseAcceptLine, secKeyAccept); responseBuilder.AppendWithCrCf(); byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString()); await session.SendAsync(data); return(true); }
public override StringPackageInfo ResolvePackage(IList <ArraySegment <byte> > packageData) { var session = AppContext.CurrentSession; var bufferManager = session.AppServer.BufferManager; var websocketContext = WebSocketContext.Get(session) as IWebSocketSession; var responseBuilder = new StringBuilder(); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine); responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine); if (!string.IsNullOrEmpty(session.Origin)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, session.Origin); } responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, session.UriScheme, session.Host, session.Path); var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue <string>(WebSocketConstant.SecWebSocketProtocol, string.Empty)); if (!string.IsNullOrEmpty(subProtocol)) { responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol); } responseBuilder.AppendWithCrCf(); var response = responseBuilder.ToString(); var encoding = Encoding.UTF8; var data = bufferManager.GetBuffer(encoding.GetMaxByteCount(response.Length)); var length = encoding.GetBytes(response, 0, response.Length, data, 0); //Encrypt message byte[] secret = GetResponseSecurityKey(secKey1, secKey2, secKey3); throw new NotImplementedException(); }
public override void SendHandshake(WebSocket websocket) { string secKey1 = Encoding.UTF8.GetString(GenerateSecKey()); string secKey2 = Encoding.UTF8.GetString(GenerateSecKey()); byte[] secKey3 = GenerateSecKey(8); m_ExpectedChallenge = GetResponseSecurityKey(secKey1, secKey2, secKey3); var handshakeBuilder = new StringBuilder(); #if SILVERLIGHT handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.GetPathAndQuery()); #else handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.PathAndQuery); #endif handshakeBuilder.AppendWithCrCf("Upgrade: WebSocket"); handshakeBuilder.AppendWithCrCf("Connection: Upgrade"); handshakeBuilder.Append("Sec-WebSocket-Key1: "); handshakeBuilder.AppendWithCrCf(secKey1); handshakeBuilder.Append("Sec-WebSocket-Key2: "); handshakeBuilder.AppendWithCrCf(secKey2); handshakeBuilder.Append("Host: "); handshakeBuilder.AppendWithCrCf(websocket.TargetUri.Host); handshakeBuilder.Append("Origin: "); handshakeBuilder.AppendWithCrCf(string.IsNullOrEmpty(websocket.Origin) ? websocket.TargetUri.Host : websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { handshakeBuilder.Append("Sec-WebSocket-Protocol: "); handshakeBuilder.AppendWithCrCf(websocket.SubProtocol); } var cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] cookiePairs = new string[cookies.Count]; for (int i = 0; i < cookies.Count; i++) { var item = cookies[i]; cookiePairs[i] = item.Key + "=" + Uri.EscapeUriString(item.Value); } handshakeBuilder.Append("Cookie: "); handshakeBuilder.AppendWithCrCf(string.Join(";", cookiePairs)); } if (websocket.CustomHeaderItems != null) { for (var i = 0; i < websocket.CustomHeaderItems.Count; i++) { var item = websocket.CustomHeaderItems[i]; handshakeBuilder.AppendFormatWithCrCf(HeaderItemFormat, item.Key, item.Value); } } handshakeBuilder.AppendWithCrCf(); handshakeBuilder.Append(Encoding.UTF8.GetString(secKey3, 0, secKey3.Length)); byte[] handshakeBuffer = Encoding.UTF8.GetBytes(handshakeBuilder.ToString()); websocket.Client.Send(handshakeBuffer, 0, handshakeBuffer.Length); }
public override void SendHandshake(WebSocket websocket) { #if !SILVERLIGHT var secKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); #else var secKey = Convert.ToBase64String(ASCIIEncoding.Instance.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); #endif string expectedAccept = (secKey + m_Magic).CalculateChallenge(); websocket.Items[m_ExpectedAcceptKey] = expectedAccept; var handshakeBuilder = new StringBuilder(); if (websocket.HttpConnectProxy == null) { #if SILVERLIGHT handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.GetPathAndQuery()); #else handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.PathAndQuery); #endif } else { handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.ToString()); } handshakeBuilder.Append("Host: "); handshakeBuilder.AppendWithCrCf(websocket.HandshakeHost); handshakeBuilder.AppendWithCrCf("Upgrade: websocket"); handshakeBuilder.AppendWithCrCf("Connection: Upgrade"); handshakeBuilder.Append("Sec-WebSocket-Version: "); handshakeBuilder.AppendWithCrCf(VersionTag); handshakeBuilder.Append("Sec-WebSocket-Key: "); handshakeBuilder.AppendWithCrCf(secKey); handshakeBuilder.Append(string.Format("{0}: ", m_OriginHeaderName)); handshakeBuilder.AppendWithCrCf(websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { handshakeBuilder.Append("Sec-WebSocket-Protocol: "); handshakeBuilder.AppendWithCrCf(websocket.SubProtocol); } var cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] cookiePairs = new string[cookies.Count]; for (int i = 0; i < cookies.Count; i++) { var item = cookies[i]; cookiePairs[i] = item.Key + "=" + Uri.EscapeUriString(item.Value); } handshakeBuilder.Append("Cookie: "); handshakeBuilder.AppendWithCrCf(string.Join(";", cookiePairs)); } if (websocket.CustomHeaderItems != null) { for (var i = 0; i < websocket.CustomHeaderItems.Count; i++) { var item = websocket.CustomHeaderItems[i]; handshakeBuilder.AppendFormatWithCrCf(HeaderItemFormat, item.Key, item.Value); } } handshakeBuilder.AppendWithCrCf(); byte[] handshakeBuffer = Encoding.UTF8.GetBytes(handshakeBuilder.ToString()); websocket.Client.Send(handshakeBuffer, 0, handshakeBuffer.Length); }
internal static byte[] CreateOpenningHandshakeRequest(AsyncWebSocketClient client, out string secWebSocketKey) { var sb = new StringBuilder(); // The handshake MUST be a valid HTTP request as specified by [RFC2616]. // The method of the request MUST be GET, and the HTTP version MUST be at least 1.1. // For example, if the WebSocket URI is "ws://example.com/chat", // the first line sent should be "GET /chat HTTP/1.1". sb.AppendFormatWithCrCf("GET {0} HTTP/{1}", !string.IsNullOrEmpty(client.Uri.PathAndQuery) ? client.Uri.PathAndQuery : "/", Consts.HttpVersion); // The request MUST contain a |Host| header field whose value // contains /host/ plus optionally ":" followed by /port/ (when not // using the default port). sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Host, client.Uri.Host); // The request MUST contain an |Upgrade| header field whose value // MUST include the "websocket" keyword. sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // The request MUST contain a |Connection| header field whose value // MUST include the "Upgrade" token. sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // The request MUST include a header field with the name // |Sec-WebSocket-Key|. The value of this header field MUST be a // nonce consisting of a randomly selected 16-byte value that has // been base64-encoded (see Section 4 of [RFC4648]). The nonce // MUST be selected randomly for each connection. secWebSocketKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketKey, secWebSocketKey); // The request MUST include a header field with the name // |Sec-WebSocket-Version|. The value of this header field MUST be 13. sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketVersion, Consts.WebSocketVersion); // The request MAY include a header field with the name // |Sec-WebSocket-Extensions|. If present, this value indicates // the protocol-level extension(s) the client wishes to speak. The // interpretation and format of this header field is described in Section 9.1. if (client.OfferedExtensions != null && client.OfferedExtensions.Any()) { foreach (var extension in client.OfferedExtensions) { sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketExtensions, extension.ExtensionNegotiationOffer); } } // The request MAY include a header field with the name // |Sec-WebSocket-Protocol|. If present, this value indicates one // or more comma-separated subprotocol the client wishes to speak, // ordered by preference. The elements that comprise this value // MUST be non-empty strings with characters in the range U+0021 to // U+007E not including separator characters as defined in // [RFC2616] and MUST all be unique strings. The ABNF for the // value of this header field is 1#token, where the definitions of // constructs and rules are as given in [RFC2616]. if (client.RequestedSubProtocols != null && client.RequestedSubProtocols.Any()) { foreach (var description in client.RequestedSubProtocols) { sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketProtocol, description.RequestedSubProtocol); } } // The request MUST include a header field with the name |Origin| // [RFC6454] if the request is coming from a browser client. If // the connection is from a non-browser client, the request MAY // include this header field if the semantics of that client match // the use-case described here for browser clients. The value of // this header field is the ASCII serialization of origin of the // context in which the code establishing the connection is // running. See [RFC6454] for the details of how this header field // value is constructed. // The request MAY include any other header fields, for example, // cookies [RFC6265] and/or authentication-related header fields // such as the |Authorization| header field [RFC2616], which are // processed according to documents that define them. sb.AppendWithCrCf(); // GET /chat HTTP/1.1 // Host: server.example.com // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== // Sec-WebSocket-Protocol: chat, superchat // Sec-WebSocket-Version: 13 // Origin: http://example.com var request = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", client.RemoteEndPoint, Environment.NewLine, request); #endif return Encoding.UTF8.GetBytes(request); }
public override void SendHandshake(WebSocket websocket) { string str1 = Encoding.UTF8.GetString(this.GenerateSecKey()); string str2 = Encoding.UTF8.GetString(this.GenerateSecKey()); byte[] secKey = this.GenerateSecKey(8); this.m_ExpectedChallenge = this.GetResponseSecurityKey(str1, str2, secKey); StringBuilder builder = new StringBuilder(); if (websocket.HttpConnectProxy == null) { builder.AppendFormatWithCrCf("GET {0} HTTP/1.1", (object)websocket.TargetUri.PathAndQuery); } else { builder.AppendFormatWithCrCf("GET {0} HTTP/1.1", (object)websocket.TargetUri.ToString()); } builder.AppendWithCrCf("Upgrade: WebSocket"); builder.AppendWithCrCf("Connection: Upgrade"); builder.Append("Sec-WebSocket-Key1: "); builder.AppendWithCrCf(str1); builder.Append("Sec-WebSocket-Key2: "); builder.AppendWithCrCf(str2); builder.Append("Host: "); builder.AppendWithCrCf(websocket.TargetUri.Host); builder.Append("Origin: "); builder.AppendWithCrCf(string.IsNullOrEmpty(websocket.Origin) ? websocket.TargetUri.Host : websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { builder.Append("Sec-WebSocket-Protocol: "); builder.AppendWithCrCf(websocket.SubProtocol); } List <KeyValuePair <string, string> > cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] strArray = new string[cookies.Count]; for (int index = 0; index < cookies.Count; ++index) { KeyValuePair <string, string> keyValuePair = cookies[index]; strArray[index] = keyValuePair.Key + "=" + Uri.EscapeUriString(keyValuePair.Value); } builder.Append("Cookie: "); builder.AppendWithCrCf(string.Join(";", strArray)); } if (websocket.CustomHeaderItems != null) { for (int index = 0; index < websocket.CustomHeaderItems.Count; ++index) { KeyValuePair <string, string> customHeaderItem = websocket.CustomHeaderItems[index]; builder.AppendFormatWithCrCf("{0}: {1}", (object)customHeaderItem.Key, (object)customHeaderItem.Value); } } builder.AppendWithCrCf(); builder.Append(Encoding.UTF8.GetString(secKey, 0, secKey.Length)); byte[] bytes = Encoding.UTF8.GetBytes(builder.ToString()); websocket.Client.Send(bytes, 0, bytes.Length); }
internal static byte[] CreateOpenningHandshakeResponse(AsyncWebSocketSession session, string secWebSocketKey) { var sb = new StringBuilder(); // A Status-Line with a 101 response code as per RFC 2616 // [RFC2616]. Such a response could look like "HTTP/1.1 101 Switching Protocols". sb.AppendFormatWithCrCf("HTTP/{0} {1} {2}", Consts.HttpVersion, (int)HttpStatusCode.SwitchingProtocols, @"Switching Protocols"); // An |Upgrade| header field with value "websocket" as per RFC2616 [RFC2616]. sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // A |Connection| header field with value "Upgrade". sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // A |Sec-WebSocket-Accept| header field. The value of this // header field is constructed by concatenating /key/, defined // above in step 4 in Section 4.2.2, with the string "258EAFA5- // E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this // concatenated value to obtain a 20-byte value and base64- // encoding (see Section 4 of [RFC4648]) this 20-byte hash. var secWebSocketAccept = GetSecWebSocketAcceptString(secWebSocketKey); sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); // Optionally, a |Sec-WebSocket-Extensions| header field, with a // value /extensions/ as defined in step 4 in Section 4.2.2. If // multiple extensions are to be used, they can all be listed in // a single |Sec-WebSocket-Extensions| header field or split // between multiple instances of the |Sec-WebSocket-Extensions| header field. // A server accepts one or more extensions by including a // |Sec-WebSocket-Extensions| header field containing one or more // extensions that were requested by the client. The interpretation of // any extension parameters, and what constitutes a valid response by a // server to a requested set of parameters by a client, will be defined // by each such extension. if (session.NegotiatedExtensions != null && session.NegotiatedExtensions.Any()) { foreach (var extension in session.NegotiatedExtensions.Values) { var offer = extension.GetAgreedOffer(); sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketExtensions, offer); } } /** * // Optionally, a |Sec-WebSocket-Protocol| header field, with a * // value /subprotocol/ as defined in step 4 in Section 4.2.2. * // * // The client can request that the server use a specific subprotocol by * // including the |Sec-WebSocket-Protocol| field in its handshake. If it * // is specified, the server needs to include the same field and one of * // the selected subprotocol values in its response for the connection to * // be established. * // * // These subprotocol names should be registered as per Section 11.5. To * // avoid potential collisions, it is recommended to use names that * // contain the ASCII version of the domain name of the subprotocol's * // originator. For example, if Example Corporation were to create a * // Chat subprotocol to be implemented by many servers around the Web, * // they could name it "chat.example.com". If the Example Organization * // called their competing subprotocol "chat.example.org", then the two * // subprotocols could be implemented by servers simultaneously, with the * // server dynamically selecting which subprotocol to use based on the * // value sent by the client. * // * // Subprotocols can be versioned in backward-incompatible ways by * // changing the subprotocol name, e.g., going from * // "bookings.example.net" to "v2.bookings.example.net". These * // subprotocols would be considered completely separate by WebSocket * // clients. Backward-compatible versioning can be implemented by * // reusing the same subprotocol string but carefully designing the * // actual subprotocol to support this kind of extensibility. */ sb.AppendWithCrCf(); // HTTP/1.1 101 Switching Protocols // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Accept: 1tGBmA9p0DQDgmFll6P0/UcVS/E= // Sec-WebSocket-Protocol: chat var response = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", session.RemoteEndPoint, Environment.NewLine, response); #endif return(Encoding.UTF8.GetBytes(response)); }
internal static byte[] CreateOpenningHandshakeResponse(AsyncWebSocketSession session, string secWebSocketKey) { var sb = new StringBuilder(); // A Status-Line with a 101 response code as per RFC 2616 // [RFC2616]. Such a response could look like "HTTP/1.1 101 Switching Protocols". sb.AppendFormatWithCrCf("HTTP/{0} {1} {2}", Consts.HttpVersion, (int)HttpStatusCode.SwitchingProtocols, @"Switching Protocols"); // An |Upgrade| header field with value "websocket" as per RFC2616 [RFC2616]. sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // A |Connection| header field with value "Upgrade". sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // A |Sec-WebSocket-Accept| header field. The value of this // header field is constructed by concatenating /key/, defined // above in step 4 in Section 4.2.2, with the string "258EAFA5- // E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this // concatenated value to obtain a 20-byte value and base64- // encoding (see Section 4 of [RFC4648]) this 20-byte hash. var secWebSocketAccept = GetSecWebSocketAcceptString(secWebSocketKey); sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); // Optionally, a |Sec-WebSocket-Extensions| header field, with a // value /extensions/ as defined in step 4 in Section 4.2.2. If // multiple extensions are to be used, they can all be listed in // a single |Sec-WebSocket-Extensions| header field or split // between multiple instances of the |Sec-WebSocket-Extensions| header field. // A server accepts one or more extensions by including a // |Sec-WebSocket-Extensions| header field containing one or more // extensions that were requested by the client. The interpretation of // any extension parameters, and what constitutes a valid response by a // server to a requested set of parameters by a client, will be defined // by each such extension. if (session.NegotiatedExtensions != null && session.NegotiatedExtensions.Any()) { foreach (var extension in session.NegotiatedExtensions.Values) { var offer = extension.GetAgreedOffer(); sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketExtensions, offer); } } /** // Optionally, a |Sec-WebSocket-Protocol| header field, with a // value /subprotocol/ as defined in step 4 in Section 4.2.2. // // The client can request that the server use a specific subprotocol by // including the |Sec-WebSocket-Protocol| field in its handshake. If it // is specified, the server needs to include the same field and one of // the selected subprotocol values in its response for the connection to // be established. // // These subprotocol names should be registered as per Section 11.5. To // avoid potential collisions, it is recommended to use names that // contain the ASCII version of the domain name of the subprotocol's // originator. For example, if Example Corporation were to create a // Chat subprotocol to be implemented by many servers around the Web, // they could name it "chat.example.com". If the Example Organization // called their competing subprotocol "chat.example.org", then the two // subprotocols could be implemented by servers simultaneously, with the // server dynamically selecting which subprotocol to use based on the // value sent by the client. // // Subprotocols can be versioned in backward-incompatible ways by // changing the subprotocol name, e.g., going from // "bookings.example.net" to "v2.bookings.example.net". These // subprotocols would be considered completely separate by WebSocket // clients. Backward-compatible versioning can be implemented by // reusing the same subprotocol string but carefully designing the // actual subprotocol to support this kind of extensibility. */ sb.AppendWithCrCf(); // HTTP/1.1 101 Switching Protocols // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Accept: 1tGBmA9p0DQDgmFll6P0/UcVS/E= // Sec-WebSocket-Protocol: chat var response = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", session.RemoteEndPoint, Environment.NewLine, response); #endif return Encoding.UTF8.GetBytes(response); }
public override void SendHandshake(WebSocket websocket) { #if !SILVERLIGHT var secKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); string expectedAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(secKey + m_Magic))); #else var secKey = Convert.ToBase64String(ASCIIEncoding.Instance.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); string expectedAccept = Convert.ToBase64String(SHA1.Create().ComputeHash(ASCIIEncoding.Instance.GetBytes(secKey + m_Magic))); #endif websocket.Items[m_ExpectedAcceptKey] = expectedAccept; var handshakeBuilder = new StringBuilder(); #if SILVERLIGHT handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.GetPathAndQuery()); #else handshakeBuilder.AppendFormatWithCrCf("GET {0} HTTP/1.1", websocket.TargetUri.PathAndQuery); #endif handshakeBuilder.AppendWithCrCf("Upgrade: WebSocket"); handshakeBuilder.AppendWithCrCf("Connection: Upgrade"); handshakeBuilder.Append("Sec-WebSocket-Version: "); handshakeBuilder.AppendWithCrCf(VersionTag); handshakeBuilder.Append("Sec-WebSocket-Key: "); handshakeBuilder.AppendWithCrCf(secKey); handshakeBuilder.Append("Host: "); handshakeBuilder.AppendWithCrCf(websocket.HandshakeHost); handshakeBuilder.Append("Origin: "); handshakeBuilder.AppendWithCrCf(string.IsNullOrEmpty(websocket.Origin) ? websocket.TargetUri.Host : websocket.Origin); if (!string.IsNullOrEmpty(websocket.SubProtocol)) { handshakeBuilder.Append("Sec-WebSocket-Protocol: "); handshakeBuilder.AppendWithCrCf(websocket.SubProtocol); } var cookies = websocket.Cookies; if (cookies != null && cookies.Count > 0) { string[] cookiePairs = new string[cookies.Count]; for (int i = 0; i < cookies.Count; i++) { var item = cookies[i]; cookiePairs[i] = item.Key + "=" + Uri.EscapeUriString(item.Value); } handshakeBuilder.Append("Cookie: "); handshakeBuilder.AppendWithCrCf(string.Join(";", cookiePairs)); } if (websocket.CustomHeaderItems != null) { for (var i = 0; i < websocket.CustomHeaderItems.Count; i++) { var item = websocket.CustomHeaderItems[i]; handshakeBuilder.AppendFormatWithCrCf(HeaderItemFormat, item.Key, item.Value); } } handshakeBuilder.AppendWithCrCf(); byte[] handshakeBuffer = Encoding.UTF8.GetBytes(handshakeBuilder.ToString()); websocket.Client.Send(handshakeBuffer, 0, handshakeBuffer.Length); }
public static HandshakeContext BuildHandeshakeContext( string host, string path, string key = null, string protocol = null, string version = null, string extensions = null, string origin = null, IEnumerable <KeyValuePair <string, string> > cookies = null) { if (string.IsNullOrEmpty(host)) { throw new ArgumentNullException("host"); } if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } var sb = new StringBuilder(); if (string.IsNullOrEmpty(key)) { key = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); } sb.AppendFormatWithCrCf("GET {0} HTTP/1.1", path); sb.AppendFormatWithCrCf("Host: {0}", host); sb.AppendWithCrCf("Upgrade: websocket"); sb.AppendWithCrCf("Connection: Upgrade"); // In addition to Upgrade headers, the client sends a Sec-WebSocket-Key header // containing base64-encoded random bytes, and the server replies with a hash of the key // in the Sec-WebSocket-Accept header. This is intended to prevent a caching proxy // from re-sending a previous WebSocket conversation, and does not provide any authentication, // privacy or integrity. The hashing function appends the // fixed string 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 (a GUID) to the value // from Sec-WebSocket-Key header (which is not decoded from base64), // applies the SHA-1 hashing function, and encodes the result using base64. sb.AppendFormatWithCrCf("Sec-WebSocket-Key: {0}", key); // The |Sec-WebSocket-Version| header field in the client's // handshake includes the version of the WebSocket Protocol with // which the client is attempting to communicate. If this // version does not match a version understood by the server, the // server MUST abort the WebSocket handshake described in this // section and instead send an appropriate HTTP error code(such // as 426 Upgrade Required) and a |Sec-WebSocket-Version| header // field indicating the version(s)the server is capable of understanding. if (!string.IsNullOrEmpty(version)) { sb.AppendFormatWithCrCf("Sec-WebSocket-Version: {0}", version); } else { sb.AppendFormatWithCrCf("Sec-WebSocket-Version: {0}", 13); } // Optionally // The |Sec-WebSocket-Protocol| request-header field can be // used to indicate what subprotocols(application - level protocols // layered over the WebSocket Protocol) are acceptable to the client. if (!string.IsNullOrEmpty(protocol)) { sb.AppendFormatWithCrCf("Sec-WebSocket-Protocol: {0}", protocol); } // Optionally // A (possibly empty) list representing the protocol-level // extensions the server is ready to use. if (!string.IsNullOrEmpty(extensions)) { sb.AppendFormatWithCrCf("Sec-WebSocket-Extensions: {0}", extensions); } // Optionally // The |Origin| header field is used to protect against // unauthorized cross-origin use of a WebSocket server by scripts using // the WebSocket API in a web browser. // This header field is sent by browser clients; for non-browser clients, // this header field may be sent if it makes sense in the context of those clients. if (!string.IsNullOrEmpty(origin)) { sb.AppendFormatWithCrCf("Origin: {0}", origin); } if (cookies != null && cookies.Any()) { string[] pairs = new string[cookies.Count()]; for (int i = 0; i < cookies.Count(); i++) { var item = cookies.ElementAt(i); pairs[i] = item.Key + "=" + Uri.EscapeUriString(item.Value); } sb.AppendFormatWithCrCf("Cookie: {0}", string.Join(";", pairs)); } sb.AppendWithCrCf(); // GET /chat HTTP/1.1 // Host: server.example.com // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== // Sec-WebSocket-Protocol: chat, superchat // Sec-WebSocket-Version: 13 // Origin: http://example.com var message = sb.ToString(); var requestBuffer = Encoding.UTF8.GetBytes(message); var context = new HandshakeContext() { RequestBuffer = requestBuffer, RequestBufferOffset = 0, RequestBufferCount = requestBuffer.Length, SecWebSocketKey = key, }; return(context); }
public static HandshakeContext BuildHandeshakeContext( string host, string path, string key = null, string protocol = null, string version = null, string extensions = null, string origin = null, IEnumerable<KeyValuePair<string, string>> cookies = null) { if (string.IsNullOrEmpty(host)) throw new ArgumentNullException("host"); if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path"); var sb = new StringBuilder(); if (string.IsNullOrEmpty(key)) key = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); sb.AppendFormatWithCrCf("GET {0} HTTP/1.1", path); sb.AppendFormatWithCrCf("Host: {0}", host); sb.AppendWithCrCf("Upgrade: websocket"); sb.AppendWithCrCf("Connection: Upgrade"); // In addition to Upgrade headers, the client sends a Sec-WebSocket-Key header // containing base64-encoded random bytes, and the server replies with a hash of the key // in the Sec-WebSocket-Accept header. This is intended to prevent a caching proxy // from re-sending a previous WebSocket conversation, and does not provide any authentication, // privacy or integrity. The hashing function appends the // fixed string 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 (a GUID) to the value // from Sec-WebSocket-Key header (which is not decoded from base64), // applies the SHA-1 hashing function, and encodes the result using base64. sb.AppendFormatWithCrCf("Sec-WebSocket-Key: {0}", key); // The |Sec-WebSocket-Version| header field in the client's // handshake includes the version of the WebSocket Protocol with // which the client is attempting to communicate. If this // version does not match a version understood by the server, the // server MUST abort the WebSocket handshake described in this // section and instead send an appropriate HTTP error code(such // as 426 Upgrade Required) and a |Sec-WebSocket-Version| header // field indicating the version(s)the server is capable of understanding. if (!string.IsNullOrEmpty(version)) sb.AppendFormatWithCrCf("Sec-WebSocket-Version: {0}", version); else sb.AppendFormatWithCrCf("Sec-WebSocket-Version: {0}", 13); // Optionally // The |Sec-WebSocket-Protocol| request-header field can be // used to indicate what subprotocols(application - level protocols // layered over the WebSocket Protocol) are acceptable to the client. if (!string.IsNullOrEmpty(protocol)) sb.AppendFormatWithCrCf("Sec-WebSocket-Protocol: {0}", protocol); // Optionally // A (possibly empty) list representing the protocol-level // extensions the server is ready to use. if (!string.IsNullOrEmpty(extensions)) sb.AppendFormatWithCrCf("Sec-WebSocket-Extensions: {0}", extensions); // Optionally // The |Origin| header field is used to protect against // unauthorized cross-origin use of a WebSocket server by scripts using // the WebSocket API in a web browser. // This header field is sent by browser clients; for non-browser clients, // this header field may be sent if it makes sense in the context of those clients. if (!string.IsNullOrEmpty(origin)) sb.AppendFormatWithCrCf("Origin: {0}", origin); if (cookies != null && cookies.Any()) { string[] pairs = new string[cookies.Count()]; for (int i = 0; i < cookies.Count(); i++) { var item = cookies.ElementAt(i); pairs[i] = item.Key + "=" + Uri.EscapeUriString(item.Value); } sb.AppendFormatWithCrCf("Cookie: {0}", string.Join(";", pairs)); } sb.AppendWithCrCf(); // GET /chat HTTP/1.1 // Host: server.example.com // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== // Sec-WebSocket-Protocol: chat, superchat // Sec-WebSocket-Version: 13 // Origin: http://example.com var message = sb.ToString(); var requestBuffer = Encoding.UTF8.GetBytes(message); var context = new HandshakeContext() { RequestBuffer = requestBuffer, RequestBufferOffset = 0, RequestBufferCount = requestBuffer.Length, SecWebSocketKey = key, }; return context; }
internal static byte[] CreateOpenningHandshakeBadRequestResponse(AsyncWebSocketSession session) { var sb = new StringBuilder(); // HTTP/1.1 400 Bad Request sb.AppendFormatWithCrCf("HTTP/{0} {1} {2}", Consts.HttpVersion, (int)HttpStatusCode.BadRequest, @"Bad Request"); // Upgrade: websocket sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // Connection: Upgrade sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // Sec-WebSocket-Version: 13 sb.AppendFormatWithCrCf(Consts.HeaderLineFormat, HttpKnownHeaderNames.SecWebSocketVersion, Consts.WebSocketVersion); sb.AppendWithCrCf(); var response = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", session.RemoteEndPoint, Environment.NewLine, response); #endif return Encoding.UTF8.GetBytes(response); }
internal static byte[] CreateOpenningHandshakeRequest(AsyncWebSocketClient client, out string secWebSocketKey) { var sb = new StringBuilder(); // The handshake MUST be a valid HTTP request as specified by [RFC2616]. // The method of the request MUST be GET, and the HTTP version MUST be at least 1.1. // For example, if the WebSocket URI is "ws://example.com/chat", // the first line sent should be "GET /chat HTTP/1.1". sb.AppendFormatWithCrCf("GET {0} HTTP/{1}", !string.IsNullOrEmpty(client.Uri.PathAndQuery) ? client.Uri.PathAndQuery : "/", Consts.HttpVersion); // The request MUST contain a |Host| header field whose value // contains /host/ plus optionally ":" followed by /port/ (when not // using the default port). sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Host, client.Uri.Host); // The request MUST contain an |Upgrade| header field whose value // MUST include the "websocket" keyword. sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Upgrade, Consts.WebSocketUpgradeToken); // The request MUST contain a |Connection| header field whose value // MUST include the "Upgrade" token. sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.Connection, Consts.WebSocketConnectionToken); // The request MUST include a header field with the name // |Sec-WebSocket-Key|. The value of this header field MUST be a // nonce consisting of a randomly selected 16-byte value that has // been base64-encoded (see Section 4 of [RFC4648]). The nonce // MUST be selected randomly for each connection. secWebSocketKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16))); sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketKey, secWebSocketKey); // The request MUST include a header field with the name // |Sec-WebSocket-Version|. The value of this header field MUST be 13. sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketVersion, Consts.WebSocketVersion); // The request MAY include a header field with the name // |Sec-WebSocket-Extensions|. If present, this value indicates // the protocol-level extension(s) the client wishes to speak. The // interpretation and format of this header field is described in Section 9.1. if (client.OfferedExtensions != null && client.OfferedExtensions.Any()) { foreach (var extension in client.OfferedExtensions) { sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketExtensions, extension.ExtensionNegotiationOffer); } } // The request MAY include a header field with the name // |Sec-WebSocket-Protocol|. If present, this value indicates one // or more comma-separated subprotocol the client wishes to speak, // ordered by preference. The elements that comprise this value // MUST be non-empty strings with characters in the range U+0021 to // U+007E not including separator characters as defined in // [RFC2616] and MUST all be unique strings. The ABNF for the // value of this header field is 1#token, where the definitions of // constructs and rules are as given in [RFC2616]. if (client.RequestedSubProtocols != null && client.RequestedSubProtocols.Any()) { foreach (var description in client.RequestedSubProtocols) { sb.AppendFormatWithCrCf(Consts.HttpHeaderLineFormat, HttpKnownHeaderNames.SecWebSocketProtocol, description.RequestedSubProtocol); } } // The request MUST include a header field with the name |Origin| // [RFC6454] if the request is coming from a browser client. If // the connection is from a non-browser client, the request MAY // include this header field if the semantics of that client match // the use-case described here for browser clients. The value of // this header field is the ASCII serialization of origin of the // context in which the code establishing the connection is // running. See [RFC6454] for the details of how this header field // value is constructed. // The request MAY include any other header fields, for example, // cookies [RFC6265] and/or authentication-related header fields // such as the |Authorization| header field [RFC2616], which are // processed according to documents that define them. sb.AppendWithCrCf(); // GET /chat HTTP/1.1 // Host: server.example.com // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== // Sec-WebSocket-Protocol: chat, superchat // Sec-WebSocket-Version: 13 // Origin: http://example.com var request = sb.ToString(); #if DEBUG _log.DebugFormat("[{0}]{1}{2}", client.RemoteEndPoint, Environment.NewLine, request); #endif return(Encoding.UTF8.GetBytes(request)); }