public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise)
        {
            if (msg is IHttpResponse response)
            {
                var headers = response.Headers;
                if (WebSocketExtensionUtil.IsWebsocketUpgrade(headers))
                {
                    if (_validExtensions is object)
                    {
                        string headerValue = null;
                        if (headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value))
                        {
                            headerValue = value?.ToString();
                        }

                        for (int i = 0; i < _validExtensions.Count; i++)
                        {
                            WebSocketExtensionData extensionData = _validExtensions[i].NewReponseData();
                            headerValue = WebSocketExtensionUtil.AppendExtension(headerValue,
                                                                                 extensionData.Name, extensionData.Parameters);
                        }

                        _ = promise.Task.ContinueWith(s_switchWebSocketExtensionHandlerAction, Tuple.Create(ctx, _validExtensions), TaskContinuationOptions.ExecuteSynchronously);

                        if (headerValue is object)
                        {
                            _ = headers.Set(HttpHeaderNames.SecWebsocketExtensions, headerValue);
                        }
                    }
                }
                _ = promise.Task.ContinueWith(s_removeWebSocketExtensionHandlerAction, Tuple.Create(ctx, this), TaskContinuationOptions.ExecuteSynchronously);
            }

            base.Write(ctx, msg, promise);
        }
        public override void ChannelRead(IChannelHandlerContext ctx, object msg)
        {
            if (msg is IHttpResponse response &&
                WebSocketExtensionUtil.IsWebsocketUpgrade(response.Headers))
            {
                string extensionsHeader = null;
                if (response.Headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value))
                {
                    extensionsHeader = value.ToString();
                }

                var pipeline = ctx.Pipeline;
                if (extensionsHeader is object)
                {
                    List <WebSocketExtensionData> extensions =
                        WebSocketExtensionUtil.ExtractExtensions(extensionsHeader);
                    var validExtensions = new List <IWebSocketClientExtension>(extensions.Count);
                    int rsv             = 0;

                    foreach (WebSocketExtensionData extensionData in extensions)
                    {
                        IWebSocketClientExtension validExtension = null;
                        foreach (IWebSocketClientExtensionHandshaker extensionHandshaker in this.extensionHandshakers)
                        {
                            validExtension = extensionHandshaker.HandshakeExtension(extensionData);
                            if (validExtension is object)
                            {
                                break;
                            }
                        }

                        if (validExtension is object && 0u >= (uint)(validExtension.Rsv & rsv))
                        {
                            rsv = rsv | validExtension.Rsv;
                            validExtensions.Add(validExtension);
                        }
                        else
                        {
                            ThrowHelper.ThrowCodecException_InvalidWSExHandshake(extensionsHeader);
                        }
                    }

                    foreach (IWebSocketClientExtension validExtension in validExtensions)
                    {
                        WebSocketExtensionDecoder decoder = validExtension.NewExtensionDecoder();
                        WebSocketExtensionEncoder encoder = validExtension.NewExtensionEncoder();
                        _ = pipeline.AddAfter(ctx.Name, decoder.GetType().Name, decoder);
                        _ = pipeline.AddAfter(ctx.Name, encoder.GetType().Name, encoder);
                    }
                }

                _ = pipeline.Remove(ctx.Name);
            }

            base.ChannelRead(ctx, msg);
        }
        public override Task WriteAsync(IChannelHandlerContext ctx, object msg)
        {
            Action <Task> continuationAction = null;

            if (msg is IHttpResponse response &&
                WebSocketExtensionUtil.IsWebsocketUpgrade(response.Headers) &&
                this.validExtensions != null)
            {
                string headerValue = null;
                if (response.Headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value))
                {
                    headerValue = value?.ToString();
                }

                foreach (IWebSocketServerExtension extension in this.validExtensions)
                {
                    WebSocketExtensionData extensionData = extension.NewReponseData();
                    headerValue = WebSocketExtensionUtil.AppendExtension(headerValue,
                                                                         extensionData.Name, extensionData.Parameters);
                }

                continuationAction = promise =>
                {
                    if (promise.Status == TaskStatus.RanToCompletion)
                    {
                        foreach (IWebSocketServerExtension extension in this.validExtensions)
                        {
                            WebSocketExtensionDecoder decoder = extension.NewExtensionDecoder();
                            WebSocketExtensionEncoder encoder = extension.NewExtensionEncoder();
                            ctx.Channel.Pipeline.AddAfter(ctx.Name, decoder.GetType().Name, decoder);
                            ctx.Channel.Pipeline.AddAfter(ctx.Name, encoder.GetType().Name, encoder);
                        }
                    }
                    ctx.Channel.Pipeline.Remove(ctx.Name);
                };

                if (headerValue != null)
                {
                    response.Headers.Set(HttpHeaderNames.SecWebsocketExtensions, headerValue);
                }
            }

            return(continuationAction == null
                ? base.WriteAsync(ctx, msg)
                : base.WriteAsync(ctx, msg)
                   .ContinueWith(continuationAction, TaskContinuationOptions.ExecuteSynchronously));
        }
        public override void ChannelRead(IChannelHandlerContext ctx, object msg)
        {
            if (msg is IHttpRequest request)
            {
                if (WebSocketExtensionUtil.IsWebsocketUpgrade(request.Headers))
                {
                    if (request.Headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value) &&
                        value is object)
                    {
                        string extensionsHeader = value.ToString();
                        List <WebSocketExtensionData> extensions =
                            WebSocketExtensionUtil.ExtractExtensions(extensionsHeader);
                        int rsv = 0;

                        for (int i = 0; i < extensions.Count; i++)
                        {
                            WebSocketExtensionData    extensionData  = extensions[i];
                            IWebSocketServerExtension validExtension = null;
                            for (int j = 0; j < _extensionHandshakers.Count; j++)
                            {
                                validExtension = _extensionHandshakers[j].HandshakeExtension(extensionData);
                                if (validExtension is object)
                                {
                                    break;
                                }
                            }

                            if (validExtension is object && 0u >= (uint)(validExtension.Rsv & rsv))
                            {
                                if (_validExtensions is null)
                                {
                                    _validExtensions = CreateValidExtensions();
                                }

                                rsv |= validExtension.Rsv;
                                _validExtensions.Add(validExtension);
                            }
                        }
                    }
                }
            }

            base.ChannelRead(ctx, msg);
        }
        public override void ChannelRead(IChannelHandlerContext ctx, object msg)
        {
            if (msg is IHttpRequest request)
            {
                if (WebSocketExtensionUtil.IsWebsocketUpgrade(request.Headers))
                {
                    if (request.Headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value) &&
                        value != null)
                    {
                        string extensionsHeader = value.ToString();
                        List <WebSocketExtensionData> extensions =
                            WebSocketExtensionUtil.ExtractExtensions(extensionsHeader);
                        int rsv = 0;

                        foreach (WebSocketExtensionData extensionData in extensions)
                        {
                            IWebSocketServerExtension validExtension = null;
                            foreach (IWebSocketServerExtensionHandshaker extensionHandshaker in this.extensionHandshakers)
                            {
                                validExtension = extensionHandshaker.HandshakeExtension(extensionData);
                                if (validExtension != null)
                                {
                                    break;
                                }
                            }

                            if (validExtension != null && (validExtension.Rsv & rsv) == 0)
                            {
                                if (this.validExtensions == null)
                                {
                                    this.validExtensions = new List <IWebSocketServerExtension>(1);
                                }

                                rsv = rsv | validExtension.Rsv;
                                this.validExtensions.Add(validExtension);
                            }
                        }
                    }
                }
            }

            base.ChannelRead(ctx, msg);
        }
        public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise)
        {
            if (msg is IHttpRequest request && WebSocketExtensionUtil.IsWebsocketUpgrade(request.Headers))
            {
                string headerValue = null;
                if (request.Headers.TryGet(HttpHeaderNames.SecWebsocketExtensions, out ICharSequence value))
                {
                    headerValue = value.ToString();
                }

                foreach (IWebSocketClientExtensionHandshaker extensionHandshaker in this.extensionHandshakers)
                {
                    WebSocketExtensionData extensionData = extensionHandshaker.NewRequestData();
                    headerValue = WebSocketExtensionUtil.AppendExtension(headerValue,
                                                                         extensionData.Name, extensionData.Parameters);
                }

                _ = request.Headers.Set(HttpHeaderNames.SecWebsocketExtensions, headerValue);
            }

            base.Write(ctx, msg, promise);
        }