示例#1
0
        // 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);
        }
        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));
        }
示例#3
0
        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 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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
        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 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 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;
        }
        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();
        }
示例#12
0
        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 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 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);
        }
        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);
        }
        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);
        }
        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[] 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);
        }
示例#20
0
        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);
        }
示例#21
0
        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);
        }
        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;
        }
示例#23
0
        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));
        }
示例#24
0
        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));
        }