Пример #1
0
 public override void OnStreamClosed(IHttp2Stream stream)
 {
     try
     {
         // When a stream is closed, consume any remaining bytes so that they
         // are restored to the connection window.
         IFlowState state           = GetState(stream);
         int        unconsumedBytes = state.UnconsumedBytes;
         if (_ctx is object && unconsumedBytes > 0)
         {
             if (ConsumeAllBytes(state, unconsumedBytes))
             {
                 // As the user has no real control on when this callback is used we should better
                 // call flush() if we produced any window update to ensure we not stale.
                 _ = _ctx.Flush();
             }
         }
     }
     catch (Http2Exception)
     {
         throw;
     }
     finally
     {
         // Unconditionally reduce the amount of memory required for flow control because there is no
         // object allocation costs associated with doing so and the stream will not have any more
         // local flow control state to keep track of anymore.
         _ = stream.SetProperty(_stateKey, REDUCED_FLOW_STATE);
     }
 }
        public WeightedFairQueueByteDistributor(IHttp2Connection connection, int maxStateOnlySize)
        {
            uint uMaxStateOnlySize = (uint)maxStateOnlySize;

            if (uMaxStateOnlySize > SharedConstants.TooBigOrNegative)
            {
                ThrowHelper.ThrowArgumentException_PositiveOrZero(maxStateOnlySize, ExceptionArgument.maxStateOnlySize);
            }
            if (0u >= uMaxStateOnlySize)
            {
                _stateOnlyMap          = EmptyDictionary <int, State> .Instance;
                _stateOnlyRemovalQueue = EmptyPriorityQueue <State> .Instance;
            }
            else
            {
                _stateOnlyMap = new Dictionary <int, State>(maxStateOnlySize);
                // +2 because we may exceed the limit by 2 if a new dependency has no associated IHttp2Stream object. We need
                // to create the State objects to put them into the dependency tree, which then impacts priority.
                _stateOnlyRemovalQueue = new PriorityQueue <State>(StateOnlyComparator.Instance, maxStateOnlySize + 2);
            }

            _maxStateOnlySize = maxStateOnlySize;

            _connection = connection;
            _stateKey   = connection.NewKey();
            IHttp2Stream connectionStream = connection.ConnectionStream;

            _ = connectionStream.SetProperty(_stateKey, _connectionState = new State(this, connectionStream, 16));

            // Register for notification of new streams.
            connection.AddListener(this);
        }
Пример #3
0
        public void ServerCreateStreamShouldSucceed()
        {
            IHttp2Stream stream = server.Local.CreateStream(2, false);

            Assert.Equal(2, stream.Id);
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.Equal(1, server.NumActiveStreams);
            Assert.Equal(2, server.Local.LastStreamCreated);

            stream = server.Local.CreateStream(4, true);
            Assert.Equal(4, stream.Id);
            Assert.Equal(Http2StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(2, server.NumActiveStreams);
            Assert.Equal(4, server.Local.LastStreamCreated);

            stream = server.Remote.CreateStream(3, true);
            Assert.Equal(3, stream.Id);
            Assert.Equal(Http2StreamState.HalfClosedRemote, stream.State);
            Assert.Equal(3, server.NumActiveStreams);
            Assert.Equal(3, server.Remote.LastStreamCreated);

            stream = server.Remote.CreateStream(5, false);
            Assert.Equal(5, stream.Id);
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.Equal(4, server.NumActiveStreams);
            Assert.Equal(5, server.Remote.LastStreamCreated);
        }
Пример #4
0
        public void StreamErrorShouldFireExceptionForInbound()
        {
            _frameInboundWriter.WriteInboundHeaders(3, _request, 31, false);

            IHttp2Stream stream = _frameCodec.Connection.Stream(3);

            Assert.NotNull(stream);

            StreamException streamEx = new StreamException(3, Http2Error.InternalError, "foo");

            _channel.Pipeline.FireExceptionCaught(streamEx);

            Http2FrameStreamEvent evt = _inboundHandler.ReadInboundMessageOrUserEvent <Http2FrameStreamEvent>();

            Assert.Equal(Http2FrameStreamEvent.EventType.State, evt.Type);
            Assert.Equal(Http2StreamState.Open, evt.Stream.State);
            IHttp2HeadersFrame headersFrame = _inboundHandler.ReadInboundMessageOrUserEvent <IHttp2HeadersFrame>();

            Assert.NotNull(headersFrame);

            try
            {
                _inboundHandler.CheckException();
                Assert.False(true, "stream exception expected");
            }
            catch (Http2FrameStreamException e)
            {
                Assert.Equal(streamEx, e.InnerException);
            }

            Assert.Null(_inboundHandler.ReadInboundMessageOrUserEvent <object>());
        }
        public override void OnStreamAdded(IHttp2Stream stream)
        {
            int streamId = stream.Id;

            if (!_stateOnlyMap.TryGetValue(streamId, out State state))
            {
                state = new State(this, stream);
                // Only the stream which was just added will change parents. So we only need an array of size 1.
                List <ParentChangedEvent> events = new List <ParentChangedEvent>(1);
                _connectionState.TakeChild(state, false, events);
                NotifyParentChanged(events);
            }
            else
            {
                _             = _stateOnlyMap.Remove(streamId);
                _             = _stateOnlyRemovalQueue.TryRemove(state);
                state._stream = stream;
            }

            Http2StreamState streamState = stream.State;

            if (Http2StreamState.ReservedRemote == streamState || Http2StreamState.ReservedLocal == streamState)
            {
                state.SetStreamReservedOrActivated();
                // wasStreamReservedOrActivated is part of the comparator for stateOnlyRemovalQueue there is no
                // need to reprioritize here because it will not be in stateOnlyRemovalQueue.
            }

            _ = stream.SetProperty(_stateKey, state);
        }
Пример #6
0
        public void SendRstStream()
        {
            _frameInboundWriter.WriteInboundHeaders(3, _request, 31, true);

            IHttp2Stream stream = _frameCodec.Connection.Stream(3);

            Assert.NotNull(stream);
            Assert.Equal(Http2StreamState.HalfClosedRemote, stream.State);

            IHttp2HeadersFrame inboundHeaders = _inboundHandler.ReadInbound <IHttp2HeadersFrame>();

            Assert.NotNull(inboundHeaders);
            Assert.True(inboundHeaders.IsEndStream);

            IHttp2FrameStream stream2 = inboundHeaders.Stream;

            Assert.NotNull(stream2);
            Assert.Equal(3, stream2.Id);

            _channel.WriteOutbound(new DefaultHttp2ResetFrame((Http2Error)314 /* non-standard error */)
            {
                Stream = stream2
            });
            _frameWriter.Verify(
                x => x.WriteRstStreamAsync(
                    It.Is <IChannelHandlerContext>(v => v == _frameCodec._ctx),
                    It.Is <int>(v => v == 3),
                    It.Is <Http2Error>(v => v == (Http2Error)314L),
                    It.IsAny <IPromise>()));
            Assert.Equal(Http2StreamState.Closed, stream.State);
            Assert.True(_channel.IsActive);
        }
Пример #7
0
        public void SendGoAway()
        {
            _frameInboundWriter.WriteInboundHeaders(3, _request, 31, false);

            IHttp2Stream stream = _frameCodec.Connection.Stream(3);

            Assert.NotNull(stream);
            Assert.Equal(Http2StreamState.Open, stream.State);

            IByteBuffer debugData = Http2TestUtil.BB("debug");
            IByteBuffer expected  = debugData.Copy();

            IHttp2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(Http2Error.NoError, debugData.RetainedDuplicate());

            goAwayFrame.ExtraStreamIds = 2;

            _channel.WriteOutbound(goAwayFrame);
            _frameWriter.Verify(
                x => x.WriteGoAwayAsync(
                    It.Is <IChannelHandlerContext>(v => v == _frameCodec._ctx),
                    It.Is <int>(v => v == 7),
                    It.Is <Http2Error>(v => v == Http2Error.NoError),
                    It.Is <IByteBuffer>(v => v.Equals(expected)),
                    It.IsAny <IPromise>()));
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.True(_channel.IsActive);
            expected.Release();
            debugData.Release();
        }
Пример #8
0
        public void WeightChangeWithNoTreeChangeShouldBeRespected()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, true);

            Assert.Equal(4, connection.NumActiveStreams);

            short newWeight = (short)(Http2CodecUtil.DefaultPriorityWeight + 1);

            this.SetPriority(streamD.Id, streamA.Id, newWeight, false);

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamA.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(1, distributor.NumChildren(streamA.Id));

            // Level 2
            Assert.True(distributor.IsChild(streamD.Id, streamA.Id, newWeight));
            Assert.Equal(2, distributor.NumChildren(streamD.Id));

            // Level 3
            Assert.True(distributor.IsChild(streamB.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));

            Assert.True(distributor.IsChild(streamC.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamC.Id));
        }
