protected override void Decode(IChannelHandlerContext context, IHttpObject message, List <object> output) { try { if (message is IHttpResponse response && response.Status.Code == StatusCodes.Status100Continue) { if (!(response is ILastHttpContent)) { _continueResponse = true; } // 100-continue response must be passed through. output.Add(ReferenceCountUtil.Retain(message)); return; } if (_continueResponse) { if (message is ILastHttpContent) { _continueResponse = false; } // 100-continue response must be passed through. output.Add(ReferenceCountUtil.Retain(message)); return; } var httpContent = message as IHttpContent; if (message is IHttpMessage httpMessage) { Cleanup(); HttpHeaders headers = httpMessage.Headers; // Determine the content encoding. if (headers.TryGet(HttpHeaderNames.ContentEncoding, out ICharSequence contentEncoding)) { contentEncoding = AsciiString.Trim(contentEncoding); } else { if (headers.TryGet(HttpHeaderNames.TransferEncoding, out var transferEncoding)) { int idx = transferEncoding.IndexOf(HttpConstants.CommaChar); if (SharedConstants.TooBigOrNegative >= (uint)idx) // != -1 { contentEncoding = AsciiString.Trim(transferEncoding.SubSequence(0, idx)); } else { contentEncoding = AsciiString.Trim(transferEncoding); } } else { contentEncoding = Identity; } //contentEncoding = Identity; } _decoder = NewContentDecoder(contentEncoding); if (_decoder is null) { if (httpContent is object) { _ = httpContent.Retain(); } output.Add(httpMessage); return; } // Remove content-length header: // the correct value can be set only after all chunks are processed/decoded. // If buffering is not an issue, add HttpObjectAggregator down the chain, it will set the header. // Otherwise, rely on LastHttpContent message. if (headers.Contains(HttpHeaderNames.ContentLength)) { _ = headers.Remove(HttpHeaderNames.ContentLength); _ = headers.Set(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); } // Either it is already chunked or EOF terminated. // See https://github.com/netty/netty/issues/5892 // set new content encoding, ICharSequence targetContentEncoding = GetTargetContentEncoding(contentEncoding); if (HttpHeaderValues.Identity.ContentEquals(targetContentEncoding)) { // Do NOT set the 'Content-Encoding' header if the target encoding is 'identity' // as per: http://tools.ietf.org/html/rfc2616#section-14.11 _ = headers.Remove(HttpHeaderNames.ContentEncoding); } else { _ = headers.Set(HttpHeaderNames.ContentEncoding, targetContentEncoding); } if (httpContent is object) { // If message is a full request or response object (headers + data), don't copy data part into out. // Output headers only; data part will be decoded below. // Note: "copy" object must not be an instance of LastHttpContent class, // as this would (erroneously) indicate the end of the HttpMessage to other handlers. IHttpMessage copy = null; switch (httpMessage) { case IHttpRequest req: // HttpRequest or FullHttpRequest copy = new DefaultHttpRequest(req.ProtocolVersion, req.Method, req.Uri); break; case IHttpResponse res: // HttpResponse or FullHttpResponse copy = new DefaultHttpResponse(res.ProtocolVersion, res.Status); break; default: ThrowHelper.ThrowCodecException_InvalidHttpMsg(httpMessage); break; } _ = copy.Headers.Set(httpMessage.Headers); copy.Result = httpMessage.Result; output.Add(copy); } else { output.Add(httpMessage); } } if (httpContent is object) { if (_decoder is null) { output.Add(httpContent.Retain()); } else { DecodeContent(httpContent, output); } } } finally { _needRead = 0u >= (uint)output.Count; } }