Question

I need help with debugging Jetty SPDY configuration issue.

Versions:

Jetty: org.eclipse.jetty.aggregate:jetty-all:9.0.6.v20130930 (Maven dependency)
Jetty-SPDY: org.eclipse.jetty.spdy:spdy-http-server:9.0.6.v20130930 (Maven dependency)
NPN-API: org.eclipse.jetty.npn:npn-api:8.1.2.v20120308 (Maven dependency, tried w/ and w/o it)
NPN-BOOT: org.mortbay.jetty.npn:npn-boot:8.1.2.v20120308 (used as -Xbootclasspath/p:/home/martin/.m2/repository/org/mortbay/jetty/npn/npn-boot/8.1.2.v20120308/npn-boot-8.1.2.v20120308.jar)
Google Chrome: 30
Firefox: 24

Embedded Jetty (Scala code):

package com.example.test

import org.apache.wicket.util.time.Duration
import org.eclipse.jetty.server.{HttpConnectionFactory, SslConnectionFactory, ServerConnector, SecureRequestCustomizer, HttpConfiguration, Server}
import org.eclipse.jetty.util.resource.Resource
import org.eclipse.jetty.util.ssl.SslContextFactory
import org.eclipse.jetty.spdy.server.http.{HTTPSPDYServerConnectionFactory, ReferrerPushStrategy, HTTPSPDYServerConnector}
import org.eclipse.jetty.webapp.WebAppContext
import org.eclipse.jetty.spdy.server.{SPDYServerConnectionFactory, NPNServerConnectionFactory}
import org.eclipse.jetty.npn.NextProtoNego

object JettyStart {

  def main(args: Array[String]) {

    val startTime = System.currentTimeMillis()

    val tlsHttpConfiguration = new HttpConfiguration()
    tlsHttpConfiguration.setSecureScheme("https")
    tlsHttpConfiguration.setSecurePort(8443)
    tlsHttpConfiguration.setOutputBufferSize(32768)
    tlsHttpConfiguration.setRequestHeaderSize(8192)
    tlsHttpConfiguration.setResponseHeaderSize(8192)
    tlsHttpConfiguration.addCustomizer(new SecureRequestCustomizer)
    tlsHttpConfiguration.setSendServerVersion(true)

    val server = new Server()

    val http = new HttpConnectionFactory(tlsHttpConfiguration)
    val connector = new ServerConnector(server, http)
    connector.setIdleTimeout(Duration.ONE_MINUTE.getMilliseconds)
    connector.setSoLingerTime(-1)
    connector.setPort(8080)
    server.addConnector(connector)

    val keystore: Resource = Resource.newClassPathResource("/keystore")

    if (keystore != null && keystore.exists) {

      SPDYServerConnectionFactory.checkNPNAvailable()

      val pushStrategy = new ReferrerPushStrategy
      pushStrategy.setReferrerPushPeriod(5000)
      pushStrategy.setMaxAssociatedResources(32)

      val factory: SslContextFactory = new SslContextFactory
      factory.setKeyStoreResource(keystore)
      factory.setKeyStorePassword("wicket")
      factory.setTrustStoreResource(keystore)
      factory.setKeyManagerPassword("wicket")
      factory.setProtocol("TLSv1")
      factory.setIncludeProtocols("TLSv1")

      NextProtoNego.debug = true

      val sslConnectionFactory = new SslConnectionFactory(factory, "npn")

      val npnConnectionFactory = new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")
      npnConnectionFactory.setDefaultProtocol("http/1.1")

      val spdy3ConnectionFactory = new HTTPSPDYServerConnectionFactory(3, tlsHttpConfiguration, pushStrategy)

      val spdy2ConnectionFactory = new HTTPSPDYServerConnectionFactory(2, tlsHttpConfiguration)

      val httpConnectionFactory = new HttpConnectionFactory(tlsHttpConfiguration)

      val spdyConnector = new ServerConnector(server, sslConnectionFactory, npnConnectionFactory, spdy3ConnectionFactory,
        spdy2ConnectionFactory, httpConnectionFactory)
      spdyConnector.setPort(8443)
      server.addConnector(spdyConnector)
    }

    val context = new WebAppContext()
    context.setServer(server)
    context.setContextPath("/")
    context.setWar("src/main/webapp")
    server.setHandler(context)
    server.setDumpAfterStart(false)

    server.start()
    println("Start took: " + Duration.valueOf(System.currentTimeMillis() - startTime))
    System.in.read()
    System.out.println(">>> STOPPING EMBEDDED JETTY SERVER")
    server.stop()
    server.join()
  }
}

The code above is inspired from https://github.com/eclipse/jetty.project/blob/master/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml.

Requesting port 8080 works fine.

Requesting port 8443 attempts to establish secure connection and times out.

NPN debugging produces such logs:

[S] NPN received for 13ef0ffb[SSLEngine[hostname=127.0.0.1 port=43086] SSL_NULL_WITH_NULL_NULL]
[S] NPN protocols [spdy/3, spdy/2, http/1.1] sent to client for 13ef0ffb[SSLEngine[hostname=127.0.0.1 port=43086] SSL_NULL_WITH_NULL_NULL]
[S] NPN selected 'spdy/3' for 13ef0ffb[SSLEngine[hostname=127.0.0.1 port=43086] SSL_NULL_WITH_NULL_NULL]
Was it helpful?

Solution

Looks like your NPN versions are off.

Here's the versions of the npn artifacts you will need to use, depending on your chosen version of Java.

Stated in Maven terms.

<dependency>
  <groupId>org.mortbay.jetty.npn</groupId>
  <artifactId>npn-boot</artifactId>
  <version>${npn-version}</version>
</dependency>
<dependency>
  <groupId>org.mortbay.jetty.npn</groupId>
  <artifactId>npn-api</artifactId>
  <version>${npn-version}</version>
</dependency>

The Java to NPN version mapping (as of Oct 23, 2013)

  Java     |  ${npn-version}
-----------+--------------------------
  1.7.0_9  |  1.1.3.v20130313
  1.7.0_11 |  1.1.3.v20130313
  1.7.0_13 |  1.1.4.v20130313
  1.7.0_15 |  1.1.4.v20130313
  1.7.0_17 |  1.1.5.v20130313
  1.7.0_21 |  1.1.5.v20130313
  1.7.0_25 |  1.1.5.v20130313
  1.7.0_40 |  1.1.6.v20130911
  1.7.0_45 |  1.1.6.v20130911

The different versions are for handling the changes done in the JVM for creating TLS extensions.

Note: Java 9 is promising better APIs for managing the entire TLS/NPN/ALPN extension setup, so this kind of strict mapping of bootjars to specific versions of Java should eventually go away.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top