Javalin: http/2 support

Created on 2 Mar 2018  路  17Comments  路  Source: tipsy/javalin

Hi, are there any plans to support http/2 ? Jetty 9.4 would support it.

QUESTION

All 17 comments

Have you tried creating a jetty-http2-server and passing it to Javalin via app.embeddedServer()?

i did not, i am not familiar yet with http2. i need bidirectional communication so my guess is that http2 could be a good choice. at the moment i just created a little test with websockets. but i would prefer to also test http2.

https://www.eclipse.org/jetty/documentation/9.4.x/http2.html
I did not find a sample on their page with streams (probably what i need).
Is there any kind of sample for http2 with javalin? Or can i use the regular rest api which switches to http2? if so, how are streams handled?

@blahmutz You can check some examples of creating embedded http2 jetty server here. The repo also has all the dependencies required in the pom file.
There are some tutorials on the Javalin website for setting up a custom server instance.

Regarding http2 push, this SO answer has some basic example of using PushBuilder. You can try to connect that to the Javalin rest api, it should work, though I haven't tried myself 馃檪

the existing examples out there are too old. they have "checkProtocolNegotiationAvailable", which was removed sometime ago

this is what I have so far.

    public static void main(String[] args) {
        Javalin app = Javalin.create()
            .embeddedServer(new EmbeddedJettyFactory(() -> {
                Server server = new Server();

                ServerConnector connector = new ServerConnector(server);
                connector.setPort(8080);
                server.addConnector(connector);

                // HTTP Configuration
                HttpConfiguration httpConfig = new HttpConfiguration();
                httpConfig.setSecureScheme("https");
                httpConfig.setSecurePort(8443);

                // SSL Context Factory for HTTPS and HTTP/2
                SslContextFactory sslContextFactory = new SslContextFactory();
                sslContextFactory.setKeyStorePath("keystore.p12");
                sslContextFactory.setKeyStorePassword("password");
                sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);

                // HTTPS Configuration
                HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
                httpsConfig.addCustomizer(new SecureRequestCustomizer());

                // HTTP/2 Connection Factory
                HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
                ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
                alpn.setDefaultProtocol("h2");

                // SSL Connection Factory
                SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());

                // HTTP/2 Connector
                ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, new HttpConnectionFactory(httpsConfig));
                http2Connector.setPort(8443);
                server.addConnector(http2Connector);

                ALPN.debug = false;

                return server;
            })).start();

        app.get("/", ctx -> ctx.result("Hello World"));
    }

I got it to start. the regular connector on port 8080 is working fine.

I also have
Started ServerConnector@ {SSL,[ssl, alpn, h2, http/1.1]}{0.0.0.0:8443}

so at least jetty isn't hating it

but...

trying to make any request with curl, I keep getting SSL error

in terms of dep, on top of javalin, I had to add

compile "org.eclipse.jetty.http2:http2-server:9.4.8.v20171121"
compile "org.eclipse.jetty:jetty-alpn-conscrypt-server:9.4.8.v20171121"
compile "org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715"
runtime "org.mortbay.jetty.alpn:alpn-boot:8.1.12.v20180117"

the api version you need to use is specific to the java 8 version as per

https://www.eclipse.org/jetty/documentation/9.4.x/alpn-chapter.html#alpn-versions

also, just to keep it all in one place and you can cut and paste.

I use

keytool -genkey -alias jetty -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650

to generate the keystore file for above

@wmacgyver What curl command do you execute and what error do you receive?

@wmacgyver have you tried running this outside of Javalin?

server.setHandler(new HelloHandler());
server.start();
server.join();
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class HelloHandler extends AbstractHandler {
    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().println("<h1>Hello Jetty</h1>");
        baseRequest.setHandled(true);
    }
}

@ShikaSD
trying curl -k --http2-prior-knowledge https://localhost:8443, I get error

even using regular https

curl -k https://localhost:8443

I get the same error OpenSSL SSL_connect: SSL_ERROR_SYSCALL

however, @tipsy is on to something

I ran the code outside of javalin, and it bombs the same way. so it's not javalin. going to make it work with just jetty first

will keep you guys posted

@wmacgyver maybe looking at what Dropwizard does would be helpful: https://github.com/dropwizard/dropwizard/tree/1bb7142cb241d3218a80c58e2018d5ad7790c90c/dropwizard-http2/src/main/java/io/dropwizard/http2

It was last updated 13 days ago, so hopefully it's not outdated.

@tipsy
doh, I figured it out right away as soon as you pointed out to try run it as pure jetty

I was missing sslContextFactory.setProvider("Conscrypt");

ie it needs to look like

                // SSL Context Factory for HTTPS and HTTP/2
                SslContextFactory sslContextFactory = new SslContextFactory();
                sslContextFactory.setKeyStorePath("keystore.p12");
                sslContextFactory.setKeyStorePassword("password");
                sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
                sslContextFactory.setProvider("Conscrypt");

it works both in pure jetty and javalin now.

I'm going to create a full working example in a github repo for using javalin with http2

and write up some docs. be back to you guys. but it works now

@wmacgyver cool. When you feel confident in your implementation it would be great if you could create a PR for https://github.com/tipsy/javalin/issues/69. It would be nice to include some "default" Jetty-servers with Javalin.

@tipsy got it, I guess this means you are moving forward on tie javalin to jetty then :)

Most likely, yes, but #69 doesn't really impact that, I just want a standalone-object like this:

JettyDefaults {

    fun http2Server(...): Server = ... 

    fun sslServer(...): Server = ... 

}

understood.

@wmacgyver thanks! I forked the repo and expanded it a bit: https://github.com/tipsy/javalin-http2-example

I added gradle-wrapper, a kotlin version, bumped all dependencies and added a static-file example. I couldn't add this to your repo, as this is now part of the official documentation: https://javalin.io/documentation#sslhttp2

@tipsy no worries, I'm glad you found it useful enough to include it in the official doc. I'm happy to help out. http2 option is so few and far in between on JVM. I'm glad it's possible with javalin.

Was this page helpful?
0 / 5 - 0 ratings