Jetty.project: java.lang.IllegalStateException: No protocol factory for SSL next protocol: 'HTTP/2.0' in ServerConnector@1817d444{SSL,[ssl, h2]}{0.0.0.0:18002}

Created on 12 Mar 2020  路  3Comments  路  Source: eclipse/jetty.project

Jetty version
9.4.26.v20200117
Java version
JDK1.8.0_u121
OS type/version
Windows
Description

Here is my code

package jetty.http.server;

import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.ssl.SslContextFactory;

public class JettyEmbeddedServer {

    public static void main(String[] args) throws Exception {

        int plainPort = 18000;
        int securePort = 18001;
        int http2Port = 18002;

        // Create a basic jetty server object without declaring the port. Since
        // we are configuring connectors directly we'll be setting ports on
        // those connectors.
        Server server = new Server();

        // HTTP Configuration
        // HttpConfiguration is a collection of configuration information
        // appropriate for http and https. The default scheme for http is
        // <code>http</code> of course, as the default for secured http is
        // <code>https</code> but we show setting the scheme to show it can be
        // done. The port for secured communication is also set here.
        HttpConfiguration httpConfig = new HttpConfiguration();
        httpConfig.setSecureScheme("https");
        httpConfig.setSecurePort(securePort);
        httpConfig.setOutputBufferSize(32768);

        // HTTP connector
        // The first server connector we create is the one for http, passing in
        // the http configuration we configured above so it can get things like
        // the output buffer size, etc. We also set the port (8080) and
        // configure an idle timeout.
        ServerConnector http = new ServerConnector(server,
                new HttpConnectionFactory(httpConfig));
        http.setPort(plainPort);
        http.setIdleTimeout(30000);

        // Since this example shows off SSL configuration, we need a keystore
        // with the appropriate key.
        String keystorePath = Resource.newClassPathResource("keystore").getURI().getPath();

        // SSL Context Factory for HTTPS
        // SSL requires a certificate so we configure a factory for ssl contents
        // with information pointing to what keystore the ssl connection needs
        // to know about. Much more configuration is available the ssl context,
        // including things like choosing the particular certificate out of a
        // keystore to be used.

        SslContextFactory sslContextFactory = new SslContextFactory.Server();
        sslContextFactory.setKeyStorePath(keystorePath);
        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");

        // OPTIONAL: Un-comment the following to use Conscrypt for SSL instead of
        // the native JSSE implementation.

        //Security.addProvider(new OpenSSLProvider());
        //sslContextFactory.setProvider("Conscrypt");

        // HTTPS Configuration
        // A new HttpConfiguration object is needed for the next connector and
        // you can pass the old one as an argument to effectively clone the
        // contents. On this HttpConfiguration object we add a
        // SecureRequestCustomizer which is how a new connector is able to
        // resolve the https connection before handing control over to the Jetty
        // Server.
        HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
        SecureRequestCustomizer src = new SecureRequestCustomizer();
        src.setStsMaxAge(2000);
        src.setStsIncludeSubDomains(true);
        httpsConfig.addCustomizer(src);

        // HTTPS connector
        // We create a second ServerConnector, passing in the http configuration
        // we just made along with the previously created ssl context factory.
        // Next we set the port and a longer idle timeout.
        ServerConnector https = new ServerConnector(server,
                new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
                new HttpConnectionFactory(httpsConfig));
        https.setPort(securePort);
        https.setIdleTimeout(500000);

        // HTTP2
        HttpConfiguration http2Config = new HttpConfiguration(httpConfig);
        SecureRequestCustomizer http2src = new SecureRequestCustomizer();
        http2src.setStsMaxAge(2000);
        http2src.setStsIncludeSubDomains(true);
        http2Config.addCustomizer(http2src);

        HTTP2ServerConnectionFactory http2ConnectionFactory = new HTTP2ServerConnectionFactory(new HttpConfiguration(http2Config));
        http2ConnectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
        http2ConnectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);

        ServerConnector http2 = new ServerConnector(server,
                new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_2.asString()),
                http2ConnectionFactory);
        http2.setPort(http2Port);
        http2.setIdleTimeout(500000);

        // Here you see the server having multiple connectors registered with
        // it, now requests can flow into the server from both http and https
        // urls to their respective ports and be processed accordingly by jetty.
        // A simple handler is also registered with the server so the example
        // has something to pass requests off to.

        // Set the connectors

        server.setConnectors(new Connector[]{http, https, http2});

        // Set a handler

        ServletContextHandler context = new ServletContextHandler(server, "/", true, false);
        context.addServlet(new ServletHolder(new JettyEmbeddedServerHandler()), "/*");

        // Start the server
        server.start();
        server.dumpStdErr();
        server.join();
    }
}

On jdk8 i have already config -Xbootclasspath/p:F:\maven-repository\org\mortbay\jetty\alpn\alpn-boot\8.1.11.v20170118\alpn-boot-8.1.11.v20170118.jar

and got the following erorr on startup

Exception in thread "main" java.lang.IllegalStateException: No protocol factory for SSL next protocol: 'HTTP/2.0' in ServerConnector@1817d444{SSL,[ssl, h2]}{0.0.0.0:18002}
at org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:316)
at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:81)
at org.eclipse.jetty.server.ServerConnector.doStart(ServerConnector.java:231)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
at org.eclipse.jetty.server.Server.doStart(Server.java:385)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
at jetty.http.server.JettyEmbeddedServer.main(JettyEmbeddedServer.java:126)

Most helpful comment

Got it working.

Thanks for your help.

All 3 comments

The problem is this line:

ServerConnector http2 = new ServerConnector(server,
            new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_2.asString()),
            http2ConnectionFactory);

The correct name for the HTTP/2 protocol is h2 not HttpVersion.HTTP_2.asString().
Use this instead:

ServerConnector http2 = new ServerConnector(server,
            new SslConnectionFactory(sslContextFactory, http2ConnectionFactory.getProtocol()),
            http2ConnectionFactory);

Note also that you are creating a connector that will only be able to speak HTTP/2 over TLS. This is called "HTTP/2 with prior knowledge" and clients may or may not be able to support this mode.

For example, curl supports it via curl --http2-prior-knowledge, but browsers won't be able to connect because they use ALPN.

If you want to setup ALPN, see this example.

Closing as I think this is solved. Please comment if you still have troubles.

Got it working.

Thanks for your help.

Was this page helpful?
0 / 5 - 0 ratings