HTTP2 example uses SSL and NPN.
Motivation: HTTP2 is generally negotiated over SSL, makes more sense to provide an SSL example. Modifications: Copy the SDPY example to add SSL and NPN negotiation to the HTTP2 example. Result: Http2Server and Http2Client examples use SSL.
This commit is contained in:
parent
bb063a9fdd
commit
c66aae3539
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.handler.codec.http2.draft10;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http2.draft10.connection.Http2ConnectionHandler;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2FrameCodec;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link io.netty.channel.ChannelHandler} which is responsible to setup the {@link io.netty.channel.ChannelPipeline}
|
||||
* either for HTTP or HTTP2. This offers an easy way for users to support both at the same time while not care to much
|
||||
* about the low-level details.
|
||||
*/
|
||||
public abstract class Http2OrHttpChooser extends ByteToMessageDecoder {
|
||||
|
||||
// TODO: Replace with generic NPN handler
|
||||
|
||||
public enum SelectedProtocol {
|
||||
/** Must be updated to match the HTTP/2 draft number. */
|
||||
HTTP_2("h2-10"),
|
||||
HTTP_1_1("http/1.1"),
|
||||
HTTP_1_0("http/1.0"),
|
||||
UNKNOWN("Unknown");
|
||||
|
||||
private final String name;
|
||||
|
||||
SelectedProtocol(String defaultName) {
|
||||
name = defaultName;
|
||||
}
|
||||
|
||||
public String protocolName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of this enum based on the protocol name returned by the NPN server provider
|
||||
*
|
||||
* @param name
|
||||
* the protocol name
|
||||
* @return the SelectedProtocol instance
|
||||
*/
|
||||
public static SelectedProtocol protocol(String name) {
|
||||
for (SelectedProtocol protocol : SelectedProtocol.values()) {
|
||||
if (protocol.protocolName().equals(name)) {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private final int maxHttpContentLength;
|
||||
|
||||
protected Http2OrHttpChooser(int maxHttpContentLength) {
|
||||
this.maxHttpContentLength = maxHttpContentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SelectedProtocol} for the {@link javax.net.ssl.SSLEngine}. If its not known yet implementations
|
||||
* MUST return {@link SelectedProtocol#UNKNOWN}.
|
||||
*
|
||||
*/
|
||||
protected abstract SelectedProtocol getProtocol(SSLEngine engine);
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (initPipeline(ctx)) {
|
||||
// When we reached here we can remove this handler as its now clear
|
||||
// what protocol we want to use
|
||||
// from this point on. This will also take care of forward all
|
||||
// messages.
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean initPipeline(ChannelHandlerContext ctx) {
|
||||
// Get the SslHandler from the ChannelPipeline so we can obtain the
|
||||
// SslEngine from it.
|
||||
SslHandler handler = ctx.pipeline().get(SslHandler.class);
|
||||
if (handler == null) {
|
||||
// HTTP2 is negotiated through SSL.
|
||||
throw new IllegalStateException("SslHandler is needed for HTTP2");
|
||||
}
|
||||
|
||||
SelectedProtocol protocol = getProtocol(handler.engine());
|
||||
switch (protocol) {
|
||||
case UNKNOWN:
|
||||
// Not done with choosing the protocol, so just return here for now,
|
||||
return false;
|
||||
case HTTP_2:
|
||||
addHttp2Handlers(ctx);
|
||||
break;
|
||||
case HTTP_1_0:
|
||||
case HTTP_1_1:
|
||||
addHttpHandlers(ctx);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown SelectedProtocol");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all {@link io.netty.channel.ChannelHandler}'s that are needed for HTTP_2.
|
||||
*/
|
||||
protected void addHttp2Handlers(ChannelHandlerContext ctx) {
|
||||
ChannelPipeline pipeline = ctx.pipeline();
|
||||
pipeline.addLast("http2FrameCodec", new Http2FrameCodec());
|
||||
pipeline.addLast("http2ConnectionHandler", new Http2ConnectionHandler(true));
|
||||
pipeline.addLast("http2RequestHandler", createHttp2RequestHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all {@link io.netty.channel.ChannelHandler}'s that are needed for HTTP.
|
||||
*/
|
||||
protected void addHttpHandlers(ChannelHandlerContext ctx) {
|
||||
ChannelPipeline pipeline = ctx.pipeline();
|
||||
pipeline.addLast("httpRequestDecoder", new HttpRequestDecoder());
|
||||
pipeline.addLast("httpResponseEncoder", new HttpResponseEncoder());
|
||||
pipeline.addLast("httpChunkAggregator", new HttpObjectAggregator(maxHttpContentLength));
|
||||
pipeline.addLast("httpRequestHandler", createHttp1RequestHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link io.netty.channel.ChannelHandler} that is responsible for handling the http requests when the
|
||||
* {@link SelectedProtocol} was {@link SelectedProtocol#HTTP_1_0} or {@link SelectedProtocol#HTTP_1_1}
|
||||
*/
|
||||
protected abstract ChannelHandler createHttp1RequestHandler();
|
||||
|
||||
/**
|
||||
* Create the {@link io.netty.channel.ChannelHandler} that is responsible for handling the http responses when the
|
||||
* when the {@link SelectedProtocol} was {@link SelectedProtocol#HTTP_2}.
|
||||
*/
|
||||
protected abstract ChannelHandler createHttp2RequestHandler();
|
||||
}
|
@ -23,6 +23,7 @@ import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.example.http2.server.Http2Server;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http2.draft10.DefaultHttp2Headers;
|
||||
import io.netty.handler.codec.http2.draft10.Http2Headers;
|
||||
@ -99,6 +100,7 @@ public class Http2Client {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Http2Server.checkForNpnSupport();
|
||||
int port;
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0]);
|
||||
|
@ -18,25 +18,38 @@ package io.netty.example.http2.client;
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.example.securechat.SecureChatSslContextFactory;
|
||||
import io.netty.handler.codec.http2.draft10.connection.Http2ConnectionHandler;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2DataFrame;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2FrameCodec;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
/**
|
||||
* Configures the client pipeline to support HTTP/2 frames.
|
||||
*/
|
||||
public class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final Http2ResponseClientHandler httpResponseHandler;
|
||||
private final SimpleChannelInboundHandler<Http2DataFrame> httpResponseHandler;
|
||||
|
||||
public Http2ClientInitializer(Http2ResponseClientHandler httpResponseHandler) {
|
||||
public Http2ClientInitializer(SimpleChannelInboundHandler<Http2DataFrame> httpResponseHandler) {
|
||||
this.httpResponseHandler = httpResponseHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
|
||||
engine.setUseClientMode(true);
|
||||
NextProtoNego.put(engine, new Http2ClientProvider());
|
||||
NextProtoNego.debug = true;
|
||||
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
|
||||
pipeline.addLast("ssl", new SslHandler(engine));
|
||||
pipeline.addLast("http2FrameCodec", new Http2FrameCodec());
|
||||
pipeline.addLast("http2FrameLogger", new Http2FrameLogger(INFO));
|
||||
pipeline.addLast("http2ConnectionHandler", new Http2ConnectionHandler(false));
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.http2.client;
|
||||
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.handler.codec.http2.draft10.Http2OrHttpChooser.SelectedProtocol.*;
|
||||
|
||||
/**
|
||||
* 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 HTTP2.
|
||||
* <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 <a href="http://www.eclipse.org/jetty/documentation/current/npn-chapter.html">Jetty documentation</a>
|
||||
*/
|
||||
public class Http2ClientProvider implements NextProtoNego.ClientProvider {
|
||||
|
||||
private String selectedProtocol;
|
||||
|
||||
@Override
|
||||
public String selectProtocol(List<String> protocols) {
|
||||
if (protocols.contains(HTTP_2.protocolName())) {
|
||||
selectedProtocol = HTTP_2.protocolName();
|
||||
}
|
||||
return selectedProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported() {
|
||||
selectedProtocol = HTTP_1_1.protocolName();
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.http2.server;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
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 HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequest> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
|
||||
if (is100ContinueExpected(req)) {
|
||||
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
|
||||
}
|
||||
boolean keepAlive = isKeepAlive(req);
|
||||
|
||||
ByteBuf content = ctx.alloc().buffer();
|
||||
content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES);
|
||||
|
||||
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.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
} else {
|
||||
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
|
||||
ctx.writeAndFlush(response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
@ -16,8 +16,8 @@
|
||||
package io.netty.example.http2.server;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http2.draft10.DefaultHttp2Headers;
|
||||
import io.netty.handler.codec.http2.draft10.Http2Headers;
|
||||
import io.netty.handler.codec.http2.draft10.frame.DefaultHttp2DataFrame;
|
||||
@ -26,24 +26,19 @@ import io.netty.handler.codec.http2.draft10.frame.Http2DataFrame;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2HeadersFrame;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2StreamFrame;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
/**
|
||||
* A simple handler that responds with the message "Hello World!".
|
||||
*/
|
||||
public class HelloWorldHandler extends ChannelHandlerAdapter {
|
||||
private static final byte[] RESPONSE_BYTES = "Hello World".getBytes(CharsetUtil.UTF_8);
|
||||
public class HelloWorldHttp2Handler extends SimpleChannelInboundHandler<Http2StreamFrame> {
|
||||
|
||||
static final byte[] RESPONSE_BYTES = "Hello World".getBytes(CharsetUtil.UTF_8);
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof Http2StreamFrame) {
|
||||
Http2StreamFrame frame = (Http2StreamFrame) msg;
|
||||
if (frame.isEndOfStream()) {
|
||||
sendResponse(ctx, frame.getStreamId());
|
||||
}
|
||||
public void messageReceived(ChannelHandlerContext ctx, Http2StreamFrame frame) throws Exception {
|
||||
if (frame.isEndOfStream()) {
|
||||
sendResponse(ctx, frame.getStreamId());
|
||||
}
|
||||
|
||||
ReferenceCountUtil.release(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,7 +46,7 @@ public class HelloWorldHandler extends ChannelHandlerAdapter {
|
||||
cause.printStackTrace();
|
||||
}
|
||||
|
||||
private void sendResponse(ChannelHandlerContext ctx, int streamId) {
|
||||
private static void sendResponse(ChannelHandlerContext ctx, int streamId) {
|
||||
ByteBuf content = ctx.alloc().buffer();
|
||||
content.writeBytes(RESPONSE_BYTES);
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.http2.server;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.codec.http2.draft10.Http2OrHttpChooser;
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Negotiates with the browser if HTTP2 or HTTP is going to be used. Once decided, the Netty pipeline is setup with
|
||||
* the correct handlers for the selected protocol.
|
||||
*/
|
||||
public class Http2OrHttpHandler extends Http2OrHttpChooser {
|
||||
private static final Logger logger = Logger.getLogger(
|
||||
Http2OrHttpHandler.class.getName());
|
||||
private static final int MAX_CONTENT_LENGTH = 1024 * 100;
|
||||
|
||||
public Http2OrHttpHandler() {
|
||||
this(MAX_CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
public Http2OrHttpHandler(int maxHttpContentLength) {
|
||||
super(maxHttpContentLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SelectedProtocol getProtocol(SSLEngine engine) {
|
||||
Http2ServerProvider provider = (Http2ServerProvider) NextProtoNego.get(engine);
|
||||
SelectedProtocol selectedProtocol = provider.getSelectedProtocol();
|
||||
|
||||
logger.info("Selected Protocol is " + selectedProtocol);
|
||||
return selectedProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler createHttp1RequestHandler() {
|
||||
return new HelloWorldHttp1Handler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler createHttp2RequestHandler() {
|
||||
return new HelloWorldHttp2Handler();
|
||||
}
|
||||
}
|
@ -55,6 +55,7 @@ public class Http2Server {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
checkForNpnSupport();
|
||||
int port;
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0]);
|
||||
@ -66,4 +67,18 @@ public class Http2Server {
|
||||
|
||||
new Http2Server(port).run();
|
||||
}
|
||||
|
||||
public static void checkForNpnSupport() {
|
||||
try {
|
||||
Class.forName("sun.security.ssl.NextProtoNegoExtension");
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
System.err.println();
|
||||
System.err.println("Could not locate Next Protocol Negotiation (NPN) implementation.");
|
||||
System.err.println("The NPN jar should have been made available when building the examples with maven.");
|
||||
System.err.println("Please check that your JDK is among those supported by Jetty-NPN:");
|
||||
System.err.println("http://wiki.eclipse.org/Jetty/Feature/NPN#Versions");
|
||||
System.err.println();
|
||||
throw new IllegalStateException("Could not locate NPN implementation. See console err for details.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,14 @@
|
||||
|
||||
package io.netty.example.http2.server;
|
||||
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.example.http2.client.Http2FrameLogger;
|
||||
import io.netty.handler.codec.http2.draft10.connection.Http2ConnectionHandler;
|
||||
import io.netty.handler.codec.http2.draft10.frame.Http2FrameCodec;
|
||||
import io.netty.example.securechat.SecureChatSslContextFactory;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
/**
|
||||
* Sets up the Netty pipeline
|
||||
@ -32,9 +33,15 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
|
||||
p.addLast("http2FrameCodec", new Http2FrameCodec());
|
||||
p.addLast("http2FrameLogger", new Http2FrameLogger(INFO));
|
||||
p.addLast("http2ConnectionHandler", new Http2ConnectionHandler(true));
|
||||
p.addLast("helloWorldHandler", new HelloWorldHandler());
|
||||
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
|
||||
engine.setUseClientMode(false);
|
||||
p.addLast("ssl", new SslHandler(engine));
|
||||
|
||||
// Setup NextProtoNego with our server provider
|
||||
NextProtoNego.put(engine, new Http2ServerProvider());
|
||||
NextProtoNego.debug = true;
|
||||
|
||||
// Negotiates with the browser if HTTP2 or HTTP is going to be used
|
||||
p.addLast("handler", new Http2OrHttpHandler());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.http2.server;
|
||||
|
||||
import io.netty.handler.codec.http2.draft10.Http2OrHttpChooser;
|
||||
import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.handler.codec.http2.draft10.Http2OrHttpChooser.SelectedProtocol.*;
|
||||
|
||||
/**
|
||||
* 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 HTTP_2.
|
||||
* <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 <a href="http://www.eclipse.org/jetty/documentation/current/npn-chapter.html">Jetty documentation</a>
|
||||
*/
|
||||
public class Http2ServerProvider implements ServerProvider {
|
||||
|
||||
private String selectedProtocol;
|
||||
|
||||
@Override
|
||||
public void unsupported() {
|
||||
// if unsupported, default to http/1.1
|
||||
selectedProtocol = HTTP_1_1.protocolName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> protocols() {
|
||||
return Arrays.asList(HTTP_2.protocolName(), HTTP_1_1.protocolName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void protocolSelected(String protocol) {
|
||||
selectedProtocol = protocol;
|
||||
}
|
||||
|
||||
public Http2OrHttpChooser.SelectedProtocol getSelectedProtocol() {
|
||||
if (selectedProtocol == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
return protocol(selectedProtocol);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user