private async Task ReadResponseAsync(WebSocketHandshake handshake, Stream stream)
        {
            var bufferSize = this.options.BufferManager.LargeBufferSize;

            using (var reader = new StreamReader(stream, Encoding.ASCII, false, bufferSize, leaveOpen: true))
            {
                var responseHeaders = handshake.Response.Headers;

                var responseLine = await reader.ReadLineAsync().ConfigureAwait(false) ?? string.Empty;

                if (HttpHelper.TryParseHttpResponse(responseLine, out handshake.Response.Status, out handshake.Response.StatusDescription) == false)
                {
                    if (string.IsNullOrEmpty(responseLine))
                    {
                        throw new WebSocketException("Empty response. Probably connection is closed by remote party.");
                    }
                    else
                    {
                        throw new WebSocketException($"Invalid handshake response: {responseLine}.");
                    }
                }

                if (handshake.Response.Status != HttpStatusCode.SwitchingProtocols)
                {
                    throw new WebSocketException($"Invalid handshake response: {responseLine}.");
                }

                var headerLine = await reader.ReadLineAsync().ConfigureAwait(false);

                while (string.IsNullOrEmpty(headerLine) == false)
                {
                    responseHeaders.TryParseAndAdd(headerLine);
                    headerLine = await reader.ReadLineAsync().ConfigureAwait(false);
                }

                handshake.Response.ThrowIfInvalid(handshake.ComputeHandshake());
            }

            ParseWebSocketExtensions(handshake);
            SelectExtensions(handshake);
        }
        private void SendNegotiationResponse(WebSocketHandshake handshake, StreamWriter writer)
        {
            writer.Write("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n");
            if (handshake.Response.Cookies.Count > 0)
            {
                foreach (var cookie in handshake.Response.Cookies)
                {
                    writer.Write("Set-Cookie: ");
                    writer.Write(cookie.ToString());
                    writer.Write("\r\n");
                }
            }
            writer.Write("Sec-WebSocket-Accept: ");
            writer.Write(handshake.ComputeHandshake());

            // https://tools.ietf.org/html/rfc6455#section-4.2.2

            /*
             * Sec-WebSocket-Protocol
             * If the client's handshake did not contain such a header field or if
             * the server does not agree to any of the client's requested
             * subprotocols, the only acceptable value is null.  The absence
             * of such a field is equivalent to the null value (meaning that
             * if the server does not wish to agree to one of the suggested
             * subprotocols, it MUST NOT send back a |Sec-WebSocket-Protocol|
             * header field in its response).
             */
            if (handshake.Response.Headers.Contains(ResponseHeader.WebSocketProtocol))
            {
                writer.Write("\r\nSec-WebSocket-Protocol: ");
                writer.Write(handshake.Response.Headers[ResponseHeader.WebSocketProtocol]);
            }

            WriteHandshakeCookies(handshake, writer);

            writer.Write("\r\n\r\n");
        }