コード例 #1
0
ファイル: HttpContentEncoder.cs プロジェクト: wxlonstar/Fenix
        /// <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;
            }
            }
        }