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); }
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); }
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); }
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); }
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(); }
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)); }
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)); }
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)); }
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)); }
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)); }
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); }
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); }
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)); }
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()); }
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)); }
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); }
// 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(); } }
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>()); }
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)); }
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)); }
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); }
public DefaultState(DefaultHttp2LocalFlowController controller, IHttp2Stream stream, int initialWindowSize) { _controller = controller; _stream = stream; Window(initialWindowSize); _streamWindowUpdateRatio = controller._windowUpdateRatio; }