private void decode(ByteBuffer buffer, Hpack.Reader reader, DecodeCallback callback,
                        Http2Stream stream, Http2Updater updater)
            throws IOException {
        // HTTP2 frame structure
        //  0                   1                   2                   3
        //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        // |                 Length (24)                   |
        // +---------------+---------------+---------------+
        // |   Type (8)    |   Flags (8)   |
        // +-+-+-----------+---------------+-------------------------------+
        // |R|                 Stream Identifier (31)                      |
        // +=+=============================================================+
        // |                   Frame Payload (0...)                      ...
        // +---------------------------------------------------------------+
        if (buffer.remaining() < Http2.FRAME_HEADER_LENGTH) {
            callback.onPending(buffer);
            return;
        }
        int length = readMedium(buffer);
        if (length < 0 || length > Http2.INITIAL_MAX_FRAME_SIZE) {
            // Values greater than 214 (16,384) MUST NOT be sent unless the receiver has set a
            // larger value for SETTINGS_MAX_FRAME_SIZE.
            throw new IOException("Http2 frame size error: " + length);
        }
        // Check payload length
        if (length + 6 > buffer.remaining()) {
            mLog.w("No enough http2 frame length, expect: %d actual: %d", length,
                    buffer.remaining() - 6);
            // Packet not enough for one frame, wait next packet.
            // Revert position.
            buffer.position(buffer.position() - 3);
            callback.onPending(buffer);
            return;
        } else if (length + 6 < buffer.remaining()) {
            mLog.w("Multi http2 frames in one buffer, first frame length : %d, buffer length: %d",
                    length + 9, buffer.remaining() + 3);
            // Separate multi-frames
            ByteBuffer newBuffer = ByteBuffer.allocate(length + 9);
            newBuffer.put(buffer.array(), buffer.position() - 3, newBuffer.capacity());
            newBuffer.flip();
            decode(newBuffer, reader, callback, stream, updater);
            // Process the left data
            buffer.position(buffer.position() + length + 6);
            decode(buffer, reader, callback, stream, updater);
            return;
        }

        byte type = (byte) (buffer.get() & 0xff);
        byte flags = (byte) (buffer.get() & 0xff);
        int streamId = buffer.getInt() & 0x7fffffff;
        FrameType frameType = FrameType.parse(type);
        if (frameType == null) {
            mLog.e("Unexpected http2 frame type: " + type);
            // Discard frames that have unknown or unsupported types.
            return;
        }
        if (stream.id != -1) {
            if (streamId != stream.id && frameType == FrameType.CONTINUATION) {
                throw new IOException("Http2 TYPE_CONTINUATION streamId changed!");
            }
        }
        mLog.i("Decode a http2 frame: " + frameType + " stream(" + streamId +
                ") length(" + length + ")");
        stream.id = streamId;
        switch (frameType) {
            case DATA:
                decodeData(buffer, length, flags, streamId, callback);
                return;
            case HEADERS:
            case CONTINUATION:
                decodeHeaders(buffer, reader, length, flags, streamId, callback);
                return;
            case SETTINGS:
                decodeSettings(buffer, length, flags, streamId, updater);
                // No return
                break;
            case GOAWAY:
                decodeGoAway(buffer, length, flags, streamId);
                // No return
                break;
            default:
                break;
        }
        // Encrypt and send it to remote server directly.
        buffer.position(buffer.position() - Http2.FRAME_HEADER_LENGTH);
        callback.onSkip(buffer);
    }
Decodes HTTP2 request and response packets.

@author Megatron King
@since 2019/1/5 14:19
netbare-core/src/main/java/com/github/megatronking/netbare/http2/Http2DecodeInterceptor.java