public void AbortPendingStreamDataWrites(StreamOutputFlowControl flowControl) { lock (_writeLock) { flowControl.Abort(); } }
public Http2OutputProducer( int streamId, Http2FrameWriter frameWriter, StreamOutputFlowControl flowControl, MemoryPool <byte> pool, Http2Stream stream, IKestrelTrace log) { _streamId = streamId; _frameWriter = frameWriter; _flowControl = flowControl; _memoryPool = pool; _stream = stream; _log = log; var pipe = CreateDataPipe(pool); _pipeWriter = new ConcurrentPipeWriter(pipe.Writer, pool, _dataWriterLock); _pipeReader = pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(_pipeWriter, timeoutControl: null, log); _dataWriteProcessingTask = ProcessDataWrites(); }
public bool TryUpdateStreamWindow(StreamOutputFlowControl flowControl, int bytes) { lock (_writeLock) { return(flowControl.TryUpdateWindow(bytes)); } }
public Task WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence <byte> data, bool endStream) { // The Length property of a ReadOnlySequence can be expensive, so we cache the value. var dataLength = data.Length; lock (_writeLock) { if (_completed || flowControl.IsAborted) { return(Task.CompletedTask); } // Zero-length data frames are allowed to be sent immediately even if there is no space available in the flow control window. // https://httpwg.org/specs/rfc7540.html#rfc.section.6.9.1 if (dataLength != 0 && dataLength > flowControl.Available) { return(WriteDataAsync(streamId, flowControl, data, dataLength, endStream)); } // This cast is safe since if dataLength would overflow an int, it's guaranteed to be greater than the available flow control window. flowControl.Advance((int)dataLength); WriteDataUnsynchronized(streamId, data, dataLength, endStream); return(TimeFlushUnsynchronizedAsync()); } }
public void Initialize(Http2StreamContext context) { base.Initialize(context); _decrementCalled = false; _completionState = StreamCompletionFlags.None; InputRemaining = null; RequestBodyStarted = false; DrainExpirationTicks = 0; _context = context; _inputFlowControl = new StreamInputFlowControl( context.StreamId, context.FrameWriter, context.ConnectionInputFlowControl, context.ServerPeerSettings.InitialWindowSize, context.ServerPeerSettings.InitialWindowSize / 2); _outputFlowControl = new StreamOutputFlowControl( context.ConnectionOutputFlowControl, context.ClientPeerSettings.InitialWindowSize); _http2Output = new Http2OutputProducer( context.StreamId, context.FrameWriter, _outputFlowControl, context.MemoryPool, this, context.ServiceContext.Log); RequestBodyPipe = CreateRequestBodyPipe(context.ServerPeerSettings.InitialWindowSize); Output = _http2Output; }
public Http2Stream(Http2StreamContext context) : base(context) { _context = context; _inputFlowControl = new StreamInputFlowControl( context.StreamId, context.FrameWriter, context.ConnectionInputFlowControl, context.ServerPeerSettings.InitialWindowSize, context.ServerPeerSettings.InitialWindowSize / 2); _outputFlowControl = new StreamOutputFlowControl( context.ConnectionOutputFlowControl, context.ClientPeerSettings.InitialWindowSize); _http2Output = new Http2OutputProducer( context.StreamId, context.FrameWriter, _outputFlowControl, context.TimeoutControl, context.MemoryPool, this, context.ServiceContext.Log); RequestBodyPipe = CreateRequestBodyPipe(context.ServerPeerSettings.InitialWindowSize); Output = _http2Output; }
public Http2OutputProducer( int streamId, Http2FrameWriter frameWriter, StreamOutputFlowControl flowControl, ITimeoutControl timeoutControl, MemoryPool <byte> pool) { _streamId = streamId; _frameWriter = frameWriter; _flowControl = flowControl; _dataPipe = CreateDataPipe(pool); _flusher = new StreamSafePipeFlusher(_dataPipe.Writer, timeoutControl); _dataWriteProcessingTask = ProcessDataWrites(); }
public Proto2OutputProducer( int streamId, Proto2FrameWriter frameWriter, StreamOutputFlowControl flowControl, ITimeoutControl timeoutControl, MemoryPool <byte> pool, Proto2Stream stream, IKestrelTrace log) { _streamId = streamId; _frameWriter = frameWriter; _flowControl = flowControl; _stream = stream; _dataPipe = CreateDataPipe(pool); _flusher = new TimingPipeFlusher(_dataPipe.Writer, timeoutControl, log); _dataWriteProcessingTask = ProcessDataWrites(); }
private async Task WriteDataAsyncAwaited(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence <byte> data, long dataLength, bool endStream) { while (dataLength > 0) { OutputFlowControlAwaitable availabilityAwaitable; var writeTask = Task.CompletedTask; lock (_writeLock) { if (_completed || flowControl.IsAborted) { break; } var actual = flowControl.AdvanceUpToAndWait(dataLength, out availabilityAwaitable); if (actual > 0) { if (actual < dataLength) { writeTask = WriteDataUnsynchronizedAsync(streamId, data.Slice(0, actual), endStream: false); data = data.Slice(actual); dataLength -= actual; } else { writeTask = WriteDataUnsynchronizedAsync(streamId, data, endStream); dataLength = 0; } } } // This awaitable releases continuations in FIFO order when the window updates. // It should be very rare for a continuation to run without any availability. if (availabilityAwaitable != null) { await availabilityAwaitable; } await writeTask; } // Ensure that the application continuation isn't executed inline by ProcessWindowUpdateFrameAsync. await ThreadPoolAwaitable.Instance; }
public Http2OutputProducer(Http2Stream stream, Http2StreamContext context, StreamOutputFlowControl flowControl) { _stream = stream; _frameWriter = context.FrameWriter; _flowControl = flowControl; _memoryPool = context.MemoryPool; _log = context.ServiceContext.Log; _pipe = CreateDataPipe(_memoryPool); _pipeWriter = new ConcurrentPipeWriter(_pipe.Writer, _memoryPool, _dataWriterLock); _pipeReader = _pipe.Reader; // No need to pass in timeoutControl here, since no minDataRates are passed to the TimingPipeFlusher. // The minimum output data rate is enforced at the connection level by Http2FrameWriter. _flusher = new TimingPipeFlusher(_pipeWriter, timeoutControl: null, _log); _dataWriteProcessingTask = ProcessDataWrites(); }
public void Initialize(Http2StreamContext context) { base.Initialize(context); CanReuse = false; _decrementCalled = false; _completionState = StreamCompletionFlags.None; InputRemaining = null; RequestBodyStarted = false; DrainExpirationTicks = 0; _context = context; // First time the stream is used we need to create flow control, producer and pipes. // When a stream is reused these types will be reset and reused. if (_inputFlowControl == null) { _inputFlowControl = new StreamInputFlowControl( this, context.FrameWriter, context.ConnectionInputFlowControl, context.ServerPeerSettings.InitialWindowSize, context.ServerPeerSettings.InitialWindowSize / 2); _outputFlowControl = new StreamOutputFlowControl( context.ConnectionOutputFlowControl, context.ClientPeerSettings.InitialWindowSize); _http2Output = new Http2OutputProducer(this, context, _outputFlowControl); RequestBodyPipe = CreateRequestBodyPipe(); Output = _http2Output; } else { _inputFlowControl.Reset(); _outputFlowControl.Reset(context.ClientPeerSettings.InitialWindowSize); _http2Output.StreamReset(); RequestBodyPipe.Reset(); } }
private async Task WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence <byte> data, long dataLength, bool endStream) { while (dataLength > 0) { OutputFlowControlAwaitable availabilityAwaitable; var writeTask = Task.CompletedTask; lock (_writeLock) { if (_completed || flowControl.IsAborted) { break; } var actual = flowControl.AdvanceUpToAndWait(dataLength, out availabilityAwaitable); if (actual > 0) { if (actual < dataLength) { WriteDataUnsynchronized(streamId, data.Slice(0, actual), actual, endStream: false); data = data.Slice(actual); dataLength -= actual; } else { WriteDataUnsynchronized(streamId, data, actual, endStream); dataLength = 0; } // Don't call TimeFlushUnsynchronizedAsync() since we time this write while also accounting for // flow control induced backpressure below. writeTask = _flusher.FlushAsync(); } if (_minResponseDataRate != null) { _timeoutControl.BytesWrittenToBuffer(_minResponseDataRate, _unflushedBytes); } _unflushedBytes = 0; } // Avoid timing writes that are already complete. This is likely to happen during the last iteration. if (availabilityAwaitable == null && writeTask.IsCompleted) { continue; } if (_minResponseDataRate != null) { _timeoutControl.StartTimingWrite(); } // This awaitable releases continuations in FIFO order when the window updates. // It should be very rare for a continuation to run without any availability. if (availabilityAwaitable != null) { await availabilityAwaitable; } await writeTask; if (_minResponseDataRate != null) { _timeoutControl.StopTimingWrite(); } } // Ensure that the application continuation isn't executed inline by ProcessWindowUpdateFrameAsync. await ThreadPoolAwaitable.Instance; }