Пример #9
0
        public void RemoveWithPrioritizableDependentsShouldNotRestructureTree()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);

            // Default removal policy will cause it to be removed immediately.
            streamB.Close();

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamA.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(2, distributor.NumChildren(streamA.Id));

            // Level 2
            Assert.True(distributor.IsChild(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamC.Id));

            Assert.True(distributor.IsChild(streamD.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamD.Id));
        }
Пример #10
0
        public void InsertExclusiveShouldAddNewLevel()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, true);

            Assert.Equal(4, connection.NumActiveStreams);

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamA.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(1, distributor.NumChildren(streamA.Id));

            // Level 2
            Assert.True(distributor.IsChild(streamD.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(2, distributor.NumChildren(streamD.Id));

            // Level 3
            Assert.True(distributor.IsChild(streamB.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));

            Assert.True(distributor.IsChild(streamC.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamC.Id));
        }
Пример #11
0
        public void ExistingChildMadeExclusiveShouldNotCreateTreeCycle()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight, false);

            // Stream C is already dependent on Stream A, but now make that an exclusive dependency
            this.SetPriority(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, true);

            Assert.Equal(4, connection.NumActiveStreams);

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamA.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(1, distributor.NumChildren(streamA.Id));

            // Level 2
            Assert.True(distributor.IsChild(streamC.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(2, distributor.NumChildren(streamC.Id));

            // Level 3
            Assert.True(distributor.IsChild(streamB.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));

            Assert.True(distributor.IsChild(streamD.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamD.Id));
        }
Пример #12
0
        public void PriorityOnlyStreamsArePreservedWhenReservedStreamsAreClosed()
        {
            this.Setup(1);

            short weight3 = Http2CodecUtil.MinWeight;

            this.SetPriority(3, connection.ConnectionStream.Id, weight3, true);

            IHttp2Stream streamA = connection.Local.CreateStream(5, false);
            IHttp2Stream streamB = connection.Remote.ReservePushStream(4, streamA);

            // Level 0
            Assert.Equal(3, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(3, connection.ConnectionStream.Id, weight3));
            Assert.Equal(0, distributor.NumChildren(3));

            Assert.True(distributor.IsChild(streamA.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamA.Id));

            Assert.True(distributor.IsChild(streamB.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));

            // Close both streams.
            streamB.Close();
            streamA.Close();

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(3, connection.ConnectionStream.Id, weight3));
            Assert.Equal(0, distributor.NumChildren(3));
        }
