/// <inheritdoc />
        protected override void Decode(IChannelHandlerContext context, IHttpObject message, List <object> output)
        {
            IFullHttpResponse response = null;

            try
            {
                if (!this.upgradeRequested)
                {
                    ThrowHelper.ThrowInvalidOperationException_ReadHttpResponse();
                }

                if (message is IHttpResponse rep)
                {
                    if (!HttpResponseStatus.SwitchingProtocols.Equals(rep.Status))
                    {
                        // The server does not support the requested protocol, just remove this handler
                        // and continue processing HTTP.
                        // NOTE: not releasing the response since we're letting it propagate to the
                        // next handler.
                        _ = context.FireUserEventTriggered(UpgradeEvent.UpgradeRejected);
                        RemoveThisHandler(context);
                        _ = context.FireChannelRead(rep);
                        return;
                    }
                }

                if (message is IFullHttpResponse fullRep)
                {
                    response = fullRep;
                    // Need to retain since the base class will release after returning from this method.
                    _ = response.Retain();
                    output.Add(response);
                }
                else
                {
                    // Call the base class to handle the aggregation of the full request.
                    base.Decode(context, message, output);
                    if (0u >= (uint)output.Count)
                    {
                        // The full request hasn't been created yet, still awaiting more data.
                        return;
                    }

                    Debug.Assert(output.Count == 1);
                    response = (IFullHttpResponse)output[0];
                }

                if (response.Headers.TryGet(HttpHeaderNames.Upgrade, out ICharSequence upgradeHeader) && !AsciiString.ContentEqualsIgnoreCase(this.upgradeCodec.Protocol, upgradeHeader))
                {
                    ThrowHelper.ThrowInvalidOperationException_UnexpectedUpgradeProtocol(upgradeHeader);
                }

                // Upgrade to the new protocol.
                this.sourceCodec.PrepareUpgradeFrom(context);
                this.upgradeCodec.UpgradeTo(context, response);

                // Notify that the upgrade to the new protocol completed successfully.
                _ = context.FireUserEventTriggered(UpgradeEvent.UpgradeSuccessful);

                // We guarantee UPGRADE_SUCCESSFUL event will be arrived at the next handler
                // before http2 setting frame and http response.
                this.sourceCodec.UpgradeFrom(context);

                // We switched protocols, so we're done with the upgrade response.
                // Release it and clear it from the output.
                _ = response.Release();
                output.Clear();
                RemoveThisHandler(context);
            }
            catch (Exception exception)
            {
                _ = ReferenceCountUtil.Release(response);
                _ = context.FireExceptionCaught(exception);
                RemoveThisHandler(context);
            }
        }