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