Пример #13
0
        public void StateOnlyPriorityShouldBePreservedWhenStreamsAreCreatedAndClosed()
        {
            this.Setup(3);

            short weight3 = Http2CodecUtil.MinWeight + 1;
            short weight5 = (short)(weight3 + 1);
            short weight7 = (short)(weight5 + 1);

            this.SetPriority(3, connection.ConnectionStream.Id, weight3, true);
            this.SetPriority(5, connection.ConnectionStream.Id, weight5, true);
            this.SetPriority(7, connection.ConnectionStream.Id, weight7, true);

            Assert.Equal(0, connection.NumActiveStreams);
            VerifyStateOnlyPriorityShouldBePreservedWhenStreamsAreCreated(weight3, weight5, weight7);

            // Now create stream objects and ensure the state and dependency tree is preserved.
            IHttp2Stream streamA = connection.Local.CreateStream(3, false);
            IHttp2Stream streamB = connection.Local.CreateStream(5, false);
            IHttp2Stream streamC = connection.Local.CreateStream(7, false);

            Assert.Equal(3, connection.NumActiveStreams);
            VerifyStateOnlyPriorityShouldBePreservedWhenStreamsAreCreated(weight3, weight5, weight7);

            // Close all the streams and ensure the state and dependency tree is preserved.
            streamA.Close();
            streamB.Close();
            streamC.Close();

            Assert.Equal(0, connection.NumActiveStreams);
            VerifyStateOnlyPriorityShouldBePreservedWhenStreamsAreCreated(weight3, weight5, weight7);
        }
 protected void WriteAnswer(IHttp2Stream stream, int numBytes)
 {
     this.stateMap.TryGetValue(stream.Id, out var state);
     state.pendingBytes -= numBytes;
     state.hasFrame      = state.pendingBytes > 0;
     distributor.UpdateStreamableBytes(state);
 }
        public override int OnDataRead(IChannelHandlerContext ctx, int streamId, IByteBuffer data, int padding, bool endOfStream)
        {
            IHttp2Stream     stream = _connection.Stream(streamId);
            IFullHttpMessage msg    = GetMessage(stream);

            if (msg is null)
            {
                ThrowHelper.ThrowConnectionError_DataFrameReceivedForUnknownStream(streamId);
            }

            var content           = msg.Content;
            int dataReadableBytes = data.ReadableBytes;

            if (content.ReadableBytes > _maxContentLength - dataReadableBytes)
            {
                ThrowHelper.ThrowConnectionError_ContentLengthExceededMax(_maxContentLength, streamId);
            }

            _ = content.WriteBytes(data, data.ReaderIndex, dataReadableBytes);

            if (endOfStream)
            {
                FireChannelRead(ctx, msg, false, stream);
            }

            // All bytes have been processed.
            return(dataReadableBytes + padding);
        }
Пример #16
0
        public void CloseWithNoPrioritizableDependentsShouldRestructureTree()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);
            IHttp2Stream streamE = connection.Local.CreateStream(9, false);
            IHttp2Stream streamF = connection.Local.CreateStream(11, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamE.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamF.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight, false);

            // Close internal nodes, leave 1 leaf node open, the only remaining stream is the one that is not closed (E).
            streamA.Close();
            streamB.Close();
            streamC.Close();
            streamD.Close();
            streamF.Close();

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamE.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamE.Id));
        }
        public override void OnPushPromiseRead(IChannelHandlerContext ctx, int streamId, int promisedStreamId, IHttp2Headers headers, int padding)
        {
            // A push promise should not be allowed to add headers to an existing stream
            IHttp2Stream promisedStream = _connection.Stream(promisedStreamId);

            if (headers.Status is null)
            {
                // A PUSH_PROMISE frame has no Http response status.
                // https://tools.ietf.org/html/rfc7540#section-8.2.1
                // Server push is semantically equivalent to a server responding to a
                // request; however, in this case, that request is also sent by the
                // server, as a PUSH_PROMISE frame.
                headers.Status = HttpResponseStatus.OK.CodeAsText;
            }
            IFullHttpMessage msg = ProcessHeadersBegin(ctx, promisedStream, headers, false, false, false);

            if (msg is null)
            {
                ThrowHelper.ThrowConnectionError_PushPromiseFrameReceivedForPreExistingStreamId(promisedStreamId);
            }

            _ = msg.Headers.SetInt(HttpConversionUtil.ExtensionHeaderNames.StreamPromiseId, streamId);
            _ = msg.Headers.SetShort(HttpConversionUtil.ExtensionHeaderNames.StreamWeight, Http2CodecUtil.DefaultPriorityWeight);

            ProcessHeadersEnd(ctx, promisedStream, msg, false);
        }
