/// <inheritdoc /> protected override void Encode(IChannelHandlerContext ctx, IHttpObject msg, List <object> output) { var res = msg as IHttpResponse; var lastContent = msg as ILastHttpContent; bool isFull = res is object && lastContent is object; switch (_state) { case State.AwaitHeaders: { EnsureHeaders(msg); Debug.Assert(_encoder is null); int code = res.Status.Code; ICharSequence acceptEncoding; if (code == StatusCodes.Status100Continue) { // We need to not poll the encoding when response with CONTINUE as another response will follow // for the issued request. See https://github.com/netty/netty/issues/4079 acceptEncoding = null; } else { // Get the list of encodings accepted by the peer. if (!_acceptEncodingQueue.TryRemoveFromFront(out acceptEncoding)) { ThrowHelper.ThrowInvalidOperationException_CannotSendMore(); } } // // per rfc2616 4.3 Message Body // All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a // message-body. All other responses do include a message-body, although it MAY be of zero length. // // 9.4 HEAD // The HEAD method is identical to GET except that the server MUST NOT return a message-body // in the response. // // Also we should pass through HTTP/1.0 as transfer-encoding: chunked is not supported. // // See https://github.com/netty/netty/issues/5382 // if (IsPassthru(res.ProtocolVersion, code, acceptEncoding)) { if (isFull) { output.Add(ReferenceCountUtil.Retain(res)); } else { output.Add(res); // Pass through all following contents. _state = State.PassThrough; } break; } if (isFull) { // Pass through the full response with empty content and continue waiting for the next resp. if (!((IByteBufferHolder)res).Content.IsReadable()) { output.Add(ReferenceCountUtil.Retain(res)); break; } } // Prepare to encode the content. Result result = BeginEncode(res, acceptEncoding); // If unable to encode, pass through. if (result is null) { if (isFull) { output.Add(ReferenceCountUtil.Retain(res)); } else { output.Add(res); // Pass through all following contents. _state = State.PassThrough; } break; } _encoder = result.ContentEncoder; // Encode the content and remove or replace the existing headers // so that the message looks like a decoded message. _ = res.Headers.Set(HttpHeaderNames.ContentEncoding, result.TargetContentEncoding); // Output the rewritten response. if (isFull) { // Convert full message into unfull one. var newRes = new DefaultHttpResponse(res.ProtocolVersion, res.Status); _ = newRes.Headers.Set(res.Headers); output.Add(newRes); EnsureContent(res); EncodeFullResponse(newRes, (IHttpContent)res, output); break; } else { // Make the response chunked to simplify content transformation. _ = res.Headers.Remove(HttpHeaderNames.ContentLength); _ = res.Headers.Set(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); output.Add(res); _state = State.AwaitContent; if (!(msg is IHttpContent)) { // only break out the switch statement if we have not content to process // See https://github.com/netty/netty/issues/2006 break; } // Fall through to encode the content goto case State.AwaitContent; } } case State.AwaitContent: { EnsureContent(msg); if (EncodeContent((IHttpContent)msg, output)) { _state = State.AwaitHeaders; } break; } case State.PassThrough: { EnsureContent(msg); output.Add(ReferenceCountUtil.Retain(msg)); // Passed through all following contents of the current response. if (lastContent is object) { _state = State.AwaitHeaders; } break; } } }