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); }
private async Task BootstrapEnv(int serverOutSize) { var prefaceWrittenLatch = new CountdownEvent(1); this.serverOut = new MemoryStream(serverOutSize); this.serverLatch = new CountdownEvent(1); this.sb = new ServerBootstrap(); this.cb = new Bootstrap(); // Streams are created before the normal flow for this test, so these connection must be initialized up front. this.serverConnection = new DefaultHttp2Connection(true); this.clientConnection = new DefaultHttp2Connection(false); this.serverConnection.AddListener(new TestHttp2ConnectionAdapter(this.serverLatch)); this.serverListener .Setup(x => x.OnDataRead( It.IsAny <IChannelHandlerContext>(), It.IsAny <int>(), It.IsAny <IByteBuffer>(), It.IsAny <int>(), It.IsAny <bool>())) .Returns <IChannelHandlerContext, int, IByteBuffer, int, bool>((ctx, id, buf, padding, end) => { int processedBytes = buf.ReadableBytes + padding; buf.ReadBytes(this.serverOut, buf.ReadableBytes); if (end) { this.serverConnection.Stream(id).Close(); } return(processedBytes); }); var serverChannelLatch = new CountdownEvent(1); this.SetupServerBootstrap(this.sb); this.sb.ChildHandler(new ActionChannelInitializer <IChannel>(ch => { this.SetInitialServerChannelPipeline(ch); serverChannelLatch.SafeSignal(); })); this.SetupBootstrap(this.cb); this.cb.Handler(new ActionChannelInitializer <IChannel>(ch => { this.SetInitialChannelPipeline(ch); ch.Pipeline.AddLast(new TestChannelHandlerAdapter(prefaceWrittenLatch)); })); var loopback = IPAddress.IPv6Loopback; this.serverChannel = await this.sb.BindAsync(loopback, Port); var port = ((IPEndPoint)this.serverChannel.LocalAddress).Port; var ccf = this.cb.ConnectAsync(loopback, port); this.clientChannel = await ccf; Assert.True(prefaceWrittenLatch.Wait(TimeSpan.FromSeconds(10))); Assert.True(serverChannelLatch.Wait(TimeSpan.FromSeconds(10))); }
// 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 DefaultHttp2RemoteFlowController(IHttp2Connection connection, IStreamByteDistributor streamByteDistributor, IHttp2RemoteFlowControllerListener listener) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } if (streamByteDistributor is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.streamByteDistributor); } _connection = connection; _streamByteDistributor = streamByteDistributor; // Add a flow state for the connection. _stateKey = connection.NewKey(); _connectionState = new FlowState(this, _connection.ConnectionStream); _ = connection.ConnectionStream.SetProperty(_stateKey, _connectionState); // Monitor may depend upon connectionState, and so initialize after connectionState Listener(listener); _monitor.WindowSize(_connectionState, _initialWindowSize); // Register for notification of new streams. connection.AddListener(this); }
/// <summary> /// Creates a new <see cref="InboundHttp2ToHttpAdapter"/> builder for the specified <see cref="IHttp2Connection"/>. /// </summary> /// <param name="connection">the object which will provide connection notification events /// for the current connection.</param> protected AbstractInboundHttp2ToHttpAdapterBuilder(IHttp2Connection connection) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } _connection = connection; }
public FrameAdapter(IHttp2Connection connection, DefaultHttp2FrameReader reader, IHttp2FrameListener listener, CountdownEvent latch) { this.connection = connection; this.listener = listener; this.reader = reader; this.latch = latch; }
public DelegatingDecompressorFrameListener(IHttp2Connection connection, IHttp2FrameListener listener, bool strict) : base(listener) { _connection = connection; _strict = strict; _propertyKey = connection.NewKey(); _connection.AddListener(new DelegatingConnectionAdapter(this)); }
public UniformStreamByteDistributor(IHttp2Connection connection) { // Add a state for the connection. _stateKey = connection.NewKey(); var connectionStream = connection.ConnectionStream; _ = connectionStream.SetProperty(_stateKey, new State(this, connectionStream)); // Register for notification of new streams. connection.AddListener(this); }
public void WindowUpdateDoesNotOverflowConnectionWindow() { IHttp2Connection connection = _frameCodec.Connection; IHttp2LocalFlowController localFlow = connection.Local.FlowController; int initialWindowSizeBefore = localFlow.InitialWindowSize; _channel.WriteAsync(new DefaultHttp2WindowUpdateFrame(int.MaxValue)); // The initial window size is only changed by Http2Settings, so it shouldn't change. Assert.Equal(initialWindowSizeBefore, localFlow.InitialWindowSize); // The connection window should be increased by the delta amount. Assert.Equal(int.MaxValue, localFlow.GetWindowSize(connection.ConnectionStream)); }
/// <summary>Create a new instance.</summary> /// <param name="connection">The <see cref="IHttp2Connection"/> associated with this decoder.</param> /// <param name="encoder">The <see cref="IHttp2ConnectionEncoder"/> associated with this decoder.</param> /// <param name="frameReader">Responsible for reading/parsing the raw frames. As opposed to this object which applies /// h2 semantics on top of the frames.</param> /// <param name="requestVerifier">Determines if push promised streams are valid.</param> /// <param name="autoAckSettings"><c>false</c> to disable automatically applying and sending settings acknowledge frame. /// The <paramref name="encoder"/> is expected to be an instance of /// <see cref="IHttp2SettingsReceivedConsumer"/> and will apply the earliest received but not yet /// ACKed SETTINGS when writing the SETTINGS ACKs. <c>true</c> to enable automatically /// applying and sending settings acknowledge frame.</param> /// <param name="autoAckPing"><c>false</c> to disable automatically sending ping acknowledge frame. <c>true</c> to enable /// automatically sending ping ack frame.</param> public DefaultHttp2ConnectionDecoder(IHttp2Connection connection, IHttp2ConnectionEncoder encoder, IHttp2FrameReader frameReader, IHttp2PromisedRequestVerifier requestVerifier, bool autoAckSettings, bool autoAckPing) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } if (frameReader is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.frameReader); } if (encoder is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.encoder); } if (requestVerifier is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.requestVerifier); } _autoAckPing = autoAckPing; if (autoAckSettings) { _settingsReceivedConsumer = null; } else { var receivedConsumer = encoder as IHttp2SettingsReceivedConsumer; if (receivedConsumer is null) { ThrowHelper.ThrowInvalidOperationException_disabling_autoAckSettings_requires_encoder_IHttp2SettingsReceivedConsumer(); } _settingsReceivedConsumer = receivedConsumer; } _connection = connection; _frameReader = frameReader; _encoder = encoder; _requestVerifier = requestVerifier; var connLocal = connection.Local; if (connLocal.FlowController is null) { connLocal.FlowController = new DefaultHttp2LocalFlowController(connection); } _ = connLocal.FlowController.FrameWriter(encoder.FrameWriter); _internalFrameListener = new PrefaceFrameListener(this); }
private void TryExpandConnectionFlowControlWindow(IHttp2Connection connection) { if (_initialFlowControlWindowSize.HasValue) { // The window size in the settings explicitly excludes the connection window. So we manually manipulate the // connection window to accommodate more concurrent data per connection. var connectionStream = connection.ConnectionStream; var localFlowController = connection.Local.FlowController; int delta = _initialFlowControlWindowSize.Value - localFlowController.GetInitialWindowSize(connectionStream); // Only increase the connection window, don't decrease it. if (delta > 0) { // Double the delta just so a single stream can't exhaust the connection window. localFlowController.IncrementWindowSize(connectionStream, Math.Max(delta << 1, delta)); Flush(_ctx); } } }
public UniformStreamByteDistributorTest() { this.writer = new Mock <IStreamByteDistributorWriter>(); stateMap = new Dictionary <int, Http2TestUtil.TestStreamByteDistributorStreamState>(); this.connection = new DefaultHttp2Connection(false); this.distributor = new UniformStreamByteDistributor(this.connection); // Assume we always write all the allocated bytes. this.ResetWriter(); connection.Local.CreateStream(STREAM_A, false); connection.Local.CreateStream(STREAM_B, false); IHttp2Stream streamC = connection.Local.CreateStream(STREAM_C, false); IHttp2Stream streamD = connection.Local.CreateStream(STREAM_D, false); this.SetPriority(streamC.Id, STREAM_A, Http2CodecUtil.DefaultPriorityWeight, false); this.SetPriority(streamD.Id, STREAM_A, Http2CodecUtil.DefaultPriorityWeight, false); }
public InboundHttp2ToHttpAdapter(IHttp2Connection connection, int maxContentLength, bool validateHttpHeaders, bool propagateSettings) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } if ((uint)(maxContentLength - 1) > SharedConstants.TooBigOrNegative) { ThrowHelper.ThrowArgumentException_Positive(maxContentLength, ExceptionArgument.maxContentLength); } _connection = connection; _maxContentLength = maxContentLength; _validateHttpHeaders = validateHttpHeaders; _propagateSettings = propagateSettings; _sendDetector = DefaultImmediateSendDetector.Instance; _messageKey = connection.NewKey(); }
public DefaultHttp2ConnectionEncoder(IHttp2Connection connection, IHttp2FrameWriter frameWriter) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } if (frameWriter is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.frameWriter); } _connection = connection; _frameWriter = frameWriter; var connRemote = connection.Remote; if (connRemote.FlowController is null) { connRemote.FlowController = new DefaultHttp2RemoteFlowController(connection); } }
public static IHttp2Stream GetOrCreateStream(IHttp2Connection connection, int streamId, bool halfClosed) { if (connection != null) { var stream = connection.Stream(streamId); if (stream == null) { if (connection.IsServer && streamId % 2 == 0 || !connection.IsServer && streamId % 2 != 0) { stream = connection.Local.CreateStream(streamId, halfClosed); } else { stream = connection.Remote.CreateStream(streamId, halfClosed); } } return(stream); } return(null); }
/// <summary> /// Constructs a controller with the given settings. /// </summary> /// <param name="connection">the connection state.</param> /// <param name="windowUpdateRatio">the window percentage below which to send a <c>WINDOW_UPDATE</c>.</param> /// <param name="autoRefillConnectionWindow">if <c>true</c>, effectively disables the connection window /// in the flow control algorithm as they will always refill automatically without requiring the /// application to consume the bytes. When enabled, the maximum bytes you must be prepared to /// queue is proportional to <c>maximum number of concurrent streams * the initial window /// size per stream</c> /// (<a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_CONCURRENT_STREAMS</a> /// <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_INITIAL_WINDOW_SIZE</a>). /// </param> public DefaultHttp2LocalFlowController(IHttp2Connection connection, float windowUpdateRatio, bool autoRefillConnectionWindow) { if (connection is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection); } _connection = connection; WindowUpdateRatio(windowUpdateRatio); // Add a flow state for the connection. _stateKey = connection.NewKey(); IFlowState connectionState = autoRefillConnectionWindow ? new AutoRefillState(this, connection.ConnectionStream, _initialWindowSize) : new DefaultState(this, connection.ConnectionStream, _initialWindowSize); _ = connection.ConnectionStream.SetProperty(_stateKey, connectionState); // Register for notification of new streams. connection.AddListener(this); }
public void StreamZeroWindowUpdateIncrementsConnectionWindow() { IHttp2Connection connection = _frameCodec.Connection; IHttp2LocalFlowController localFlow = connection.Local.FlowController; int initialWindowSizeBefore = localFlow.InitialWindowSize; IHttp2Stream connectionStream = connection.ConnectionStream; int connectionWindowSizeBefore = localFlow.GetWindowSize(connectionStream); // We only replenish the flow control window after the amount consumed drops below the following threshold. // We make the threshold very "high" so that window updates will be sent when the delta is relatively small. ((DefaultHttp2LocalFlowController)localFlow).WindowUpdateRatio(connectionStream, .999f); int windowUpdate = 1024; _channel.WriteAsync(new DefaultHttp2WindowUpdateFrame(windowUpdate)); // The initial window size is only changed by Http2Settings, so it shouldn't change. Assert.Equal(initialWindowSizeBefore, localFlow.InitialWindowSize); // The connection window should be increased by the delta amount. Assert.Equal(connectionWindowSizeBefore + windowUpdate, localFlow.GetWindowSize(connectionStream)); }
/// <summary>Create a new instance.</summary> /// <param name="connection">The <see cref="IHttp2Connection"/> associated with this decoder.</param> /// <param name="encoder">The <see cref="IHttp2ConnectionEncoder"/> associated with this decoder.</param> /// <param name="frameReader">Responsible for reading/parsing the raw frames. As opposed to this object which applies /// h2 semantics on top of the frames.</param> public DefaultHttp2ConnectionDecoder(IHttp2Connection connection, IHttp2ConnectionEncoder encoder, IHttp2FrameReader frameReader) : this(connection, encoder, frameReader, AlwaysVerifyPromisedRequestVerifier.Instance) { }
/// <summary> /// Creates a new <see cref="InboundHttp2ToHttpAdapter"/> builder for the specified <see cref="IHttp2Connection"/>. /// </summary> /// <param name="connection">the object which will provide connection notification events /// for the current connection.</param> public InboundHttp2ToHttpAdapterBuilder(IHttp2Connection connection) : base(connection) { }
public DefaultHttp2RemoteFlowController(IHttp2Connection connection, IHttp2RemoteFlowControllerListener listener) : this(connection, new WeightedFairQueueByteDistributor(connection), listener) { }
public DefaultHttp2RemoteFlowController(IHttp2Connection connection, IStreamByteDistributor streamByteDistributor) : this(connection, streamByteDistributor, null) { }
public DefaultHttp2RemoteFlowController(IHttp2Connection connection) : this(connection, (IHttp2RemoteFlowControllerListener)null) { }
protected override InboundHttp2ToHttpAdapter Build(IHttp2Connection connection, int maxContentLength, bool validateHttpHeaders, bool propagateSettings) { return(new InboundHttp2ToHttpAdapter(connection, maxContentLength, validateHttpHeaders, propagateSettings)); }
public WeightedFairQueueByteDistributor(IHttp2Connection connection) : this(connection, DefaultMaxStateOnlySize) { }
protected override IStreamByteDistributor NewDistributor(IHttp2Connection connection) { return(new WeightedFairQueueByteDistributor(connection)); }
public DelegatingDecompressorFrameListener(IHttp2Connection connection, IHttp2FrameListener listener) : this(connection, listener, true) { }
public StreamBufferingEncoderTest() { _writer = new Mock <IHttp2FrameWriter>(); _ctx = new Mock <IChannelHandlerContext>(); _channel = new Mock <IChannel>(); _channelUnsafe = new Mock <IChannelUnsafe>(); _config = new Mock <IChannelConfiguration>(); _executor = new Mock <IEventExecutor>(); var configuration = new Mock <IHttp2FrameWriterConfiguration>(); var frameSizePolicy = new Mock <IHttp2FrameSizePolicy>(); _writer.SetupGet(x => x.Configuration).Returns(() => configuration.Object); configuration.SetupGet(x => x.FrameSizePolicy).Returns(() => frameSizePolicy.Object); frameSizePolicy.SetupGet(x => x.MaxFrameSize).Returns(Http2CodecUtil.DefaultMaxFrameSize); _writer .Setup(x => x.WriteDataAsync( It.IsAny <IChannelHandlerContext>(), It.IsAny <int>(), It.IsAny <IByteBuffer>(), It.IsAny <int>(), It.IsAny <bool>(), It.IsAny <IPromise>())) .Returns <IChannelHandlerContext, int, IByteBuffer, int, bool, IPromise>((c, i, buf, x, y, p) => SuccessAnswer(buf)); _writer .Setup(x => x.WriteRstStreamAsync( It.Is <IChannelHandlerContext>(v => v == _ctx.Object), It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IPromise>())) .Returns <IChannelHandlerContext, int, Http2Error, IPromise>((x, y, z, p) => SuccessAnswer()); _writer .Setup(x => x.WriteGoAwayAsync( It.IsAny <IChannelHandlerContext>(), It.IsAny <int>(), It.IsAny <Http2Error>(), It.IsAny <IByteBuffer>(), It.IsAny <IPromise>())) .Returns <IChannelHandlerContext, int, Http2Error, IByteBuffer, IPromise>((c, i, e, buf, p) => SuccessAnswer(buf)); _connection = new DefaultHttp2Connection(false); _connection.Remote.FlowController = new DefaultHttp2RemoteFlowController(_connection); _connection.Local.FlowController = new DefaultHttp2LocalFlowController(_connection).FrameWriter(_writer.Object); var defaultEncoder = new DefaultHttp2ConnectionEncoder(_connection, _writer.Object); _encoder = new StreamBufferingEncoder(defaultEncoder); var decoder = new DefaultHttp2ConnectionDecoder(_connection, _encoder, new Mock <IHttp2FrameReader>().Object); var builder = new Http2ConnectionHandlerBuilder() { FrameListener = new Mock <IHttp2FrameListener>().Object }; var handler = builder.Codec(decoder, _encoder).Build(); // Set LifeCycleManager on encoder and decoder _ctx.SetupGet(x => x.Channel).Returns(_channel.Object); _ctx.SetupGet(x => x.Allocator).Returns(UnpooledByteBufferAllocator.Default); _channel.SetupGet(x => x.Allocator).Returns(UnpooledByteBufferAllocator.Default); _executor.SetupGet(x => x.InEventLoop).Returns(true); _ctx.Setup(x => x.NewPromise()).Returns(() => NewPromise()); _ctx.SetupGet(x => x.Executor).Returns(() => _executor.Object); _channel.SetupGet(x => x.IsActive).Returns(false); _channel.SetupGet(x => x.Configuration).Returns(() => _config.Object); _channel.SetupGet(x => x.IsWritable).Returns(true); _channel.SetupGet(x => x.BytesBeforeUnwritable).Returns(long.MaxValue); _config.SetupGet(x => x.WriteBufferHighWaterMark).Returns(int.MaxValue); _config.SetupGet(x => x.MessageSizeEstimator).Returns(DefaultMessageSizeEstimator.Default); ChannelMetadata metadata = new ChannelMetadata(false, 16); _channel.SetupGet(x => x.Metadata).Returns(metadata); _channel.SetupGet(x => x.Unsafe).Returns(() => _channelUnsafe.Object); handler.HandlerAdded(_ctx.Object); }
/// <summary>Create a new instance.</summary> /// <param name="connection">The <see cref="IHttp2Connection"/> associated with this decoder.</param> /// <param name="encoder">The <see cref="IHttp2ConnectionEncoder"/> associated with this decoder.</param> /// <param name="frameReader">Responsible for reading/parsing the raw frames. As opposed to this object which applies /// h2 semantics on top of the frames.</param> /// <param name="requestVerifier">Determines if push promised streams are valid.</param> /// <param name="autoAckSettings"><c>false</c> to disable automatically applying and sending settings acknowledge frame. /// The <paramref name="encoder"/> is expected to be an instance of /// <see cref="IHttp2SettingsReceivedConsumer"/> and will apply the earliest received but not yet /// ACKed SETTINGS when writing the SETTINGS ACKs. <c>true</c> to enable automatically /// applying and sending settings acknowledge frame.</param> public DefaultHttp2ConnectionDecoder(IHttp2Connection connection, IHttp2ConnectionEncoder encoder, IHttp2FrameReader frameReader, IHttp2PromisedRequestVerifier requestVerifier, bool autoAckSettings) : this(connection, encoder, frameReader, requestVerifier, autoAckSettings, true) { }
protected override IStreamByteDistributor NewDistributor(IHttp2Connection connection) { return(new UniformStreamByteDistributor(connection)); }
/// <summary>Create a new instance.</summary> /// <param name="connection">The <see cref="IHttp2Connection"/> associated with this decoder.</param> /// <param name="encoder">The <see cref="IHttp2ConnectionEncoder"/> associated with this decoder.</param> /// <param name="frameReader">Responsible for reading/parsing the raw frames. As opposed to this object which applies /// h2 semantics on top of the frames.</param> /// <param name="requestVerifier">Determines if push promised streams are valid.</param> public DefaultHttp2ConnectionDecoder(IHttp2Connection connection, IHttp2ConnectionEncoder encoder, IHttp2FrameReader frameReader, IHttp2PromisedRequestVerifier requestVerifier) : this(connection, encoder, frameReader, requestVerifier, true, true) { }