Пример #18
0
        public void PriorityChangeWithNoPrioritizableDependentsShouldRestructureTree()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(1, false);
            IHttp2Stream streamB = connection.Local.CreateStream(3, false);
            IHttp2Stream streamC = connection.Local.CreateStream(5, false);
            IHttp2Stream streamD = connection.Local.CreateStream(7, false);
            IHttp2Stream streamE = connection.Local.CreateStream(9, false);
            IHttp2Stream streamF = connection.Local.CreateStream(11, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamC.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamD.Id, streamB.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamF.Id, streamD.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            this.SetPriority(streamE.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight, false);

            // Leave leaf nodes open (E & F)
            streamA.Close();
            streamB.Close();
            streamC.Close();
            streamD.Close();

            // Move F to depend on C, even though C is closed.
            this.SetPriority(streamF.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight, false);

            // Level 0
            Assert.Equal(2, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamE.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamE.Id));

            Assert.True(distributor.IsChild(streamF.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamF.Id));
        }
Пример #19
0
        public void ReceiveRstStream()
        {
            _frameInboundWriter.WriteInboundHeaders(3, _request, 31, false);

            IHttp2Stream stream = _frameCodec.Connection.Stream(3);

            Assert.NotNull(stream);
            Assert.Equal(Http2StreamState.Open, stream.State);

            IHttp2HeadersFrame expectedHeaders = new DefaultHttp2HeadersFrame(_request, false, 31);
            IHttp2HeadersFrame actualHeaders   = _inboundHandler.ReadInbound <IHttp2HeadersFrame>();

            expectedHeaders.Stream = actualHeaders.Stream;
            Assert.Equal(expectedHeaders, actualHeaders);

            _frameInboundWriter.WriteInboundRstStream(3, Http2Error.NoError);

            IHttp2ResetFrame expectedRst = new DefaultHttp2ResetFrame(Http2Error.NoError)
            {
                Stream = actualHeaders.Stream
            };
            IHttp2ResetFrame actualRst = _inboundHandler.ReadInbound <IHttp2ResetFrame>();

            Assert.Equal(expectedRst, actualRst);

            Assert.Null(_inboundHandler.ReadInbound());
        }
