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);
public Task FlushAsync(IHttpOutputAborter outputAborter, CancellationToken cancellationToken) { lock (_writeLock) { if (_completed) { return(Task.CompletedTask); } return(_flusher.FlushAsync(outputAborter, cancellationToken)); } }
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)); } }
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)); } }
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);
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)); }