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

com.firefly.codec.http2.stream.AbstractHTTP1OutputStream Maven / Gradle / Ivy

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

import com.firefly.codec.http2.encode.HttpGenerator;
import com.firefly.codec.http2.model.MetaData;
import com.firefly.net.Session;
import com.firefly.utils.io.BufferUtils;

import java.io.IOException;
import java.nio.ByteBuffer;

abstract public class AbstractHTTP1OutputStream extends HTTPOutputStream {

    public AbstractHTTP1OutputStream(MetaData info, boolean clientMode) {
        super(info, clientMode);
    }

    @Override
    public void commit() throws IOException {
        commit(null);
    }

    protected synchronized void commit(ByteBuffer data) throws IOException {
        if (closed)
            return;

        if (committed)
            return;

        final HttpGenerator generator = getHttpGenerator();
        final Session tcpSession = getSession();
        HttpGenerator.Result generatorResult;
        ByteBuffer header = getHeaderByteBuffer();

        generatorResult = generate(info, header, null, data, false);
        if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMMITTED) {
            if (data != null) {
                ByteBuffer[] headerAndData = new ByteBuffer[]{header, data};
                tcpSession.encode(headerAndData);
            } else {
                tcpSession.encode(header);
            }
            committed = true;
        } else {
            generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMMITTED);
        }
    }

    @Override
    public synchronized void write(ByteBuffer data) throws IOException {
        if (closed)
            return;

        if (!data.hasRemaining())
            return;

        final HttpGenerator generator = getHttpGenerator();
        final Session tcpSession = getSession();
        HttpGenerator.Result generatorResult;

        if (!committed) {
            commit(data);
        } else {
            if (generator.isChunking()) {
                ByteBuffer chunk = BufferUtils.allocate(HttpGenerator.CHUNK_SIZE);

                generatorResult = generate(null, null, chunk, data, false);
                if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMMITTED) {
                    ByteBuffer[] chunkAndData = new ByteBuffer[]{chunk, data};
                    tcpSession.encode(chunkAndData);
                } else {
                    generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMMITTED);
                }
            } else {
                generatorResult = generate(null, null, null, data, false);
                if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMMITTED) {
                    tcpSession.encode(data);
                } else {
                    generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMMITTED);
                }
            }
        }
    }

    @Override
    public synchronized void close() throws IOException {
        if (closed)
            return;

        try {
            log.debug("http1 output stream is closing");
            final HttpGenerator generator = getHttpGenerator();
            final Session tcpSession = getSession();
            HttpGenerator.Result generatorResult;

            if (!committed) {
                ByteBuffer header = getHeaderByteBuffer();
                generatorResult = generate(info, header, null, null, true);
                if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMPLETING) {
                    tcpSession.encode(header);
                    generateLastData(generator);
                } else {
                    generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMPLETING);
                }
                committed = true;
            } else {
                if (generator.isChunking()) {
                    log.debug("http1 output stream is generating chunk");
                    generatorResult = generate(null, null, null, null, true);
                    if (generatorResult == HttpGenerator.Result.CONTINUE && generator.getState() == HttpGenerator.State.COMPLETING) {
                        generatorResult = generate(null, null, null, null, true);
                        if (generatorResult == HttpGenerator.Result.NEED_CHUNK && generator.getState() == HttpGenerator.State.COMPLETING) {
                            generateLastChunk(generator, tcpSession);
                        } else if (generatorResult == HttpGenerator.Result.NEED_CHUNK_TRAILER && generator.getState() == HttpGenerator.State.COMPLETING) {
                            generateTrailer(generator, tcpSession);
                        }
                    } else {
                        generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.CONTINUE, HttpGenerator.State.COMPLETING);
                    }
                } else {
                    generatorResult = generate(null, null, null, null, true);
                    if (generatorResult == HttpGenerator.Result.CONTINUE && generator.getState() == HttpGenerator.State.COMPLETING) {
                        generateLastData(generator);
                    } else {
                        generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.CONTINUE, HttpGenerator.State.COMPLETING);
                    }
                }
            }
        } finally {
            closed = true;
        }
    }

    private void generateLastChunk(HttpGenerator generator, Session tcpSession) throws IOException {
        ByteBuffer chunk = BufferUtils.allocate(HttpGenerator.CHUNK_SIZE);
        HttpGenerator.Result generatorResult = generate(null, null, chunk, null, true);
        if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMPLETING) {
            tcpSession.encode(chunk);
            generateLastData(generator);
        } else {
            generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMPLETING);
        }
    }

    private void generateTrailer(HttpGenerator generator, Session tcpSession) throws IOException {
        ByteBuffer trailer = getTrailerByteBuffer();
        HttpGenerator.Result generatorResult = generate(null, null, trailer, null, true);
        if (generatorResult == HttpGenerator.Result.FLUSH && generator.getState() == HttpGenerator.State.COMPLETING) {
            tcpSession.encode(trailer);
            generateLastData(generator);
        } else {
            generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.FLUSH, HttpGenerator.State.COMPLETING);
        }
    }

    private void generateLastData(HttpGenerator generator) throws IOException {
        HttpGenerator.Result generatorResult = generate(null, null, null, null, true);
        if (generator.getState() == HttpGenerator.State.END) {
            if (generatorResult == HttpGenerator.Result.DONE) {
                generateHTTPMessageSuccessfully();
            } else if (generatorResult == HttpGenerator.Result.SHUTDOWN_OUT) {
                getSession().close();
            } else {
                generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.DONE, HttpGenerator.State.END);
            }
        } else {
            generateHTTPMessageExceptionally(generatorResult, generator.getState(), HttpGenerator.Result.DONE, HttpGenerator.State.END);
        }
    }

    protected HttpGenerator.Result generate(MetaData info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content,
                                            boolean last) throws IOException {
        final HttpGenerator generator = getHttpGenerator();
        if (clientMode) {
            return generator.generateRequest((MetaData.Request) info, header, chunk, content, last);
        } else {
            return generator.generateResponse((MetaData.Response) info, false, header, chunk, content, last);
        }
    }

    abstract protected ByteBuffer getHeaderByteBuffer();

    abstract protected ByteBuffer getTrailerByteBuffer();

    abstract protected Session getSession();

    abstract protected HttpGenerator getHttpGenerator();

    abstract protected void generateHTTPMessageSuccessfully();

    abstract protected void generateHTTPMessageExceptionally(HttpGenerator.Result actualResult,
                                                             HttpGenerator.State actualState,
                                                             HttpGenerator.Result expectedResult,
                                                             HttpGenerator.State expectedState);

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy