예제 #1
0
        public ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return new ValueTask<FlushResult>(Task.FromCanceled<FlushResult>(cancellationToken));
            }

            lock (_dataWriterLock)
            {
                ThrowIfSuffixSentOrCompleted();

                if (_streamCompleted)
                {
                    return default;
                }

                if (_startedWritingDataFrames)
                {
                    // If there's already been response data written to the stream, just wait for that. Any header
                    // should be in front of the data frames in the connection pipe. Trailers could change things.
                    return _flusher.FlushAsync(this, cancellationToken);
                }
                else
                {
                    // Flushing the connection pipe ensures headers already in the pipe are flushed even if no data
                    // frames have been written.
                    return _frameWriter.FlushAsync(this, cancellationToken);
                }
            }
        }
        public async Task IfFlushIsCalledAgainBeforeTheLastFlushCompletedItWaitsForTheLastCall()
        {
            var mockPipeWriter          = new Mock <PipeWriter>();
            var pipeWriterFlushTcsArray = new[] {
                new TaskCompletionSource <FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
                new TaskCompletionSource <FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
                new TaskCompletionSource <FlushResult>(TaskCreationOptions.RunContinuationsAsynchronously),
            };
            var pipeWriterFlushCallCount = 0;

            mockPipeWriter.Setup(p => p.FlushAsync(CancellationToken.None)).Returns(() =>
            {
                return(new ValueTask <FlushResult>(pipeWriterFlushTcsArray[pipeWriterFlushCallCount++].Task));
            });

            var timingPipeFlusher = new TimingPipeFlusher(mockPipeWriter.Object, null, null);

            var flushTask0 = timingPipeFlusher.FlushAsync();
            var flushTask1 = timingPipeFlusher.FlushAsync();
            var flushTask2 = timingPipeFlusher.FlushAsync();

            Assert.False(flushTask0.IsCompleted);
            Assert.False(flushTask1.IsCompleted);
            Assert.False(flushTask2.IsCompleted);
            Assert.Equal(1, pipeWriterFlushCallCount);

            pipeWriterFlushTcsArray[0].SetResult(default);
예제 #3
0
        public Task FlushAsync(IHttpOutputAborter outputAborter, CancellationToken cancellationToken)
        {
            lock (_writeLock)
            {
                if (_completed)
                {
                    return(Task.CompletedTask);
                }

                return(_flusher.FlushAsync(outputAborter, cancellationToken));
            }
        }
예제 #4
0
        public Task FlushAsync(IHttpOutputAborter outputAborter, CancellationToken cancellationToken)
        {
            lock (_writeLock)
            {
                if (_completed)
                {
                    return(Task.CompletedTask);
                }

                var bytesWritten = _unflushedBytes;
                _unflushedBytes = 0;

                return(_flusher.FlushAsync(_minResponseDataRate, bytesWritten, outputAborter, cancellationToken));
            }
        }
예제 #5
0
        private Task WriteAsync(
            ReadOnlySpan <byte> buffer,
            CancellationToken cancellationToken = default)
        {
            lock (_contextLock)
            {
                if (_completed)
                {
                    return(Task.CompletedTask);
                }

                var writer = new BufferWriter <PipeWriter>(_pipeWriter);
                if (buffer.Length > 0)
                {
                    writer.Write(buffer);

                    _unflushedBytes += buffer.Length;
                }
                writer.Commit();

                var bytesWritten = _unflushedBytes;
                _unflushedBytes = 0;

                return(_flusher.FlushAsync(
                           _minResponseDataRateFeature.MinDataRate,
                           bytesWritten,
                           this,
                           cancellationToken));
            }
        }
예제 #6
0
    public ValueTask <FlushResult> FlushAsync(CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return(new ValueTask <FlushResult>(Task.FromCanceled <FlushResult>(cancellationToken)));
        }

        lock (_dataWriterLock)
        {
            ThrowIfSuffixSentOrCompleted();

            if (_completeScheduled)
            {
                return(new ValueTask <FlushResult>(new FlushResult(false, true)));
            }

            if (_startedWritingDataFrames)
            {
                // If there's already been response data written to the stream, just wait for that. Any header
                // should be in front of the data frames in the connection pipe. Trailers could change things.
                var task = _flusher.FlushAsync(this, cancellationToken);

                Schedule();

                return(task);
            }
            else
            {
                Schedule();

                return(default);
예제 #7
0
    public ValueTask <FlushResult> FlushAsync(CancellationToken cancellationToken = default)
    {
        lock (_contextLock)
        {
            if (_pipeWriterCompleted)
            {
                return(new ValueTask <FlushResult>(new FlushResult(false, true)));
            }

            if (_autoChunk)
            {
                if (_advancedBytesForChunk > 0)
                {
                    // If there is data that was chunked before flushing (ex someone did GetMemory->Advance->FlushAsync)
                    // make sure to write whatever was advanced first
                    return(FlushAsyncChunked(this, cancellationToken));
                }
                else
                {
                    // If there is an empty write, we still need to update the current chunk
                    _currentChunkMemoryUpdated = false;
                }
            }

            var bytesWritten = _unflushedBytes;
            _unflushedBytes = 0;

            return(_flusher.FlushAsync(_minResponseDataRateFeature.MinDataRate, bytesWritten, _outputAborter, cancellationToken));
        }