Most people have already heard about SPDY, the protocol, from google,
proposed as a replacement for the aging HTTP protocol. Webservers are
browsers are slowly implementing this protocol and support is growing.
In a recent article
I already wrote about how SPDY works and how you can enable SPDY
support in Jetty. Since a couple of months Netty (originally from JBoss)
also has support for SPDY.
Since Netty is often used for high performant protocol servers, SPDY is
a logical fit. In this article I'll show you how you can create a basic
Netty based server that does protocol negotiation between SPDY and
HTTP. It used the example HTTPRequestHandler from the Netty snoop example to consume and produce some HTTP content.

To get everything working we'll need to do the following things:

Enable NPN in Java to determine protocol to use.

Determine, based on the negotiated protocol, whether to use HTTP or SPDY.

Make sure the correct SPDY headers are sent back with HTTP.

SPDY uses an TLS extension to determine the protocol to use in
communication. This is called NPN. I wrote a more complete explanation
and shown the messages involved in the article on how to use SPDY on Jetty,
so for more info look at that article. Basically what this extension
does is that during the TLS exchange a server and client also exchange
the transport level protocols they support. In the case of SPDY a server
could support both the SPDY protocol and the HTTP protocol. A client
implementation can then determine which protocol to use.
Since this isn't something which is available in the standard Java
implementation, we need to extend the Java TLS functionality with NPN.

Enable NPN support in Java

So far I found two options that can be used to add NPN support in Java. One is from https://github.com/benmmurphy/ssl_npn who also has a basic SPDY/Netty example in his repo where he uses his own implementation. The other option, and the one I'll be using, is the NPN support provided by Jetty.
Jetty provides an easy to use API that you can use to add NPN support
to your Java SSL contexts. Once again, in the in the article on Jetty you can find more info on this. To set up NPN for Netty, we need to do the following:

With this piece of code, Java SSL has support for NPN. We still,
however, need access to the results from this negotiation. We need to
know whether we're using HTTP or SPDY, since that determines how we
process the received data. For this Jetty provides an API. For this and
for the required Netty libraries, we add the following dependencies,
since I'm using maven, to the pom.

Connect the SSL context to the NPN API

Now that we've got NPN enabled and the correct API added to the
project, we can configure the Netty SSL handler. Configuring handlers in
Netty is done in a PipelineFactory. For our server I created the
following PipelineFactory:

In the constructor from this class we setup a basic SSL context. The
keystore and key we use I created using the java keytool, this is normal
SSL configuration. When we receive a request, the getPipeline operation
is called to determine how to handle the request. Here we use the
NextProtoNego class, provided by Jetty-NPN-API, to connect our SSL
connection to the NPN implementation. In this operation we pass a
provider that is used as callback and configuration for our server. We
also set NextProtoNego.debug to true. This prints out some debugging
information that makes, well, debugging easier. The code for the
SimpleServerProvider is very simple:

The unsupported operation is called when the client doesn't support NPN. In that case we default to HTTP.

The protocols() operation returns the protocols the server supports

The protocolSelected operation is called when a protocol has been negotiated by the server and the client

The getSelectedProtocol is a method we will use to get the selected protocol from a different handler in the Netty pipeline.

Determine, based on the negotiated protocol, whether to use HTTP or SPDY

Now we need to configure Netty in such a way that it runs a specific
pipeline for HTTPS request and a pipeline for SPDY requests. For this
let's look back at a small part of the pipelinefactory.

pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("pipeLineSelector", new HttpOrSpdyHandler());

The first part of this pipeline is the SslHandler that is configured
with NPN support. The next handler that will be called is the
HttpOrSpdyHandler. This handler determines, based on the protocol, which
pipeline to use. The code for this handler is listed next:

Using the NPN API and our current SSL context, we retrieve the
SimpleServerProvider we added earlier. We check whether the
selectedProtocol has been set, and if so, we setup a chain for
processing. We handle three options in this class:

There is no protocol: It's possible that no
protocol has been negotiated yet. In that case we don't do anything
special, and just process it normally.

There is a http protocol: We set up a handler chain to handle HTTP requests.

There is a spdy protocol: We set up a handler chain to handle SPDY requests.

With this chain all the messages we receive eventually by the
HttpRequestHandler are HTTP Requests. We can process this HTTP request
normally, and return a HTTP response. The various pipeline
configurations will handle all this correctly.

Make sure the correct SPDY headers are sent back with HTTP

The final step we need to do, is this test. We'll test this with the
latest version of Chrome to test whether SPDY is working, and we'll use
wget to test the normal http requests. I mentioned that the
HttpRequestHandler, the last handler in the chain, does our HTTP
processing. I've used the http://netty.io/docs/stable/xref/org/jboss/netty/example/http/snoop/Http...
as the HTTPRequestHandler since that one nicely returns information
about the HTTP request, without me having to do anything. If you run
this without alteration, you do run into an issue. To correlate the HTTP
response to the correct SPDY session, we need to copy a header from the
incoming request to the response: the "X-SPDY-Stream-ID" header. I've
added the following to the HttpSnoopServerHandler to make sure these
headers are copied (should really have done this in a seperate handler).

And it works! Wget uses standard HTTPS, and we get a result, and
chrome uses SPDY and presents the result from the same handler. In the
net couple of days, I'll also post on article on how you can enable SPDY
for the Play Framework 2.0, since their webserver is also based on
Netty.

The Java Zone is brought to you in partnership with AppDynamics. AppDynamics helps you gain the fundamentals behind application performance, and implement best practices so you can proactively analyze and act on performance problems as they arise, and more specifically with your Java applications. Start a Free Trial.