public async Task <WebSocket> AcceptAsync(WebSocketAcceptContext acceptContext)
            {
                if (!IsWebSocketRequest)
                {
                    throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC
                }

                string?subProtocol = null;

                if (acceptContext != null)
                {
                    subProtocol = acceptContext.SubProtocol;
                }

                TimeSpan keepAliveInterval     = _options.KeepAliveInterval;
                var      advancedAcceptContext = acceptContext as ExtendedWebSocketAcceptContext;

                if (advancedAcceptContext != null)
                {
                    if (advancedAcceptContext.KeepAliveInterval.HasValue)
                    {
                        keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value;
                    }
                }

                string key = _context.Request.Headers[HeaderNames.SecWebSocketKey];

                HandshakeHelpers.GenerateResponseHeaders(key, subProtocol, _context.Response.Headers);

                Stream opaqueTransport = await _upgradeFeature.UpgradeAsync(); // Sets status code to 101

                return(WebSocket.CreateFromStream(opaqueTransport, isServer: true, subProtocol: subProtocol, keepAliveInterval: keepAliveInterval));
            }
            public async Task <WebSocket> AcceptAsync(WebSocketAcceptContext acceptContext)
            {
                if (!IsWebSocketRequest)
                {
                    throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC
                }

                string subProtocol = null;

                if (acceptContext != null)
                {
                    subProtocol = acceptContext.SubProtocol;
                }

                TimeSpan keepAliveInterval     = _options.KeepAliveInterval;
                int      receiveBufferSize     = _options.ReceiveBufferSize;
                var      advancedAcceptContext = acceptContext as ExtendedWebSocketAcceptContext;

                if (advancedAcceptContext != null)
                {
                    if (advancedAcceptContext.ReceiveBufferSize.HasValue)
                    {
                        receiveBufferSize = advancedAcceptContext.ReceiveBufferSize.Value;
                    }
                    if (advancedAcceptContext.KeepAliveInterval.HasValue)
                    {
                        keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value;
                    }
                }

                string key = string.Join(", ", _context.Request.Headers[Constants.Headers.SecWebSocketKey]);

                var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key, subProtocol);

                foreach (var headerPair in responseHeaders)
                {
                    _context.Response.Headers[headerPair.Key] = headerPair.Value;
                }

                Stream opaqueTransport = await _upgradeFeature.UpgradeAsync(); // Sets status code to 101

                // Allocate a buffer for receive (default is 4k)
                var buffer = new byte[receiveBufferSize];

                return(WebSocketProtocol.CreateFromStream(opaqueTransport, isServer: true, subProtocol: subProtocol, keepAliveInterval: keepAliveInterval, buffer: buffer));
            }
            public static bool CheckSupportedWebSocketRequest(string method, IHeaderDictionary requestHeaders)
            {
                if (!HttpMethods.IsGet(method))
                {
                    return(false);
                }

                var foundHeader = false;

                var values = requestHeaders.GetCommaSeparatedValues(HeaderNames.SecWebSocketVersion);

                foreach (var value in values)
                {
                    if (string.Equals(value, Constants.Headers.SupportedVersion, StringComparison.OrdinalIgnoreCase))
                    {
                        // WebSockets are long lived; so if the header values are valid we switch them out for the interned versions.
                        if (values.Length == 1)
                        {
                            requestHeaders.SecWebSocketVersion = Constants.Headers.SupportedVersion;
                        }
                        foundHeader = true;
                        break;
                    }
                }
                if (!foundHeader)
                {
                    return(false);
                }
                foundHeader = false;

                values = requestHeaders.GetCommaSeparatedValues(HeaderNames.Connection);
                foreach (var value in values)
                {
                    if (string.Equals(value, HeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase))
                    {
                        // WebSockets are long lived; so if the header values are valid we switch them out for the interned versions.
                        if (values.Length == 1)
                        {
                            requestHeaders.Connection = HeaderNames.Upgrade;
                        }
                        foundHeader = true;
                        break;
                    }
                }
                if (!foundHeader)
                {
                    return(false);
                }
                foundHeader = false;

                values = requestHeaders.GetCommaSeparatedValues(HeaderNames.Upgrade);
                foreach (var value in values)
                {
                    if (string.Equals(value, Constants.Headers.UpgradeWebSocket, StringComparison.OrdinalIgnoreCase))
                    {
                        // WebSockets are long lived; so if the header values are valid we switch them out for the interned versions.
                        if (values.Length == 1)
                        {
                            requestHeaders.Upgrade = Constants.Headers.UpgradeWebSocket;
                        }
                        foundHeader = true;
                        break;
                    }
                }
                if (!foundHeader)
                {
                    return(false);
                }

                return(HandshakeHelpers.IsRequestKeyValid(requestHeaders.SecWebSocketKey.ToString()));
            }
            public async Task <WebSocket> AcceptAsync(WebSocketAcceptContext acceptContext)
            {
                if (!IsWebSocketRequest)
                {
                    throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC
                }

                string?  subProtocol           = null;
                bool     enableCompression     = false;
                bool     serverContextTakeover = true;
                int      serverMaxWindowBits   = 15;
                TimeSpan keepAliveInterval     = _options.KeepAliveInterval;

                if (acceptContext != null)
                {
                    subProtocol           = acceptContext.SubProtocol;
                    enableCompression     = acceptContext.DangerousEnableCompression;
                    serverContextTakeover = !acceptContext.DisableServerContextTakeover;
                    serverMaxWindowBits   = acceptContext.ServerMaxWindowBits;
                    keepAliveInterval     = acceptContext.KeepAliveInterval ?? keepAliveInterval;
                }

#pragma warning disable CS0618 // Type or member is obsolete
                if (acceptContext is ExtendedWebSocketAcceptContext advancedAcceptContext)
#pragma warning restore CS0618 // Type or member is obsolete
                {
                    if (advancedAcceptContext.KeepAliveInterval.HasValue)
                    {
                        keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value;
                    }
                }

                var key = _context.Request.Headers.SecWebSocketKey.ToString();
                HandshakeHelpers.GenerateResponseHeaders(key, subProtocol, _context.Response.Headers);

                WebSocketDeflateOptions?deflateOptions = null;
                if (enableCompression)
                {
                    var ext = _context.Request.Headers.SecWebSocketExtensions;
                    if (ext.Count != 0)
                    {
                        // loop over each extension offer, extensions can have multiple offers, we can accept any
                        foreach (var extension in _context.Request.Headers.GetCommaSeparatedValues(HeaderNames.SecWebSocketExtensions))
                        {
                            if (extension.AsSpan().TrimStart().StartsWith("permessage-deflate", StringComparison.Ordinal))
                            {
                                if (HandshakeHelpers.ParseDeflateOptions(extension.AsSpan().TrimStart(), serverContextTakeover, serverMaxWindowBits, out var parsedOptions, out var response))
                                {
                                    Log.CompressionAccepted(_logger, response);
                                    deflateOptions = parsedOptions;
                                    // If more extension types are added, this would need to be a header append
                                    // and we wouldn't want to break out of the loop
                                    _context.Response.Headers.SecWebSocketExtensions = response;
                                    break;
                                }
                            }
                        }

                        if (deflateOptions is null)
                        {
                            Log.CompressionNotAccepted(_logger);
                        }
                    }
                }

                Stream opaqueTransport = await _upgradeFeature.UpgradeAsync(); // Sets status code to 101

                return(WebSocket.CreateFromStream(opaqueTransport, new WebSocketCreationOptions()
                {
                    IsServer = true,
                    KeepAliveInterval = keepAliveInterval,
                    SubProtocol = subProtocol,
                    DangerousDeflateOptions = deflateOptions
                }));
            }