Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Jetty/Feature/SPDY
Contents
Introduction
The SPDY protocol is supported in Jetty since version 7.6.2 and 8.1.2.
The SPDY protocol is normally advertised by server deployed over TLS, via the Next Protocol Negotiation TLS Extension (NPN). In order to provide the best support possible for SPDY, the Jetty project provides also an implementation for NPN.
Both the SPDY and the NPN implementation require OpenJDK 1.7 or greater, and both a client and a server implementations are provided.
Feature
SPDY Modules
Jetty's SPDY implementation consists of 4 modules:
- a
spdy-core
module, that contains the SPDY API and a partial implementation. This module is independent of Jetty (the Servlet Container) and can be reused by other Java SPDY implementations. One of the goals of this module is to standardize the SPDY Java API. - a
spdy-jetty
module, which binds thespdy-core
module to Jetty's NIO framework to provide asynchronous socket I/O. This module makes use of Jetty internals, but can be used by Java SPDY client applications to communicate with a SPDY server. - a
spdy-jetty-http
module, which provides a server-side layering of HTTP over SPDY. This module allows any SPDY compliant browser such as Chromium/Chrome to talk SPDY to a Jetty server that deploys a standard web application made of servlets, filters and JSPs. This module will perform the conversion SPDY to HTTP and viceversa so that for the web application will be as if a normal HTTP request arrived, and a normal HTTP response is returned. - a
spdy-jetty-http-webapp
module, which provides a demo application for the aspdy-jetty-http
module.
Transparently Enabling HTTP over SPDY in Jetty
The spdy-jetty-http
module provides an out-of-the-box server connector that performs the SPDY to HTTP conversion and viceversa (aka HTTP over SPDY).
This connector can be used instead of Jetty's SslSelectChannelConnector
(that only speaks HTTP), and will fall back to HTTPS if SPDY is not negotiated.
Below you can find an example jetty-spdy.xml
file that you can use instead of jetty-ssl.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure id="Server" class="org.eclipse.jetty.server.Server"> <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> <Set name="keyStorePath">your_keystore.jks</Set> <Set name="keyStorePassword">storepwd</Set> <Set name="protocol">TLSv1</Set> </New> <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.spdy.http.HTTPSPDYServerConnector"> <Arg> <Ref id="sslContextFactory" /> </Arg> <Set name="Port">8443</Set> </New> </Arg> </Call> </Configure>
This is sufficient to enable your Jetty server to speak SPDY to browsers that supports it.
SPDY Client Applications
The spdy-jetty
module provides a SPDY client (that speaks pure SPDY, and not HTTP over SPDY), which can be used in this way:
// Start a SPDYClient factory shared among all SPDYClient instances SPDYClient.Factory clientFactory = new SPDYClient.Factory(); clientFactory.start(); // Create one SPDYClient instance SPDYClient client = clientFactory.newSPDYClient(SPDY.V2); // Obtain a Session instance to send data to the server that listens on port 8181 Session session = client.connect(new InetSocketAddress("localhost", 8181), null).get(5, TimeUnit.SECONDS); // Sends SYN_STREAM and DATA to the server Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS); stream.data(new StringDataInfo("Hello, World", true));
To listen to SPDY frames sent by the server, you need to pass a StreamFrameListener
upon stream creation:
StreamFrameListener streamListener = new StreamFrameListener.Adapter() { public void onReply(Stream stream, ReplyInfo replyInfo) { // Reply received from server, send DATA to the server stream.data(new StringDataInfo("Hello, World", true)); } public void onData(Stream stream, DataInfo dataInfo) { // Data received from server String content = dataInfo.asString("UTF-8", true); System.err.printf("SPDY content: %s%n", content); } }; // Sends SYN_STREAM to the server, adding headers Headers headers = new Headers(); headers.put("url", "/echo"); Stream stream = session.syn(new SynInfo(headers, false), null).get(5, TimeUnit.SECONDS);
You can familiarize with the SPDY API to understand how to use the API.
SPDY Server Applications
The spdy-jetty
module provides a server connector that speaks pure SPDY, and that can be used in conjunction with the SPDY client (see above).
The SPDYServerConnector
can be started in this way:
// The application code that handles incoming SYN_STREAMS ServerSessionFrameListener application = new ServerSessionFrameListener.Adapter() { public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) { // Reply upon receiving a SYN_STREAM stream.reply(new ReplyInfo(false)); // Inspect the headers Headers headers = synInfo.getHeaders(); if ("/echo".equals(headers.get("url").value())) { return new StreamFrameListener.Adapter() { public void onData(Stream stream, DataInfo dataInfo) { // Upon receiving hello data from the client, echo it back String clientData = dataInfo.asString("UTF-8", true); stream.data(new StringDataInfo("Echo for " + clientData, true)); } }; } return null; } }; // Wire up and start the connector org.eclipse.jetty.server.Server server = new Server(); server.addConnector(new SPDYServerConnector(application)); server.start();
The ServerSessionFrameListener
can inspect the incoming SynInfo
and provide different execution paths depending on headers and/or data content.
You can familiarize with the SPDY API to understand how to use the API.