Beispiel #1
0
        public void CloseShouldSucceed()
        {
            IHttp2Stream stream = _server.Remote.CreateStream(3, true);

            stream.Close();
            Assert.Equal(Http2StreamState.Closed, stream.State);
            Assert.Equal(0, _server.NumActiveStreams);
        }
        public void DataReceivedForClosedStreamShouldImmediatelyConsumeBytes()
        {
            IHttp2Stream stream = Stream(STREAM_ID);

            stream.Close();
            ReceiveFlowControlledFrame(stream, 10, 0, false);
            Assert.Equal(0, controller.UnconsumedBytes(_connection.ConnectionStream));
        }
Beispiel #3
0
 protected void WriteAnswer(IHttp2Stream stream, int numBytes, bool closeIfNoFrame)
 {
     this.stateMap.TryGetValue(stream.Id, out var state);
     state.pendingBytes  -= numBytes;
     state.hasFrame       = state.pendingBytes > 0;
     state.isWriteAllowed = state.hasFrame;
     if (closeIfNoFrame && !state.hasFrame)
     {
         stream.Close();
     }
     distributor.UpdateStreamableBytes(state);
 }
Beispiel #4
0
        public void CloseWhileIteratingDoesNotNPE()
        {
            IHttp2Stream streamA = connection.Local.CreateStream(3, false);
            IHttp2Stream streamB = connection.Local.CreateStream(5, false);
            IHttp2Stream streamC = connection.Local.CreateStream(7, false);

            this.SetPriority(streamB.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            connection.ForEachActiveStream(stream =>
            {
                streamA.Close();
                this.SetPriority(streamB.Id, streamC.Id, Http2CodecUtil.DefaultPriorityWeight, false);
                return(true);
            });
        }
Beispiel #5
0
        public void ClosingStreamWithChildrenDoesNotCauseConcurrentModification()
        {
            // We create enough streams to wrap around the child array. We carefully craft the stream ids so that they hash
            // codes overlap with respect to the child collection. If the implementation is not careful this may lead to a
            // concurrent modification exception while promoting all children to the connection stream.
            IHttp2Stream streamA    = connection.Local.CreateStream(1, false);
            int          numStreams = WeightedFairQueueByteDistributor.InitialChildrenMapSize - 1;

            for (int i = 0, streamId = 3; i < numStreams; ++i, streamId += WeightedFairQueueByteDistributor.InitialChildrenMapSize)
            {
                IHttp2Stream stream = connection.Local.CreateStream(streamId, false);
                this.SetPriority(stream.Id, streamA.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            }
            Assert.Equal(WeightedFairQueueByteDistributor.InitialChildrenMapSize, connection.NumActiveStreams);
            streamA.Close();
            Assert.Equal(numStreams, connection.NumActiveStreams);
        }
Beispiel #6
0
        public void LowestPrecedenceStateShouldBeDropped()
        {
            this.Setup(3);

            short weight3 = Http2CodecUtil.MaxWeight;
            short weight5 = (short)(weight3 - 1);
            short weight7 = (short)(weight5 - 1);
            short weight9 = (short)(weight7 - 1);

            this.SetPriority(3, connection.ConnectionStream.Id, weight3, true);
            this.SetPriority(5, connection.ConnectionStream.Id, weight5, true);
            this.SetPriority(7, connection.ConnectionStream.Id, weight7, false);
            Assert.Equal(0, connection.NumActiveStreams);
            VerifyLowestPrecedenceStateShouldBeDropped1(weight3, weight5, weight7);

            // Attempt to create a new item in the dependency tree but the maximum amount of "state only" streams is meet
            // so a stream will have to be dropped. Currently the new stream is the lowest "precedence" so it is dropped.
            this.SetPriority(9, 3, weight9, false);
            Assert.Equal(0, connection.NumActiveStreams);
            VerifyLowestPrecedenceStateShouldBeDropped1(weight3, weight5, weight7);

            // Set the priority for stream 9 such that its depth in the dependency tree is numerically lower than stream 3,
            // and therefore the dependency state associated with stream 3 will be dropped.
            this.SetPriority(9, 5, weight9, true);
            VerifyLowestPrecedenceStateShouldBeDropped2(weight9, weight5, weight7);

            // Test that stream which has been activated is lower priority than other streams that have not been activated.
            IHttp2Stream streamA = connection.Local.CreateStream(5, false);

            streamA.Close();
            VerifyLowestPrecedenceStateShouldBeDropped2(weight9, weight5, weight7);

            // Stream 3 (hasn't been opened) should result in stream 5 being dropped.
            this.SetPriority(3, 9, weight3, false);
            VerifyLowestPrecedenceStateShouldBeDropped3(weight3, weight7, weight9);

            // Stream 5's state has been discarded so we should be able to re-insert this state.
            this.SetPriority(5, 0, weight5, false);
            VerifyLowestPrecedenceStateShouldBeDropped4(weight5, weight7, weight9);

            // All streams are at the same level, so stream ID should be used to drop the numeric lowest valued stream.
            short weight11 = (short)(weight9 - 1);

            this.SetPriority(11, 0, weight11, false);
            VerifyLowestPrecedenceStateShouldBeDropped5(weight7, weight9, weight11);
        }
Beispiel #7
0
        public void RemoveIndividualStreamsWhileCloseDoesNotNPE()
        {
            IHttp2Stream streamA = client.Local.CreateStream(3, false);
            IHttp2Stream streamB = client.Remote.CreateStream(2, false);

            this.clientListener2
            .Setup(x => x.OnStreamClosed(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(stream =>
            {
                streamA.Close();
                streamB.Close();
            });
            try
            {
                client.AddListener(this.clientListener2.Object);
                this.TestRemoveAllStreams();
            }
            finally
            {
                client.RemoveListener(this.clientListener2.Object);
            }
        }
        public void WindowUpdateShouldNotBeSentAfterStreamIsClosedForUnconsumedBytes()
        {
            int dataSize = (int)(Http2CodecUtil.DefaultWindowSize * DefaultHttp2LocalFlowController.DefaultWindowUpdateRatio) + 1;

            // Don't set end-of-stream on the frame as we want to verify that we not return the unconsumed bytes in this
            // case once the stream was closed,
            ReceiveFlowControlledFrame(STREAM_ID, dataSize, 0, false);
            VerifyWindowUpdateNotSent(Http2CodecUtil.ConnectionStreamId);
            VerifyWindowUpdateNotSent(STREAM_ID);

            // Close the stream
            IHttp2Stream stream = _connection.Stream(STREAM_ID);

            stream.Close();
            Assert.Equal(Http2StreamState.Closed, stream.State);
            Assert.Null(_connection.Stream(STREAM_ID));

            // The window update for the connection should made it through but not the update for the already closed
            // stream
            VerifyWindowUpdateSent(Http2CodecUtil.ConnectionStreamId, dataSize);
            VerifyWindowUpdateNotSent(STREAM_ID);
        }
Beispiel #9
0
        public void ListenerThrowShouldNotPreventOtherListenersFromBeingNotified()
        {
            var calledArray = new bool[128];
            // The following setup will ensure that clientListener throws exceptions, and marks a value in an array
            // such that clientListener2 will verify that is is set or fail the test.
            int methodIndex = 0;

            this.clientListener
            .Setup(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnStreamActive(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamActive(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnStreamHalfClosed(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamHalfClosed(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnStreamClosed(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamClosed(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnStreamRemoved(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamRemoved(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnGoAwaySent(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()))
            .Callback <int, Http2Error, IByteBuffer>((id, err, buf) => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnGoAwaySent(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()))
            .Callback <int, Http2Error, IByteBuffer>((id, err, buf) => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnGoAwayReceived(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()))
            .Callback <int, Http2Error, IByteBuffer>((id, err, buf) => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnGoAwayReceived(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()))
            .Callback <int, Http2Error, IByteBuffer>((id, err, buf) => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            this.clientListener
            .Setup(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerExceptionThrower(calledArray, methodIndex));
            this.clientListener2
            .Setup(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()))
            .Callback <IHttp2Stream>(s => ListenerVerifyCallAnswer(calledArray, methodIndex++));

            // Now we add clientListener2 and exercise all listener functionality
            try
            {
                this.client.AddListener(this.clientListener2.Object);
                IHttp2Stream stream = client.Local.CreateStream(3, false);
                this.clientListener.Verify(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()));
                this.clientListener2.Verify(x => x.OnStreamAdded(It.IsAny <IHttp2Stream>()));
                this.clientListener.Verify(x => x.OnStreamActive(It.IsAny <IHttp2Stream>()));
                this.clientListener2.Verify(x => x.OnStreamActive(It.IsAny <IHttp2Stream>()));

                IHttp2Stream reservedStream = client.Remote.ReservePushStream(2, stream);
                this.clientListener.Verify(x => x.OnStreamActive(It.Is <IHttp2Stream>(s => StreamEq(s, reservedStream))), Times.Never());
                this.clientListener2.Verify(x => x.OnStreamActive(It.Is <IHttp2Stream>(s => StreamEq(s, reservedStream))), Times.Never());

                reservedStream.Open(false);
                this.clientListener.Verify(x => x.OnStreamActive(It.Is <IHttp2Stream>(s => StreamEq(s, reservedStream))));
                this.clientListener2.Verify(x => x.OnStreamActive(It.Is <IHttp2Stream>(s => StreamEq(s, reservedStream))));

                stream.CloseLocalSide();
                this.clientListener.Verify(x => x.OnStreamHalfClosed(It.IsAny <IHttp2Stream>()));
                this.clientListener2.Verify(x => x.OnStreamHalfClosed(It.IsAny <IHttp2Stream>()));

                stream.Close();
                this.clientListener.Verify(x => x.OnStreamClosed(It.IsAny <IHttp2Stream>()));
                this.clientListener2.Verify(x => x.OnStreamClosed(It.IsAny <IHttp2Stream>()));
                this.clientListener.Verify(x => x.OnStreamRemoved(It.IsAny <IHttp2Stream>()));
                this.clientListener2.Verify(x => x.OnStreamRemoved(It.IsAny <IHttp2Stream>()));

                this.client.GoAwaySent(this.client.ConnectionStream.Id, Http2Error.InternalError, Unpooled.Empty);
                this.clientListener.Verify(x => x.OnGoAwaySent(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()));
                this.clientListener2.Verify(x => x.OnGoAwaySent(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()));

                this.client.GoAwayReceived(this.client.ConnectionStream.Id, Http2Error.InternalError, Unpooled.Empty);
                this.clientListener.Verify(x => x.OnGoAwayReceived(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()));
                this.clientListener2.Verify(x => x.OnGoAwayReceived(It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>()));
            }
            finally
            {
                this.client.RemoveListener(this.clientListener2.Object);
            }
        }
Beispiel #10
0
        public void FireFoxQoSStreamsRemainAfterDataStreamsAreClosed()
        {
            // http://bitsup.blogspot.com/2015/01/http2-dependency-priorities-in-firefox.html
            this.Setup(5);

            this.SetPriority(leadersId, connection.ConnectionStream.Id, leadersWeight, false);
            this.SetPriority(unblockedId, connection.ConnectionStream.Id, unblockedWeight, false);
            this.SetPriority(backgroundId, connection.ConnectionStream.Id, backgroundWeight, false);
            this.SetPriority(speculativeId, backgroundId, speculativeWeight, false);
            this.SetPriority(followersId, leadersId, followersWeight, false);

            VerifyFireFoxQoSStreams();

            // Simulate a HTML request
            short        htmlGetStreamWeight = 2;
            IHttp2Stream htmlGetStream       = connection.Local.CreateStream(13, false);

            this.SetPriority(htmlGetStream.Id, followersId, htmlGetStreamWeight, false);
            IHttp2Stream favIconStream = connection.Local.CreateStream(15, false);

            this.SetPriority(favIconStream.Id, connection.ConnectionStream.Id, Http2CodecUtil.DefaultPriorityWeight, false);
            IHttp2Stream cssStream = connection.Local.CreateStream(17, false);

            this.SetPriority(cssStream.Id, leadersId, Http2CodecUtil.DefaultPriorityWeight, false);
            IHttp2Stream jsStream = connection.Local.CreateStream(19, false);

            this.SetPriority(jsStream.Id, leadersId, Http2CodecUtil.DefaultPriorityWeight, false);
            IHttp2Stream imageStream = connection.Local.CreateStream(21, false);

            this.SetPriority(imageStream.Id, followersId, 1, false);

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

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

            Assert.True(distributor.IsChild(unblockedId, connection.ConnectionStream.Id, unblockedWeight));
            Assert.Equal(0, distributor.NumChildren(unblockedId));

            Assert.True(distributor.IsChild(backgroundId, connection.ConnectionStream.Id, backgroundWeight));
            Assert.Equal(1, distributor.NumChildren(backgroundId));

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

            // Level 2
            Assert.True(distributor.IsChild(followersId, leadersId, followersWeight));
            Assert.Equal(2, distributor.NumChildren(followersId));

            Assert.True(distributor.IsChild(speculativeId, backgroundId, speculativeWeight));
            Assert.Equal(0, distributor.NumChildren(speculativeId));

            Assert.True(distributor.IsChild(cssStream.Id, leadersId, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(cssStream.Id));

            Assert.True(distributor.IsChild(jsStream.Id, leadersId, Http2CodecUtil.DefaultPriorityWeight));
            Assert.Equal(0, distributor.NumChildren(jsStream.Id));

            // Level 3
            Assert.True(distributor.IsChild(htmlGetStream.Id, followersId, htmlGetStreamWeight));
            Assert.Equal(0, distributor.NumChildren(htmlGetStream.Id));

            Assert.True(distributor.IsChild(imageStream.Id, followersId, followersWeight));
            Assert.Equal(0, distributor.NumChildren(imageStream.Id));

            // Close all the data streams and ensure the "priority only streams" are retained in the dependency tree.
            htmlGetStream.Close();
            favIconStream.Close();
            cssStream.Close();
            jsStream.Close();
            imageStream.Close();

            VerifyFireFoxQoSStreams();
        }