@Override protected void notifyListenerOnDataRead( ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, boolean endOfStream, Http2FrameListener listener) throws Http2Exception { final Http2Stream stream = connection.stream(streamId); final EmbeddedChannel decoder = stream == null ? null : stream.decompressor(); if (decoder == null) { super.notifyListenerOnDataRead(ctx, streamId, data, padding, endOfStream, listener); } else { // call retain here as it will call release after its written to the channel decoder.writeInbound(data.retain()); ByteBuf buf = nextReadableBuf(decoder); if (buf == null) { if (endOfStream) { super.notifyListenerOnDataRead( ctx, streamId, Unpooled.EMPTY_BUFFER, padding, true, listener); } // END_STREAM is not set and the data could not be decoded yet. // The assumption has to be there will be more data frames to complete the decode. // We don't have enough information here to know if this is an error. } else { for (; ; ) { final ByteBuf nextBuf = nextReadableBuf(decoder); if (nextBuf == null) { super.notifyListenerOnDataRead(ctx, streamId, buf, padding, endOfStream, listener); break; } else { super.notifyListenerOnDataRead(ctx, streamId, buf, padding, false, listener); } buf = nextBuf; } } if (endOfStream) { cleanup(stream, decoder); } } }
/** * Checks if a new decoder object is needed for the stream identified by {@code streamId}. This * method will modify the {@code content-encoding} header contained in {@code builder}. * * @param streamId The identifier for the headers inside {@code builder} * @param builder Object representing headers which have been read * @param endOfStream Indicates if the stream has ended * @throws Http2Exception If the {@code content-encoding} is not supported */ private void initDecoder(int streamId, Http2Headers headers, boolean endOfStream) throws Http2Exception { // Convert the names into a case-insensitive map. final Http2Stream stream = connection.stream(streamId); if (stream != null) { EmbeddedChannel decoder = stream.decompressor(); if (decoder == null) { if (!endOfStream) { // Determine the content encoding. AsciiString contentEncoding = headers.get(CONTENT_ENCODING_LOWER_CASE); if (contentEncoding == null) { contentEncoding = IDENTITY; } decoder = newContentDecoder(contentEncoding); if (decoder != null) { stream.decompressor(decoder); // Decode the content and remove or replace the existing headers // so that the message looks like a decoded message. AsciiString targetContentEncoding = getTargetContentEncoding(contentEncoding); if (IDENTITY.equalsIgnoreCase(targetContentEncoding)) { headers.remove(CONTENT_ENCODING_LOWER_CASE); } else { headers.set(CONTENT_ENCODING_LOWER_CASE, targetContentEncoding); } } } } else if (endOfStream) { cleanup(stream, decoder); } if (decoder != null) { // The content length will be for the compressed data. Since we will decompress the data // this content-length will not be correct. Instead of queuing messages or delaying sending // header frames...just remove the content-length header headers.remove(CONTENT_LENGTH_LOWER_CASE); } } }