Esempio n. 1
0
 public void AbortPendingStreamDataWrites(StreamOutputFlowControl flowControl)
 {
     lock (_writeLock)
     {
         flowControl.Abort();
     }
 }
Esempio n. 2
0
        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();
        }
Esempio n. 3
0
 public bool TryUpdateStreamWindow(StreamOutputFlowControl flowControl, int bytes)
 {
     lock (_writeLock)
     {
         return(flowControl.TryUpdateWindow(bytes));
     }
 }
Esempio n. 4
0
        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());
            }
        }
Esempio n. 5
0
        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;
        }
Esempio n. 6
0
        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;
        }
Esempio n. 7
0
 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();
 }
Esempio n. 8
0
 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();
 }
Esempio n. 9
0
        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();
        }
Esempio n. 11
0
        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();
            }
        }
Esempio n. 12
0
        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;
        }