Exemple #1
0
        /// <summary>
        /// Sends the handshake asynchronous.
        /// </summary>
        /// <param name="handshake">The handshake.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task <WebSocketResponseHandshake> SendHandshakeAsync(WebSocketRequestHandshake handshake, CancellationToken cancellationToken)
        {
            var oldState = Interlocked.CompareExchange(ref _state, WebSocketState.Opening, WebSocketState.Connected);

            if (oldState != WebSocketState.Connected)
            {
                throw new InvalidOperationException(ErrorMessages.InvalidState + _state);
            }

            var data = handshake.ToString();

            await this.SendAsync(data, Encoding.UTF8, cancellationToken);

            var responseHeaders = new List <string>();
            var line            = await _tcp.ReadLineAsync(cancellationToken);

            while (!String.IsNullOrEmpty(line))
            {
                responseHeaders.Add(line);
                line = await _tcp.ReadLineAsync(cancellationToken);
            }

            var response = WebSocketResponseHandshake.Parse(responseHeaders);

            if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
            {
                var versions = response.SecWebSocketVersion;
                if (versions != null && !versions.Intersect(Consts.SupportedClientVersions).Any())
                {
                    throw new WebSocketException(WebSocketErrorCode.HandshakeVersionNotSupported);
                }

                throw new WebSocketException(WebSocketErrorCode.HandshakeInvalidStatusCode);
            }

            var challenge        = Encoding.UTF8.GetBytes(handshake.SecWebSocketKey + Consts.ServerGuid);
            var hash             = Sha1Digest.ComputeHash(challenge);
            var calculatedAccept = Convert.ToBase64String(hash);

            if (response.SecWebSocketAccept != calculatedAccept)
            {
                throw new WebSocketException(WebSocketErrorCode.HandshakeInvalidSecWebSocketAccept);
            }

            response.RequestMessage = handshake;

            Interlocked.Exchange(ref _state, WebSocketState.Open);


            return(response);
        }
Exemple #2
0
        public static WebSocketResponseHandshake Parse(IList <string> responseLines)
        {
            if (responseLines == null || responseLines.Count < 1)
            {
                throw new ArgumentException(ErrorMessages.NoHeaderLines, "responseLines");
            }

            var responseLine = responseLines[0].Split(' ');

            if (responseLine.Length < 3)
            {
                throw new ArgumentException(ErrorMessages.InvalidResponseLine + responseLines[0], "responseLines");
            }

            var response = new WebSocketResponseHandshake
            {
                StatusCode   = (HttpStatusCode)Convert.ToInt32(responseLine[1]),
                ReasonPhrase = string.Join(" ", responseLine.Skip(2)),
                Version      = new Version(responseLine[0].Substring(5)), // "HTTP/x.x"
            };

            foreach (var line in responseLines.Skip(1))
            {
                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                var pos = line.IndexOf(':');
                if (pos < 0)
                {
                    continue;
                }

                var key    = line.Substring(0, pos).Trim().ToLowerInvariant();
                var value  = line.Substring(pos + 1).Trim();
                var values = value.Split(',').Select(v => v.Trim()).Where(v => v.Length > 0);

                if (key == "date")
                {
                    response.Headers.Add(key, value);
                }
                else if (key.StartsWith("content-") || key == "expires" || key == "last-modified")
                {
                    if (response.Content == null)
                    {
                        response.Content = new CustomHttpContent();
                    }
                    if (key == "expires")
                    {
                        int offset;
                        if (int.TryParse(value, out offset)) // "0" or "-1"
                        {
                            response.Content.Headers.Add(key, DateTime.UtcNow.AddSeconds(offset).ToString("R"));
                        }
                        else
                        {
                            response.Content.Headers.Add(key, value);
                        }
                    }
                    else
                    {
                        response.Content.Headers.Add(key, values);
                    }
                }
                else
                {
                    try
                    {
                        response.Headers.Add(key, values);
                    }
                    catch
                    {
                        try
                        {
                            response.Headers.Add(key, value);
                        }
                        catch (Exception ex)
                        {
                            response.LogWarning("Failed to add header '{0}': {1}", key, ex);
                        }
                    }
                }
            }


            return(response);
        }