Exemplo n.º 1
0
    private async Task ProcessDataWrites()
    {
        // ProcessDataWrites runs for the lifetime of the Http2OutputProducer, and is designed to be reused by multiple streams.
        // When Http2OutputProducer is no longer used (e.g. a stream is aborted and will no longer be used, or the connection is closed)
        // it should be disposed so ProcessDataWrites exits. Not disposing won't cause a memory leak in release builds, but in debug
        // builds active tasks are rooted on Task.s_currentActiveTasks. Dispose could be removed in the future when active tasks are
        // tracked by a weak reference. See https://github.com/dotnet/runtime/issues/26565
        do
        {
            FlushResult flushResult = default;
            ReadResult readResult = default;
            try
            {

                do
                {
                    var firstWrite = true;

                    readResult = await _pipeReader.ReadAsync();

                    if (readResult.IsCanceled)
                    {
                        // Response body is aborted, break and complete reader.
                        break;
                    }
                    else if (readResult.IsCompleted && _stream.ResponseTrailers?.Count > 0)
                    {
                        // Output is ending and there are trailers to write
                        // Write any remaining content then write trailers

                        _stream.ResponseTrailers.SetReadOnly();
                        _stream.DecrementActiveClientStreamCount();

                        if (readResult.Buffer.Length > 0)
                        {
                            // It is faster to write data and trailers together. Locking once reduces lock contention.
                            flushResult = await _frameWriter.WriteDataAndTrailersAsync(StreamId, _flowControl, readResult.Buffer, firstWrite, _stream.ResponseTrailers);
                        }
                        else
                        {
                            flushResult = await _frameWriter.WriteResponseTrailersAsync(StreamId, _stream.ResponseTrailers);
                        }
                    }
                    else if (readResult.IsCompleted && _streamEnded)
                    {
                        if (readResult.Buffer.Length != 0)
                        {
                            ThrowUnexpectedState();
                        }

                        // Headers have already been written and there is no other content to write
                        flushResult = await _frameWriter.FlushAsync(outputAborter: null, cancellationToken: default);
                    }