Index: components/cronet/android/test/src/org/chromium/net/Http2TestServer.java |
diff --git a/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6a2d6e5815821eea684b97ddc69d7c584f30fd44 |
--- /dev/null |
+++ b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java |
@@ -0,0 +1,173 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.net; |
+ |
+import android.content.Context; |
+import android.os.ConditionVariable; |
+ |
+import org.chromium.base.Log; |
+import org.chromium.net.test.util.CertTestUtil; |
+ |
+import java.io.File; |
+ |
+import io.netty.bootstrap.ServerBootstrap; |
+import io.netty.channel.Channel; |
+import io.netty.channel.ChannelHandlerContext; |
+import io.netty.channel.ChannelInitializer; |
+import io.netty.channel.ChannelOption; |
+import io.netty.channel.EventLoopGroup; |
+import io.netty.channel.nio.NioEventLoopGroup; |
+import io.netty.channel.socket.SocketChannel; |
+import io.netty.channel.socket.nio.NioServerSocketChannel; |
+import io.netty.handler.codec.http2.Http2SecurityUtil; |
+import io.netty.handler.logging.LogLevel; |
+import io.netty.handler.logging.LoggingHandler; |
+import io.netty.handler.ssl.ApplicationProtocolConfig; |
+import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; |
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; |
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; |
+import io.netty.handler.ssl.ApplicationProtocolNames; |
+import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; |
+import io.netty.handler.ssl.OpenSslServerContext; |
+import io.netty.handler.ssl.SslContext; |
+import io.netty.handler.ssl.SupportedCipherSuiteFilter; |
+ |
+/** |
+ * Wrapper class to start a HTTP/2 test server. |
+ */ |
+public final class Http2TestServer { |
xunjieli
2016/01/21 19:13:08
maybe add a private constructor?
mef
2016/01/22 14:33:44
Done.
|
+ private static final ConditionVariable sBlock = new ConditionVariable(); |
+ private static final String TAG = "Http2TestServer"; |
+ |
+ // Host-based server. |
+ static final int PORT = 8443; |
xunjieli
2016/01/21 19:13:08
add private?
mef
2016/01/22 14:33:44
Done.
|
+ |
+ public static boolean startHttp2TestServer( |
+ Context context, String certFileName, String keyFileName) throws Exception { |
+ new Thread( |
+ new Http2TestServerRunnable(new File(CertTestUtil.CERTS_DIRECTORY + certFileName), |
+ new File(CertTestUtil.CERTS_DIRECTORY + keyFileName))) |
+ .start(); |
+ sBlock.block(); |
+ return true; |
+ } |
+ |
+ public static boolean shutdownHttp2TestServer() throws Exception { |
+ return true; |
+ } |
+ |
+ public static String getServerUrl() { |
+ return "https://127.0.0.1:" + PORT + '/'; |
+ } |
+ |
+ public static String getServerHost() { |
+ return "127.0.0.1"; |
+ } |
+ |
+ public static int getServerPort() { |
+ return PORT; |
+ } |
+ |
+ static String getEchoAllHeadersUrl() { |
+ return getServerUrl() + "echoallheaders"; |
+ } |
+ |
+ static String getEchoHeaderUrl(String headerName) { |
+ return getServerUrl() + "echoheader?" + headerName; |
+ } |
+ |
+ static String getEchoMethodUrl() { |
+ return getServerUrl() + "echomethod"; |
+ } |
+ |
+ static String getEchoStreamUrl() { |
+ return getServerUrl() + "echostream"; |
+ } |
+ |
+ static String getEchoTrailersUrl() { |
xunjieli
2016/01/21 19:13:08
Why are these methods some public and some package
mef
2016/01/22 14:33:44
Done.
|
+ return getServerUrl() + "echotrailers"; |
+ } |
+ |
+ private static class Http2TestServerRunnable implements Runnable { |
+ private final File mCertFile; |
+ private final File mKeyFile; |
+ |
+ Http2TestServerRunnable(File certFile, File keyFile) { |
+ mCertFile = certFile; |
+ mKeyFile = keyFile; |
+ } |
+ |
+ public void run() { |
+ Log.i(TAG, "Hello from Http2TestServerRunnable!"); |
+ try { |
+ runHttp2TestServer(mCertFile, mKeyFile); |
+ } catch (Exception e) { |
+ Log.e(TAG, e.toString()); |
+ } |
+ } |
+ } |
+ |
+ private static void runHttp2TestServer(File certFile, File keyFile) throws Exception { |
xunjieli
2016/01/21 19:13:08
maybe move this method to Http2TestServerRunnable?
mef
2016/01/22 14:33:44
Done.
|
+ ApplicationProtocolConfig applicationProtocolConfig = |
+ new ApplicationProtocolConfig(Protocol.ALPN, SelectorFailureBehavior.NO_ADVERTISE, |
+ SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2); |
+ |
+ final SslContext sslCtx = |
+ new OpenSslServerContext(certFile, keyFile, null, null, Http2SecurityUtil.CIPHERS, |
+ SupportedCipherSuiteFilter.INSTANCE, applicationProtocolConfig, 0, 0); |
+ |
+ // Configure the server. |
+ EventLoopGroup group = new NioEventLoopGroup(); |
+ try { |
+ ServerBootstrap b = new ServerBootstrap(); |
+ b.option(ChannelOption.SO_BACKLOG, 1024); |
+ b.group(group) |
+ .channel(NioServerSocketChannel.class) |
+ .handler(new LoggingHandler(LogLevel.INFO)) |
+ .childHandler(new Http2ServerInitializer(sslCtx)); |
+ |
+ Channel ch = b.bind(PORT).sync().channel(); |
+ Log.i(TAG, "Netty HTTP/2 server started on " + getServerUrl()); |
+ sBlock.open(); |
+ ch.closeFuture().sync(); |
+ } finally { |
+ group.shutdownGracefully(); |
+ } |
+ Log.i(TAG, "Stopped Http2TestServerRunnable!"); |
+ } |
+ |
+ /** |
+ * Sets up the Netty pipeline for the test server. |
+ */ |
+ private static class Http2ServerInitializer extends ChannelInitializer<SocketChannel> { |
+ private final SslContext mSslCtx; |
+ |
+ public Http2ServerInitializer(SslContext sslCtx) { |
+ this.mSslCtx = sslCtx; |
+ } |
+ |
+ @Override |
+ public void initChannel(SocketChannel ch) { |
+ ch.pipeline().addLast(mSslCtx.newHandler(ch.alloc()), new Http2NegotiationHandler()); |
+ } |
+ } |
+ |
+ private static class Http2NegotiationHandler extends ApplicationProtocolNegotiationHandler { |
+ protected Http2NegotiationHandler() { |
+ super(ApplicationProtocolNames.HTTP_1_1); |
+ } |
+ |
+ @Override |
+ protected void configurePipeline(ChannelHandlerContext ctx, String protocol) |
+ throws Exception { |
+ if (ApplicationProtocolNames.HTTP_2.equals(protocol)) { |
+ ctx.pipeline().addLast(new Http2TestHandler.Builder().build()); |
+ return; |
+ } |
+ |
+ throw new IllegalStateException("unknown protocol: " + protocol); |
+ } |
+ } |
+} |