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)); }
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); }
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); }); }
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); }
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); }
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); }
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); } }
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(); }