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

com.firefly.server.http2.HTTP2ServerRequestHandler Maven / Gradle / Ivy

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

import com.firefly.Version;
import com.firefly.codec.http2.frame.*;
import com.firefly.codec.http2.model.*;
import com.firefly.codec.http2.stream.AbstractHTTP2OutputStream;
import com.firefly.codec.http2.stream.Session;
import com.firefly.codec.http2.stream.Stream;
import com.firefly.codec.http2.stream.Stream.Listener;
import com.firefly.utils.concurrent.Callback;
import com.firefly.utils.io.IO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

import static com.firefly.codec.http2.stream.DataFrameHandler.handleDataFrame;

public class HTTP2ServerRequestHandler extends ServerSessionListener.Adapter {

    protected static final Logger log = LoggerFactory.getLogger("firefly-system");

    private final ServerHTTPHandler serverHTTPHandler;
    HTTP2ServerConnection connection;

    public HTTP2ServerRequestHandler(ServerHTTPHandler serverHTTPHandler) {
        this.serverHTTPHandler = serverHTTPHandler;
    }

    @Override
    public void onClose(Session session, GoAwayFrame frame) {
        log.warn("Server received the GoAwayFrame -> {}", frame.toString());
        connection.close();
    }

    @Override
    public void onFailure(Session session, Throwable failure) {
        log.error("Server failure: " + session, failure);
        Optional.ofNullable(connection).ifPresent(IO::close);
    }

    @Override
    public void onReset(Session session, ResetFrame frame) {
        log.warn("Server received ResetFrame {}", frame.toString());
        Optional.ofNullable(connection).ifPresent(IO::close);
    }

    @Override
    public Listener onNewStream(final Stream stream, final HeadersFrame headersFrame) {
        if (!headersFrame.getMetaData().isRequest()) {
            throw new IllegalArgumentException("the stream " + stream.getId() + " received meta data that is not request type");
        }

        if (log.isDebugEnabled()) {
            log.debug("Server received stream: {}, {}", stream.getId(), headersFrame.toString());
        }

        final MetaData.Request request = (MetaData.Request) headersFrame.getMetaData();
        final MetaData.Response response = new HTTPServerResponse();
        final ServerHttp2OutputStream output = new ServerHttp2OutputStream(response, stream);

        String expectedValue = request.getFields().get(HttpHeader.EXPECT);
        if ("100-continue".equalsIgnoreCase(expectedValue)) {
            boolean skipNext = serverHTTPHandler.accept100Continue(request, response, output, connection);
            if (!skipNext) {
                MetaData.Response continue100 = new MetaData.Response(HttpVersion.HTTP_1_1,
                        HttpStatus.CONTINUE_100, HttpStatus.Code.CONTINUE.getMessage(),
                        new HttpFields(), -1);
                output.writeFrame(new HeadersFrame(stream.getId(), continue100, null, false));
            }
        } else {
            serverHTTPHandler.headerComplete(request, response, output, connection);
            if (headersFrame.isEndStream()) {
                serverHTTPHandler.messageComplete(request, response, output, connection);
            }
        }

        return new Listener.Adapter() {

            @Override
            public void onHeaders(Stream stream, HeadersFrame trailerFrame) {
                if (log.isDebugEnabled()) {
                    log.debug("Server received trailer frame: {}, {}", stream.toString(), trailerFrame);
                }

                if (trailerFrame.isEndStream()) {
                    request.setTrailerSupplier(() -> trailerFrame.getMetaData().getFields());
                    serverHTTPHandler.contentComplete(request, response, output, connection);
                    serverHTTPHandler.messageComplete(request, response, output, connection);
                } else {
                    throw new IllegalArgumentException("the stream " + stream.getId() + " received illegal meta data");
                }
            }

            @Override
            public void onData(Stream stream, DataFrame dataFrame, Callback callback) {
                handleDataFrame(dataFrame, callback, request, response, output, connection, serverHTTPHandler);
            }

            @Override
            public void onReset(Stream stream, ResetFrame resetFrame) {
                ErrorCode errorCode = ErrorCode.from(resetFrame.getError());
                String reason = errorCode == null ? "error=" + resetFrame.getError() : errorCode.name().toLowerCase();
                int status = HttpStatus.INTERNAL_SERVER_ERROR_500;
                if (errorCode != null) {
                    switch (errorCode) {
                        case PROTOCOL_ERROR:
                            status = HttpStatus.BAD_REQUEST_400;
                            break;
                        default:
                            status = HttpStatus.INTERNAL_SERVER_ERROR_500;
                            break;
                    }
                }
                serverHTTPHandler.badMessage(status, reason, request, response, output, connection);
            }

        };
    }

    public static class ServerHttp2OutputStream extends AbstractHTTP2OutputStream {

        public static final String X_POWERED_BY_VALUE = "Firefly " + Version.value;
        public static final String SERVER_VALUE = "Firefly " + Version.value;

        private final Stream stream;

        public ServerHttp2OutputStream(MetaData info, Stream stream) {
            super(info, false);
            this.stream = stream;
            info.getFields().put(HttpHeader.X_POWERED_BY, X_POWERED_BY_VALUE);
            info.getFields().put(HttpHeader.SERVER, SERVER_VALUE);
        }

        @Override
        protected Stream getStream() {
            return stream;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy