Esempio n. 1
0
 public ConsumedBytesConverter(DelegatingDecompressorFrameListener frameListener, IHttp2LocalFlowController flowController)
 {
     if (flowController is null)
     {
         ThrowHelper.ThrowArgumentNullException(ExceptionArgument.flowController);
     }
     _flowController = flowController;
     _frameListener  = frameListener;
 }
Esempio n. 2
0
        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));
        }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        public override int OnDataRead(IChannelHandlerContext ctx, int streamId, IByteBuffer data, int padding, bool endOfStream)
        {
            IHttp2Stream      stream       = _connection.Stream(streamId);
            Http2Decompressor decompressor = Decompressor(stream);

            if (decompressor is null)
            {
                // The decompressor may be null if no compatible encoding type was found in this stream's headers
                return(_listener.OnDataRead(ctx, streamId, data, padding, endOfStream));
            }

            EmbeddedChannel channel         = decompressor.Decompressor;
            int             compressedBytes = data.ReadableBytes + padding;

            decompressor.IncrementCompressedBytes(compressedBytes);
            try
            {
                // call retain here as it will call release after its written to the channel
                _ = channel.WriteInbound(data.Retain());
                var buf = NextReadableBuf(channel);
                if (buf is null && endOfStream && channel.Finish())
                {
                    buf = NextReadableBuf(channel);
                }
                if (buf is null)
                {
                    if (endOfStream)
                    {
                        _ = _listener.OnDataRead(ctx, streamId, Unpooled.Empty, padding, true);
                    }
                    // No new decompressed data was extracted from the compressed data. This means the application could
                    // not be provided with data and thus could not return how many bytes were processed. We will assume
                    // there is more data coming which will complete the decompression block. To allow for more data we
                    // return all bytes to the flow control window (so the peer can send more data).
                    decompressor.IncrementDecompressedBytes(compressedBytes);
                    return(compressedBytes);
                }
                try
                {
                    IHttp2LocalFlowController flowController = _connection.Local.FlowController;
                    decompressor.IncrementDecompressedBytes(padding);
                    while (true)
                    {
                        var nextBuf = NextReadableBuf(channel);
                        var decompressedEndOfStream = nextBuf is null && endOfStream;
                        if (decompressedEndOfStream && channel.Finish())
                        {
                            nextBuf = NextReadableBuf(channel);
                            decompressedEndOfStream = nextBuf is null;
                        }

                        decompressor.IncrementDecompressedBytes(buf.ReadableBytes);
                        // Immediately return the bytes back to the flow controller. ConsumedBytesConverter will convert
                        // from the decompressed amount which the user knows about to the compressed amount which flow
                        // control knows about.
                        _ = flowController.ConsumeBytes(stream,
                                                        _listener.OnDataRead(ctx, streamId, buf, padding, decompressedEndOfStream));
                        if (nextBuf is null)
                        {
                            break;
                        }

                        padding = 0; // Padding is only communicated once on the first iteration.
                        _       = buf.Release();
                        buf     = nextBuf;
                    }
                    // We consume bytes each time we call the listener to ensure if multiple frames are decompressed
                    // that the bytes are accounted for immediately. Otherwise the user may see an inconsistent state of
                    // flow control.
                    return(0);
                }
                finally
                {
                    _ = buf.Release();
                }
            }
            catch (Http2Exception)
            {
                throw;
            }
            catch (Exception t)
            {
                return(ThrowHelper.ThrowStreamError_DecompressorErrorDetectedWhileDelegatingDataReadOnStream(stream.Id, t));
            }
        }