This source file includes following definitions.
- setStaticInstance
- shutdown
- setResponseInternal
- getResponseUrl
- setResponse
- setResponseWithRunnableAction
- setRedirect
- setResponseBase64
- getRequestCount
- getLastRequest
- getBaseUrl
- openConnection
- checkClientTrusted
- checkServerTrusted
- getAcceptedIssuers
- verify
- servedResponseFor
- getResponse
- setDateHeaders
- createResponse
- createEntity
- getKeyManagers
- run
- isShutdownRequest
package org.chromium.net.test.util;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.RequestLine;
import org.apache.http.StatusLine;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
public class TestWebServer {
private static final String TAG = "TestWebServer";
private static final int SERVER_PORT = 4444;
private static final int SSL_SERVER_PORT = 4445;
public static final String SHUTDOWN_PREFIX = "/shutdown";
private static TestWebServer sInstance;
private static Hashtable<Integer, String> sReasons;
private final ServerThread mServerThread;
private String mServerUri;
private final boolean mSsl;
private static class Response {
final byte[] mResponseData;
final List<Pair<String, String>> mResponseHeaders;
final boolean mIsRedirect;
final Runnable mResponseAction;
Response(byte[] resposneData, List<Pair<String, String>> responseHeaders,
boolean isRedirect, Runnable responseAction) {
mIsRedirect = isRedirect;
mResponseData = resposneData;
mResponseHeaders = responseHeaders == null ?
new ArrayList<Pair<String, String>>() : responseHeaders;
mResponseAction = responseAction;
}
}
private final Object mLock = new Object();
private final Map<String, Response> mResponseMap = new HashMap<String, Response>();
private final Map<String, Integer> mResponseCountMap = new HashMap<String, Integer>();
private final Map<String, HttpRequest> mLastRequestMap = new HashMap<String, HttpRequest>();
public TestWebServer(boolean ssl) throws Exception {
if (sInstance != null) {
sInstance.shutdown();
}
setStaticInstance(this);
mSsl = ssl;
if (mSsl) {
mServerUri = "https://localhost:" + SSL_SERVER_PORT;
} else {
mServerUri = "http://localhost:" + SERVER_PORT;
}
mServerThread = new ServerThread(this, mSsl);
mServerThread.start();
}
private static void setStaticInstance(TestWebServer instance) {
sInstance = instance;
}
public void shutdown() {
try {
URL url = new URL(mServerUri + SHUTDOWN_PREFIX);
URLConnection connection = openConnection(url);
connection.connect();
InputStream is = connection.getInputStream();
is.close();
mServerThread.join();
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
} catch (KeyManagementException e) {
throw new IllegalStateException(e);
}
setStaticInstance(null);
}
private static final int RESPONSE_STATUS_NORMAL = 0;
private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1;
private String setResponseInternal(
String requestPath, byte[] responseData,
List<Pair<String, String>> responseHeaders, Runnable responseAction,
int status) {
final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY);
synchronized (mLock) {
mResponseMap.put(requestPath, new Response(
responseData, responseHeaders, isRedirect, responseAction));
mResponseCountMap.put(requestPath, Integer.valueOf(0));
mLastRequestMap.put(requestPath, null);
}
return getResponseUrl(requestPath);
}
public String getResponseUrl(String requestPath) {
return mServerUri + requestPath;
}
public String setResponse(
String requestPath, String responseString,
List<Pair<String, String>> responseHeaders) {
return setResponseInternal(requestPath, responseString.getBytes(), responseHeaders, null,
RESPONSE_STATUS_NORMAL);
}
public String setResponseWithRunnableAction(
String requestPath, String responseString, List<Pair<String, String>> responseHeaders,
Runnable responseAction) {
return setResponseInternal(
requestPath, responseString.getBytes(), responseHeaders, responseAction,
RESPONSE_STATUS_NORMAL);
}
public String setRedirect(
String requestPath, String targetPath) {
List<Pair<String, String>> responseHeaders = new ArrayList<Pair<String, String>>();
responseHeaders.add(Pair.create("Location", targetPath));
return setResponseInternal(requestPath, targetPath.getBytes(), responseHeaders, null,
RESPONSE_STATUS_MOVED_TEMPORARILY);
}
public String setResponseBase64(
String requestPath, String base64EncodedResponse,
List<Pair<String, String>> responseHeaders) {
return setResponseInternal(
requestPath, Base64.decode(base64EncodedResponse, Base64.DEFAULT),
responseHeaders, null, RESPONSE_STATUS_NORMAL);
}
public int getRequestCount(String requestPath) {
Integer count = null;
synchronized (mLock) {
count = mResponseCountMap.get(requestPath);
}
if (count == null) throw new IllegalArgumentException("Path not set: " + requestPath);
return count.intValue();
}
public HttpRequest getLastRequest(String requestPath) {
synchronized (mLock) {
if (!mLastRequestMap.containsKey(requestPath))
throw new IllegalArgumentException("Path not set: " + requestPath);
return mLastRequestMap.get(requestPath);
}
}
public String getBaseUrl() {
return mServerUri + "/";
}
private URLConnection openConnection(URL url)
throws IOException, NoSuchAlgorithmException, KeyManagementException {
if (mSsl) {
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setHostnameVerifier(new TestHostnameVerifier());
SSLContext context = SSLContext.getInstance("TLS");
TestTrustManager trustManager = new TestTrustManager();
context.init(null, new TestTrustManager[] {trustManager}, null);
connection.setSSLSocketFactory(context.getSocketFactory());
return connection;
} else {
return url.openConnection();
}
}
private static class TestTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
private static class TestHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private void servedResponseFor(String path, HttpRequest request) {
synchronized (mLock) {
mResponseCountMap.put(path, Integer.valueOf(
mResponseCountMap.get(path).intValue() + 1));
mLastRequestMap.put(path, request);
}
}
private HttpResponse getResponse(HttpRequest request) throws InterruptedException {
assert Thread.currentThread() == mServerThread
: "getResponse called from non-server thread";
RequestLine requestLine = request.getRequestLine();
HttpResponse httpResponse = null;
Log.i(TAG, requestLine.getMethod() + ": " + requestLine.getUri());
String uriString = requestLine.getUri();
URI uri = URI.create(uriString);
String path = uri.getPath();
Response response = null;
synchronized (mLock) {
response = mResponseMap.get(path);
}
if (path.equals(SHUTDOWN_PREFIX)) {
httpResponse = createResponse(HttpStatus.SC_OK);
} else if (response == null) {
httpResponse = createResponse(HttpStatus.SC_NOT_FOUND);
} else if (response.mIsRedirect) {
httpResponse = createResponse(HttpStatus.SC_MOVED_TEMPORARILY);
for (Pair<String, String> header : response.mResponseHeaders) {
httpResponse.addHeader(header.first, header.second);
}
servedResponseFor(path, request);
} else {
if (response.mResponseAction != null) response.mResponseAction.run();
httpResponse = createResponse(HttpStatus.SC_OK);
httpResponse.setEntity(createEntity(response.mResponseData));
for (Pair<String, String> header : response.mResponseHeaders) {
httpResponse.addHeader(header.first, header.second);
}
servedResponseFor(path, request);
}
StatusLine sl = httpResponse.getStatusLine();
Log.i(TAG, sl.getStatusCode() + "(" + sl.getReasonPhrase() + ")");
setDateHeaders(httpResponse);
return httpResponse;
}
private void setDateHeaders(HttpResponse response) {
response.addHeader("Date", DateUtils.formatDate(new Date(), DateUtils.PATTERN_RFC1123));
}
private HttpResponse createResponse(int status) {
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_0, status, null);
String reason = null;
synchronized (TestWebServer.class) {
if (sReasons == null) {
sReasons = new Hashtable<Integer, String>();
sReasons.put(HttpStatus.SC_UNAUTHORIZED, "Unauthorized");
sReasons.put(HttpStatus.SC_NOT_FOUND, "Not Found");
sReasons.put(HttpStatus.SC_FORBIDDEN, "Forbidden");
sReasons.put(HttpStatus.SC_MOVED_TEMPORARILY, "Moved Temporarily");
}
reason = sReasons.get(status);
}
if (reason != null) {
StringBuffer buf = new StringBuffer("<html><head><title>");
buf.append(reason);
buf.append("</title></head><body>");
buf.append(reason);
buf.append("</body></html>");
response.setEntity(createEntity(buf.toString().getBytes()));
}
return response;
}
private ByteArrayEntity createEntity(byte[] data) {
ByteArrayEntity entity = new ByteArrayEntity(data);
entity.setContentType("text/html");
return entity;
}
private static class ServerThread extends Thread {
private TestWebServer mServer;
private ServerSocket mSocket;
private boolean mIsSsl;
private boolean mIsCancelled;
private SSLContext mSslContext;
private static final String SERVER_KEYS_BKS =
"AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" +
"MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
"MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
"BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" +
"MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
"VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" +
"cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" +
"DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" +
"zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" +
"9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" +
"hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" +
"yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" +
"4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" +
"MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" +
"vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" +
"P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" +
"MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" +
"J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" +
"rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" +
"V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" +
"OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" +
"bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" +
"1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
"k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
private static final String PASSWORD = "android";
private KeyManager[] getKeyManagers() throws Exception {
byte[] bytes = Base64.decode(SERVER_KEYS_BKS, Base64.DEFAULT);
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(inputStream, PASSWORD.toCharArray());
inputStream.close();
String algorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
keyManagerFactory.init(keyStore, PASSWORD.toCharArray());
return keyManagerFactory.getKeyManagers();
}
public ServerThread(TestWebServer server, boolean ssl) throws Exception {
super("ServerThread");
mServer = server;
mIsSsl = ssl;
int retry = 3;
while (true) {
try {
if (mIsSsl) {
mSslContext = SSLContext.getInstance("TLS");
mSslContext.init(getKeyManagers(), null, null);
mSocket = mSslContext.getServerSocketFactory().createServerSocket(
SSL_SERVER_PORT);
} else {
mSocket = new ServerSocket(SERVER_PORT);
}
return;
} catch (IOException e) {
Log.w(TAG, e);
if (--retry == 0) {
throw e;
}
Thread.sleep(1000);
}
}
}
@Override
public void run() {
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
while (!mIsCancelled) {
try {
Socket socket = mSocket.accept();
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
conn.bind(socket, params);
HttpRequest request = conn.receiveRequestHeader();
if (isShutdownRequest(request)) {
mIsCancelled = true;
}
HttpResponse response = mServer.getResponse(request);
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
conn.close();
} catch (IOException e) {
Log.w(TAG, e);
} catch (HttpException e) {
Log.w(TAG, e);
} catch (InterruptedException e) {
Log.w(TAG, e);
} catch (UnsupportedOperationException e) {
Log.w(TAG, e);
}
}
try {
mSocket.close();
} catch (IOException ignored) {
}
}
private boolean isShutdownRequest(HttpRequest request) {
RequestLine requestLine = request.getRequestLine();
String uriString = requestLine.getUri();
URI uri = URI.create(uriString);
String path = uri.getPath();
return path.equals(SHUTDOWN_PREFIX);
}
}
}