public Http2OutputProducer(
     int streamId,
     Http2FrameWriter frameWriter,
     StreamOutputFlowControl flowControl,
     ITimeoutControl timeoutControl,
     MemoryPool <byte> pool,
     Http2Stream stream,
     IKestrelTrace log)
 {
     _streamId                = streamId;
     _frameWriter             = frameWriter;
     _flowControl             = flowControl;
     _stream                  = stream;
     _dataPipe                = CreateDataPipe(pool);
     _flusher                 = new TimingPipeFlusher(_dataPipe.Writer, timeoutControl, log);
     _dataWriteProcessingTask = ProcessDataWrites();
 }
        public bool TryPop(out Http2Stream result)
        {
            int size = _size - 1;

            Http2StreamAsValueType[] array = _array;

            if ((uint)size >= (uint)array.Length)
            {
                result = default;
                return(false);
            }

            _size       = size;
            result      = array[size];
            array[size] = default;
            return(true);
        }
        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 RemoveExpired(long now)
        {
            int size = _size;

            Http2StreamAsValueType[] array = _array;

            var removeCount = CalculateRemoveCount(now, size, array);

            if (removeCount == 0)
            {
                return;
            }

            var newSize = size - removeCount;

            // Dispose removed streams
            for (var i = 0; i < removeCount; i++)
            {
                Http2Stream stream = array[i];
                stream.Dispose();
            }

            // Move remaining streams
            for (var i = 0; i < newSize; i++)
            {
                array[i] = array[i + removeCount];
            }

            // Clear unused array indexes
            for (var i = newSize; i < size; i++)
            {
                array[i] = default;
            }

            _size = newSize;
        }
 private Http2MessageBody(Http2Stream context)
     : base(context)
 {
     _context = context;
 }
        private async Task ProcessHeadersFrameAsync <TContext>(IHttpApplication <TContext> application)
        {
            if (_currentHeadersStream != null)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.StreamId == 0)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.Length)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPriority && _incomingFrame.HeadersStreamDependency == _incomingFrame.StreamId)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamSelfDependency(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream))
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1
                //
                // ...an endpoint that receives any frames after receiving a frame with the
                // END_STREAM flag set MUST treat that as a connection error (Section 5.4.1)
                // of type STREAM_CLOSED, unless the frame is permitted as described below.
                //
                // (The allowed frame types after END_STREAM are WINDOW_UPDATE, RST_STREAM and PRIORITY)
                if (stream.EndStreamReceived)
                {
                    throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(_incomingFrame.Type, stream.StreamId), Http2ErrorCode.STREAM_CLOSED);
                }

                // This is the last chance for the client to send END_STREAM
                if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == 0)
                {
                    throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorHeadersWithTrailersNoEndStream, Http2ErrorCode.PROTOCOL_ERROR);
                }

                // Since we found an active stream, this HEADERS frame contains trailers
                _currentHeadersStream      = stream;
                _requestHeaderParsingState = RequestHeaderParsingState.Trailers;

                var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
                await DecodeTrailersAsync(endHeaders, _incomingFrame.HeadersPayload);
            }
            else if (_incomingFrame.StreamId <= _highestOpenedStreamId)
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1
                //
                // The first use of a new stream identifier implicitly closes all streams in the "idle"
                // state that might have been initiated by that peer with a lower-valued stream identifier.
                //
                // If we couldn't find the stream, it was previously closed (either implicitly or with
                // END_STREAM or RST_STREAM).
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED);
            }
            else
            {
                // Start a new stream
                _currentHeadersStream = new Http2Stream(new Http2StreamContext
                {
                    ConnectionId                = ConnectionId,
                    StreamId                    = _incomingFrame.StreamId,
                    ServiceContext              = _context.ServiceContext,
                    ConnectionFeatures          = _context.ConnectionFeatures,
                    MemoryPool                  = _context.MemoryPool,
                    LocalEndPoint               = _context.LocalEndPoint,
                    RemoteEndPoint              = _context.RemoteEndPoint,
                    StreamLifetimeHandler       = this,
                    ClientPeerSettings          = _clientSettings,
                    FrameWriter                 = _frameWriter,
                    ConnectionOutputFlowControl = _outputFlowControl,
                    TimeoutControl              = this,
                });

                if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == Http2HeadersFrameFlags.END_STREAM)
                {
                    await _currentHeadersStream.OnDataAsync(Constants.EmptyData, endStream : true);
                }

                _currentHeadersStream.Reset();

                var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
                await DecodeHeadersAsync(application, endHeaders, _incomingFrame.HeadersPayload);
            }
        }
Exemple #7
0
 public Http2MessageBody(Http2Stream context)
     : base(context)
 {
     _context = context;
 }
Exemple #8
0
 public ForHttp2(Http2Stream context)
     : base(context)
 {
 }
Exemple #9
0
 protected Http2MessageBody(Http2Stream context)
     : base(context)
 {
     _context = context;
 }
 private Http2StreamAsValueType(Http2Stream value) => _value = value;
 private void PushWithResize(Http2Stream item)
 {
     Array.Resize(ref _array, 2 * _array.Length);
     _array[_size] = item;
     _size++;
 }
Exemple #12
0
 private Http2MessageBody(Http2Stream context, MinDataRate minRequestBodyDataRate)
     : base(context, minRequestBodyDataRate)
 {
     _context = context;
 }
        private async Task ProcessHeadersFrameAsync <TContext>(IHttpApplication <TContext> application)
        {
            if (_currentHeadersStream != null)
            {
                throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.StreamId == 0)
            {
                throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.Length)
            {
                throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPriority && _incomingFrame.HeadersStreamDependency == _incomingFrame.StreamId)
            {
                throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream))
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1
                //
                // ...an endpoint that receives any frames after receiving a frame with the
                // END_STREAM flag set MUST treat that as a connection error (Section 5.4.1)
                // of type STREAM_CLOSED, unless the frame is permitted as described below.
                //
                // (The allowed frame types for this situation are WINDOW_UPDATE, RST_STREAM and PRIORITY)
                if (stream.EndStreamReceived)
                {
                    throw new Http2ConnectionErrorException(Http2ErrorCode.STREAM_CLOSED);
                }

                // TODO: trailers
            }
            else if (_incomingFrame.StreamId <= _highestOpenedStreamId)
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1
                //
                // The first use of a new stream identifier implicitly closes all streams in the "idle"
                // state that might have been initiated by that peer with a lower-valued stream identifier.
                //
                // If we couldn't find the stream, it was previously closed (either implicitly or with
                // END_STREAM or RST_STREAM).
                throw new Http2ConnectionErrorException(Http2ErrorCode.STREAM_CLOSED);
            }
            else
            {
                // Start a new stream
                _currentHeadersStream = new Http2Stream <TContext>(application, new Http2StreamContext
                {
                    ConnectionId          = ConnectionId,
                    StreamId              = _incomingFrame.StreamId,
                    ServiceContext        = _context.ServiceContext,
                    ConnectionFeatures    = _context.ConnectionFeatures,
                    PipeFactory           = _context.PipeFactory,
                    LocalEndPoint         = _context.LocalEndPoint,
                    RemoteEndPoint        = _context.RemoteEndPoint,
                    StreamLifetimeHandler = this,
                    FrameWriter           = _frameWriter
                });

                if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == Http2HeadersFrameFlags.END_STREAM)
                {
                    await _currentHeadersStream.OnDataAsync(Constants.EmptyData, endStream : true);
                }

                _currentHeadersStream.Reset();

                var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
                await DecodeHeadersAsync(endHeaders, _incomingFrame.HeadersPayload);
            }
        }