All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.codec.http2.encode.HeadersGenerator Maven / Gradle / Ivy

There is a newer version: 5.0.0-dev6
Show newest version
package com.firefly.codec.http2.encode;

import com.firefly.codec.http2.frame.*;
import com.firefly.codec.http2.hpack.HpackEncoder;
import com.firefly.codec.http2.model.MetaData;
import com.firefly.utils.io.BufferUtils;

import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;

public class HeadersGenerator extends FrameGenerator {
    private final HpackEncoder encoder;
    private final int maxHeaderBlockFragment;
    private final PriorityGenerator priorityGenerator;

    public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder) {
        this(headerGenerator, encoder, 0);
    }

    public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder, int maxHeaderBlockFragment) {
        super(headerGenerator);
        this.encoder = encoder;
        this.maxHeaderBlockFragment = maxHeaderBlockFragment;
        this.priorityGenerator = new PriorityGenerator(headerGenerator);
    }

    @Override
    public List generate(Frame frame) {
        HeadersFrame headersFrame = (HeadersFrame) frame;
        return generateHeaders(headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(),
                headersFrame.isEndStream());
    }

    public List generateHeaders(int streamId, MetaData metaData, PriorityFrame priority,
                                            boolean endStream) {
        List list = new LinkedList<>();
        if (streamId < 0)
            throw new IllegalArgumentException("Invalid stream id: " + streamId);

        int flags = Flags.NONE;

        if (priority != null)
            flags = Flags.PRIORITY;

        int maxFrameSize = getMaxFrameSize();
        ByteBuffer hpacked = ByteBuffer.allocate(maxFrameSize);
        BufferUtils.clearToFill(hpacked);
        encoder.encode(hpacked, metaData);
        int hpackedLength = hpacked.position();
        BufferUtils.flipToFlush(hpacked, 0);

        // Split into CONTINUATION frames if necessary.
        if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment) {
            if (endStream)
                flags |= Flags.END_STREAM;

            int length = maxHeaderBlockFragment;
            if (priority != null)
                length += PriorityFrame.PRIORITY_LENGTH;

            ByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId);
            generatePriority(header, priority);
            BufferUtils.flipToFlush(header, 0);
            list.add(header);

            hpacked.limit(maxHeaderBlockFragment);
            list.add(hpacked.slice());

            int position = maxHeaderBlockFragment;
            int limit = position + maxHeaderBlockFragment;
            while (limit < hpackedLength) {
                hpacked.position(position).limit(limit);
                header = generateHeader(FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
                BufferUtils.flipToFlush(header, 0);
                list.add(header);
                list.add(hpacked.slice());
                position += maxHeaderBlockFragment;
                limit += maxHeaderBlockFragment;
            }

            hpacked.position(position).limit(hpackedLength);
            header = generateHeader(FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId);
            BufferUtils.flipToFlush(header, 0);
            list.add(header);
            list.add(hpacked);
        } else {
            flags |= Flags.END_HEADERS;
            if (endStream)
                flags |= Flags.END_STREAM;

            int length = hpackedLength;
            if (priority != null)
                length += PriorityFrame.PRIORITY_LENGTH;

            ByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId);
            generatePriority(header, priority);
            BufferUtils.flipToFlush(header, 0);
            list.add(header);
            list.add(hpacked);
        }
        return list;
    }

    private void generatePriority(ByteBuffer header, PriorityFrame priority) {
        if (priority != null) {
            priorityGenerator.generatePriorityBody(header, priority.getStreamId(), priority.getParentStreamId(),
                    priority.getWeight(), priority.isExclusive());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy