SPDY example app

This commit is contained in:
Veebs 2014-01-15 03:29:18 -08:00 committed by Norman Maurer
parent 2be6d1bcc1
commit 09fdb08fe4
8 changed files with 368 additions and 0 deletions

View File

@ -68,6 +68,10 @@
<artifactId>javassist</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
</dependency>
<!-- see https://github.com/netty/netty/issues/874 -->
<dependency>

View File

@ -0,0 +1,67 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.spdy;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.npn.NextProtoNego;
import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.spdy.SpdyOrHttpChooser;
/**
* Negotiates with the browser if SPDY or HTTP is going to be used. Once decided, the Netty pipeline is setup with
* the correct handlers for the selected protocol.
*/
public class SpdyOrHttpHandler extends SpdyOrHttpChooser {
private static final int MAX_CONTENT_LENGTH = 1024 * 100;
public SpdyOrHttpHandler() {
this(MAX_CONTENT_LENGTH, MAX_CONTENT_LENGTH);
}
public SpdyOrHttpHandler(int maxSpdyContentLength, int maxHttpContentLength) {
super(maxSpdyContentLength, maxHttpContentLength);
}
@Override
protected SelectedProtocol getProtocol(SSLEngine engine) {
SpdyServerProvider provider = (SpdyServerProvider) NextProtoNego.get(engine);
String selectedProtocol = provider.getSelectedProtocol();
System.out.println("Selected Protocol is " + (selectedProtocol == null ? "Unknown" : selectedProtocol));
if (selectedProtocol == null) {
return SpdyOrHttpChooser.SelectedProtocol.UNKNOWN;
} else if (selectedProtocol.equalsIgnoreCase("spdy/3.1")) {
return SpdyOrHttpChooser.SelectedProtocol.SPDY_3_1;
} else if (selectedProtocol.equalsIgnoreCase("spdy/3")) {
return SpdyOrHttpChooser.SelectedProtocol.SPDY_3;
} else if (selectedProtocol.equalsIgnoreCase("http/1.1")) {
return SpdyOrHttpChooser.SelectedProtocol.HTTP_1_1;
} else if (selectedProtocol.equalsIgnoreCase("http/1.0")) {
return SpdyOrHttpChooser.SelectedProtocol.HTTP_1_0;
} else {
return SpdyOrHttpChooser.SelectedProtocol.UNKNOWN;
}
}
@Override
protected ChannelHandler createHttpRequestHandlerForHttp() {
return new SpdyServerHandler();
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.spdy;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* A SPDY Server that responds to a GET request with a Hello World.
* <p>
* This class must be run with the JVM parameter: {@code java -Xbootclasspath/p:<path_to_npn_boot_jar> ...}.
* The "path_to_npn_boot_jar" is the path on the file system for the NPN Boot Jar file which can be downloaded from
* Maven at coordinates org.mortbay.jetty.npn:npn-boot. Different versions applies to different OpenJDK versions.
* See {@link http://www.eclipse.org/jetty/documentation/current/npn-chapter.html Jetty docs} for more information.
* <p>
* Once started, you can test the server with your
* {@link http://en.wikipedia.org/wiki/SPDY#Browser_support_and_usage SPDY enabled web browser} by navigating
* to https://localhost:8443/.
*/
public class SpdyServer {
private final int port;
public SpdyServer(int port) {
this.port = port;
}
public void run() throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new SpdyServerInitializer());
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8443;
}
System.out.println("SPDY web server started at port " + port + '.');
System.out.println("Open your SPDY enabled browser and navigate to https://localhost:" + port + '/');
System.out.println("If using Chrome browser, check your SPDY sessions at chrome://net-internals/#spdy");
new SpdyServer(port).run();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.spdy;
import java.util.Date;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpHeaders.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
* HTTP handler that responds with a "Hello World"
*/
public class SpdyServerHandler extends ChannelHandlerAdapter {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest) msg;
if (is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
boolean keepAlive = isKeepAlive(req);
ByteBuf content = Unpooled.copiedBuffer("Hello World " + (new Date()).toString(), CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
ctx.write(response);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.spdy;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.npn.NextProtoNego;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.example.securechat.SecureChatSslContextFactory;
import io.netty.handler.ssl.SslHandler;
/**
* Sets up the Netty pipeline
*/
public class SpdyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
engine.setUseClientMode(false);
p.addLast("ssl", new SslHandler(engine));
// Setup NextProtoNego with our server provider
NextProtoNego.put(engine, new SpdyServerProvider());
NextProtoNego.debug = true;
// Negotiates with the browser if SPDY or HTTP is going to be used
p.addLast("handler", new SpdyOrHttpHandler());
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.spdy;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
/**
* The Jetty project provides an implementation of the Transport Layer Security (TLS) extension for Next
* Protocol Negotiation (NPN) for OpenJDK 7 or greater. NPN allows the application layer to negotiate which
* protocol to use over the secure connection.
* <p>
* This NPN service provider negotiates using SPDY.
* <p>
* To enable NPN support, start the JVM with: {@code java -Xbootclasspath/p:<path_to_npn_boot_jar> ...}. The
* "path_to_npn_boot_jar" is the path on the file system for the NPN Boot Jar file which can be downloaded from
* Maven at coordinates org.mortbay.jetty.npn:npn-boot. Different versions applies to different OpenJDK versions.
*
* @see http://www.eclipse.org/jetty/documentation/current/npn-chapter.html
*/
public class SpdyServerProvider implements ServerProvider {
private String selectedProtocol;
@Override
public void unsupported() {
// if unsupported, default to http/1.1
selectedProtocol = "http/1.1";
}
@Override
public List<String> protocols() {
return Arrays.asList("spdy/3.1", "spdy/3", "http/1.1");
}
@Override
public void protocolSelected(String protocol) {
selectedProtocol = protocol;
}
public String getSelectedProtocol() {
return selectedProtocol;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* This package contains an example SPDY HTTP web server.
* <p>
* This package relies on the Jetty project's implementation of the Transport Layer Security (TLS) extension for Next
* Protocol Negotiation (NPN) for OpenJDK 7 is required. NPN allows the application layer to negotiate which
* protocol, SPDY or HTTP, to use.
* <p>
* To start, run {@link SpdyServer} with the JVM parameter: {@code java -Xbootclasspath/p:<path_to_npn_boot_jar> ...}.
* The "path_to_npn_boot_jar" is the path on the file system for the NPN Boot Jar file which can be downloaded from
* Maven at coordinates org.mortbay.jetty.npn:npn-boot. Different versions applies to different OpenJDK versions.
* See {@link http://www.eclipse.org/jetty/documentation/current/npn-chapter.html Jetty docs} for more information.
* <p>
* Once started, you can test the server with your
* {@link http://en.wikipedia.org/wiki/SPDY#Browser_support_and_usage SPDY enabled web browser} by navigating
* to https://localhost:8443/.
*/
package io.netty.example.spdy;

View File

@ -143,6 +143,13 @@
<optional>true</optional>
</dependency>
<!-- SPDY Example - completely optional -->
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>1.1.0.v20120525</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>