public bool ConsumeBytes(IHttp2Stream stream, int numBytes) { Http2Decompressor decompressor = _frameListener.Decompressor(stream); if (decompressor is object) { // Convert the decompressed bytes to compressed (on the wire) bytes. numBytes = decompressor.ConsumeBytes(stream.Id, numBytes); } try { return(_flowController.ConsumeBytes(stream, numBytes)); } catch (Http2Exception) { throw; } catch (Exception t) { // The stream should be closed at this point. We have already changed our state tracking the compressed // bytes, and there is no guarantee we can recover if the underlying flow controller throws. return(ThrowHelper.ThrowStreamError_ErrorWhileReturningBytesToFlowControlWindow(stream.Id, t)); } }
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)); } }