/// <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); } }