Пример #20
0
        public void UnknownParentShouldBeCreatedUnderConnection()
        {
            this.Setup(5);

            // Purposefully avoid creating streamA's IHttp2Stream so that is it completely unknown.
            // It shouldn't matter whether the ID is before or after streamB.Id
            int          streamAId = 1;
            IHttp2Stream streamB   = connection.Local.CreateStream(3, false);

            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));

            // Build the tree
            this.SetPriority(streamB.Id, streamAId, Http2CodecUtil.DefaultPriorityWeight, false);

            Assert.Equal(1, connection.NumActiveStreams);

            // Level 0
            Assert.Equal(1, distributor.NumChildren(connection.ConnectionStream.Id));

            // Level 1
            Assert.True(distributor.IsChild(streamAId, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(1, distributor.NumChildren(streamAId));

            // Level 2
            Assert.True(distributor.IsChild(streamB.Id, streamAId, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(streamB.Id));
        }
Пример #21
0
        public void GoAwayLastStreamIdOverflowed()
        {
            _frameInboundWriter.WriteInboundHeaders(5, _request, 31, false);

            IHttp2Stream stream = _frameCodec.Connection.Stream(5);

            Assert.NotNull(stream);
            Assert.Equal(Http2StreamState.Open, stream.State);

            var debugData = Http2TestUtil.BB("debug");
            IHttp2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(Http2Error.NoError, debugData.RetainedDuplicate());

            goAwayFrame.ExtraStreamIds = int.MaxValue;

            _channel.WriteOutbound(goAwayFrame);
            // When the last stream id computation overflows, the last stream id should just be set to 2^31 - 1.
            _frameWriter.Verify(
                x => x.WriteGoAwayAsync(
                    It.Is <IChannelHandlerContext>(v => v == _frameCodec._ctx),
                    It.Is <int>(v => v == int.MaxValue),
                    It.Is <Http2Error>(v => v == Http2Error.NoError),
                    It.Is <IByteBuffer>(v => v.Equals(debugData)),
                    It.IsAny <IPromise>()));
            debugData.Release();
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.True(_channel.IsActive);
        }
Пример #22
0
 // note that this may behave strangely when used for the initial upgrade
 // message when using h2c, since that message is ineligible for flow
 // control, but there is not yet an API for signaling that.
 internal static void Handle(IChannelHandlerContext ctx, IHttp2Connection connection,
                             IHttp2FrameListener listener, IFullHttpMessage message)
 {
     try
     {
         int          streamId = GetStreamId(connection, message.Headers);
         IHttp2Stream stream   = connection.Stream(streamId);
         if (stream is null)
         {
             stream = connection.Remote.CreateStream(streamId, false);
         }
         _ = message.Headers.Set(HttpConversionUtil.ExtensionHeaderNames.Scheme, HttpScheme.Http.Name);
         IHttp2Headers messageHeaders = HttpConversionUtil.ToHttp2Headers(message, true);
         var           hasContent     = message.Content.IsReadable();
         var           hasTrailers    = !message.TrailingHeaders.IsEmpty;
         listener.OnHeadersRead(ctx, streamId, messageHeaders, 0, !(hasContent || hasTrailers));
         if (hasContent)
         {
             _ = listener.OnDataRead(ctx, streamId, message.Content, 0, !hasTrailers);
         }
         if (hasTrailers)
         {
             IHttp2Headers headers = HttpConversionUtil.ToHttp2Headers(message.TrailingHeaders, true);
             listener.OnHeadersRead(ctx, streamId, headers, 0, true);
         }
         _ = stream.CloseRemoteSide();
     }
     finally
     {
         _ = message.Release();
     }
 }
Пример #23
0
        public void StreamErrorShouldNotFireExceptionForOutbound()
        {
            _frameInboundWriter.WriteInboundHeaders(3, _request, 31, false);

            IHttp2Stream stream = _frameCodec.Connection.Stream(3);

            Assert.NotNull(stream);

            StreamException streamEx = new StreamException(3, Http2Error.InternalError, "foo");

            _frameCodec.OnError(_frameCodec._ctx, true, streamEx);

            Http2FrameStreamEvent evt = _inboundHandler.ReadInboundMessageOrUserEvent <Http2FrameStreamEvent>();

            Assert.Equal(Http2FrameStreamEvent.EventType.State, evt.Type);
            Assert.Equal(Http2StreamState.Open, evt.Stream.State);
            IHttp2HeadersFrame headersFrame = _inboundHandler.ReadInboundMessageOrUserEvent <IHttp2HeadersFrame>();

            Assert.NotNull(headersFrame);

            // No exception expected
            _inboundHandler.CheckException();

            Assert.Null(_inboundHandler.ReadInboundMessageOrUserEvent <object>());
        }
Пример #24
0
 protected void CloseStream(IHttp2Stream stream, bool dataRead)
 {
     if (stream != null)
     {
         stream.Close();
     }
 }
 internal State(WeightedFairQueueByteDistributor distributor, int streamId, IHttp2Stream stream, int initialSize)
 {
     _distributor     = distributor;
     _stream          = stream;
     _streamId        = streamId;
     _pseudoTimeQueue = new PriorityQueue <State>(StatePseudoTimeComparator.Instance, initialSize);
 }
        public void WriteWithNonActiveStreamShouldNotDobuleAddToPriorityQueue()
        {
            this.InitState(STREAM_A, 400, true);
            this.InitState(STREAM_B, 500, true);
            this.InitState(STREAM_C, 600, true);
            this.InitState(STREAM_D, 700, true);

            this.SetPriority(STREAM_B, STREAM_A, Http2CodecUtil.DefaultPriorityWeight, true);
            this.SetPriority(STREAM_D, STREAM_C, Http2CodecUtil.DefaultPriorityWeight, true);

            // Block B, but it should still remain in the queue/tree structure.
            this.InitState(STREAM_B, 0, false);

            // Get the streams before the write, because they may be be closed.
            IHttp2Stream streamA = this.Stream(STREAM_A);
            IHttp2Stream streamB = this.Stream(STREAM_B);
            IHttp2Stream streamC = this.Stream(STREAM_C);
            IHttp2Stream streamD = this.Stream(STREAM_D);

            this.writer.Reset();
            this.writer.Setup(x => x.Write(It.IsAny <IHttp2Stream>(), It.IsAny <int>()))
            .Callback <IHttp2Stream, int>((stream, numBytes) => this.WriteAnswer(stream, numBytes, true));

            Assert.False(this.Write(400 + 600 + 700));
            Assert.Equal(400, this.CaptureWrites(streamA));
            this.VerifyNeverWrite(streamB);
            Assert.Equal(600, this.CaptureWrites(streamC));
            Assert.Equal(700, this.CaptureWrites(streamD));
        }
Пример #27
0
 public DefaultHttp2FrameStream SetStreamAndProperty(IHttp2ConnectionPropertyKey streamKey, IHttp2Stream stream)
 {
     Debug.Assert(v_id == -1 || stream.Id == v_id);
     _ = stream.SetProperty(streamKey, this);
     InternalStream = stream;
     return(this);
 }
        public void BytesDistributedWithAdditionShouldBeCorrect()
        {
            IHttp2Stream streamE = connection.Local.CreateStream(STREAM_E, false);

            this.SetPriority(streamE.Id, STREAM_A, Http2CodecUtil.DefaultPriorityWeight, true);

            // Send a bunch of data on each stream.
            this.InitState(STREAM_A, 400, true);
            this.InitState(STREAM_B, 500, true);
            this.InitState(STREAM_C, 600, true);
            this.InitState(STREAM_D, 700, true);
            this.InitState(STREAM_E, 900, true);

            Assert.True(this.Write(900));
            Assert.Equal(400, this.CaptureWrites(STREAM_A));
            Assert.Equal(500, this.CaptureWrites(STREAM_B));
            this.VerifyNeverWrite(STREAM_C);
            this.VerifyNeverWrite(STREAM_D);
            this.VerifyWrite(Times.AtMost(1), STREAM_E, 0);

            Assert.True(this.Write(900));
            Assert.Equal(400, this.CaptureWrites(STREAM_A));
            Assert.Equal(500, this.CaptureWrites(STREAM_B));
            this.VerifyWrite(Times.AtMost(1), STREAM_C, 0);
            this.VerifyWrite(Times.AtMost(1), STREAM_D, 0);
            Assert.Equal(900, this.CaptureWrites(STREAM_E));

            Assert.False(this.Write(1301));
            Assert.Equal(400, this.CaptureWrites(STREAM_A));
            Assert.Equal(500, this.CaptureWrites(STREAM_B));
            Assert.Equal(600, this.CaptureWrites(STREAM_C));
            Assert.Equal(700, this.CaptureWrites(STREAM_D));
            Assert.Equal(900, this.CaptureWrites(STREAM_E));
        }
Пример #29
0
        public void ClientCreateStreamShouldSucceed()
        {
            IHttp2Stream stream = client.Remote.CreateStream(2, false);

            Assert.Equal(2, stream.Id);
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.Equal(1, client.NumActiveStreams);
            Assert.Equal(2, client.Remote.LastStreamCreated);

            stream = client.Remote.CreateStream(4, true);
            Assert.Equal(4, stream.Id);
            Assert.Equal(Http2StreamState.HalfClosedRemote, stream.State);
            Assert.Equal(2, client.NumActiveStreams);
            Assert.Equal(4, client.Remote.LastStreamCreated);
            Assert.True(stream.IsHeadersReceived);

            stream = client.Local.CreateStream(3, true);
            Assert.Equal(3, stream.Id);
            Assert.Equal(Http2StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(3, client.NumActiveStreams);
            Assert.Equal(3, client.Local.LastStreamCreated);
            Assert.True(stream.IsHeadersSent);

            stream = client.Local.CreateStream(5, false);
            Assert.Equal(5, stream.Id);
            Assert.Equal(Http2StreamState.Open, stream.State);
            Assert.Equal(4, client.NumActiveStreams);
            Assert.Equal(5, client.Local.LastStreamCreated);
        }
Пример #30
0
 public DefaultState(DefaultHttp2LocalFlowController controller, IHttp2Stream stream, int initialWindowSize)
 {
     _controller = controller;
     _stream     = stream;
     Window(initialWindowSize);
     _streamWindowUpdateRatio = controller._windowUpdateRatio;
 }