Chromium Code Reviews| 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..e37fec14e85250685e56acb6591571115d35c23d |
| --- /dev/null |
| +++ b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java |
| @@ -0,0 +1,178 @@ |
| +// 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 { |
| + private static final ConditionVariable sBlock = new ConditionVariable(); |
| + private static final String TAG = "Http2TestServer"; |
| + |
| + // Host-based server. |
| + static final int PORT = 8443; |
| + |
| + public static boolean startHttp2TestServer( |
| + Context context, String certFileName, String keyFileName) throws Exception { |
| + (new Thread( |
|
pauljensen
2016/01/19 16:03:41
I don't think the extra parenthesis around "new Th
mef
2016/01/20 15:37:41
Done.
|
| + 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 getBaseUrl() { |
| + 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 getBaseUrl() + "echoallheaders"; |
| + } |
| + |
| + static String getEchoHeaderUrl(String headerName) { |
| + return getBaseUrl() + "echoheader?" + headerName; |
| + } |
| + |
| + static String getEchoMethodUrl() { |
| + return getBaseUrl() + "echomethod"; |
|
pauljensen
2016/01/19 16:03:41
these strings (e.g. "echomethod") seem duplicated
mef
2016/01/20 15:37:41
They sure can. I think it would make sense to unif
pauljensen
2016/01/22 03:55:31
The more unification the better :) It may be hard
|
| + } |
| + |
| + static String getEchoStreamUrl() { |
| + return getBaseUrl() + "echostream"; |
| + } |
| + |
| + static String getEchoTrailersUrl() { |
| + return getBaseUrl() + "echotrailers"; |
| + } |
| + |
| + private static void onServerStarted() { |
| + Log.i(TAG, "Http2 server started."); |
|
pauljensen
2016/01/19 16:03:41
any reason onServerStarted is in a seperate functi
mef
2016/01/20 15:37:41
Done.
|
| + sBlock.open(); |
| + } |
| + |
| + static class Http2TestServerRunnable implements Runnable { |
| + File mCertFile; |
|
pauljensen
2016/01/19 16:03:41
private final?
mef
2016/01/20 15:37:41
Done.
|
| + File mKeyFile; |
|
pauljensen
2016/01/19 16:03:41
ditto
mef
2016/01/20 15:37:41
Done.
|
| + |
| + 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 { |
| + 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 " + getBaseUrl()); |
| + onServerStarted(); |
| + ch.closeFuture().sync(); |
| + } finally { |
| + group.shutdownGracefully(); |
| + } |
| + Log.i(TAG, "Stopped Http2TestServerRunnable!"); |
| + } |
| + |
| + /** |
| + * Sets up the Netty pipeline for the test server. |
| + */ |
| + 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()); |
| + } |
| + } |
| + |
| + 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); |
| + } |
| + } |
| +} |