summaryrefslogtreecommitdiff
path: root/chromium/net/test
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/net/test
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'chromium/net/test')
-rw-r--r--chromium/net/test/OWNERS5
-rw-r--r--chromium/net/test/android/OWNERS3
-rw-r--r--chromium/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java557
-rw-r--r--chromium/net/test/cert_test_util.cc57
-rw-r--r--chromium/net/test/cert_test_util.h53
-rw-r--r--chromium/net/test/embedded_test_server/OWNERS2
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server.cc276
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server.h172
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc244
-rw-r--r--chromium/net/test/embedded_test_server/http_connection.cc35
-rw-r--r--chromium/net/test/embedded_test_server/http_connection.h58
-rw-r--r--chromium/net/test/embedded_test_server/http_request.cc202
-rw-r--r--chromium/net/test/embedded_test_server/http_request.h115
-rw-r--r--chromium/net/test/embedded_test_server/http_request_unittest.cc82
-rw-r--r--chromium/net/test/embedded_test_server/http_response.cc58
-rw-r--r--chromium/net/test/embedded_test_server/http_response.h71
-rw-r--r--chromium/net/test/embedded_test_server/http_response_unittest.cc31
-rw-r--r--chromium/net/test/net_test_suite.cc67
-rw-r--r--chromium/net/test/net_test_suite.h55
-rw-r--r--chromium/net/test/openssl_helper.cc264
-rw-r--r--chromium/net/test/python_utils.cc127
-rw-r--r--chromium/net/test/python_utils.h28
-rw-r--r--chromium/net/test/python_utils_unittest.cc61
-rw-r--r--chromium/net/test/run_all_unittests.cc53
-rw-r--r--chromium/net/test/spawned_test_server/base_test_server.cc407
-rw-r--r--chromium/net/test/spawned_test_server/base_test_server.h263
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server.cc252
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server.h117
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server_posix.cc179
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server_win.cc175
-rw-r--r--chromium/net/test/spawned_test_server/remote_test_server.cc204
-rw-r--r--chromium/net/test/spawned_test_server/remote_test_server.h71
-rw-r--r--chromium/net/test/spawned_test_server/spawned_test_server.h27
-rw-r--r--chromium/net/test/spawned_test_server/spawner_communicator.cc379
-rw-r--r--chromium/net/test/spawned_test_server/spawner_communicator.h151
-rw-r--r--chromium/net/test/test_certificate_data.h786
36 files changed, 5687 insertions, 0 deletions
diff --git a/chromium/net/test/OWNERS b/chromium/net/test/OWNERS
new file mode 100644
index 00000000000..5b08e349893
--- /dev/null
+++ b/chromium/net/test/OWNERS
@@ -0,0 +1,5 @@
+# General reviewer, except sync-specific bits.
+phajdan.jr@chromium.org
+
+# For changes to local_sync_test_server.{h|cc}.
+akalin@chromium.org
diff --git a/chromium/net/test/android/OWNERS b/chromium/net/test/android/OWNERS
new file mode 100644
index 00000000000..4bcb60f934c
--- /dev/null
+++ b/chromium/net/test/android/OWNERS
@@ -0,0 +1,3 @@
+digit@chromium.org
+pliard@chromium.org
+yfriedman@chromium.org
diff --git a/chromium/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/chromium/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
new file mode 100644
index 00000000000..9e60a43fa41
--- /dev/null
+++ b/chromium/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
@@ -0,0 +1,557 @@
+// Copyright (c) 2012 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.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;
+
+/**
+ * Simple http test server for testing.
+ *
+ * This server runs in a thread in the current process, so it is convenient
+ * for loopback testing without the need to setup tcp forwarding to the
+ * host computer.
+ *
+ * Based heavily on the CTSWebServer in Android.
+ */
+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;
+
+ Response(byte[] resposneData, List<Pair<String, String>> responseHeaders,
+ boolean isRedirect) {
+ mIsRedirect = isRedirect;
+ mResponseData = resposneData;
+ mResponseHeaders = responseHeaders == null ?
+ new ArrayList<Pair<String, String>>() : responseHeaders;
+ }
+ }
+
+ // The Maps below are modified on both the client thread and the internal server thread, so
+ // need to use a lock when accessing them.
+ 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>();
+
+ /**
+ * Create and start a local HTTP server instance.
+ * @param ssl True if the server should be using secure sockets.
+ * @throws Exception
+ */
+ public TestWebServer(boolean ssl) throws Exception {
+ if (sInstance != null) {
+ // attempt to start a new instance while one is still running
+ // shut down the old instance first
+ 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;
+ }
+
+ /**
+ * Terminate the http server.
+ */
+ public void shutdown() {
+ try {
+ // Avoid a deadlock between two threads where one is trying to call
+ // close() and the other one is calling accept() by sending a GET
+ // request for shutdown and having the server's one thread
+ // sequentially call accept() and close().
+ URL url = new URL(mServerUri + SHUTDOWN_PREFIX);
+ URLConnection connection = openConnection(url);
+ connection.connect();
+
+ // Read the input from the stream to send the request.
+ InputStream is = connection.getInputStream();
+ is.close();
+
+ // Block until the server thread is done shutting down.
+ 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 final static int RESPONSE_STATUS_NORMAL = 0;
+ private final static int RESPONSE_STATUS_MOVED_TEMPORARILY = 1;
+
+ private String setResponseInternal(
+ String requestPath, byte[] responseData,
+ List<Pair<String, String>> responseHeaders,
+ int status) {
+ final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY);
+
+ synchronized (mLock) {
+ mResponseMap.put(requestPath, new Response(responseData, responseHeaders, isRedirect));
+ mResponseCountMap.put(requestPath, Integer.valueOf(0));
+ mLastRequestMap.put(requestPath, null);
+ }
+ return getResponseUrl(requestPath);
+ }
+
+ /**
+ * Gets the URL on the server under which a particular request path will be accessible.
+ *
+ * This only gets the URL, you still need to set the response if you intend to access it.
+ *
+ * @param requestPath The path to respond to.
+ * @return The full URL including the requestPath.
+ */
+ public String getResponseUrl(String requestPath) {
+ return mServerUri + requestPath;
+ }
+
+ /**
+ * Sets a response to be returned when a particular request path is passed
+ * in (with the option to specify additional headers).
+ *
+ * @param requestPath The path to respond to.
+ * @param responseString The response body that will be returned.
+ * @param responseHeaders Any additional headers that should be returned along with the
+ * response (null is acceptable).
+ * @return The full URL including the path that should be requested to get the expected
+ * response.
+ */
+ public String setResponse(
+ String requestPath, String responseString,
+ List<Pair<String, String>> responseHeaders) {
+ return setResponseInternal(requestPath, responseString.getBytes(), responseHeaders,
+ RESPONSE_STATUS_NORMAL);
+ }
+
+ /**
+ * Sets a redirect.
+ *
+ * @param requestPath The path to respond to.
+ * @param targetPath The path to redirect to.
+ * @return The full URL including the path that should be requested to get the expected
+ * response.
+ */
+ 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,
+ RESPONSE_STATUS_MOVED_TEMPORARILY);
+ }
+
+ /**
+ * Sets a base64 encoded response to be returned when a particular request path is passed
+ * in (with the option to specify additional headers).
+ *
+ * @param requestPath The path to respond to.
+ * @param base64EncodedResponse The response body that is base64 encoded. The actual server
+ * response will the decoded binary form.
+ * @param responseHeaders Any additional headers that should be returned along with the
+ * response (null is acceptable).
+ * @return The full URL including the path that should be requested to get the expected
+ * response.
+ */
+ public String setResponseBase64(
+ String requestPath, String base64EncodedResponse,
+ List<Pair<String, String>> responseHeaders) {
+ return setResponseInternal(requestPath,
+ Base64.decode(base64EncodedResponse, Base64.DEFAULT),
+ responseHeaders,
+ RESPONSE_STATUS_NORMAL);
+ }
+
+ /**
+ * Get the number of requests was made at this path since it was last set.
+ */
+ 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();
+ }
+
+ /**
+ * Returns the last HttpRequest at this path. Can return null if it is never requested.
+ */
+ 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) {
+ // Install hostname verifiers and trust managers that don't do
+ // anything in order to get around the client not trusting
+ // the test server due to a lack of certificates.
+
+ 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();
+ }
+ }
+
+ /**
+ * {@link X509TrustManager} that trusts everybody. This is used so that
+ * the client calling {@link TestWebServer#shutdown()} can issue a request
+ * for shutdown by blindly trusting the {@link TestWebServer}'s
+ * credentials.
+ */
+ private static class TestTrustManager implements X509TrustManager {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ // Trust the TestWebServer...
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+ // Trust the TestWebServer...
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ }
+
+ /**
+ * {@link HostnameVerifier} that verifies everybody. This permits
+ * the client to trust the web server and call
+ * {@link TestWebServer#shutdown()}.
+ */
+ 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);
+ }
+ }
+
+ /**
+ * Generate a response to the given request.
+ * @throws InterruptedException
+ */
+ private HttpResponse getResponse(HttpRequest request) throws InterruptedException {
+ 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 {
+ 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));
+ }
+
+ /**
+ * Create an empty response with the given status.
+ */
+ private HttpResponse createResponse(int status) {
+ HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_0, status, null);
+ String reason = null;
+
+ // This synchronized silences findbugs.
+ 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");
+ }
+ // Fill in error reason. Avoid use of the ReasonPhraseCatalog, which is
+ // Locale-dependent.
+ 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;
+ }
+
+ /**
+ * Create a string entity for the given content.
+ */
+ 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;
+
+ /**
+ * Defines the keystore contents for the server, BKS version. Holds just a
+ * single self-generated key. The subject name is "Test Server".
+ */
+ 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";
+
+ /**
+ * Loads a keystore from a base64-encoded String. Returns the KeyManager[]
+ * for the result.
+ */
+ 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;
+ }
+ // sleep in case server socket is still being closed
+ 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);
+
+ // Determine whether we need to shutdown early before
+ // parsing the response since conn.close() will crash
+ // for SSL requests due to UnsupportedOperationException.
+ 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) {
+ // normal during shutdown, ignore
+ Log.w(TAG, e);
+ } catch (HttpException e) {
+ Log.w(TAG, e);
+ } catch (InterruptedException e) {
+ Log.w(TAG, e);
+ } catch (UnsupportedOperationException e) {
+ // DefaultHttpServerConnection's close() throws an
+ // UnsupportedOperationException.
+ Log.w(TAG, e);
+ }
+ }
+ try {
+ mSocket.close();
+ } catch (IOException ignored) {
+ // safe to ignore
+ }
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/chromium/net/test/cert_test_util.cc b/chromium/net/test/cert_test_util.cc
new file mode 100644
index 00000000000..085a4594c76
--- /dev/null
+++ b/chromium/net/test/cert_test_util.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/cert_test_util.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "net/cert/ev_root_ca_metadata.h"
+#include "net/cert/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+CertificateList CreateCertificateListFromFile(
+ const base::FilePath& certs_dir,
+ const std::string& cert_file,
+ int format) {
+ base::FilePath cert_path = certs_dir.AppendASCII(cert_file);
+ std::string cert_data;
+ if (!file_util::ReadFileToString(cert_path, &cert_data))
+ return CertificateList();
+ return X509Certificate::CreateCertificateListFromBytes(cert_data.data(),
+ cert_data.size(),
+ format);
+}
+
+scoped_refptr<X509Certificate> ImportCertFromFile(
+ const base::FilePath& certs_dir,
+ const std::string& cert_file) {
+ base::FilePath cert_path = certs_dir.AppendASCII(cert_file);
+ std::string cert_data;
+ if (!file_util::ReadFileToString(cert_path, &cert_data))
+ return NULL;
+
+ CertificateList certs_in_file =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ if (certs_in_file.empty())
+ return NULL;
+ return certs_in_file[0];
+}
+
+ScopedTestEVPolicy::ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata,
+ const SHA1HashValue& fingerprint,
+ const char* policy)
+ : fingerprint_(fingerprint),
+ ev_root_ca_metadata_(ev_root_ca_metadata) {
+ EXPECT_TRUE(ev_root_ca_metadata->AddEVCA(fingerprint, policy));
+}
+
+ScopedTestEVPolicy::~ScopedTestEVPolicy() {
+ EXPECT_TRUE(ev_root_ca_metadata_->RemoveEVCA(fingerprint_));
+}
+
+} // namespace net
diff --git a/chromium/net/test/cert_test_util.h b/chromium/net/test/cert_test_util.h
new file mode 100644
index 00000000000..d4aa4d7d325
--- /dev/null
+++ b/chromium/net/test/cert_test_util.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_CERT_TEST_UTIL_H_
+#define NET_TEST_CERT_TEST_UTIL_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "net/cert/x509_cert_types.h"
+#include "net/cert/x509_certificate.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace net {
+
+class EVRootCAMetadata;
+
+CertificateList CreateCertificateListFromFile(const base::FilePath& certs_dir,
+ const std::string& cert_file,
+ int format);
+
+// Imports a certificate file in the directory net::GetTestCertsDirectory()
+// returns.
+// |certs_dir| represents the test certificates directory. |cert_file| is the
+// name of the certificate file. If cert_file contains multiple certificates,
+// the first certificate found will be returned.
+scoped_refptr<X509Certificate> ImportCertFromFile(const base::FilePath& certs_dir,
+ const std::string& cert_file);
+
+// ScopedTestEVPolicy causes certificates marked with |policy|, issued from a
+// root with the given fingerprint, to be treated as EV. |policy| is expressed
+// as a string of dotted numbers: i.e. "1.2.3.4".
+// This should only be used in unittests as adding a CA twice causes a CHECK
+// failure.
+class ScopedTestEVPolicy {
+ public:
+ ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata,
+ const SHA1HashValue& fingerprint,
+ const char* policy);
+ ~ScopedTestEVPolicy();
+
+ private:
+ SHA1HashValue fingerprint_;
+ EVRootCAMetadata* const ev_root_ca_metadata_;
+};
+
+} // namespace net
+
+#endif // NET_TEST_CERT_TEST_UTIL_H_
diff --git a/chromium/net/test/embedded_test_server/OWNERS b/chromium/net/test/embedded_test_server/OWNERS
new file mode 100644
index 00000000000..e0abbce9eac
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/OWNERS
@@ -0,0 +1,2 @@
+mtomasz@chromium.org
+satorux@chromium.org
diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.cc b/chromium/net/test/embedded_test_server/embedded_test_server.cc
new file mode 100644
index 00000000000..9175d6ca894
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc
@@ -0,0 +1,276 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/test/embedded_test_server/http_connection.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/tools/fetch/http_listen_socket.h"
+
+namespace net {
+namespace test_server {
+
+namespace {
+
+class CustomHttpResponse : public HttpResponse {
+ public:
+ CustomHttpResponse(const std::string& headers, const std::string& contents)
+ : headers_(headers), contents_(contents) {
+ }
+
+ virtual std::string ToResponseString() const OVERRIDE {
+ return headers_ + "\r\n" + contents_;
+ }
+
+ private:
+ std::string headers_;
+ std::string contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
+};
+
+// Handles |request| by serving a file from under |server_root|.
+scoped_ptr<HttpResponse> HandleFileRequest(
+ const base::FilePath& server_root,
+ const HttpRequest& request) {
+ // This is a test-only server. Ignore I/O thread restrictions.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ // Trim the first byte ('/').
+ std::string request_path(request.relative_url.substr(1));
+
+ // Remove the query string if present.
+ size_t query_pos = request_path.find('?');
+ if (query_pos != std::string::npos)
+ request_path = request_path.substr(0, query_pos);
+
+ base::FilePath file_path(server_root.AppendASCII(request_path));
+ std::string file_contents;
+ if (!file_util::ReadFileToString(file_path, &file_contents))
+ return scoped_ptr<HttpResponse>();
+
+ base::FilePath headers_path(
+ file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
+
+ if (base::PathExists(headers_path)) {
+ std::string headers_contents;
+ if (!file_util::ReadFileToString(headers_path, &headers_contents))
+ return scoped_ptr<HttpResponse>();
+
+ scoped_ptr<CustomHttpResponse> http_response(
+ new CustomHttpResponse(headers_contents, file_contents));
+ return http_response.PassAs<HttpResponse>();
+ }
+
+ scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+ http_response->set_code(HTTP_OK);
+ http_response->set_content(file_contents);
+ return http_response.PassAs<HttpResponse>();
+}
+
+} // namespace
+
+HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor,
+ StreamListenSocket::Delegate* delegate)
+ : TCPListenSocket(socket_descriptor, delegate) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void HttpListenSocket::Listen() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TCPListenSocket::Listen();
+}
+
+HttpListenSocket::~HttpListenSocket() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+EmbeddedTestServer::EmbeddedTestServer(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_thread)
+ : io_thread_(io_thread),
+ port_(-1),
+ weak_factory_(this) {
+ DCHECK(io_thread_.get());
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+EmbeddedTestServer::~EmbeddedTestServer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (Started() && !ShutdownAndWaitUntilComplete()) {
+ LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
+ }
+}
+
+bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ base::RunLoop run_loop;
+ if (!io_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&EmbeddedTestServer::InitializeOnIOThread,
+ base::Unretained(this)),
+ run_loop.QuitClosure())) {
+ return false;
+ }
+ run_loop.Run();
+
+ return Started() && base_url_.is_valid();
+}
+
+bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ base::RunLoop run_loop;
+ if (!io_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&EmbeddedTestServer::ShutdownOnIOThread,
+ base::Unretained(this)),
+ run_loop.QuitClosure())) {
+ return false;
+ }
+ run_loop.Run();
+
+ return true;
+}
+
+void EmbeddedTestServer::InitializeOnIOThread() {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+ DCHECK(!Started());
+
+ SocketDescriptor socket_descriptor =
+ TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_);
+ if (socket_descriptor == TCPListenSocket::kInvalidSocket)
+ return;
+
+ listen_socket_ = new HttpListenSocket(socket_descriptor, this);
+ listen_socket_->Listen();
+
+ IPEndPoint address;
+ int result = listen_socket_->GetLocalAddress(&address);
+ if (result == OK) {
+ base_url_ = GURL(std::string("http://") + address.ToString());
+ } else {
+ LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
+ }
+}
+
+void EmbeddedTestServer::ShutdownOnIOThread() {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ listen_socket_ = NULL; // Release the listen socket.
+ STLDeleteContainerPairSecondPointers(connections_.begin(),
+ connections_.end());
+ connections_.clear();
+}
+
+void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
+ scoped_ptr<HttpRequest> request) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ bool request_handled = false;
+
+ for (size_t i = 0; i < request_handlers_.size(); ++i) {
+ scoped_ptr<HttpResponse> response =
+ request_handlers_[i].Run(*request.get());
+ if (response.get()) {
+ connection->SendResponse(response.Pass());
+ request_handled = true;
+ break;
+ }
+ }
+
+ if (!request_handled) {
+ LOG(WARNING) << "Request not handled. Returning 404: "
+ << request->relative_url;
+ scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
+ not_found_response->set_code(HTTP_NOT_FOUND);
+ connection->SendResponse(
+ not_found_response.PassAs<HttpResponse>());
+ }
+
+ // Drop the connection, since we do not support multiple requests per
+ // connection.
+ connections_.erase(connection->socket_.get());
+ delete connection;
+}
+
+GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
+ DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
+ << relative_url;
+ return base_url_.Resolve(relative_url);
+}
+
+void EmbeddedTestServer::ServeFilesFromDirectory(
+ const base::FilePath& directory) {
+ RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
+}
+
+void EmbeddedTestServer::RegisterRequestHandler(
+ const HandleRequestCallback& callback) {
+ request_handlers_.push_back(callback);
+}
+
+void EmbeddedTestServer::DidAccept(StreamListenSocket* server,
+ StreamListenSocket* connection) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ HttpConnection* http_connection = new HttpConnection(
+ connection,
+ base::Bind(&EmbeddedTestServer::HandleRequest,
+ weak_factory_.GetWeakPtr()));
+ connections_[connection] = http_connection;
+}
+
+void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
+ const char* data,
+ int length) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ HttpConnection* http_connection = FindConnection(connection);
+ if (http_connection == NULL) {
+ LOG(WARNING) << "Unknown connection.";
+ return;
+ }
+ http_connection->ReceiveData(std::string(data, length));
+}
+
+void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ HttpConnection* http_connection = FindConnection(connection);
+ if (http_connection == NULL) {
+ LOG(WARNING) << "Unknown connection.";
+ return;
+ }
+ delete http_connection;
+ connections_.erase(connection);
+}
+
+HttpConnection* EmbeddedTestServer::FindConnection(
+ StreamListenSocket* socket) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+
+ std::map<StreamListenSocket*, HttpConnection*>::iterator it =
+ connections_.find(socket);
+ if (it == connections_.end()) {
+ return NULL;
+ }
+ return it->second;
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.h b/chromium/net/test/embedded_test_server/embedded_test_server.h
new file mode 100644
index 00000000000..879c4a947f9
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/embedded_test_server.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_
+#define NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "net/socket/tcp_listen_socket.h"
+#include "url/gurl.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace net {
+namespace test_server {
+
+class HttpConnection;
+class HttpResponse;
+struct HttpRequest;
+
+// This class is required to be able to have composition instead of inheritance,
+class HttpListenSocket : public TCPListenSocket {
+ public:
+ HttpListenSocket(const SocketDescriptor socket_descriptor,
+ StreamListenSocket::Delegate* delegate);
+ virtual void Listen();
+
+ private:
+ virtual ~HttpListenSocket();
+
+ base::ThreadChecker thread_checker_;
+};
+
+// Class providing an HTTP server for testing purpose. This is a basic server
+// providing only an essential subset of HTTP/1.1 protocol. Especially,
+// it assumes that the request syntax is correct. It *does not* support
+// a Chunked Transfer Encoding.
+//
+// The common use case is below:
+//
+// base::Thread io_thread_;
+// scoped_ptr<EmbeddedTestServer> test_server_;
+//
+// void SetUp() {
+// base::Thread::Options thread_options;
+// thread_options.message_loop_type = MessageLoop::TYPE_IO;
+// ASSERT_TRUE(io_thread_.StartWithOptions(thread_options));
+//
+// test_server_.reset(
+// new EmbeddedTestServer(io_thread_.message_loop_proxy()));
+// ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady());
+// test_server_->RegisterRequestHandler(
+// base::Bind(&FooTest::HandleRequest, base::Unretained(this)));
+// }
+//
+// scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
+// GURL absolute_url = test_server_->GetURL(request.relative_url);
+// if (absolute_url.path() != "/test")
+// return scoped_ptr<HttpResponse>();
+//
+// scoped_ptr<HttpResponse> http_response(new HttpResponse());
+// http_response->set_code(test_server::SUCCESS);
+// http_response->set_content("hello");
+// http_response->set_content_type("text/plain");
+// return http_response.Pass();
+// }
+//
+class EmbeddedTestServer : public StreamListenSocket::Delegate {
+ public:
+ typedef base::Callback<scoped_ptr<HttpResponse>(
+ const HttpRequest& request)> HandleRequestCallback;
+
+ // Creates a http test server. |io_thread| is a task runner
+ // with IO message loop, used as a backend thread.
+ // InitializeAndWaitUntilReady() must be called to start the server.
+ explicit EmbeddedTestServer(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_thread);
+ virtual ~EmbeddedTestServer();
+
+ // Initializes and waits until the server is ready to accept requests.
+ bool InitializeAndWaitUntilReady() WARN_UNUSED_RESULT;
+
+ // Shuts down the http server and waits until the shutdown is complete.
+ bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT;
+
+ // Checks if the server is started.
+ bool Started() const {
+ return listen_socket_.get() != NULL;
+ }
+
+ // Returns the base URL to the server, which looks like
+ // http://127.0.0.1:<port>/, where <port> is the actual port number used by
+ // the server.
+ const GURL& base_url() const { return base_url_; }
+
+ // Returns a URL to the server based on the given relative URL, which
+ // should start with '/'. For example: GetURL("/path?query=foo") =>
+ // http://127.0.0.1:<port>/path?query=foo.
+ GURL GetURL(const std::string& relative_url) const;
+
+ // Returns the port number used by the server.
+ int port() const { return port_; }
+
+ // Registers request handler which serves files from |directory|.
+ // For instance, a request to "/foo.html" is served by "foo.html" under
+ // |directory|. Files under sub directories are also handled in the same way
+ // (i.e. "/foo/bar.html" is served by "foo/bar.html" under |directory|).
+ void ServeFilesFromDirectory(const base::FilePath& directory);
+
+ // The most general purpose method. Any request processing can be added using
+ // this method. Takes ownership of the object. The |callback| is called
+ // on UI thread.
+ void RegisterRequestHandler(const HandleRequestCallback& callback);
+
+ private:
+ // Initializes and starts the server. If initialization succeeds, Starts()
+ // will return true.
+ void InitializeOnIOThread();
+
+ // Shuts down the server.
+ void ShutdownOnIOThread();
+
+ // Handles a request when it is parsed. It passes the request to registed
+ // request handlers and sends a http response.
+ void HandleRequest(HttpConnection* connection,
+ scoped_ptr<HttpRequest> request);
+
+ // StreamListenSocket::Delegate overrides:
+ virtual void DidAccept(StreamListenSocket* server,
+ StreamListenSocket* connection) OVERRIDE;
+ virtual void DidRead(StreamListenSocket* connection,
+ const char* data,
+ int length) OVERRIDE;
+ virtual void DidClose(StreamListenSocket* connection) OVERRIDE;
+
+ HttpConnection* FindConnection(StreamListenSocket* socket);
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
+
+ scoped_refptr<HttpListenSocket> listen_socket_;
+ int port_;
+ GURL base_url_;
+
+ // Owns the HttpConnection objects.
+ std::map<StreamListenSocket*, HttpConnection*> connections_;
+
+ // Vector of registered request handlers.
+ std::vector<HandleRequestCallback> request_handlers_;
+
+ // Note: This should remain the last member so it'll be destroyed and
+ // invalidate its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<EmbeddedTestServer> weak_factory_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer);
+};
+
+} // namespace test_servers
+} // namespace net
+
+#endif // NET_TEST_EMBEDDED_TEST_SERVER_EMBEDDED_TEST_SERVER_H_
diff --git a/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc
new file mode 100644
index 00000000000..35d0fd414e1
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -0,0 +1,244 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
+#include "net/http/http_response_headers.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test_server {
+
+namespace {
+
+// Gets the content from the given URLFetcher.
+std::string GetContentFromFetcher(const URLFetcher& fetcher) {
+ std::string result;
+ const bool success = fetcher.GetResponseAsString(&result);
+ EXPECT_TRUE(success);
+ return result;
+}
+
+// Gets the content type from the given URLFetcher.
+std::string GetContentTypeFromFetcher(const URLFetcher& fetcher) {
+ const HttpResponseHeaders* headers = fetcher.GetResponseHeaders();
+ if (headers) {
+ std::string content_type;
+ if (headers->GetMimeType(&content_type))
+ return content_type;
+ }
+ return std::string();
+}
+
+} // namespace
+
+class EmbeddedTestServerTest : public testing::Test,
+ public URLFetcherDelegate {
+ public:
+ EmbeddedTestServerTest()
+ : num_responses_received_(0),
+ num_responses_expected_(0),
+ io_thread_("io_thread") {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
+ ASSERT_TRUE(io_thread_.StartWithOptions(thread_options));
+
+ request_context_getter_ = new TestURLRequestContextGetter(
+ io_thread_.message_loop_proxy());
+
+ server_.reset(new EmbeddedTestServer(io_thread_.message_loop_proxy()));
+ ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ ASSERT_TRUE(server_->ShutdownAndWaitUntilComplete());
+ }
+
+ // URLFetcherDelegate override.
+ virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE {
+ ++num_responses_received_;
+ if (num_responses_received_ == num_responses_expected_)
+ base::MessageLoop::current()->Quit();
+ }
+
+ // Waits until the specified number of responses are received.
+ void WaitForResponses(int num_responses) {
+ num_responses_received_ = 0;
+ num_responses_expected_ = num_responses;
+ // Will be terminated in OnURLFetchComplete().
+ base::MessageLoop::current()->Run();
+ }
+
+ // Handles |request| sent to |path| and returns the response per |content|,
+ // |content type|, and |code|. Saves the request URL for verification.
+ scoped_ptr<HttpResponse> HandleRequest(const std::string& path,
+ const std::string& content,
+ const std::string& content_type,
+ HttpStatusCode code,
+ const HttpRequest& request) {
+ request_relative_url_ = request.relative_url;
+
+ GURL absolute_url = server_->GetURL(request.relative_url);
+ if (absolute_url.path() == path) {
+ scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+ http_response->set_code(code);
+ http_response->set_content(content);
+ http_response->set_content_type(content_type);
+ return http_response.PassAs<HttpResponse>();
+ }
+
+ return scoped_ptr<HttpResponse>();
+ }
+
+ protected:
+ int num_responses_received_;
+ int num_responses_expected_;
+ std::string request_relative_url_;
+ base::Thread io_thread_;
+ scoped_refptr<TestURLRequestContextGetter> request_context_getter_;
+ scoped_ptr<EmbeddedTestServer> server_;
+};
+
+TEST_F(EmbeddedTestServerTest, GetBaseURL) {
+ EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/", server_->port()),
+ server_->base_url().spec());
+}
+
+TEST_F(EmbeddedTestServerTest, GetURL) {
+ EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/path?query=foo",
+ server_->port()),
+ server_->GetURL("/path?query=foo").spec());
+}
+
+TEST_F(EmbeddedTestServerTest, RegisterRequestHandler) {
+ server_->RegisterRequestHandler(
+ base::Bind(&EmbeddedTestServerTest::HandleRequest,
+ base::Unretained(this),
+ "/test",
+ "<b>Worked!</b>",
+ "text/html",
+ HTTP_OK));
+
+ scoped_ptr<URLFetcher> fetcher(
+ URLFetcher::Create(server_->GetURL("/test?q=foo"),
+ URLFetcher::GET,
+ this));
+ fetcher->SetRequestContext(request_context_getter_.get());
+ fetcher->Start();
+ WaitForResponses(1);
+
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
+ EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode());
+ EXPECT_EQ("<b>Worked!</b>", GetContentFromFetcher(*fetcher));
+ EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher));
+
+ EXPECT_EQ("/test?q=foo", request_relative_url_);
+}
+
+TEST_F(EmbeddedTestServerTest, ServeFilesFromDirectory) {
+ base::FilePath src_dir;
+ ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
+ server_->ServeFilesFromDirectory(
+ src_dir.AppendASCII("net").AppendASCII("data"));
+
+ scoped_ptr<URLFetcher> fetcher(
+ URLFetcher::Create(server_->GetURL("/test.html"),
+ URLFetcher::GET,
+ this));
+ fetcher->SetRequestContext(request_context_getter_.get());
+ fetcher->Start();
+ WaitForResponses(1);
+
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
+ EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode());
+ EXPECT_EQ("<p>Hello World!</p>", GetContentFromFetcher(*fetcher));
+ EXPECT_EQ("", GetContentTypeFromFetcher(*fetcher));
+}
+
+TEST_F(EmbeddedTestServerTest, DefaultNotFoundResponse) {
+ scoped_ptr<URLFetcher> fetcher(
+ URLFetcher::Create(server_->GetURL("/non-existent"),
+ URLFetcher::GET,
+ this));
+ fetcher->SetRequestContext(request_context_getter_.get());
+
+ fetcher->Start();
+ WaitForResponses(1);
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
+ EXPECT_EQ(HTTP_NOT_FOUND, fetcher->GetResponseCode());
+}
+
+TEST_F(EmbeddedTestServerTest, ConcurrentFetches) {
+ server_->RegisterRequestHandler(
+ base::Bind(&EmbeddedTestServerTest::HandleRequest,
+ base::Unretained(this),
+ "/test1",
+ "Raspberry chocolate",
+ "text/html",
+ HTTP_OK));
+ server_->RegisterRequestHandler(
+ base::Bind(&EmbeddedTestServerTest::HandleRequest,
+ base::Unretained(this),
+ "/test2",
+ "Vanilla chocolate",
+ "text/html",
+ HTTP_OK));
+ server_->RegisterRequestHandler(
+ base::Bind(&EmbeddedTestServerTest::HandleRequest,
+ base::Unretained(this),
+ "/test3",
+ "No chocolates",
+ "text/plain",
+ HTTP_NOT_FOUND));
+
+ scoped_ptr<URLFetcher> fetcher1 = scoped_ptr<URLFetcher>(
+ URLFetcher::Create(server_->GetURL("/test1"),
+ URLFetcher::GET,
+ this));
+ fetcher1->SetRequestContext(request_context_getter_.get());
+ scoped_ptr<URLFetcher> fetcher2 = scoped_ptr<URLFetcher>(
+ URLFetcher::Create(server_->GetURL("/test2"),
+ URLFetcher::GET,
+ this));
+ fetcher2->SetRequestContext(request_context_getter_.get());
+ scoped_ptr<URLFetcher> fetcher3 = scoped_ptr<URLFetcher>(
+ URLFetcher::Create(server_->GetURL("/test3"),
+ URLFetcher::GET,
+ this));
+ fetcher3->SetRequestContext(request_context_getter_.get());
+
+ // Fetch the three URLs concurrently.
+ fetcher1->Start();
+ fetcher2->Start();
+ fetcher3->Start();
+ WaitForResponses(3);
+
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher1->GetStatus().status());
+ EXPECT_EQ(HTTP_OK, fetcher1->GetResponseCode());
+ EXPECT_EQ("Raspberry chocolate", GetContentFromFetcher(*fetcher1));
+ EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher1));
+
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher2->GetStatus().status());
+ EXPECT_EQ(HTTP_OK, fetcher2->GetResponseCode());
+ EXPECT_EQ("Vanilla chocolate", GetContentFromFetcher(*fetcher2));
+ EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher2));
+
+ EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher3->GetStatus().status());
+ EXPECT_EQ(HTTP_NOT_FOUND, fetcher3->GetResponseCode());
+ EXPECT_EQ("No chocolates", GetContentFromFetcher(*fetcher3));
+ EXPECT_EQ("text/plain", GetContentTypeFromFetcher(*fetcher3));
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/http_connection.cc b/chromium/net/test/embedded_test_server/http_connection.cc
new file mode 100644
index 00000000000..8b5317e320b
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_connection.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/http_connection.h"
+
+#include "net/socket/stream_listen_socket.h"
+#include "net/test/embedded_test_server/http_response.h"
+
+namespace net {
+namespace test_server {
+
+HttpConnection::HttpConnection(StreamListenSocket* socket,
+ const HandleRequestCallback& callback)
+ : socket_(socket),
+ callback_(callback) {
+}
+
+HttpConnection::~HttpConnection() {
+}
+
+void HttpConnection::SendResponse(scoped_ptr<HttpResponse> response) const {
+ const std::string response_string = response->ToResponseString();
+ socket_->Send(response_string.c_str(), response_string.length());
+}
+
+void HttpConnection::ReceiveData(const base::StringPiece& data) {
+ request_parser_.ProcessChunk(data);
+ if (request_parser_.ParseRequest() == HttpRequestParser::ACCEPTED) {
+ callback_.Run(this, request_parser_.GetRequest());
+ }
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/http_connection.h b/chromium/net/test/embedded_test_server/http_connection.h
new file mode 100644
index 00000000000..da9353404c6
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_connection.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECTION_H_
+#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECTION_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/test/embedded_test_server/http_request.h"
+
+namespace net {
+
+class StreamListenSocket;
+
+namespace test_server {
+
+class HttpConnection;
+class HttpResponse;
+
+// Calblack called when a request is parsed. Response should be sent
+// using HttpConnection::SendResponse() on the |connection| argument.
+typedef base::Callback<void(HttpConnection* connection,
+ scoped_ptr<HttpRequest> request)>
+ HandleRequestCallback;
+
+// Wraps the connection socket. Accepts incoming data and sends responses.
+// If a valid request is parsed, then |callback_| is invoked.
+class HttpConnection {
+ public:
+ HttpConnection(StreamListenSocket* socket,
+ const HandleRequestCallback& callback);
+ ~HttpConnection();
+
+ // Sends the HTTP response to the client.
+ void SendResponse(scoped_ptr<HttpResponse> response) const;
+
+ private:
+ friend class EmbeddedTestServer;
+
+ // Accepts raw chunk of data from the client. Internally, passes it to the
+ // HttpRequestParser class. If a request is parsed, then |callback_| is
+ // called.
+ void ReceiveData(const base::StringPiece& data);
+
+ scoped_refptr<StreamListenSocket> socket_;
+ const HandleRequestCallback callback_;
+ HttpRequestParser request_parser_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpConnection);
+};
+
+} // namespace test_server
+} // namespace net
+
+#endif // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECTION_H_
diff --git a/chromium/net/test/embedded_test_server/http_request.cc b/chromium/net/test/embedded_test_server/http_request.cc
new file mode 100644
index 00000000000..8ac76d35923
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_request.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/http_request.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+
+namespace net {
+namespace test_server {
+
+namespace {
+
+size_t kRequestSizeLimit = 64 * 1024 * 1024; // 64 mb.
+
+// Helper function used to trim tokens in http request headers.
+std::string Trim(const std::string& value) {
+ std::string result;
+ TrimString(value, " \t", &result);
+ return result;
+}
+
+} // namespace
+
+HttpRequest::HttpRequest() : method(METHOD_UNKNOWN),
+ has_content(false) {
+}
+
+HttpRequest::~HttpRequest() {
+}
+
+HttpRequestParser::HttpRequestParser()
+ : http_request_(new HttpRequest()),
+ buffer_position_(0),
+ state_(STATE_HEADERS),
+ declared_content_length_(0) {
+}
+
+HttpRequestParser::~HttpRequestParser() {
+}
+
+void HttpRequestParser::ProcessChunk(const base::StringPiece& data) {
+ data.AppendToString(&buffer_);
+ DCHECK_LE(buffer_.size() + data.size(), kRequestSizeLimit) <<
+ "The HTTP request is too large.";
+}
+
+std::string HttpRequestParser::ShiftLine() {
+ size_t eoln_position = buffer_.find("\r\n", buffer_position_);
+ DCHECK_NE(std::string::npos, eoln_position);
+ const int line_length = eoln_position - buffer_position_;
+ std::string result = buffer_.substr(buffer_position_, line_length);
+ buffer_position_ += line_length + 2;
+ return result;
+}
+
+HttpRequestParser::ParseResult HttpRequestParser::ParseRequest() {
+ DCHECK_NE(STATE_ACCEPTED, state_);
+ // Parse the request from beginning. However, entire request may not be
+ // available in the buffer.
+ if (state_ == STATE_HEADERS) {
+ if (ParseHeaders() == ACCEPTED)
+ return ACCEPTED;
+ }
+ // This should not be 'else if' of the previous block, as |state_| can be
+ // changed in ParseHeaders().
+ if (state_ == STATE_CONTENT) {
+ if (ParseContent() == ACCEPTED)
+ return ACCEPTED;
+ }
+ return WAITING;
+}
+
+HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() {
+ // Check if the all request headers are available.
+ if (buffer_.find("\r\n\r\n", buffer_position_) == std::string::npos)
+ return WAITING;
+
+ // Parse request's the first header line.
+ // Request main main header, eg. GET /foobar.html HTTP/1.1
+ {
+ const std::string header_line = ShiftLine();
+ std::vector<std::string> header_line_tokens;
+ base::SplitString(header_line, ' ', &header_line_tokens);
+ DCHECK_EQ(3u, header_line_tokens.size());
+ // Method.
+ http_request_->method = GetMethodType(StringToLowerASCII(
+ header_line_tokens[0]));
+ // Address.
+ // Don't build an absolute URL as the parser does not know (should not
+ // know) anything about the server address.
+ http_request_->relative_url = header_line_tokens[1];
+ // Protocol.
+ const std::string protocol = StringToLowerASCII(header_line_tokens[2]);
+ CHECK(protocol == "http/1.0" || protocol == "http/1.1") <<
+ "Protocol not supported: " << protocol;
+ }
+
+ // Parse further headers.
+ {
+ std::string header_name;
+ while (true) {
+ std::string header_line = ShiftLine();
+ if (header_line.empty())
+ break;
+
+ if (header_line[0] == ' ' || header_line[0] == '\t') {
+ // Continuation of the previous multi-line header.
+ std::string header_value =
+ Trim(header_line.substr(1, header_line.size() - 1));
+ http_request_->headers[header_name] += " " + header_value;
+ } else {
+ // New header.
+ size_t delimiter_pos = header_line.find(":");
+ DCHECK_NE(std::string::npos, delimiter_pos) << "Syntax error.";
+ header_name = Trim(header_line.substr(0, delimiter_pos));
+ std::string header_value = Trim(header_line.substr(
+ delimiter_pos + 1,
+ header_line.size() - delimiter_pos - 1));
+ http_request_->headers[header_name] = header_value;
+ }
+ }
+ }
+
+ // Headers done. Is any content data attached to the request?
+ declared_content_length_ = 0;
+ if (http_request_->headers.count("Content-Length") > 0) {
+ http_request_->has_content = true;
+ const bool success = base::StringToSizeT(
+ http_request_->headers["Content-Length"],
+ &declared_content_length_);
+ DCHECK(success) << "Malformed Content-Length header's value.";
+ }
+ if (declared_content_length_ == 0) {
+ // No content data, so parsing is finished.
+ state_ = STATE_ACCEPTED;
+ return ACCEPTED;
+ }
+
+ // The request has not yet been parsed yet, content data is still to be
+ // processed.
+ state_ = STATE_CONTENT;
+ return WAITING;
+}
+
+HttpRequestParser::ParseResult HttpRequestParser::ParseContent() {
+ const size_t available_bytes = buffer_.size() - buffer_position_;
+ const size_t fetch_bytes = std::min(
+ available_bytes,
+ declared_content_length_ - http_request_->content.size());
+ http_request_->content.append(buffer_.data() + buffer_position_,
+ fetch_bytes);
+ buffer_position_ += fetch_bytes;
+
+ if (declared_content_length_ == http_request_->content.size()) {
+ state_ = STATE_ACCEPTED;
+ return ACCEPTED;
+ }
+
+ state_ = STATE_CONTENT;
+ return WAITING;
+}
+
+scoped_ptr<HttpRequest> HttpRequestParser::GetRequest() {
+ DCHECK_EQ(STATE_ACCEPTED, state_);
+ scoped_ptr<HttpRequest> result = http_request_.Pass();
+
+ // Prepare for parsing a new request.
+ state_ = STATE_HEADERS;
+ http_request_.reset(new HttpRequest());
+ buffer_.clear();
+ buffer_position_ = 0;
+ declared_content_length_ = 0;
+
+ return result.Pass();
+}
+
+HttpMethod HttpRequestParser::GetMethodType(const std::string& token) const {
+ if (token == "get") {
+ return METHOD_GET;
+ } else if (token == "head") {
+ return METHOD_HEAD;
+ } else if (token == "post") {
+ return METHOD_POST;
+ } else if (token == "put") {
+ return METHOD_PUT;
+ } else if (token == "delete") {
+ return METHOD_DELETE;
+ } else if (token == "patch") {
+ return METHOD_PATCH;
+ }
+ NOTREACHED() << "Method not implemented: " << token;
+ return METHOD_UNKNOWN;
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/http_request.h b/chromium/net/test/embedded_test_server/http_request.h
new file mode 100644
index 00000000000..1e849d87d25
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_request.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
+#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+
+namespace net {
+namespace test_server {
+
+// Methods of HTTP requests supported by the test HTTP server.
+enum HttpMethod {
+ METHOD_UNKNOWN,
+ METHOD_GET,
+ METHOD_HEAD,
+ METHOD_POST,
+ METHOD_PUT,
+ METHOD_DELETE,
+ METHOD_PATCH,
+};
+
+// Represents a HTTP request. Since it can be big, use scoped_ptr to pass it
+// instead of copying. However, the struct is copyable so tests can save and
+// examine a HTTP request.
+struct HttpRequest {
+ HttpRequest();
+ ~HttpRequest();
+
+ std::string relative_url; // Starts with '/'. Example: "/test?query=foo"
+ HttpMethod method;
+ std::map<std::string, std::string> headers;
+ std::string content;
+ bool has_content;
+};
+
+// Parses the input data and produces a valid HttpRequest object. If there is
+// more than one request in one chunk, then only the first one will be parsed.
+// The common use is as below:
+// HttpRequestParser parser;
+// (...)
+// void OnDataChunkReceived(Socket* socket, const char* data, int size) {
+// parser.ProcessChunk(std::string(data, size));
+// if (parser.ParseRequest() == HttpRequestParser::ACCEPTED) {
+// scoped_ptr<HttpRequest> request = parser.GetRequest();
+// (... process the request ...)
+// }
+class HttpRequestParser {
+ public:
+ // Parsing result.
+ enum ParseResult {
+ WAITING, // A request is not completed yet, waiting for more data.
+ ACCEPTED, // A request has been parsed and it is ready to be processed.
+ };
+
+ // Parser state.
+ enum State {
+ STATE_HEADERS, // Waiting for a request headers.
+ STATE_CONTENT, // Waiting for content data.
+ STATE_ACCEPTED, // Request has been parsed.
+ };
+
+ HttpRequestParser();
+ ~HttpRequestParser();
+
+ // Adds chunk of data into the internal buffer.
+ void ProcessChunk(const base::StringPiece& data);
+
+ // Parses the http request (including data - if provided).
+ // If returns ACCEPTED, then it means that the whole request has been found
+ // in the internal buffer (and parsed). After calling GetRequest(), it will be
+ // ready to parse another request.
+ ParseResult ParseRequest();
+
+ // Retrieves parsed request. Can be only called, when the parser is in
+ // STATE_ACCEPTED state. After calling it, the parser is ready to parse
+ // another request.
+ scoped_ptr<HttpRequest> GetRequest();
+
+ private:
+ HttpMethod GetMethodType(const std::string& token) const;
+
+ // Parses headers and returns ACCEPTED if whole request was parsed. Otherwise
+ // returns WAITING.
+ ParseResult ParseHeaders();
+
+ // Parses request's content data and returns ACCEPTED if all of it have been
+ // processed. Chunked Transfer Encoding *is not* supported.
+ ParseResult ParseContent();
+
+ // Fetches the next line from the buffer. Result does not contain \r\n.
+ // Returns an empty string for an empty line. It will assert if there is
+ // no line available.
+ std::string ShiftLine();
+
+ scoped_ptr<HttpRequest> http_request_;
+ std::string buffer_;
+ size_t buffer_position_; // Current position in the internal buffer.
+ State state_;
+ // Content length of the request currently being parsed.
+ size_t declared_content_length_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpRequestParser);
+};
+
+} // namespace test_server
+} // namespace net
+
+#endif // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
diff --git a/chromium/net/test/embedded_test_server/http_request_unittest.cc b/chromium/net/test/embedded_test_server/http_request_unittest.cc
new file mode 100644
index 00000000000..b45742cf37b
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_request_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/http_request.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test_server {
+
+TEST(HttpRequestTest, ParseRequest) {
+ HttpRequestParser parser;
+
+ // Process request in chunks to check if the parser deals with border cases.
+ // Also, check multi-line headers as well as multiple requests in the same
+ // chunk. This basically should cover all the simplest border cases.
+ parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ parser.ProcessChunk("Host: localhost:1234\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ parser.ProcessChunk("Multi-line-header: abcd\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ parser.ProcessChunk(" efgh\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ parser.ProcessChunk(" ijkl\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ parser.ProcessChunk("Content-Length: 10\r\n\r\n");
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+ // Content data and another request in the same chunk (possible in http/1.1).
+ parser.ProcessChunk("1234567890GET /another.html HTTP/1.1\r\n\r\n");
+ ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());
+
+ // Fetch the first request and validate it.
+ {
+ scoped_ptr<HttpRequest> request = parser.GetRequest();
+ EXPECT_EQ("/foobar.html", request->relative_url);
+ EXPECT_EQ(METHOD_POST, request->method);
+ EXPECT_EQ("1234567890", request->content);
+ ASSERT_EQ(3u, request->headers.size());
+
+ EXPECT_EQ(1u, request->headers.count("Host"));
+ EXPECT_EQ(1u, request->headers.count("Multi-line-header"));
+ EXPECT_EQ(1u, request->headers.count("Content-Length"));
+
+ EXPECT_EQ("localhost:1234", request->headers["Host"]);
+ EXPECT_EQ("abcd efgh ijkl", request->headers["Multi-line-header"]);
+ EXPECT_EQ("10", request->headers["Content-Length"]);
+ }
+
+ // No other request available yet since we do not support multiple requests
+ // per connection.
+ EXPECT_EQ(HttpRequestParser::WAITING, parser.ParseRequest());
+}
+
+TEST(HttpRequestTest, ParseRequestWithEmptyBody) {
+ HttpRequestParser parser;
+
+ parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n");
+ parser.ProcessChunk("Content-Length: 0\r\n\r\n");
+ ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());
+
+ scoped_ptr<HttpRequest> request = parser.GetRequest();
+ EXPECT_EQ("", request->content);
+ EXPECT_TRUE(request->has_content);
+ EXPECT_EQ(1u, request->headers.count("Content-Length"));
+ EXPECT_EQ("0", request->headers["Content-Length"]);
+}
+
+TEST(HttpRequestTest, ParseRequestWithoutBody) {
+ HttpRequestParser parser;
+
+ parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n\r\n");
+ ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest());
+
+ scoped_ptr<HttpRequest> request = parser.GetRequest();
+ EXPECT_EQ("", request->content);
+ EXPECT_FALSE(request->has_content);
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/http_response.cc b/chromium/net/test/embedded_test_server/http_response.cc
new file mode 100644
index 00000000000..04155b5ffa5
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_response.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/http_response.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "net/http/http_status_code.h"
+
+namespace net {
+namespace test_server {
+
+HttpResponse::~HttpResponse() {
+}
+
+BasicHttpResponse::BasicHttpResponse() : code_(HTTP_OK) {
+}
+
+BasicHttpResponse::~BasicHttpResponse() {
+}
+
+std::string BasicHttpResponse::ToResponseString() const {
+ // Response line with headers.
+ std::string response_builder;
+
+ std::string http_reason_phrase(GetHttpReasonPhrase(code_));
+
+ // TODO(mtomasz): For http/1.0 requests, send http/1.0.
+ base::StringAppendF(&response_builder,
+ "HTTP/1.1 %d %s\r\n",
+ code_,
+ http_reason_phrase.c_str());
+ base::StringAppendF(&response_builder, "Connection: close\r\n");
+ base::StringAppendF(&response_builder,
+ "Content-Length: %" PRIuS "\r\n",
+ content_.size());
+ base::StringAppendF(&response_builder,
+ "Content-Type: %s\r\n",
+ content_type_.c_str());
+ for (size_t i = 0; i < custom_headers_.size(); ++i) {
+ const std::string& header_name = custom_headers_[i].first;
+ const std::string& header_value = custom_headers_[i].second;
+ DCHECK(header_value.find_first_of("\n\r") == std::string::npos) <<
+ "Malformed header value.";
+ base::StringAppendF(&response_builder,
+ "%s: %s\r\n",
+ header_name.c_str(),
+ header_value.c_str());
+ }
+ base::StringAppendF(&response_builder, "\r\n");
+
+ return response_builder + content_;
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/embedded_test_server/http_response.h b/chromium/net/test/embedded_test_server/http_response.h
new file mode 100644
index 00000000000..422a52553ea
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_response.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_RESPONSE_H_
+#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_RESPONSE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/http/http_status_code.h"
+
+namespace net {
+namespace test_server {
+
+// Interface for HTTP response implementations.
+class HttpResponse{
+ public:
+ virtual ~HttpResponse();
+
+ // Returns raw contents to be written to the network socket
+ // in response. If you intend to make this a valid HTTP response,
+ // it should start with "HTTP/x.x" line, followed by response headers.
+ virtual std::string ToResponseString() const = 0;
+};
+
+// This class is used to handle basic HTTP responses with commonly used
+// response headers such as "Content-Type".
+class BasicHttpResponse : public HttpResponse {
+ public:
+ BasicHttpResponse();
+ virtual ~BasicHttpResponse();
+
+ // The response code.
+ HttpStatusCode code() const { return code_; }
+ void set_code(HttpStatusCode code) { code_ = code; }
+
+ // The content of the response.
+ const std::string& content() const { return content_; }
+ void set_content(const std::string& content) { content_ = content; }
+
+ // The content type.
+ const std::string& content_type() const { return content_type_; }
+ void set_content_type(const std::string& content_type) {
+ content_type_ = content_type;
+ }
+
+ // Adds a custom header.
+ void AddCustomHeader(const std::string& key, const std::string& value) {
+ custom_headers_.push_back(std::make_pair(key, value));
+ }
+
+ // Generates and returns a http response string.
+ virtual std::string ToResponseString() const OVERRIDE;
+
+ private:
+ HttpStatusCode code_;
+ std::string content_;
+ std::string content_type_;
+ std::vector<std::pair<std::string, std::string> > custom_headers_;
+
+ DISALLOW_COPY_AND_ASSIGN(BasicHttpResponse);
+};
+
+} // namespace test_server
+} // namespace net
+
+#endif // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_RESPONSE_H_
diff --git a/chromium/net/test/embedded_test_server/http_response_unittest.cc b/chromium/net/test/embedded_test_server/http_response_unittest.cc
new file mode 100644
index 00000000000..83b767f5fa8
--- /dev/null
+++ b/chromium/net/test/embedded_test_server/http_response_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/embedded_test_server/http_response.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test_server {
+
+TEST(HttpResponseTest, GenerateResponse) {
+ BasicHttpResponse response;
+ response.set_code(HTTP_OK);
+ response.set_content("Sample content - Hello world!");
+ response.set_content_type("text/plain");
+ response.AddCustomHeader("Simple-Header", "Simple value.");
+
+ std::string kExpectedResponseString =
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: 29\r\n"
+ "Content-Type: text/plain\r\n"
+ "Simple-Header: Simple value.\r\n\r\n"
+ "Sample content - Hello world!";
+
+ EXPECT_EQ(kExpectedResponseString, response.ToResponseString());
+}
+
+} // namespace test_server
+} // namespace net
diff --git a/chromium/net/test/net_test_suite.cc b/chromium/net/test/net_test_suite.cc
new file mode 100644
index 00000000000..175cec29754
--- /dev/null
+++ b/chromium/net/test/net_test_suite.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/net_test_suite.h"
+
+#include "base/message_loop/message_loop.h"
+#include "net/base/network_change_notifier.h"
+#include "net/http/http_stream_factory.h"
+#include "net/spdy/spdy_session.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(USE_NSS) || defined(OS_IOS)
+#include "net/ocsp/nss_ocsp.h"
+#endif
+
+class StaticReset : public ::testing::EmptyTestEventListener {
+ virtual void OnTestStart(const ::testing::TestInfo& test_info) OVERRIDE {
+ net::HttpStreamFactory::ResetStaticSettingsToInit();
+ }
+};
+
+NetTestSuite::NetTestSuite(int argc, char** argv)
+ : TestSuite(argc, argv) {
+}
+
+NetTestSuite::NetTestSuite(int argc, char** argv,
+ bool create_at_exit_manager)
+ : TestSuite(argc, argv, create_at_exit_manager) {
+}
+
+NetTestSuite::~NetTestSuite() {}
+
+void NetTestSuite::Initialize() {
+ TestSuite::Initialize();
+ ::testing::UnitTest::GetInstance()->listeners().Append(new StaticReset());
+ InitializeTestThread();
+}
+
+void NetTestSuite::Shutdown() {
+#if defined(USE_NSS) || defined(OS_IOS)
+ net::ShutdownNSSHttpIO();
+#endif
+
+ // We want to destroy this here before the TestSuite continues to tear down
+ // the environment.
+ message_loop_.reset();
+
+ TestSuite::Shutdown();
+}
+
+void NetTestSuite::InitializeTestThread() {
+ network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
+
+ InitializeTestThreadNoNetworkChangeNotifier();
+}
+
+void NetTestSuite::InitializeTestThreadNoNetworkChangeNotifier() {
+ host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL);
+ scoped_host_resolver_proc_.Init(host_resolver_proc_.get());
+ // In case any attempts are made to resolve host names, force them all to
+ // be mapped to localhost. This prevents DNS queries from being sent in
+ // the process of running these unit tests.
+ host_resolver_proc_->AddRule("*", "127.0.0.1");
+
+ message_loop_.reset(new base::MessageLoopForIO());
+}
diff --git a/chromium/net/test/net_test_suite.h b/chromium/net/test/net_test_suite.h
new file mode 100644
index 00000000000..c8479d724ed
--- /dev/null
+++ b/chromium/net/test/net_test_suite.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_TEST_NET_TEST_SUITE_H_
+#define NET_TEST_NET_TEST_SUITE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace net {
+class NetworkChangeNotifier;
+}
+
+class NetTestSuite : public base::TestSuite {
+ public:
+ NetTestSuite(int argc, char** argv);
+ virtual ~NetTestSuite();
+
+ virtual void Initialize() OVERRIDE;
+
+ virtual void Shutdown() OVERRIDE;
+
+ protected:
+ // This constructor is only accessible to specialized net test
+ // implementations which need to control the creation of an AtExitManager
+ // instance for the duration of the test.
+ NetTestSuite(int argc, char** argv, bool create_at_exit_manager);
+
+ // Called from within Initialize(), but separate so that derived classes
+ // can initialize the NetTestSuite instance only and not
+ // TestSuite::Initialize(). TestSuite::Initialize() performs some global
+ // initialization that can only be done once.
+ void InitializeTestThread();
+
+ // Same as above, except it does not create a mock
+ // NetworkChangeNotifier. Use this if your test needs to create and
+ // manage its own mock NetworkChangeNotifier, or if your test uses
+ // the production NetworkChangeNotifier.
+ void InitializeTestThreadNoNetworkChangeNotifier();
+
+ private:
+ scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_;
+ net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
+};
+
+#endif // NET_TEST_NET_TEST_SUITE_H_
diff --git a/chromium/net/test/openssl_helper.cc b/chromium/net/test/openssl_helper.cc
new file mode 100644
index 00000000000..25989cb6016
--- /dev/null
+++ b/chromium/net/test/openssl_helper.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2010 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.
+
+// This helper binary is only used for testing Chrome's SSL stack.
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+static const char kDefaultPEMFile[] = "net/data/ssl/certificates/ok_cert.pem";
+
+// Server Name Indication callback from OpenSSL
+static int sni_cb(SSL *s, int *ad, void *arg) {
+ const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+ if (servername && strcmp(servername, "test.example.com") == 0)
+ *reinterpret_cast<bool*>(arg) = true;
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+// Client certificate verification callback from OpenSSL
+static int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
+ return 1;
+}
+
+// Next Protocol Negotiation callback from OpenSSL
+static int next_proto_cb(SSL *ssl, const unsigned char **out,
+ unsigned int *outlen, void *arg) {
+ bool* npn_mispredict = reinterpret_cast<bool*>(arg);
+ static char kProtos[] = "\003foo\003bar";
+ static char kProtos2[] = "\003baz\003boo";
+ static unsigned count = 0;
+
+ if (!*npn_mispredict || count == 0) {
+ *out = (const unsigned char*) kProtos;
+ *outlen = sizeof(kProtos) - 1;
+ } else {
+ *out = (const unsigned char*) kProtos2;
+ *outlen = sizeof(kProtos2) - 1;
+ }
+ count++;
+ return SSL_TLSEXT_ERR_OK;
+}
+
+int
+main(int argc, char **argv) {
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+
+ bool sni = false, sni_good = false, snap_start = false;
+ bool snap_start_recovery = false, sslv3 = false, session_tickets = false;
+ bool fail_resume = false, client_cert = false, npn = false;
+ bool npn_mispredict = false;
+
+ const char* key_file = kDefaultPEMFile;
+ const char* cert_file = kDefaultPEMFile;
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "sni") == 0) {
+ // Require SNI
+ sni = true;
+ } else if (strcmp(argv[i], "snap-start") == 0) {
+ // Support Snap Start
+ snap_start = true;
+ } else if (strcmp(argv[i], "snap-start-recovery") == 0) {
+ // Support Snap Start, but always trigger a recovery
+ snap_start = true;
+ snap_start_recovery = true;
+ } else if (strcmp(argv[i], "sslv3") == 0) {
+ // Use SSLv3
+ sslv3 = true;
+ } else if (strcmp(argv[i], "session-tickets") == 0) {
+ // Enable Session Tickets
+ session_tickets = true;
+ } else if (strcmp(argv[i], "fail-resume") == 0) {
+ // Always fail to resume sessions
+ fail_resume = true;
+ } else if (strcmp(argv[i], "client-cert") == 0) {
+ // Request a client certificate
+ client_cert = true;
+ } else if (strcmp(argv[i], "npn") == 0) {
+ // Advertise NPN
+ npn = true;
+ } else if (strcmp(argv[i], "npn-mispredict") == 0) {
+ // Advertise NPN
+ npn = true;
+ npn_mispredict = true;
+ } else if (strcmp(argv[i], "--key-file") == 0) {
+ // Use alternative key file
+ i++;
+ if (i == argc) {
+ fprintf(stderr, "Missing argument to --key-file\n");
+ return 1;
+ }
+ key_file = argv[i];
+ } else if (strcmp(argv[i], "--cert-file") == 0) {
+ // Use alternative certificate file
+ i++;
+ if (i == argc) {
+ fprintf(stderr, "Missing argument to --cert-file\n");
+ return 1;
+ }
+ cert_file = argv[i];
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", argv[i]);
+ return 1;
+ }
+ }
+
+ SSL_CTX* ctx;
+
+ if (sslv3) {
+ ctx = SSL_CTX_new(SSLv3_server_method());
+ } else {
+ ctx = SSL_CTX_new(TLSv1_server_method());
+ }
+
+ if (sni) {
+ SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb);
+ SSL_CTX_set_tlsext_servername_arg(ctx, &sni_good);
+ }
+
+ BIO* key = BIO_new(BIO_s_file());
+ if (BIO_read_filename(key, key_file) <= 0) {
+ fprintf(stderr, "Failed to read %s\n", key_file);
+ return 1;
+ }
+
+ EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
+ if (!pkey) {
+ fprintf(stderr, "Failed to parse %s\n", key_file);
+ return 1;
+ }
+ BIO_free(key);
+
+
+ BIO* cert = BIO_new(BIO_s_file());
+ if (BIO_read_filename(cert, cert_file) <= 0) {
+ fprintf(stderr, "Failed to read %s\n", cert_file);
+ return 1;
+ }
+
+ X509 *pcert = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
+ if (!pcert) {
+ fprintf(stderr, "Failed to parse %s\n", cert_file);
+ return 1;
+ }
+ BIO_free(cert);
+
+ if (SSL_CTX_use_certificate(ctx, pcert) <= 0) {
+ fprintf(stderr, "Failed to load %s\n", cert_file);
+ return 1;
+ }
+
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) {
+ fprintf(stderr, "Failed to load %s\n", key_file);
+ return 1;
+ }
+
+ if (!SSL_CTX_check_private_key(ctx)) {
+ fprintf(stderr, "Public and private keys don't match\n");
+ return 1;
+ }
+
+ if (client_cert)
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
+
+ if (session_tickets)
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
+
+ if (snap_start) {
+ static const unsigned char orbit[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ SSL_CTX_set_snap_start_orbit(ctx, orbit);
+ }
+
+ if (npn)
+ SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &npn_mispredict);
+
+ unsigned connection_limit = 1;
+ if (snap_start || session_tickets)
+ connection_limit = 2;
+ if (npn_mispredict)
+ connection_limit = 3;
+
+ for (unsigned connections = 0; connections < connection_limit;
+ connections++) {
+ const int fd = accept(3, NULL, NULL);
+
+ SSL* server = SSL_new(ctx);
+ BIO* bio = BIO_new_socket(fd, 1 /* take ownership of fd */);
+ SSL_set_bio(server, bio, bio);
+
+ if (fail_resume) {
+ SSL_set_session_id_context(server, (unsigned char*) &connections,
+ sizeof(connections));
+ }
+
+ int err;
+ for (;;) {
+ const int ret = SSL_accept(server);
+ if (ret == 1)
+ break;
+
+ err = SSL_get_error(server, ret);
+ if (err == SSL_ERROR_WANT_READ)
+ continue;
+ if (err == SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING && snap_start) {
+ SSL_set_suggested_server_random_validity(
+ server, !snap_start_recovery);
+ continue;
+ }
+ ERR_print_errors_fp(stderr);
+ fprintf(stderr, "SSL_accept failed: %d\n", err);
+ return 1;
+ }
+
+ if (sni && !sni_good) {
+ fprintf(stderr, "SNI failed\n");
+ return 1;
+ }
+
+ if (npn) {
+ const unsigned char *data, *expected_data;
+ unsigned len, expected_len;
+ SSL_get0_next_proto_negotiated(server, &data, &len);
+ if (!npn_mispredict || connections == 0) {
+ expected_data = (unsigned char*) "foo";
+ expected_len = 3;
+ } else {
+ expected_data = (unsigned char*) "baz";
+ expected_len = 3;
+ }
+ if (len != expected_len || memcmp(data, expected_data, len) != 0) {
+ fprintf(stderr, "Bad NPN: %d\n", len);
+ return 1;
+ }
+ }
+
+ unsigned char buffer[6];
+
+ int ret = SSL_read(server, buffer, sizeof(buffer));
+ if (ret == -1) {
+ err = SSL_get_error(server, ret);
+ ERR_print_errors_fp(stderr);
+ fprintf(stderr, "SSL_read failed: %d\n", err);
+ }
+ if (memcmp(buffer, "hello!", sizeof(buffer)) == 0) {
+ SSL_write(server, "goodbye!", 8);
+ }
+
+ SSL_shutdown(server);
+ SSL_shutdown(server);
+ }
+
+ SSL_CTX_free(ctx);
+
+ return 0;
+}
diff --git a/chromium/net/test/python_utils.cc b/chromium/net/test/python_utils.cc
new file mode 100644
index 00000000000..30c5f679a8a
--- /dev/null
+++ b/chromium/net/test/python_utils.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2011 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.
+
+#include "net/test/python_utils.h"
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+
+const char kPythonPathEnv[] = "PYTHONPATH";
+
+void AppendToPythonPath(const base::FilePath& dir) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string old_path;
+ std::string dir_path;
+#if defined(OS_WIN)
+ dir_path = WideToUTF8(dir.value());
+#elif defined(OS_POSIX)
+ dir_path = dir.value();
+#endif
+ if (!env->GetVar(kPythonPathEnv, &old_path)) {
+ env->SetVar(kPythonPathEnv, dir_path.c_str());
+ } else if (old_path.find(dir_path) == std::string::npos) {
+ std::string new_path(old_path);
+#if defined(OS_WIN)
+ new_path.append(";");
+#elif defined(OS_POSIX)
+ new_path.append(":");
+#endif
+ new_path.append(dir_path.c_str());
+ env->SetVar(kPythonPathEnv, new_path);
+ }
+}
+
+namespace {
+
+// Search for |to_try|, rolling up the directory tree from
+// |start_dir|. If found, return true and put the path to |to_try| in
+// |out_dir|. If not, return false and leave |out_dir| untouched.
+bool TryRelativeToDir(const base::FilePath& start_dir,
+ const base::FilePath& to_try,
+ base::FilePath* out_dir) {
+ base::FilePath dir(start_dir);
+ while (!base::DirectoryExists(dir.Append(to_try))) {
+ base::FilePath parent = dir.DirName();
+ if (parent == dir) {
+ // We hit the root directory.
+ return false;
+ }
+ dir = parent;
+ }
+ *out_dir = dir;
+ return true;
+}
+
+} // namespace
+
+bool GetPyProtoPath(base::FilePath* dir) {
+ // Locate the Python code generated by the protocol buffers compiler.
+ base::FilePath generated_code_dir;
+ if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
+ LOG(ERROR) << "Can't find " << generated_code_dir.value();
+ return false;
+ }
+
+ const base::FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+ base::FilePath source_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) {
+ LOG(ERROR) << "Can't find " << source_dir.value();
+ return false;
+ }
+ // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep
+ // into the Release/ (or Debug/) directory and we can't depend on
+ // how far down it goes. So we walk upwards from DIR_EXE until we
+ // find a likely looking spot.
+ if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
+ LOG(WARNING) << "Can't find " << kPyProto.value()
+ << " next to " << generated_code_dir.value();
+ // On Chrome OS, we may have installed the test binaries and support tools
+ // in a wholly separate location, relative to DIR_SOURCE_ROOT. We'll want
+ // to do a similar investigation from that point as well.
+ generated_code_dir = source_dir
+ .Append(FILE_PATH_LITERAL("out"))
+ .Append(FILE_PATH_LITERAL("Release"));
+ if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
+ LOG(WARNING) << "Can't find " << kPyProto.value()
+ << " next to " << generated_code_dir.value();
+ return false;
+ }
+ }
+ generated_code_dir = *dir;
+#endif
+ *dir = generated_code_dir.Append(kPyProto);
+ VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value();
+ return true;
+}
+
+bool GetPythonCommand(CommandLine* python_cmd) {
+ DCHECK(python_cmd);
+ base::FilePath dir;
+#if defined(OS_WIN)
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &dir))
+ return false;
+ dir = dir.Append(FILE_PATH_LITERAL("third_party"))
+ .Append(FILE_PATH_LITERAL("python_26"))
+ .Append(FILE_PATH_LITERAL("python.exe"));
+#elif defined(OS_POSIX)
+ dir = base::FilePath("python");
+#endif
+
+ python_cmd->SetProgram(dir);
+
+ // Launch python in unbuffered mode, so that python output doesn't mix with
+ // gtest output in buildbot log files. See http://crbug.com/147368.
+ python_cmd->AppendArg("-u");
+
+ return true;
+}
diff --git a/chromium/net/test/python_utils.h b/chromium/net/test/python_utils.h
new file mode 100644
index 00000000000..30776456503
--- /dev/null
+++ b/chromium/net/test/python_utils.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 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.
+
+#ifndef NET_TEST_PYTHON_UTILS_H_
+#define NET_TEST_PYTHON_UTILS_H_
+
+#include "base/compiler_specific.h"
+
+class CommandLine;
+
+namespace base {
+class FilePath;
+}
+
+// This is the python path variable name.
+extern const char kPythonPathEnv[];
+
+// Appends the dir to python path environment variable.
+void AppendToPythonPath(const base::FilePath& dir);
+
+// Return the location of the compiler-generated python protobuf.
+bool GetPyProtoPath(base::FilePath* dir);
+
+// Returns the command that should be used to launch Python.
+bool GetPythonCommand(CommandLine* python_cmd) WARN_UNUSED_RESULT;
+
+#endif // NET_TEST_PYTHON_UTILS_H_
diff --git a/chromium/net/test/python_utils_unittest.cc b/chromium/net/test/python_utils_unittest.cc
new file mode 100644
index 00000000000..04f11ec266d
--- /dev/null
+++ b/chromium/net/test/python_utils_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 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.
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/test/python_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(PythonUtils, Append) {
+ const base::FilePath::CharType kAppendDir1[] =
+ FILE_PATH_LITERAL("test/path_append1");
+ const base::FilePath::CharType kAppendDir2[] =
+ FILE_PATH_LITERAL("test/path_append2");
+
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+
+ std::string python_path;
+ base::FilePath append_path1(kAppendDir1);
+ base::FilePath append_path2(kAppendDir2);
+
+ // Get a clean start
+ env->UnSetVar(kPythonPathEnv);
+
+ // Append the path
+ AppendToPythonPath(append_path1);
+ env->GetVar(kPythonPathEnv, &python_path);
+ ASSERT_EQ(python_path, "test/path_append1");
+
+ // Append the safe path again, nothing changes
+ AppendToPythonPath(append_path2);
+ env->GetVar(kPythonPathEnv, &python_path);
+#if defined(OS_WIN)
+ ASSERT_EQ(std::string("test/path_append1;test/path_append2"), python_path);
+#elif defined(OS_POSIX)
+ ASSERT_EQ(std::string("test/path_append1:test/path_append2"), python_path);
+#endif
+}
+
+TEST(PythonUtils, PythonRunTime) {
+ CommandLine cmd_line(CommandLine::NO_PROGRAM);
+ EXPECT_TRUE(GetPythonCommand(&cmd_line));
+
+ // Run a python command to print a string and make sure the output is what
+ // we want.
+ cmd_line.AppendArg("-c");
+ std::string input("PythonUtilsTest");
+ std::string python_cmd = base::StringPrintf("print '%s';", input.c_str());
+ cmd_line.AppendArg(python_cmd);
+ std::string output;
+ EXPECT_TRUE(base::GetAppOutput(cmd_line, &output));
+ TrimWhitespace(output, TRIM_TRAILING, &output);
+ EXPECT_EQ(input, output);
+}
diff --git a/chromium/net/test/run_all_unittests.cc b/chromium/net/test/run_all_unittests.cc
new file mode 100644
index 00000000000..d8392ff0e2a
--- /dev/null
+++ b/chromium/net/test/run_all_unittests.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 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.
+
+#include "base/metrics/statistics_recorder.h"
+#include "build/build_config.h"
+#include "crypto/nss_util.h"
+#include "net/socket/client_socket_pool_base.h"
+#include "net/socket/ssl_server_socket.h"
+#include "net/spdy/spdy_session.h"
+#include "net/test/net_test_suite.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "net/android/net_jni_registrar.h"
+#endif
+
+#if !defined(OS_IOS)
+#include "net/proxy/proxy_resolver_v8.h"
+#endif
+
+using net::internal::ClientSocketPoolBaseHelper;
+using net::SpdySession;
+
+int main(int argc, char** argv) {
+ // Record histograms, so we can get histograms data in tests.
+ base::StatisticsRecorder::Initialize();
+
+#if defined(OS_ANDROID)
+ // Register JNI bindings for android. Doing it early as the test suite setup
+ // may initiate a call to Java.
+ net::android::RegisterJni(base::android::AttachCurrentThread());
+#endif
+
+ NetTestSuite test_suite(argc, argv);
+ ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(false);
+
+#if defined(OS_WIN)
+ // We want to be sure to init NSPR on the main thread.
+ crypto::EnsureNSPRInit();
+#endif
+
+ // Enable support for SSL server sockets, which must be done while
+ // single-threaded.
+ net::EnableSSLServerSockets();
+
+#if !defined(OS_IOS)
+ // This has to be done on the main thread.
+ net::ProxyResolverV8::RememberDefaultIsolate();
+#endif
+
+ return test_suite.Run();
+}
diff --git a/chromium/net/test/spawned_test_server/base_test_server.cc b/chromium/net/test/spawned_test_server/base_test_server.cc
new file mode 100644
index 00000000000..c13745bf51e
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/base_test_server.cc
@@ -0,0 +1,407 @@
+// Copyright 2013 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.
+
+#include "net/test/spawned_test_server/base_test_server.h"
+
+#include <string>
+#include <vector>
+
+#include "base/base64.h"
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "net/base/address_list.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/base/net_util.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/test_root_certs.h"
+#include "net/dns/host_resolver.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+std::string GetHostname(BaseTestServer::Type type,
+ const BaseTestServer::SSLOptions& options) {
+ if (BaseTestServer::UsingSSL(type) &&
+ options.server_certificate ==
+ BaseTestServer::SSLOptions::CERT_MISMATCHED_NAME) {
+ // Return a different hostname string that resolves to the same hostname.
+ return "localhost";
+ }
+
+ // Use the 127.0.0.1 as default.
+ return BaseTestServer::kLocalhost;
+}
+
+void GetCiphersList(int cipher, base::ListValue* values) {
+ if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_RC4)
+ values->Append(new base::StringValue("rc4"));
+ if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_AES128)
+ values->Append(new base::StringValue("aes128"));
+ if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_AES256)
+ values->Append(new base::StringValue("aes256"));
+ if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_3DES)
+ values->Append(new base::StringValue("3des"));
+}
+
+} // namespace
+
+BaseTestServer::SSLOptions::SSLOptions()
+ : server_certificate(CERT_OK),
+ ocsp_status(OCSP_OK),
+ cert_serial(0),
+ request_client_certificate(false),
+ bulk_ciphers(SSLOptions::BULK_CIPHER_ANY),
+ record_resume(false),
+ tls_intolerant(TLS_INTOLERANT_NONE) {}
+
+BaseTestServer::SSLOptions::SSLOptions(
+ BaseTestServer::SSLOptions::ServerCertificate cert)
+ : server_certificate(cert),
+ ocsp_status(OCSP_OK),
+ cert_serial(0),
+ request_client_certificate(false),
+ bulk_ciphers(SSLOptions::BULK_CIPHER_ANY),
+ record_resume(false),
+ tls_intolerant(TLS_INTOLERANT_NONE) {}
+
+BaseTestServer::SSLOptions::~SSLOptions() {}
+
+base::FilePath BaseTestServer::SSLOptions::GetCertificateFile() const {
+ switch (server_certificate) {
+ case CERT_OK:
+ case CERT_MISMATCHED_NAME:
+ return base::FilePath(FILE_PATH_LITERAL("ok_cert.pem"));
+ case CERT_EXPIRED:
+ return base::FilePath(FILE_PATH_LITERAL("expired_cert.pem"));
+ case CERT_CHAIN_WRONG_ROOT:
+ // This chain uses its own dedicated test root certificate to avoid
+ // side-effects that may affect testing.
+ return base::FilePath(FILE_PATH_LITERAL("redundant-server-chain.pem"));
+ case CERT_AUTO:
+ return base::FilePath();
+ default:
+ NOTREACHED();
+ }
+ return base::FilePath();
+}
+
+std::string BaseTestServer::SSLOptions::GetOCSPArgument() const {
+ if (server_certificate != CERT_AUTO)
+ return std::string();
+
+ switch (ocsp_status) {
+ case OCSP_OK:
+ return "ok";
+ case OCSP_REVOKED:
+ return "revoked";
+ case OCSP_INVALID:
+ return "invalid";
+ case OCSP_UNAUTHORIZED:
+ return "unauthorized";
+ case OCSP_UNKNOWN:
+ return "unknown";
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+}
+
+const char BaseTestServer::kLocalhost[] = "127.0.0.1";
+
+BaseTestServer::BaseTestServer(Type type, const std::string& host)
+ : type_(type),
+ started_(false),
+ log_to_console_(false) {
+ Init(host);
+}
+
+BaseTestServer::BaseTestServer(Type type, const SSLOptions& ssl_options)
+ : ssl_options_(ssl_options),
+ type_(type),
+ started_(false),
+ log_to_console_(false) {
+ DCHECK(UsingSSL(type));
+ Init(GetHostname(type, ssl_options));
+}
+
+BaseTestServer::~BaseTestServer() {}
+
+const HostPortPair& BaseTestServer::host_port_pair() const {
+ DCHECK(started_);
+ return host_port_pair_;
+}
+
+const base::DictionaryValue& BaseTestServer::server_data() const {
+ DCHECK(started_);
+ DCHECK(server_data_.get());
+ return *server_data_;
+}
+
+std::string BaseTestServer::GetScheme() const {
+ switch (type_) {
+ case TYPE_FTP:
+ return "ftp";
+ case TYPE_HTTP:
+ return "http";
+ case TYPE_HTTPS:
+ return "https";
+ case TYPE_WS:
+ return "ws";
+ case TYPE_WSS:
+ return "wss";
+ case TYPE_TCP_ECHO:
+ case TYPE_UDP_ECHO:
+ default:
+ NOTREACHED();
+ }
+ return std::string();
+}
+
+bool BaseTestServer::GetAddressList(AddressList* address_list) const {
+ DCHECK(address_list);
+
+ scoped_ptr<HostResolver> resolver(HostResolver::CreateDefaultResolver(NULL));
+ HostResolver::RequestInfo info(host_port_pair_);
+ TestCompletionCallback callback;
+ int rv = resolver->Resolve(info, address_list, callback.callback(), NULL,
+ BoundNetLog());
+ if (rv == ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ if (rv != net::OK) {
+ LOG(ERROR) << "Failed to resolve hostname: " << host_port_pair_.host();
+ return false;
+ }
+ return true;
+}
+
+uint16 BaseTestServer::GetPort() {
+ return host_port_pair_.port();
+}
+
+void BaseTestServer::SetPort(uint16 port) {
+ host_port_pair_.set_port(port);
+}
+
+GURL BaseTestServer::GetURL(const std::string& path) const {
+ return GURL(GetScheme() + "://" + host_port_pair_.ToString() + "/" + path);
+}
+
+GURL BaseTestServer::GetURLWithUser(const std::string& path,
+ const std::string& user) const {
+ return GURL(GetScheme() + "://" + user + "@" + host_port_pair_.ToString() +
+ "/" + path);
+}
+
+GURL BaseTestServer::GetURLWithUserAndPassword(const std::string& path,
+ const std::string& user,
+ const std::string& password) const {
+ return GURL(GetScheme() + "://" + user + ":" + password + "@" +
+ host_port_pair_.ToString() + "/" + path);
+}
+
+// static
+bool BaseTestServer::GetFilePathWithReplacements(
+ const std::string& original_file_path,
+ const std::vector<StringPair>& text_to_replace,
+ std::string* replacement_path) {
+ std::string new_file_path = original_file_path;
+ bool first_query_parameter = true;
+ const std::vector<StringPair>::const_iterator end = text_to_replace.end();
+ for (std::vector<StringPair>::const_iterator it = text_to_replace.begin();
+ it != end;
+ ++it) {
+ const std::string& old_text = it->first;
+ const std::string& new_text = it->second;
+ std::string base64_old;
+ std::string base64_new;
+ if (!base::Base64Encode(old_text, &base64_old))
+ return false;
+ if (!base::Base64Encode(new_text, &base64_new))
+ return false;
+ if (first_query_parameter) {
+ new_file_path += "?";
+ first_query_parameter = false;
+ } else {
+ new_file_path += "&";
+ }
+ new_file_path += "replace_text=";
+ new_file_path += base64_old;
+ new_file_path += ":";
+ new_file_path += base64_new;
+ }
+
+ *replacement_path = new_file_path;
+ return true;
+}
+
+void BaseTestServer::Init(const std::string& host) {
+ host_port_pair_ = HostPortPair(host, 0);
+
+ // TODO(battre) Remove this after figuring out why the TestServer is flaky.
+ // http://crbug.com/96594
+ log_to_console_ = true;
+}
+
+void BaseTestServer::SetResourcePath(const base::FilePath& document_root,
+ const base::FilePath& certificates_dir) {
+ // This method shouldn't get called twice.
+ DCHECK(certificates_dir_.empty());
+ document_root_ = document_root;
+ certificates_dir_ = certificates_dir;
+ DCHECK(!certificates_dir_.empty());
+}
+
+bool BaseTestServer::ParseServerData(const std::string& server_data) {
+ VLOG(1) << "Server data: " << server_data;
+ base::JSONReader json_reader;
+ scoped_ptr<base::Value> value(json_reader.ReadToValue(server_data));
+ if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY)) {
+ LOG(ERROR) << "Could not parse server data: "
+ << json_reader.GetErrorMessage();
+ return false;
+ }
+
+ server_data_.reset(static_cast<base::DictionaryValue*>(value.release()));
+ int port = 0;
+ if (!server_data_->GetInteger("port", &port)) {
+ LOG(ERROR) << "Could not find port value";
+ return false;
+ }
+ if ((port <= 0) || (port > kuint16max)) {
+ LOG(ERROR) << "Invalid port value: " << port;
+ return false;
+ }
+ host_port_pair_.set_port(port);
+
+ return true;
+}
+
+bool BaseTestServer::LoadTestRootCert() const {
+ TestRootCerts* root_certs = TestRootCerts::GetInstance();
+ if (!root_certs)
+ return false;
+
+ // Should always use absolute path to load the root certificate.
+ base::FilePath root_certificate_path = certificates_dir_;
+ if (!certificates_dir_.IsAbsolute()) {
+ base::FilePath src_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir))
+ return false;
+ root_certificate_path = src_dir.Append(certificates_dir_);
+ }
+
+ return root_certs->AddFromFile(
+ root_certificate_path.AppendASCII("root_ca_cert.pem"));
+}
+
+bool BaseTestServer::SetupWhenServerStarted() {
+ DCHECK(host_port_pair_.port());
+
+ if (UsingSSL(type_) && !LoadTestRootCert())
+ return false;
+
+ started_ = true;
+ allowed_port_.reset(new ScopedPortException(host_port_pair_.port()));
+ return true;
+}
+
+void BaseTestServer::CleanUpWhenStoppingServer() {
+ TestRootCerts* root_certs = TestRootCerts::GetInstance();
+ root_certs->Clear();
+
+ host_port_pair_.set_port(0);
+ allowed_port_.reset();
+ started_ = false;
+}
+
+// Generates a dictionary of arguments to pass to the Python test server via
+// the test server spawner, in the form of
+// { argument-name: argument-value, ... }
+// Returns false if an invalid configuration is specified.
+bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
+ DCHECK(arguments);
+
+ arguments->SetString("host", host_port_pair_.host());
+ arguments->SetInteger("port", host_port_pair_.port());
+ arguments->SetString("data-dir", document_root_.value());
+
+ if (VLOG_IS_ON(1) || log_to_console_)
+ arguments->Set("log-to-console", base::Value::CreateNullValue());
+
+ if (UsingSSL(type_)) {
+ // Check the certificate arguments of the HTTPS server.
+ base::FilePath certificate_path(certificates_dir_);
+ base::FilePath certificate_file(ssl_options_.GetCertificateFile());
+ if (!certificate_file.value().empty()) {
+ certificate_path = certificate_path.Append(certificate_file);
+ if (certificate_path.IsAbsolute() &&
+ !base::PathExists(certificate_path)) {
+ LOG(ERROR) << "Certificate path " << certificate_path.value()
+ << " doesn't exist. Can't launch https server.";
+ return false;
+ }
+ arguments->SetString("cert-and-key-file", certificate_path.value());
+ }
+
+ // Check the client certificate related arguments.
+ if (ssl_options_.request_client_certificate)
+ arguments->Set("ssl-client-auth", base::Value::CreateNullValue());
+ scoped_ptr<base::ListValue> ssl_client_certs(new base::ListValue());
+
+ std::vector<base::FilePath>::const_iterator it;
+ for (it = ssl_options_.client_authorities.begin();
+ it != ssl_options_.client_authorities.end(); ++it) {
+ if (it->IsAbsolute() && !base::PathExists(*it)) {
+ LOG(ERROR) << "Client authority path " << it->value()
+ << " doesn't exist. Can't launch https server.";
+ return false;
+ }
+ ssl_client_certs->Append(new base::StringValue(it->value()));
+ }
+
+ if (ssl_client_certs->GetSize())
+ arguments->Set("ssl-client-ca", ssl_client_certs.release());
+ }
+
+ if (type_ == TYPE_HTTPS) {
+ arguments->Set("https", base::Value::CreateNullValue());
+
+ std::string ocsp_arg = ssl_options_.GetOCSPArgument();
+ if (!ocsp_arg.empty())
+ arguments->SetString("ocsp", ocsp_arg);
+
+ if (ssl_options_.cert_serial != 0) {
+ arguments->Set("cert-serial",
+ base::Value::CreateIntegerValue(ssl_options_.cert_serial));
+ }
+
+ // Check bulk cipher argument.
+ scoped_ptr<base::ListValue> bulk_cipher_values(new base::ListValue());
+ GetCiphersList(ssl_options_.bulk_ciphers, bulk_cipher_values.get());
+ if (bulk_cipher_values->GetSize())
+ arguments->Set("ssl-bulk-cipher", bulk_cipher_values.release());
+ if (ssl_options_.record_resume)
+ arguments->Set("https-record-resume", base::Value::CreateNullValue());
+ if (ssl_options_.tls_intolerant != SSLOptions::TLS_INTOLERANT_NONE) {
+ arguments->Set("tls-intolerant",
+ new base::FundamentalValue(ssl_options_.tls_intolerant));
+ }
+ }
+
+ return GenerateAdditionalArguments(arguments);
+}
+
+bool BaseTestServer::GenerateAdditionalArguments(
+ base::DictionaryValue* arguments) const {
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/test/spawned_test_server/base_test_server.h b/chromium/net/test/spawned_test_server/base_test_server.h
new file mode 100644
index 00000000000..ff395c56f8b
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/base_test_server.h
@@ -0,0 +1,263 @@
+// Copyright 2013 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.
+
+#ifndef NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/host_port_pair.h"
+
+class GURL;
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace net {
+
+class AddressList;
+class ScopedPortException;
+
+// The base class of Test server implementation.
+class BaseTestServer {
+ public:
+ typedef std::pair<std::string, std::string> StringPair;
+
+ // Following types represent protocol schemes. See also
+ // http://www.iana.org/assignments/uri-schemes.html
+ enum Type {
+ TYPE_BASIC_AUTH_PROXY,
+ TYPE_FTP,
+ TYPE_HTTP,
+ TYPE_HTTPS,
+ TYPE_WS,
+ TYPE_WSS,
+ TYPE_TCP_ECHO,
+ TYPE_UDP_ECHO,
+ };
+
+ // Container for various options to control how the HTTPS or WSS server is
+ // initialized.
+ struct SSLOptions {
+ enum ServerCertificate {
+ CERT_OK,
+
+ // CERT_AUTO causes the testserver to generate a test certificate issued
+ // by "Testing CA" (see net/data/ssl/certificates/ocsp-test-root.pem).
+ CERT_AUTO,
+
+ CERT_MISMATCHED_NAME,
+ CERT_EXPIRED,
+ // Cross-signed certificate to test PKIX path building. Contains an
+ // intermediate cross-signed by an unknown root, while the client (via
+ // TestRootStore) is expected to have a self-signed version of the
+ // intermediate.
+ CERT_CHAIN_WRONG_ROOT,
+ };
+
+ // OCSPStatus enumerates the types of OCSP response that the testserver
+ // can produce.
+ enum OCSPStatus {
+ OCSP_OK,
+ OCSP_REVOKED,
+ OCSP_INVALID,
+ OCSP_UNAUTHORIZED,
+ OCSP_UNKNOWN,
+ };
+
+ // Bitmask of bulk encryption algorithms that the test server supports
+ // and that can be selectively enabled or disabled.
+ enum BulkCipher {
+ // Special value used to indicate that any algorithm the server supports
+ // is acceptable. Preferred over explicitly OR-ing all ciphers.
+ BULK_CIPHER_ANY = 0,
+
+ BULK_CIPHER_RC4 = (1 << 0),
+ BULK_CIPHER_AES128 = (1 << 1),
+ BULK_CIPHER_AES256 = (1 << 2),
+
+ // NOTE: 3DES support in the Python test server has external
+ // dependencies and not be available on all machines. Clients may not
+ // be able to connect if only 3DES is specified.
+ BULK_CIPHER_3DES = (1 << 3),
+ };
+
+ // NOTE: the values of these enumerators are passed to the the Python test
+ // server. Do not change them.
+ enum TLSIntolerantLevel {
+ TLS_INTOLERANT_NONE = 0,
+ TLS_INTOLERANT_ALL = 1, // Intolerant of all TLS versions.
+ TLS_INTOLERANT_TLS1_1 = 2, // Intolerant of TLS 1.1 or higher.
+ TLS_INTOLERANT_TLS1_2 = 3, // Intolerant of TLS 1.2 or higher.
+ };
+
+ // Initialize a new SSLOptions using CERT_OK as the certificate.
+ SSLOptions();
+
+ // Initialize a new SSLOptions that will use the specified certificate.
+ explicit SSLOptions(ServerCertificate cert);
+ ~SSLOptions();
+
+ // Returns the relative filename of the file that contains the
+ // |server_certificate|.
+ base::FilePath GetCertificateFile() const;
+
+ // GetOCSPArgument returns the value of any OCSP argument to testserver or
+ // the empty string if there is none.
+ std::string GetOCSPArgument() const;
+
+ // The certificate to use when serving requests.
+ ServerCertificate server_certificate;
+
+ // If |server_certificate==CERT_AUTO| then this determines the type of OCSP
+ // response returned.
+ OCSPStatus ocsp_status;
+
+ // If not zero, |cert_serial| will be the serial number of the
+ // auto-generated leaf certificate when |server_certificate==CERT_AUTO|.
+ uint64 cert_serial;
+
+ // True if a CertificateRequest should be sent to the client during
+ // handshaking.
+ bool request_client_certificate;
+
+ // If |request_client_certificate| is true, an optional list of files,
+ // each containing a single, PEM-encoded X.509 certificates. The subject
+ // from each certificate will be added to the certificate_authorities
+ // field of the CertificateRequest.
+ std::vector<base::FilePath> client_authorities;
+
+ // A bitwise-OR of BulkCipher that should be used by the
+ // HTTPS server, or BULK_CIPHER_ANY to indicate that all implemented
+ // ciphers are acceptable.
+ int bulk_ciphers;
+
+ // If true, pass the --https-record-resume argument to testserver.py which
+ // causes it to log session cache actions and echo the log on
+ // /ssl-session-cache.
+ bool record_resume;
+
+ // If not TLS_INTOLERANT_NONE, the server will abort any handshake that
+ // negotiates an intolerant TLS version in order to test version fallback.
+ TLSIntolerantLevel tls_intolerant;
+ };
+
+ // Pass as the 'host' parameter during construction to server on 127.0.0.1
+ static const char kLocalhost[];
+
+ // Initialize a TestServer listening on a specific host (IP or hostname).
+ BaseTestServer(Type type, const std::string& host);
+
+ // Initialize a TestServer with a specific set of SSLOptions for HTTPS or WSS.
+ explicit BaseTestServer(Type type, const SSLOptions& ssl_options);
+
+ // Returns the host port pair used by current Python based test server only
+ // if the server is started.
+ const HostPortPair& host_port_pair() const;
+
+ const base::FilePath& document_root() const { return document_root_; }
+ const base::DictionaryValue& server_data() const;
+ std::string GetScheme() const;
+ bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;
+
+ GURL GetURL(const std::string& path) const;
+
+ GURL GetURLWithUser(const std::string& path,
+ const std::string& user) const;
+
+ GURL GetURLWithUserAndPassword(const std::string& path,
+ const std::string& user,
+ const std::string& password) const;
+
+ static bool GetFilePathWithReplacements(
+ const std::string& original_path,
+ const std::vector<StringPair>& text_to_replace,
+ std::string* replacement_path);
+
+ static bool UsingSSL(Type type) {
+ return type == BaseTestServer::TYPE_HTTPS ||
+ type == BaseTestServer::TYPE_WSS;
+ }
+
+ protected:
+ virtual ~BaseTestServer();
+ Type type() const { return type_; }
+
+ // Gets port currently assigned to host_port_pair_ without checking
+ // whether it's available (server started) or not.
+ uint16 GetPort();
+
+ // Sets |port| as the actual port used by Python based test server.
+ void SetPort(uint16 port);
+
+ // Set up internal status when the server is started.
+ bool SetupWhenServerStarted() WARN_UNUSED_RESULT;
+
+ // Clean up internal status when starting to stop server.
+ void CleanUpWhenStoppingServer();
+
+ // Set path of test resources.
+ void SetResourcePath(const base::FilePath& document_root,
+ const base::FilePath& certificates_dir);
+
+ // Parses the server data read from the test server. Returns true
+ // on success.
+ bool ParseServerData(const std::string& server_data) WARN_UNUSED_RESULT;
+
+ // Generates a DictionaryValue with the arguments for launching the external
+ // Python test server.
+ bool GenerateArguments(base::DictionaryValue* arguments) const
+ WARN_UNUSED_RESULT;
+
+ // Subclasses can override this to add arguments that are specific to their
+ // own test servers.
+ virtual bool GenerateAdditionalArguments(
+ base::DictionaryValue* arguments) const WARN_UNUSED_RESULT;
+
+ private:
+ void Init(const std::string& host);
+
+ // Marks the root certificate of an HTTPS test server as trusted for
+ // the duration of tests.
+ bool LoadTestRootCert() const WARN_UNUSED_RESULT;
+
+ // Document root of the test server.
+ base::FilePath document_root_;
+
+ // Directory that contains the SSL certificates.
+ base::FilePath certificates_dir_;
+
+ // Address the test server listens on.
+ HostPortPair host_port_pair_;
+
+ // Holds the data sent from the server (e.g., port number).
+ scoped_ptr<base::DictionaryValue> server_data_;
+
+ // If |type_| is TYPE_HTTPS or TYPE_WSS, the TLS settings to use for the test
+ // server.
+ SSLOptions ssl_options_;
+
+ Type type_;
+
+ // Has the server been started?
+ bool started_;
+
+ // Enables logging of the server to the console.
+ bool log_to_console_;
+
+ scoped_ptr<ScopedPortException> allowed_port_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseTestServer);
+};
+
+} // namespace net
+
+#endif // NET_TEST_SPAWNED_TEST_SERVER_BASE_TEST_SERVER_H_
+
diff --git a/chromium/net/test/spawned_test_server/local_test_server.cc b/chromium/net/test/spawned_test_server/local_test_server.cc
new file mode 100644
index 00000000000..bf1b0590786
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/local_test_server.cc
@@ -0,0 +1,252 @@
+// Copyright 2013 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.
+
+#include "net/test/spawned_test_server/local_test_server.h"
+
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process/kill.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_errors.h"
+#include "net/test/python_utils.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+bool AppendArgumentFromJSONValue(const std::string& key,
+ const base::Value& value_node,
+ CommandLine* command_line) {
+ std::string argument_name = "--" + key;
+ switch (value_node.GetType()) {
+ case base::Value::TYPE_NULL:
+ command_line->AppendArg(argument_name);
+ break;
+ case base::Value::TYPE_INTEGER: {
+ int value;
+ bool result = value_node.GetAsInteger(&value);
+ DCHECK(result);
+ command_line->AppendArg(argument_name + "=" + base::IntToString(value));
+ break;
+ }
+ case Value::TYPE_STRING: {
+ std::string value;
+ bool result = value_node.GetAsString(&value);
+ if (!result || value.empty())
+ return false;
+ command_line->AppendArg(argument_name + "=" + value);
+ break;
+ }
+ case base::Value::TYPE_BOOLEAN:
+ case base::Value::TYPE_DOUBLE:
+ case base::Value::TYPE_LIST:
+ case base::Value::TYPE_DICTIONARY:
+ case base::Value::TYPE_BINARY:
+ default:
+ NOTREACHED() << "improper json type";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+LocalTestServer::LocalTestServer(Type type,
+ const std::string& host,
+ const base::FilePath& document_root)
+ : BaseTestServer(type, host) {
+ if (!Init(document_root))
+ NOTREACHED();
+}
+
+LocalTestServer::LocalTestServer(Type type,
+ const SSLOptions& ssl_options,
+ const base::FilePath& document_root)
+ : BaseTestServer(type, ssl_options) {
+ if (!Init(document_root))
+ NOTREACHED();
+}
+
+LocalTestServer::~LocalTestServer() {
+ Stop();
+}
+
+bool LocalTestServer::GetTestServerPath(base::FilePath* testserver_path) const {
+ base::FilePath testserver_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_dir)) {
+ LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
+ return false;
+ }
+ testserver_dir = testserver_dir.Append(FILE_PATH_LITERAL("net"))
+ .Append(FILE_PATH_LITERAL("tools"))
+ .Append(FILE_PATH_LITERAL("testserver"));
+ *testserver_path = testserver_dir.Append(FILE_PATH_LITERAL("testserver.py"));
+ return true;
+}
+
+bool LocalTestServer::Start() {
+ return StartInBackground() && BlockUntilStarted();
+}
+
+bool LocalTestServer::StartInBackground() {
+ // Get path to Python server script.
+ base::FilePath testserver_path;
+ if (!GetTestServerPath(&testserver_path))
+ return false;
+
+ if (!SetPythonPath())
+ return false;
+
+ if (!LaunchPython(testserver_path))
+ return false;
+
+ return true;
+}
+
+bool LocalTestServer::BlockUntilStarted() {
+ if (!WaitToStart()) {
+ Stop();
+ return false;
+ }
+
+ return SetupWhenServerStarted();
+}
+
+bool LocalTestServer::Stop() {
+ CleanUpWhenStoppingServer();
+
+ if (!process_handle_)
+ return true;
+
+ // First check if the process has already terminated.
+ bool ret = base::WaitForSingleProcess(process_handle_, base::TimeDelta());
+ if (!ret)
+ ret = base::KillProcess(process_handle_, 1, true);
+
+ if (ret) {
+ base::CloseProcessHandle(process_handle_);
+ process_handle_ = base::kNullProcessHandle;
+ } else {
+ VLOG(1) << "Kill failed?";
+ }
+
+ return ret;
+}
+
+bool LocalTestServer::Init(const base::FilePath& document_root) {
+ if (document_root.IsAbsolute())
+ return false;
+
+ // At this point, the port that the test server will listen on is unknown.
+ // The test server will listen on an ephemeral port, and write the port
+ // number out over a pipe that this TestServer object will read from. Once
+ // that is complete, the host port pair will contain the actual port.
+ DCHECK(!GetPort());
+ process_handle_ = base::kNullProcessHandle;
+
+ base::FilePath src_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir))
+ return false;
+ SetResourcePath(src_dir.Append(document_root),
+ src_dir.AppendASCII("net")
+ .AppendASCII("data")
+ .AppendASCII("ssl")
+ .AppendASCII("certificates"));
+ return true;
+}
+
+bool LocalTestServer::SetPythonPath() const {
+ base::FilePath third_party_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
+ LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
+ return false;
+ }
+ third_party_dir = third_party_dir.AppendASCII("third_party");
+
+ // For simplejson. (simplejson, unlike all the other Python modules
+ // we include, doesn't have an extra 'simplejson' directory, so we
+ // need to include its parent directory, i.e. third_party_dir).
+ AppendToPythonPath(third_party_dir);
+
+ AppendToPythonPath(third_party_dir.AppendASCII("tlslite"));
+ AppendToPythonPath(
+ third_party_dir.AppendASCII("pyftpdlib").AppendASCII("src"));
+ AppendToPythonPath(
+ third_party_dir.AppendASCII("pywebsocket").AppendASCII("src"));
+
+ // Locate the Python code generated by the protocol buffers compiler.
+ base::FilePath pyproto_dir;
+ if (!GetPyProtoPath(&pyproto_dir)) {
+ LOG(WARNING) << "Cannot find pyproto dir for generated code. "
+ << "Testserver features that rely on it will not work";
+ return true;
+ }
+ AppendToPythonPath(pyproto_dir);
+
+ return true;
+}
+
+bool LocalTestServer::AddCommandLineArguments(CommandLine* command_line) const {
+ base::DictionaryValue arguments_dict;
+ if (!GenerateArguments(&arguments_dict))
+ return false;
+
+ // Serialize the argument dictionary into CommandLine.
+ for (base::DictionaryValue::Iterator it(arguments_dict); !it.IsAtEnd();
+ it.Advance()) {
+ const base::Value& value = it.value();
+ const std::string& key = it.key();
+
+ // Add arguments from a list.
+ if (value.IsType(Value::TYPE_LIST)) {
+ const base::ListValue* list = NULL;
+ if (!value.GetAsList(&list) || !list || list->empty())
+ return false;
+ for (base::ListValue::const_iterator list_it = list->begin();
+ list_it != list->end(); ++list_it) {
+ if (!AppendArgumentFromJSONValue(key, *(*list_it), command_line))
+ return false;
+ }
+ } else if (!AppendArgumentFromJSONValue(key, value, command_line)) {
+ return false;
+ }
+ }
+
+ // Append the appropriate server type argument.
+ switch (type()) {
+ case TYPE_HTTP: // The default type is HTTP, no argument required.
+ break;
+ case TYPE_HTTPS:
+ command_line->AppendArg("--https");
+ break;
+ case TYPE_WS:
+ case TYPE_WSS:
+ command_line->AppendArg("--websocket");
+ break;
+ case TYPE_FTP:
+ command_line->AppendArg("--ftp");
+ break;
+ case TYPE_TCP_ECHO:
+ command_line->AppendArg("--tcp-echo");
+ break;
+ case TYPE_UDP_ECHO:
+ command_line->AppendArg("--udp-echo");
+ break;
+ case TYPE_BASIC_AUTH_PROXY:
+ command_line->AppendArg("--basic-auth-proxy");
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/test/spawned_test_server/local_test_server.h b/chromium/net/test/spawned_test_server/local_test_server.h
new file mode 100644
index 00000000000..cfd2eb3baee
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/local_test_server.h
@@ -0,0 +1,117 @@
+// Copyright 2013 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.
+
+#ifndef NET_TEST_SPAWNED_TEST_SERVER_LOCAL_TEST_SERVER_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_LOCAL_TEST_SERVER_H_
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/process/process_handle.h"
+#include "net/test/spawned_test_server/base_test_server.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+class CommandLine;
+
+namespace net {
+
+// The LocalTestServer runs an external Python-based test server in the
+// same machine in which the LocalTestServer runs.
+class LocalTestServer : public BaseTestServer {
+ public:
+ // Initialize a TestServer listening on a specific host (IP or hostname).
+ // |document_root| must be a relative path under the root tree.
+ LocalTestServer(Type type,
+ const std::string& host,
+ const base::FilePath& document_root);
+
+ // Initialize a TestServer with a specific set of SSLOptions.
+ // |document_root| must be a relative path under the root tree.
+ LocalTestServer(Type type,
+ const SSLOptions& ssl_options,
+ const base::FilePath& document_root);
+
+ virtual ~LocalTestServer();
+
+ // Start the test server and block until it's ready. Returns true on success.
+ bool Start() WARN_UNUSED_RESULT;
+
+ // Start the test server without blocking. Use this if you need multiple test
+ // servers (such as WebSockets and HTTP, or HTTP and HTTPS). You must call
+ // BlockUntilStarted on all servers your test requires before executing the
+ // test. For example:
+ //
+ // // Start the servers in parallel.
+ // ASSERT_TRUE(http_server.StartInBackground());
+ // ASSERT_TRUE(websocket_server.StartInBackground());
+ // // Wait for both servers to be ready.
+ // ASSERT_TRUE(http_server.BlockUntilStarted());
+ // ASSERT_TRUE(websocket_server.BlockUntilStarted());
+ // RunMyTest();
+ //
+ // Returns true on success.
+ bool StartInBackground() WARN_UNUSED_RESULT;
+
+ // Block until ths test server is ready. Returns true on success. See
+ // StartInBackground() documentation for more information.
+ bool BlockUntilStarted() WARN_UNUSED_RESULT;
+
+ // Stop the server started by Start().
+ bool Stop();
+
+ // Modify PYTHONPATH to contain libraries we need.
+ virtual bool SetPythonPath() const WARN_UNUSED_RESULT;
+
+ // Returns true if the base::FilePath for the testserver python script is
+ // successfully stored in |*testserver_path|.
+ virtual bool GetTestServerPath(base::FilePath* testserver_path) const
+ WARN_UNUSED_RESULT;
+
+ // Adds the command line arguments for the Python test server to
+ // |command_line|. Returns true on success.
+ virtual bool AddCommandLineArguments(CommandLine* command_line) const
+ WARN_UNUSED_RESULT;
+
+ // Returns the actual path of document root for test cases. This function
+ // should be called by test cases to retrieve the actual document root path.
+ base::FilePath GetDocumentRoot() const { return document_root(); };
+
+ private:
+ bool Init(const base::FilePath& document_root);
+
+ // Launches the Python test server. Returns true on success.
+ bool LaunchPython(const base::FilePath& testserver_path) WARN_UNUSED_RESULT;
+
+ // Waits for the server to start. Returns true on success.
+ bool WaitToStart() WARN_UNUSED_RESULT;
+
+ // Handle of the Python process running the test server.
+ base::ProcessHandle process_handle_;
+
+#if defined(OS_WIN)
+ // JobObject used to clean up orphaned child processes.
+ base::win::ScopedHandle job_handle_;
+
+ // The pipe file handle we read from.
+ base::win::ScopedHandle child_read_fd_;
+
+ // The pipe file handle the child and we write to.
+ base::win::ScopedHandle child_write_fd_;
+#endif
+
+#if defined(OS_POSIX)
+ // The file descriptor the child writes to when it starts.
+ int child_fd_;
+ file_util::ScopedFD child_fd_closer_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(LocalTestServer);
+};
+
+} // namespace net
+
+#endif // NET_TEST_SPAWNED_TEST_SERVER_LOCAL_TEST_SERVER_H_
diff --git a/chromium/net/test/spawned_test_server/local_test_server_posix.cc b/chromium/net/test/spawned_test_server/local_test_server_posix.cc
new file mode 100644
index 00000000000..10c2d0f9932
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/local_test_server_posix.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/spawned_test_server/local_test_server.h"
+
+#include <poll.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/process/process_iterator.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/test/test_timeouts.h"
+#include "net/test/python_utils.h"
+
+namespace {
+
+// Helper class used to detect and kill orphaned python test server processes.
+// Checks if the command line of a process contains |path_string| (the path
+// from which the test server was launched) and |port_string| (the port used by
+// the test server), and if the parent pid of the process is 1 (indicating that
+// it is an orphaned process).
+class OrphanedTestServerFilter : public base::ProcessFilter {
+ public:
+ OrphanedTestServerFilter(
+ const std::string& path_string, const std::string& port_string)
+ : path_string_(path_string),
+ port_string_(port_string) {}
+
+ virtual bool Includes(const base::ProcessEntry& entry) const OVERRIDE {
+ if (entry.parent_pid() != 1)
+ return false;
+ bool found_path_string = false;
+ bool found_port_string = false;
+ for (std::vector<std::string>::const_iterator it =
+ entry.cmd_line_args().begin();
+ it != entry.cmd_line_args().end();
+ ++it) {
+ if (it->find(path_string_) != std::string::npos)
+ found_path_string = true;
+ if (it->find(port_string_) != std::string::npos)
+ found_port_string = true;
+ }
+ return found_path_string && found_port_string;
+ }
+
+ private:
+ std::string path_string_;
+ std::string port_string_;
+ DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
+};
+
+// Given a file descriptor, reads into |buffer| until |bytes_max|
+// bytes has been read or an error has been encountered. Returns true
+// if the read was successful. |remaining_time| is used as a timeout.
+bool ReadData(int fd, ssize_t bytes_max, uint8* buffer,
+ base::TimeDelta* remaining_time) {
+ ssize_t bytes_read = 0;
+ base::TimeTicks previous_time = base::TimeTicks::Now();
+ while (bytes_read < bytes_max) {
+ struct pollfd poll_fds[1];
+
+ poll_fds[0].fd = fd;
+ poll_fds[0].events = POLLIN | POLLPRI;
+ poll_fds[0].revents = 0;
+
+ int rv = HANDLE_EINTR(poll(poll_fds, 1,
+ remaining_time->InMilliseconds()));
+ if (rv == 0) {
+ LOG(ERROR) << "poll() timed out; bytes_read=" << bytes_read;
+ return false;
+ } else if (rv < 0) {
+ PLOG(ERROR) << "poll() failed for child file descriptor; bytes_read="
+ << bytes_read;
+ return false;
+ }
+
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ base::TimeDelta elapsed_time_cycle = current_time - previous_time;
+ DCHECK_GE(elapsed_time_cycle.InMilliseconds(), 0);
+ *remaining_time -= elapsed_time_cycle;
+ previous_time = current_time;
+
+ ssize_t num_bytes = HANDLE_EINTR(read(fd, buffer + bytes_read,
+ bytes_max - bytes_read));
+ if (num_bytes <= 0)
+ return false;
+ bytes_read += num_bytes;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace net {
+
+bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) {
+ // Log is useful in the event you want to run a nearby script (e.g. a test) in
+ // the same environment as the TestServer.
+ VLOG(1) << "LaunchPython called with PYTHONPATH = " << getenv(kPythonPathEnv);
+
+ CommandLine python_command(CommandLine::NO_PROGRAM);
+ if (!GetPythonCommand(&python_command))
+ return false;
+
+ python_command.AppendArgPath(testserver_path);
+ if (!AddCommandLineArguments(&python_command))
+ return false;
+
+ int pipefd[2];
+ if (pipe(pipefd) != 0) {
+ PLOG(ERROR) << "Could not create pipe.";
+ return false;
+ }
+
+ // Save the read half. The write half is sent to the child.
+ child_fd_ = pipefd[0];
+ child_fd_closer_.reset(&child_fd_);
+ file_util::ScopedFD write_closer(&pipefd[1]);
+ base::FileHandleMappingVector map_write_fd;
+ map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1]));
+
+ python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1]));
+
+ // Try to kill any orphaned testserver processes that may be running.
+ OrphanedTestServerFilter filter(testserver_path.value(),
+ base::IntToString(GetPort()));
+ if (!base::KillProcesses("python", -1, &filter)) {
+ LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
+ }
+
+ // Launch a new testserver process.
+ base::LaunchOptions options;
+
+ options.fds_to_remap = &map_write_fd;
+ if (!base::LaunchProcess(python_command, options, &process_handle_)) {
+ LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
+ return false;
+ }
+
+ return true;
+}
+
+bool LocalTestServer::WaitToStart() {
+ file_util::ScopedFD child_fd_closer(child_fd_closer_.release());
+
+ base::TimeDelta remaining_time = TestTimeouts::action_timeout();
+
+ uint32 server_data_len = 0;
+ if (!ReadData(child_fd_, sizeof(server_data_len),
+ reinterpret_cast<uint8*>(&server_data_len),
+ &remaining_time)) {
+ LOG(ERROR) << "Could not read server_data_len";
+ return false;
+ }
+ std::string server_data(server_data_len, '\0');
+ if (!ReadData(child_fd_, server_data_len,
+ reinterpret_cast<uint8*>(&server_data[0]),
+ &remaining_time)) {
+ LOG(ERROR) << "Could not read server_data (" << server_data_len
+ << " bytes)";
+ return false;
+ }
+
+ if (!ParseServerData(server_data)) {
+ LOG(ERROR) << "Could not parse server_data: " << server_data;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/test/spawned_test_server/local_test_server_win.cc b/chromium/net/test/spawned_test_server/local_test_server_win.cc
new file mode 100644
index 00000000000..fd26483ed47
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/local_test_server_win.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/spawned_test_server/local_test_server.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
+#include "base/win/scoped_handle.h"
+#include "net/test/python_utils.h"
+
+#pragma comment(lib, "crypt32.lib")
+
+namespace {
+
+// Writes |size| bytes to |handle| and sets |*unblocked| to true.
+// Used as a crude timeout mechanism by ReadData().
+void UnblockPipe(HANDLE handle, DWORD size, bool* unblocked) {
+ std::string unblock_data(size, '\0');
+ // Unblock the ReadFile in LocalTestServer::WaitToStart by writing to the
+ // pipe. Make sure the call succeeded, otherwise we are very likely to hang.
+ DWORD bytes_written = 0;
+ LOG(WARNING) << "Timeout reached; unblocking pipe by writing "
+ << size << " bytes";
+ CHECK(WriteFile(handle, unblock_data.data(), size, &bytes_written,
+ NULL));
+ CHECK_EQ(size, bytes_written);
+ *unblocked = true;
+}
+
+// Given a file handle, reads into |buffer| until |bytes_max| bytes
+// has been read or an error has been encountered. Returns
+// true if the read was successful.
+bool ReadData(HANDLE read_fd, HANDLE write_fd,
+ DWORD bytes_max, uint8* buffer) {
+ base::Thread thread("test_server_watcher");
+ if (!thread.Start())
+ return false;
+
+ // Prepare a timeout in case the server fails to start.
+ bool unblocked = false;
+ thread.message_loop()->PostDelayedTask(
+ FROM_HERE, base::Bind(UnblockPipe, write_fd, bytes_max, &unblocked),
+ TestTimeouts::action_max_timeout());
+
+ DWORD bytes_read = 0;
+ while (bytes_read < bytes_max) {
+ DWORD num_bytes;
+ if (!ReadFile(read_fd, buffer + bytes_read, bytes_max - bytes_read,
+ &num_bytes, NULL)) {
+ PLOG(ERROR) << "ReadFile failed";
+ return false;
+ }
+ if (num_bytes <= 0) {
+ LOG(ERROR) << "ReadFile returned invalid byte count: " << num_bytes;
+ return false;
+ }
+ bytes_read += num_bytes;
+ }
+
+ thread.Stop();
+ // If the timeout kicked in, abort.
+ if (unblocked) {
+ LOG(ERROR) << "Timeout exceeded for ReadData";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace net {
+
+bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) {
+ CommandLine python_command(CommandLine::NO_PROGRAM);
+ if (!GetPythonCommand(&python_command))
+ return false;
+
+ python_command.AppendArgPath(testserver_path);
+ if (!AddCommandLineArguments(&python_command))
+ return false;
+
+ HANDLE child_read = NULL;
+ HANDLE child_write = NULL;
+ if (!CreatePipe(&child_read, &child_write, NULL, 0)) {
+ PLOG(ERROR) << "Failed to create pipe";
+ return false;
+ }
+ child_read_fd_.Set(child_read);
+ child_write_fd_.Set(child_write);
+
+ // Have the child inherit the write half.
+ if (!SetHandleInformation(child_write, HANDLE_FLAG_INHERIT,
+ HANDLE_FLAG_INHERIT)) {
+ PLOG(ERROR) << "Failed to enable pipe inheritance";
+ return false;
+ }
+
+ // Pass the handle on the command-line. Although HANDLE is a
+ // pointer, truncating it on 64-bit machines is okay. See
+ // http://msdn.microsoft.com/en-us/library/aa384203.aspx
+ //
+ // "64-bit versions of Windows use 32-bit handles for
+ // interoperability. When sharing a handle between 32-bit and 64-bit
+ // applications, only the lower 32 bits are significant, so it is
+ // safe to truncate the handle (when passing it from 64-bit to
+ // 32-bit) or sign-extend the handle (when passing it from 32-bit to
+ // 64-bit)."
+ python_command.AppendArg("--startup-pipe=" +
+ base::IntToString(reinterpret_cast<uintptr_t>(child_write)));
+
+ job_handle_.Set(CreateJobObject(NULL, NULL));
+ if (!job_handle_.IsValid()) {
+ LOG(ERROR) << "Could not create JobObject.";
+ return false;
+ }
+
+ if (!base::SetJobObjectAsKillOnJobClose(job_handle_.Get())) {
+ LOG(ERROR) << "Could not SetInformationJobObject.";
+ return false;
+ }
+
+ base::LaunchOptions launch_options;
+ launch_options.inherit_handles = true;
+ launch_options.job_handle = job_handle_.Get();
+ if (!base::LaunchProcess(python_command, launch_options, &process_handle_)) {
+ LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
+ return false;
+ }
+
+ return true;
+}
+
+bool LocalTestServer::WaitToStart() {
+ base::win::ScopedHandle read_fd(child_read_fd_.Take());
+ base::win::ScopedHandle write_fd(child_write_fd_.Take());
+
+ uint32 server_data_len = 0;
+ if (!ReadData(read_fd.Get(), write_fd.Get(), sizeof(server_data_len),
+ reinterpret_cast<uint8*>(&server_data_len))) {
+ LOG(ERROR) << "Could not read server_data_len";
+ return false;
+ }
+ std::string server_data(server_data_len, '\0');
+ if (!ReadData(read_fd.Get(), write_fd.Get(), server_data_len,
+ reinterpret_cast<uint8*>(&server_data[0]))) {
+ LOG(ERROR) << "Could not read server_data (" << server_data_len
+ << " bytes)";
+ return false;
+ }
+
+ if (!ParseServerData(server_data)) {
+ LOG(ERROR) << "Could not parse server_data: " << server_data;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace net
+
diff --git a/chromium/net/test/spawned_test_server/remote_test_server.cc b/chromium/net/test/spawned_test_server/remote_test_server.cc
new file mode 100644
index 00000000000..a3b4ef3fdf5
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/remote_test_server.cc
@@ -0,0 +1,204 @@
+// Copyright 2013 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.
+
+#include "net/test/spawned_test_server/remote_test_server.h"
+
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_errors.h"
+#include "net/test/spawned_test_server/spawner_communicator.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+// To reduce the running time of tests, tests may be sharded across several
+// devices. This means that it may be necessary to support multiple instances
+// of the test server spawner and the Python test server simultaneously on the
+// same host. Each pair of (test server spawner, Python test server) correspond
+// to a single testing device.
+// The mapping between the test server spawner and the individual Python test
+// servers is written to a file on the device prior to executing any tests.
+base::FilePath GetTestServerPortInfoFile() {
+#if !defined(OS_ANDROID)
+ return base::FilePath("/tmp/net-test-server-ports");
+#else
+ base::FilePath test_data_dir;
+ PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE, &test_data_dir);
+ return test_data_dir.Append("net-test-server-ports");
+#endif
+}
+
+// Please keep it sync with dictionary SERVER_TYPES in testserver.py
+std::string GetServerTypeString(BaseTestServer::Type type) {
+ switch (type) {
+ case BaseTestServer::TYPE_FTP:
+ return "ftp";
+ case BaseTestServer::TYPE_HTTP:
+ case BaseTestServer::TYPE_HTTPS:
+ return "http";
+ case BaseTestServer::TYPE_WS:
+ case BaseTestServer::TYPE_WSS:
+ return "ws";
+ case BaseTestServer::TYPE_TCP_ECHO:
+ return "tcpecho";
+ case BaseTestServer::TYPE_UDP_ECHO:
+ return "udpecho";
+ default:
+ NOTREACHED();
+ }
+ return std::string();
+}
+
+} // namespace
+
+RemoteTestServer::RemoteTestServer(Type type,
+ const std::string& host,
+ const base::FilePath& document_root)
+ : BaseTestServer(type, host),
+ spawner_server_port_(0) {
+ if (!Init(document_root))
+ NOTREACHED();
+}
+
+RemoteTestServer::RemoteTestServer(Type type,
+ const SSLOptions& ssl_options,
+ const base::FilePath& document_root)
+ : BaseTestServer(type, ssl_options),
+ spawner_server_port_(0) {
+ if (!Init(document_root))
+ NOTREACHED();
+}
+
+RemoteTestServer::~RemoteTestServer() {
+ Stop();
+}
+
+bool RemoteTestServer::Start() {
+ if (spawner_communicator_.get())
+ return true;
+ spawner_communicator_.reset(new SpawnerCommunicator(spawner_server_port_));
+
+ base::DictionaryValue arguments_dict;
+ if (!GenerateArguments(&arguments_dict))
+ return false;
+
+ // Append the 'server-type' argument which is used by spawner server to
+ // pass right server type to Python test server.
+ arguments_dict.SetString("server-type", GetServerTypeString(type()));
+
+ // Generate JSON-formatted argument string.
+ std::string arguments_string;
+ base::JSONWriter::Write(&arguments_dict, &arguments_string);
+ if (arguments_string.empty())
+ return false;
+
+ // Start the Python test server on the remote machine.
+ uint16 test_server_port;
+ if (!spawner_communicator_->StartServer(arguments_string,
+ &test_server_port)) {
+ return false;
+ }
+ if (0 == test_server_port)
+ return false;
+
+ // Construct server data to initialize BaseTestServer::server_data_.
+ base::DictionaryValue server_data_dict;
+ // At this point, the test server should be spawned on the host. Update the
+ // local port to real port of Python test server, which will be forwarded to
+ // the remote server.
+ server_data_dict.SetInteger("port", test_server_port);
+ std::string server_data;
+ base::JSONWriter::Write(&server_data_dict, &server_data);
+ if (server_data.empty() || !ParseServerData(server_data)) {
+ LOG(ERROR) << "Could not parse server_data: " << server_data;
+ return false;
+ }
+
+ return SetupWhenServerStarted();
+}
+
+bool RemoteTestServer::StartInBackground() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool RemoteTestServer::BlockUntilStarted() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool RemoteTestServer::Stop() {
+ if (!spawner_communicator_.get())
+ return true;
+ CleanUpWhenStoppingServer();
+ bool stopped = spawner_communicator_->StopServer();
+ // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one.
+ spawner_communicator_.reset(NULL);
+ return stopped;
+}
+
+// On Android, the document root in the device is not the same as the document
+// root in the host machine where the test server is launched. So prepend
+// DIR_SOURCE_ROOT here to get the actual path of document root on the Android
+// device.
+base::FilePath RemoteTestServer::GetDocumentRoot() const {
+ base::FilePath src_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
+ return src_dir.Append(document_root());
+}
+
+bool RemoteTestServer::Init(const base::FilePath& document_root) {
+ if (document_root.IsAbsolute())
+ return false;
+
+ // Gets ports information used by test server spawner and Python test server.
+ int test_server_port = 0;
+
+ // Parse file to extract the ports information.
+ std::string port_info;
+ if (!file_util::ReadFileToString(GetTestServerPortInfoFile(),
+ &port_info) ||
+ port_info.empty()) {
+ return false;
+ }
+
+ std::vector<std::string> ports;
+ base::SplitString(port_info, ':', &ports);
+ if (ports.size() != 2u)
+ return false;
+
+ // Verify the ports information.
+ base::StringToInt(ports[0], &spawner_server_port_);
+ if (!spawner_server_port_ ||
+ static_cast<uint32>(spawner_server_port_) >= kuint16max)
+ return false;
+
+ // Allow the test_server_port to be 0, which means the test server spawner
+ // will pick up a random port to run the test server.
+ base::StringToInt(ports[1], &test_server_port);
+ if (static_cast<uint32>(test_server_port) >= kuint16max)
+ return false;
+ SetPort(test_server_port);
+
+ SetResourcePath(document_root, base::FilePath().AppendASCII("net")
+ .AppendASCII("data")
+ .AppendASCII("ssl")
+ .AppendASCII("certificates"));
+ return true;
+}
+
+} // namespace net
+
diff --git a/chromium/net/test/spawned_test_server/remote_test_server.h b/chromium/net/test/spawned_test_server/remote_test_server.h
new file mode 100644
index 00000000000..de12e4ebe44
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/remote_test_server.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_H_
+
+#include <string>
+
+#include "net/test/spawned_test_server/base_test_server.h"
+
+namespace net {
+
+class SpawnerCommunicator;
+
+// The RemoteTestServer runs an external Python-based test server in another
+// machine that is different from the machine in which RemoteTestServer runs.
+class RemoteTestServer : public BaseTestServer {
+ public:
+ // Initialize a TestServer listening on a specific host (IP or hostname).
+ // |document_root| must be a relative path under the root tree.
+ RemoteTestServer(Type type,
+ const std::string& host,
+ const base::FilePath& document_root);
+
+ // Initialize a TestServer with a specific set of SSLOptions.
+ // |document_root| must be a relative path under the root tree.
+ RemoteTestServer(Type type,
+ const SSLOptions& ssl_options,
+ const base::FilePath& document_root);
+
+ virtual ~RemoteTestServer();
+
+ // Starts the Python test server on the host, instead of on the device, and
+ // blocks until the server is ready.
+ bool Start() WARN_UNUSED_RESULT;
+
+ // These are currently unused and unimplemented for RemoteTestServer. See
+ // the same methods in LocalTestServer for more information.
+ bool StartInBackground() WARN_UNUSED_RESULT;
+ bool BlockUntilStarted() WARN_UNUSED_RESULT;
+
+ // Stops the Python test server that is running on the host machine.
+ bool Stop();
+
+ // Returns the actual path of document root for the test cases. This function
+ // should be called by test cases to retrieve the actual document root path
+ // on the Android device, otherwise document_root() function is used to get
+ // the document root.
+ base::FilePath GetDocumentRoot() const;
+
+ private:
+ bool Init(const base::FilePath& document_root);
+
+ // The local port used to communicate with the TestServer spawner. This is
+ // used to control the startup and shutdown of the Python TestServer running
+ // on the remote machine. On Android, this port will be redirected to the
+ // same port on the host machine.
+ int spawner_server_port_;
+
+ // Helper to start and stop instances of the Python test server that runs on
+ // the host machine.
+ scoped_ptr<SpawnerCommunicator> spawner_communicator_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteTestServer);
+};
+
+} // namespace net
+
+#endif // NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_H_
+
diff --git a/chromium/net/test/spawned_test_server/spawned_test_server.h b/chromium/net/test/spawned_test_server/spawned_test_server.h
new file mode 100644
index 00000000000..9bf5831d503
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/spawned_test_server.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_SPAWNED_TEST_SERVER_SPAWNED_TEST_SERVER_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_SPAWNED_TEST_SERVER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "net/test/spawned_test_server/remote_test_server.h"
+#else
+#include "net/test/spawned_test_server/local_test_server.h"
+#endif
+
+namespace net {
+
+#if defined(OS_ANDROID)
+typedef RemoteTestServer SpawnedTestServer;
+#else
+typedef LocalTestServer SpawnedTestServer;
+#endif
+
+} // namespace net
+
+#endif // NET_TEST_SPAWNED_TEST_SERVER_SPAWNED_TEST_SERVER_H_
+
diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.cc b/chromium/net/test/spawned_test_server/spawner_communicator.cc
new file mode 100644
index 00000000000..f93ff971d6f
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/spawner_communicator.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 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.
+
+#include "net/test/spawned_test_server/spawner_communicator.h"
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/supports_user_data.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "net/base/net_util.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_data_stream.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_test_util.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+GURL GenerateSpawnerCommandURL(const std::string& command, uint16 port) {
+ // Always performs HTTP request for sending command to the spawner server.
+ return GURL(base::StringPrintf("%s:%u/%s", "http://127.0.0.1", port,
+ command.c_str()));
+}
+
+int kBufferSize = 2048;
+
+// A class to hold all data needed to send a command to spawner server.
+class SpawnerRequestData : public base::SupportsUserData::Data {
+ public:
+ SpawnerRequestData(int id, int* result_code, std::string* data_received)
+ : request_id_(id),
+ buf_(new IOBuffer(kBufferSize)),
+ result_code_(result_code),
+ data_received_(data_received),
+ response_started_count_(0) {
+ DCHECK(result_code);
+ *result_code_ = OK;
+ DCHECK(data_received);
+ data_received_->clear();
+ }
+
+ virtual ~SpawnerRequestData() {}
+
+ bool DoesRequestIdMatch(int request_id) const {
+ return request_id_ == request_id;
+ }
+
+ IOBuffer* buf() const { return buf_.get(); }
+
+ bool IsResultOK() const { return *result_code_ == OK; }
+
+ void ClearReceivedData() { data_received_->clear(); }
+
+ void SetResultCode(int result_code) { *result_code_ = result_code; }
+
+ void IncreaseResponseStartedCount() { response_started_count_++; }
+
+ int response_started_count() const { return response_started_count_; }
+
+ // Write data read from URLRequest::Read() to |data_received_|. Returns true
+ // if |num_bytes| is great than 0. |num_bytes| is 0 for EOF, < 0 on errors.
+ bool ConsumeBytesRead(int num_bytes) {
+ // Error while reading, or EOF.
+ if (num_bytes <= 0)
+ return false;
+
+ data_received_->append(buf_->data(), num_bytes);
+ return true;
+ }
+
+ private:
+ // Unique ID for the current request.
+ int request_id_;
+
+ // Buffer that URLRequest writes into.
+ scoped_refptr<IOBuffer> buf_;
+
+ // Holds the error condition that was hit on the current request, or OK.
+ int* result_code_;
+
+ // Data received from server;
+ std::string* data_received_;
+
+ // Used to track how many times the OnResponseStarted get called after
+ // sending a command to spawner server.
+ int response_started_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpawnerRequestData);
+};
+
+} // namespace
+
+SpawnerCommunicator::SpawnerCommunicator(uint16 port)
+ : io_thread_("spawner_communicator"),
+ event_(false, false),
+ port_(port),
+ next_id_(0),
+ weak_factory_(this),
+ is_running_(false) {}
+
+SpawnerCommunicator::~SpawnerCommunicator() {
+ DCHECK(!is_running_);
+}
+
+void SpawnerCommunicator::WaitForResponse() {
+ DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop());
+ event_.Wait();
+ event_.Reset();
+}
+
+void SpawnerCommunicator::StartIOThread() {
+ DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop());
+ if (is_running_)
+ return;
+
+ allowed_port_.reset(new ScopedPortException(port_));
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ is_running_ = io_thread_.StartWithOptions(options);
+ DCHECK(is_running_);
+}
+
+void SpawnerCommunicator::Shutdown() {
+ DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop());
+ DCHECK(is_running_);
+ // The request and its context should be created and destroyed only on the
+ // IO thread.
+ DCHECK(!cur_request_.get());
+ DCHECK(!context_.get());
+ is_running_ = false;
+ io_thread_.Stop();
+ allowed_port_.reset();
+}
+
+void SpawnerCommunicator::SendCommandAndWaitForResult(
+ const std::string& command,
+ const std::string& post_data,
+ int* result_code,
+ std::string* data_received) {
+ if (!result_code || !data_received)
+ return;
+ // Start the communicator thread to talk to test server spawner.
+ StartIOThread();
+ DCHECK(io_thread_.message_loop());
+
+ // Since the method will be blocked until SpawnerCommunicator gets result
+ // from the spawner server or timed-out. It's safe to use base::Unretained
+ // when using base::Bind.
+ io_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
+ &SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread,
+ base::Unretained(this), command, post_data, result_code, data_received));
+ WaitForResponse();
+}
+
+void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread(
+ const std::string& command,
+ const std::string& post_data,
+ int* result_code,
+ std::string* data_received) {
+ base::MessageLoop* loop = io_thread_.message_loop();
+ DCHECK(loop);
+ DCHECK_EQ(base::MessageLoop::current(), loop);
+
+ // Prepare the URLRequest for sending the command.
+ DCHECK(!cur_request_.get());
+ context_.reset(new TestURLRequestContext);
+ cur_request_.reset(context_->CreateRequest(
+ GenerateSpawnerCommandURL(command, port_), this));
+ DCHECK(cur_request_.get());
+ int current_request_id = ++next_id_;
+ SpawnerRequestData* data = new SpawnerRequestData(current_request_id,
+ result_code,
+ data_received);
+ DCHECK(data);
+ cur_request_->SetUserData(this, data);
+
+ if (post_data.empty()) {
+ cur_request_->set_method("GET");
+ } else {
+ cur_request_->set_method("POST");
+ scoped_ptr<UploadElementReader> reader(
+ UploadOwnedBytesElementReader::CreateWithString(post_data));
+ cur_request_->set_upload(make_scoped_ptr(
+ UploadDataStream::CreateWithReader(reader.Pass(), 0)));
+ net::HttpRequestHeaders headers;
+ headers.SetHeader(net::HttpRequestHeaders::kContentType,
+ "application/json");
+ cur_request_->SetExtraRequestHeaders(headers);
+ }
+
+ // Post a task to timeout this request if it takes too long.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SpawnerCommunicator::OnTimeout,
+ weak_factory_.GetWeakPtr(),
+ current_request_id),
+ TestTimeouts::action_max_timeout());
+
+ // Start the request.
+ cur_request_->Start();
+}
+
+void SpawnerCommunicator::OnTimeout(int id) {
+ // Timeout tasks may outlive the URLRequest they reference. Make sure it
+ // is still applicable.
+ if (!cur_request_.get())
+ return;
+ SpawnerRequestData* data =
+ static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
+ DCHECK(data);
+
+ if (!data->DoesRequestIdMatch(id))
+ return;
+ // Set the result code and cancel the timed-out task.
+ data->SetResultCode(ERR_TIMED_OUT);
+ cur_request_->Cancel();
+ OnSpawnerCommandCompleted(cur_request_.get());
+}
+
+void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request) {
+ if (!cur_request_.get())
+ return;
+ DCHECK_EQ(request, cur_request_.get());
+ SpawnerRequestData* data =
+ static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
+ DCHECK(data);
+
+ // If request is faild,return the error code.
+ if (!cur_request_->status().is_success())
+ data->SetResultCode(cur_request_->status().error());
+
+ if (!data->IsResultOK()) {
+ LOG(ERROR) << "request failed, status: "
+ << static_cast<int>(request->status().status())
+ << ", error: " << request->status().error();
+ // Clear the buffer of received data if any net error happened.
+ data->ClearReceivedData();
+ } else {
+ DCHECK_EQ(1, data->response_started_count());
+ }
+
+ // Clear current request to indicate the completion of sending a command
+ // to spawner server and getting the result.
+ cur_request_.reset();
+ context_.reset();
+ // Invalidate the weak pointers on the IO thread.
+ weak_factory_.InvalidateWeakPtrs();
+
+ // Wakeup the caller in user thread.
+ event_.Signal();
+}
+
+void SpawnerCommunicator::ReadResult(URLRequest* request) {
+ DCHECK_EQ(request, cur_request_.get());
+ SpawnerRequestData* data =
+ static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
+ DCHECK(data);
+
+ IOBuffer* buf = data->buf();
+ // Read as many bytes as are available synchronously.
+ while (true) {
+ int num_bytes;
+ if (!request->Read(buf, kBufferSize, &num_bytes)) {
+ // Check whether the read failed synchronously.
+ if (!request->status().is_io_pending())
+ OnSpawnerCommandCompleted(request);
+ return;
+ }
+ if (!data->ConsumeBytesRead(num_bytes)) {
+ OnSpawnerCommandCompleted(request);
+ return;
+ }
+ }
+}
+
+void SpawnerCommunicator::OnResponseStarted(URLRequest* request) {
+ DCHECK_EQ(request, cur_request_.get());
+ SpawnerRequestData* data =
+ static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
+ DCHECK(data);
+
+ data->IncreaseResponseStartedCount();
+
+ if (!request->status().is_success()) {
+ OnSpawnerCommandCompleted(request);
+ return;
+ }
+
+ // Require HTTP responses to have a success status code.
+ if (request->GetResponseCode() != 200) {
+ LOG(ERROR) << "Spawner server returned bad status: "
+ << request->response_headers()->GetStatusLine();
+ data->SetResultCode(ERR_FAILED);
+ request->Cancel();
+ OnSpawnerCommandCompleted(request);
+ return;
+ }
+
+ ReadResult(request);
+}
+
+void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) {
+ if (!cur_request_.get())
+ return;
+ DCHECK_EQ(request, cur_request_.get());
+ SpawnerRequestData* data =
+ static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
+ DCHECK(data);
+
+ if (data->ConsumeBytesRead(num_bytes)) {
+ // Keep reading.
+ ReadResult(request);
+ } else {
+ OnSpawnerCommandCompleted(request);
+ }
+}
+
+bool SpawnerCommunicator::StartServer(const std::string& arguments,
+ uint16* port) {
+ *port = 0;
+ // Send the start command to spawner server to start the Python test server
+ // on remote machine.
+ std::string server_return_data;
+ int result_code;
+ SendCommandAndWaitForResult("start", arguments, &result_code,
+ &server_return_data);
+ if (OK != result_code || server_return_data.empty())
+ return false;
+
+ // Check whether the data returned from spawner server is JSON-formatted.
+ scoped_ptr<base::Value> value(base::JSONReader::Read(server_return_data));
+ if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY)) {
+ LOG(ERROR) << "Invalid server data: " << server_return_data.c_str();
+ return false;
+ }
+
+ // Check whether spawner server returns valid data.
+ base::DictionaryValue* server_data =
+ static_cast<base::DictionaryValue*>(value.get());
+ std::string message;
+ if (!server_data->GetString("message", &message) || message != "started") {
+ LOG(ERROR) << "Invalid message in server data: ";
+ return false;
+ }
+ int int_port;
+ if (!server_data->GetInteger("port", &int_port) || int_port <= 0 ||
+ int_port > kuint16max) {
+ LOG(ERROR) << "Invalid port value: " << int_port;
+ return false;
+ }
+ *port = static_cast<uint16>(int_port);
+ return true;
+}
+
+bool SpawnerCommunicator::StopServer() {
+ // It's OK to stop the SpawnerCommunicator without starting it. Some tests
+ // have test server on their test fixture but do not actually use it.
+ if (!is_running_)
+ return true;
+
+ // When the test is done, ask the test server spawner to kill the test server
+ // on the remote machine.
+ std::string server_return_data;
+ int result_code;
+ SendCommandAndWaitForResult("kill", "", &result_code, &server_return_data);
+ Shutdown();
+ if (OK != result_code || server_return_data != "killed")
+ return false;
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.h b/chromium/net/test/spawned_test_server/spawner_communicator.h
new file mode 100644
index 00000000000..bf426e63502
--- /dev/null
+++ b/chromium/net/test/spawned_test_server/spawner_communicator.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 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.
+
+#ifndef NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "net/url_request/url_request.h"
+
+namespace net {
+
+class ScopedPortException;
+
+// SpawnerCommunicator communicates with a spawner server that runs on a
+// remote system.
+//
+// The test server used by unit tests is written in Python. However, Android
+// does not support running Python code, so the test server cannot run on the
+// same device running unit tests.
+//
+// The actual test server is executed on the host machine, while the unit tests
+// themselves continue running on the device. To control the test server on the
+// host machine, a second HTTP server is started, the spawner server, which
+// controls the life cycle of remote test servers. Calls to start/kill the
+// net::SpawnedTestServer are then redirected to the spawner server via
+// this spawner communicator.
+//
+// Currently only three commands are supported by spawner.
+//
+// (1) Start Python test server, format is:
+// Path: "/start".
+// Method: "POST".
+// Data to server: all arguments needed to launch the Python test server, in
+// JSON format.
+// Data from server: a JSON dict includes the following two field if success,
+// "port": the port the Python test server actually listen on that.
+// "message": must be "started".
+//
+// (2) Kill Python test server, format is:
+// Path: "/kill".
+// Method: "GET".
+// Data to server: None.
+// Data from server: String "killed" returned if success.
+//
+// (3) Ping Python test server to see whether it is alive, format is:
+// Path: "/ping".
+// Method: "GET".
+// Data to server: None.
+// Data from server: String "ready" returned if success.
+//
+// The internal I/O thread is required by net stack to perform net I/O.
+// The Start/StopServer methods block the caller thread until result is
+// fetched from spawner server or timed-out.
+class SpawnerCommunicator : public net::URLRequest::Delegate {
+ public:
+ explicit SpawnerCommunicator(uint16 port);
+ virtual ~SpawnerCommunicator();
+
+ // Starts an instance of the Python test server on the host/ machine.
+ // If successfully started, returns true, setting |*port| to the port
+ // on the local machine that can be used to communicate with the remote
+ // test server.
+ bool StartServer(const std::string& arguments,
+ uint16* port) WARN_UNUSED_RESULT;
+
+ bool StopServer() WARN_UNUSED_RESULT;
+
+ private:
+ // Starts the IO thread. Called on the user thread.
+ void StartIOThread();
+
+ // Shuts down the remote test server spawner. Called on the user thread.
+ void Shutdown();
+
+ // Waits for the server response on IO thread. Called on the user thread.
+ void WaitForResponse();
+
+ // Sends a command to the test server over HTTP, returning the result code
+ // |*result_code| and response data in |*data_received|, those two arguments
+ // must be not NULL, otherwise the method returns immediately without sending
+ // the |command|. If |post_data| is empty, HTTP GET will be used to send
+ // |command|. If |post_data| is non-empty, performs an HTTP POST.
+ // This method is called on the user thread.
+ void SendCommandAndWaitForResult(const std::string& command,
+ const std::string& post_data,
+ int* result_code,
+ std::string* data_received);
+
+ // Performs the command sending on the IO thread. Called on the IO thread.
+ void SendCommandAndWaitForResultOnIOThread(const std::string& command,
+ const std::string& post_data,
+ int* result_code,
+ std::string* data_received);
+
+ // URLRequest::Delegate methods. Called on the IO thread.
+ virtual void OnResponseStarted(URLRequest* request) OVERRIDE;
+ virtual void OnReadCompleted(URLRequest* request, int num_bytes) OVERRIDE;
+
+ // Reads Result from the response. Called on the IO thread.
+ void ReadResult(URLRequest* request);
+
+ // Called on the IO thread upon completion of the spawner command.
+ void OnSpawnerCommandCompleted(URLRequest* request);
+
+ // Callback on the IO thread for time-out task of request with id |id|.
+ void OnTimeout(int id);
+
+ // A thread to communicate with test_spawner server.
+ base::Thread io_thread_;
+
+ // WaitableEvent to notify whether the communication is done.
+ base::WaitableEvent event_;
+
+ // The local port used to communicate with the TestServer spawner. This is
+ // used to control the startup and shutdown of the Python TestServer running
+ // on the remote machine. On Android, this port will be redirected to the
+ // same port on the host machine.
+ const uint16 port_;
+
+ // Helper to add |port_| to the list of the globally explicitly allowed ports.
+ scoped_ptr<ScopedPortException> allowed_port_;
+
+ // The next ID to use for |cur_request_| (monotonically increasing).
+ int next_id_;
+
+ // Factory for creating the time-out task. This takes care of revoking
+ // outstanding tasks when |this| is deleted.
+ base::WeakPtrFactory<SpawnerCommunicator> weak_factory_;
+
+ // Request context used by |cur_request_|.
+ scoped_ptr<URLRequestContext> context_;
+
+ // The current (in progress) request, or NULL.
+ scoped_ptr<URLRequest> cur_request_;
+
+ // Only gets/sets |is_running_| on user's thread to avoid race-condition.
+ bool is_running_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpawnerCommunicator);
+};
+
+} // namespace net
+
+#endif // NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
diff --git a/chromium/net/test/test_certificate_data.h b/chromium/net/test/test_certificate_data.h
new file mode 100644
index 00000000000..3ccda5e34cb
--- /dev/null
+++ b/chromium/net/test/test_certificate_data.h
@@ -0,0 +1,786 @@
+// Copyright (c) 2012 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.
+
+namespace {
+
+// This is the SHA1 hash of the SubjectPublicKeyInfo of nist.der.
+static const char kNistSPKIHash[] =
+ "\x15\x60\xde\x65\x4e\x03\x9f\xd0\x08\x82"
+ "\xa9\x6a\xc4\x65\x8e\x6f\x92\x06\x84\x35";
+
+// kSatvedaSPKIs contains the SHA1 hashes of the SPKIs of the satveda.pem
+// certificate chain, in order.
+static const char kSatvedaSPKIs[2][21] = {
+ "\xd6\x2d\x7a\x12\x02\x7f\x9b\x8e\x4f\x2b"
+ "\x07\xc5\xfb\xf9\x2a\x2e\x9a\xcc\x0e\xe3",
+ "\xba\x2e\xb5\xa8\x3e\x13\x23\xd9\x53\x4b"
+ "\x5e\x65\xbc\xe7\xa3\x13\x5d\xd0\xa9\x96",
+};
+
+// kSatvedaSPKIsSHA256 contains the SHA256 hashes of the SPKIs of the
+// satveda.pem certificate chain, in order.
+static const char kSatvedaSPKIsSHA256[2][33] = {
+ "\xb9\x42\xab\xf2\x08\x63\xef\x81\x70\x88\x45\xc4\x39\xa2\x6e\x9c"
+ "\x2f\x9a\xf9\xf4\xcb\x23\x61\xd4\x83\x97\x61\x6d\xf2\x5b\x27\xa8",
+ "\x32\xb6\x4b\x66\x72\x7a\x20\x63\xe4\x06\x6f\x3b\x95\x8c\xb0\xaa"
+ "\xee\x57\x6a\x5e\xce\xfd\x95\x33\x99\xbb\x88\x74\x73\x1d\x95\x87",
+};
+
+// Certificates for test data. They're obtained with:
+//
+// $ openssl s_client -connect [host]:443 -showcerts > /tmp/host.pem < /dev/null
+// $ openssl x509 -inform PEM -outform DER < /tmp/host.pem > /tmp/host.der
+// $ xxd -i /tmp/host.der
+//
+// TODO(wtc): move these certificates to data files in the
+// src/net/data/ssl/certificates directory.
+
+// The linux compiler is nitty about unused variables. Declaring variables
+// in headers is not generally a good idea, but for our test data it is not
+// a big deal. Mark these as potentially unused so that the compiler won't
+// complain.
+#ifdef __GNUC__
+#define VARIABLE_IS_NOT_USED __attribute__ ((unused))
+#else
+#define VARIABLE_IS_NOT_USED
+#endif
+
+// Google's cert.
+
+unsigned char VARIABLE_IS_NOT_USED google_der[] = {
+ 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x8a, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x01, 0x2a, 0x39, 0x76, 0x0d, 0x3f, 0x4f, 0xc9, 0x0b,
+ 0xe7, 0xbd, 0x2b, 0xcf, 0x95, 0x2e, 0x7a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a,
+ 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c,
+ 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75,
+ 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20,
+ 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47,
+ 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x33,
+ 0x32, 0x37, 0x32, 0x32, 0x32, 0x30, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x31,
+ 0x30, 0x30, 0x33, 0x32, 0x37, 0x32, 0x32, 0x32, 0x30, 0x30, 0x37, 0x5a,
+ 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
+ 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x4d,
+ 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77,
+ 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30,
+ 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x77, 0x77, 0x77, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81,
+ 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+ 0x81, 0x81, 0x00, 0xd6, 0xb9, 0xe1, 0xad, 0xb8, 0x61, 0x0b, 0x1f, 0x4e,
+ 0xb6, 0x3c, 0x09, 0x3d, 0xab, 0xe8, 0xe3, 0x2b, 0xb6, 0xe8, 0xa4, 0x3a,
+ 0x78, 0x2f, 0xd3, 0x51, 0x20, 0x22, 0x45, 0x95, 0xd8, 0x00, 0x91, 0x33,
+ 0x9a, 0xa7, 0xa2, 0x48, 0xea, 0x30, 0x57, 0x26, 0x97, 0x66, 0xc7, 0x5a,
+ 0xef, 0xf1, 0x9b, 0x0c, 0x3f, 0xe1, 0xb9, 0x7f, 0x7b, 0xc3, 0xc7, 0xcc,
+ 0xaf, 0x9c, 0xd0, 0x1f, 0x3c, 0x81, 0x15, 0x10, 0x58, 0xfc, 0x06, 0xb3,
+ 0xbf, 0xbc, 0x9c, 0x02, 0xb9, 0x51, 0xdc, 0xfb, 0xa6, 0xb9, 0x17, 0x42,
+ 0xe6, 0x46, 0xe7, 0x22, 0xcf, 0x6c, 0x27, 0x10, 0xfe, 0x54, 0xe6, 0x92,
+ 0x6c, 0x0c, 0x60, 0x76, 0x9a, 0xce, 0xf8, 0x7f, 0xac, 0xb8, 0x5a, 0x08,
+ 0x4a, 0xdc, 0xb1, 0x64, 0xbd, 0xa0, 0x74, 0x41, 0xb2, 0xac, 0x8f, 0x86,
+ 0x9d, 0x1a, 0xde, 0x58, 0x09, 0xfd, 0x6c, 0x0a, 0x25, 0xe0, 0x79, 0x02,
+ 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x28,
+ 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xf8, 0x42, 0x04, 0x01, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
+ 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68,
+ 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61,
+ 0x77, 0x74, 0x65, 0x53, 0x47, 0x43, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c,
+ 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
+ 0x04, 0x66, 0x30, 0x64, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
+ 0x72, 0x79, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x5f, 0x53, 0x47,
+ 0x43, 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+ 0x00, 0x03, 0x81, 0x81, 0x00, 0x39, 0xb6, 0xfb, 0x11, 0xbc, 0x33, 0x2c,
+ 0xc3, 0x90, 0x48, 0xe3, 0x6e, 0xc3, 0x9b, 0x38, 0xb1, 0x42, 0xd1, 0x00,
+ 0x09, 0x58, 0x63, 0xa0, 0xe1, 0x98, 0x1c, 0x85, 0xf2, 0xef, 0x10, 0x1d,
+ 0x60, 0x4e, 0x51, 0x09, 0x62, 0xf5, 0x05, 0xbd, 0x9d, 0x4f, 0x87, 0x6c,
+ 0x98, 0x72, 0x07, 0x80, 0xc3, 0x59, 0x48, 0x14, 0xe2, 0xd6, 0xef, 0xd0,
+ 0x8f, 0x33, 0x6a, 0x68, 0x31, 0xfa, 0xb7, 0xbb, 0x85, 0xcc, 0xf7, 0xc7,
+ 0x47, 0x7b, 0x67, 0x93, 0x3c, 0xc3, 0x16, 0x51, 0x9b, 0x6f, 0x87, 0x20,
+ 0xfd, 0x67, 0x4c, 0x2b, 0xea, 0x6a, 0x49, 0xdb, 0x11, 0xd1, 0xbd, 0xd7,
+ 0x95, 0x22, 0x43, 0x7a, 0x06, 0x7b, 0x4e, 0xf6, 0x37, 0x8e, 0xa2, 0xb9,
+ 0xcf, 0x1f, 0xa5, 0xd2, 0xbd, 0x3b, 0x04, 0x97, 0x39, 0xb3, 0x0f, 0xfa,
+ 0x38, 0xb5, 0xaf, 0x55, 0x20, 0x88, 0x60, 0x93, 0xf2, 0xde, 0xdb, 0xff,
+ 0xdf
+};
+
+// webkit.org's cert.
+
+unsigned char VARIABLE_IS_NOT_USED webkit_der[] = {
+ 0x30, 0x82, 0x05, 0x0d, 0x30, 0x82, 0x03, 0xf5, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xca,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
+ 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73,
+ 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33, 0x30, 0x31,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a,
+ 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
+ 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27,
+ 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53, 0x65, 0x63,
+ 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+ 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x05,
+ 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37, 0x30, 0x1e,
+ 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35,
+ 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x38, 0x32,
+ 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
+ 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69,
+ 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+ 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, 0x65, 0x72, 0x74, 0x69,
+ 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
+ 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0c, 0x4d, 0x61,
+ 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x31, 0x15,
+ 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x2a, 0x2e, 0x77,
+ 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
+ 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28, 0xf2, 0xc0, 0x4f, 0xe0,
+ 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5, 0xc9, 0x26, 0x3a, 0x1b,
+ 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0, 0xf0, 0x40, 0x9e, 0x27,
+ 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c, 0xb8, 0x9b, 0x01, 0x2f,
+ 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1, 0x7e, 0x8e, 0xcd, 0xa6,
+ 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff, 0x2a, 0x6d, 0x0e, 0xba,
+ 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39, 0xdc, 0x1e, 0x34, 0xd0,
+ 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca, 0x65, 0xf6, 0x85, 0x3a,
+ 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1, 0xce, 0x88, 0x47, 0xcd,
+ 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb, 0x57, 0xdc, 0xca, 0x99,
+ 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e, 0xe9, 0xb1, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30, 0x82, 0x01, 0xca, 0x30,
+ 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b,
+ 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30,
+ 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57, 0x06, 0x03, 0x55, 0x1d,
+ 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0, 0x4a, 0xa0, 0x48, 0x86,
+ 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64,
+ 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x6f, 0x64, 0x61,
+ 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x69,
+ 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30,
+ 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b, 0x30, 0x49, 0x30, 0x47,
+ 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07, 0x17,
+ 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73,
+ 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30,
+ 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+ 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+ 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
+ 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64,
+ 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x1d, 0x06, 0x03,
+ 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48, 0xdf, 0x60, 0x32, 0xcc,
+ 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5, 0x9c, 0x16, 0x58, 0x32,
+ 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6,
+ 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7,
+ 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1c, 0x30, 0x1a, 0x82,
+ 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72,
+ 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72,
+ 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1e, 0x6a, 0xe7,
+ 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f, 0x99, 0xb4, 0x18,
+ 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37, 0xf4, 0x7d, 0xd5,
+ 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82, 0x56, 0xe3, 0x94,
+ 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01, 0x64, 0xd3, 0x7c,
+ 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01, 0x74, 0xe8, 0x35,
+ 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98, 0x95, 0x24, 0x9e,
+ 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56, 0x8d, 0x23, 0x9c,
+ 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8, 0xa0, 0xe9, 0x7d,
+ 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff, 0x9a, 0x01, 0x31,
+ 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d, 0xbb, 0xbb, 0xcd,
+ 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84, 0x71, 0x08, 0xd2,
+ 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8, 0x12, 0x6a, 0x6f,
+ 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9, 0xe0, 0xb5, 0xb3,
+ 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2, 0xca, 0x20, 0xd3,
+ 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94, 0x93, 0x8c, 0x64,
+ 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3, 0xd3, 0xc1, 0x50,
+ 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a, 0x7a, 0x21, 0x87,
+ 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e, 0xbe, 0xcd, 0x70,
+ 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08, 0x01, 0x6f, 0x37,
+ 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd, 0x35, 0x52, 0xdd,
+ 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8, 0x3c, 0xd8, 0x48,
+ 0x8a
+};
+
+// thawte.com's cert (it's EV-licious!).
+unsigned char VARIABLE_IS_NOT_USED thawte_der[] = {
+ 0x30, 0x82, 0x04, 0xa5, 0x30, 0x82, 0x03, 0x8d, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x17, 0x76, 0x05, 0x88, 0x95, 0x58, 0xee, 0xbb, 0x00,
+ 0xda, 0x10, 0xe5, 0xf0, 0xf3, 0x9c, 0xf0, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
+ 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+ 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+ 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30,
+ 0x54, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65,
+ 0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+ 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x36,
+ 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x21, 0x74,
+ 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64,
+ 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d,
+ 0x30, 0x38, 0x31, 0x31, 0x31, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5a, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x31, 0x37, 0x32, 0x33, 0x35,
+ 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xc7, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01, 0x03,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x19, 0x30, 0x17, 0x06, 0x0b, 0x2b, 0x06,
+ 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01, 0x02, 0x14, 0x08, 0x44,
+ 0x65, 0x6c, 0x61, 0x77, 0x61, 0x72, 0x65, 0x31, 0x1b, 0x30, 0x19, 0x06,
+ 0x03, 0x55, 0x04, 0x0f, 0x13, 0x12, 0x56, 0x31, 0x2e, 0x30, 0x2c, 0x20,
+ 0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x35, 0x2e, 0x28, 0x62, 0x29,
+ 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x0a, 0x54,
+ 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x10, 0x30,
+ 0x0e, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x07, 0x33, 0x38, 0x39, 0x38,
+ 0x32, 0x36, 0x31, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69,
+ 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x14, 0x0d,
+ 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65,
+ 0x77, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0e,
+ 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe7, 0x89, 0x68, 0xb5, 0x6e,
+ 0x1d, 0x38, 0x19, 0xf6, 0x2d, 0x61, 0xc2, 0x00, 0xba, 0x6e, 0xab, 0x66,
+ 0x92, 0xd6, 0x85, 0x87, 0x2d, 0xd5, 0xa8, 0x58, 0xa9, 0x7a, 0x75, 0x27,
+ 0x9d, 0xed, 0x9e, 0xfe, 0x06, 0x71, 0x70, 0x2d, 0x21, 0x70, 0x4c, 0x3e,
+ 0x9c, 0xb6, 0xd5, 0x5d, 0x44, 0x92, 0xb4, 0xe0, 0xee, 0x7c, 0x0a, 0x50,
+ 0x4c, 0x0d, 0x67, 0x98, 0xaa, 0x01, 0x0e, 0x37, 0xa3, 0x2a, 0xef, 0xe6,
+ 0xe0, 0x11, 0x7b, 0xee, 0xb0, 0xa2, 0xb4, 0x32, 0x64, 0xa7, 0x0d, 0xda,
+ 0x6c, 0x15, 0xf8, 0xc5, 0xa5, 0x5a, 0x2c, 0xfc, 0xc9, 0xa6, 0x3c, 0x88,
+ 0x88, 0xbf, 0xdf, 0xa7, 0x38, 0xf0, 0x78, 0xed, 0x81, 0x93, 0x29, 0x0c,
+ 0xae, 0xc7, 0xab, 0x51, 0x21, 0x5e, 0xca, 0x95, 0xe5, 0x48, 0x52, 0x41,
+ 0xb6, 0x18, 0x60, 0x04, 0x19, 0x6f, 0x3d, 0x80, 0x14, 0xd3, 0xaf, 0x23,
+ 0x03, 0x10, 0x95, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x49,
+ 0x30, 0x82, 0x01, 0x45, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x39, 0x06, 0x03, 0x55, 0x1d,
+ 0x1f, 0x04, 0x32, 0x30, 0x30, 0x30, 0x2e, 0xa0, 0x2c, 0xa0, 0x2a, 0x86,
+ 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
+ 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54,
+ 0x68, 0x61, 0x77, 0x74, 0x65, 0x45, 0x56, 0x43, 0x41, 0x32, 0x30, 0x30,
+ 0x36, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, 0x20,
+ 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01,
+ 0x86, 0xf8, 0x45, 0x01, 0x07, 0x30, 0x01, 0x30, 0x28, 0x30, 0x26, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74,
+ 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70,
+ 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x1f, 0x06, 0x03,
+ 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xcd, 0x32, 0xe2,
+ 0xf2, 0x5d, 0x25, 0x47, 0x02, 0xaa, 0x8f, 0x79, 0x4b, 0x32, 0xee, 0x03,
+ 0x99, 0xfd, 0x30, 0x49, 0xd1, 0x30, 0x76, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x6a, 0x30, 0x68, 0x30, 0x22, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74,
+ 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x42, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x36, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68,
+ 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x54, 0x68, 0x61, 0x77,
+ 0x74, 0x65, 0x5f, 0x45, 0x56, 0x5f, 0x43, 0x41, 0x5f, 0x32, 0x30, 0x30,
+ 0x36, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+ 0x00, 0xb2, 0xa0, 0x96, 0xdd, 0xec, 0x04, 0x38, 0x6b, 0xc3, 0x7a, 0xad,
+ 0x23, 0x44, 0x91, 0xe5, 0x62, 0x8c, 0xb1, 0xf6, 0x9c, 0x03, 0x21, 0x1f,
+ 0xef, 0x03, 0xd9, 0xca, 0x63, 0xb2, 0xf8, 0xdb, 0x5a, 0x93, 0xc2, 0xcc,
+ 0xf1, 0x7c, 0x6f, 0xeb, 0x0f, 0x51, 0x7b, 0x4b, 0xe7, 0xb5, 0xfc, 0xbc,
+ 0x9b, 0x87, 0x48, 0xcc, 0x5b, 0xf9, 0xc8, 0x66, 0xa4, 0x40, 0xac, 0xe9,
+ 0x42, 0x5d, 0xed, 0xf3, 0x53, 0x13, 0xe7, 0xbd, 0x6e, 0x7f, 0x50, 0x53,
+ 0x64, 0xb3, 0x95, 0xf1, 0x42, 0x4f, 0x36, 0x54, 0xb4, 0x1e, 0x7f, 0x18,
+ 0x37, 0x39, 0x3b, 0x06, 0x5b, 0xe5, 0x13, 0xd9, 0x57, 0xbc, 0xd5, 0x68,
+ 0xe3, 0x71, 0x5f, 0x5f, 0x2b, 0xf5, 0xa6, 0xc2, 0x8f, 0x67, 0x81, 0x3a,
+ 0x44, 0x63, 0x8c, 0x36, 0xfa, 0xa8, 0xed, 0xfd, 0xd7, 0x5e, 0xa2, 0x9f,
+ 0xb0, 0x9d, 0x47, 0x86, 0xfb, 0x71, 0x60, 0x8e, 0xc8, 0xd3, 0x45, 0x19,
+ 0xb7, 0xda, 0xcd, 0x9e, 0xea, 0x70, 0x10, 0x87, 0x37, 0x10, 0xdd, 0x2c,
+ 0x11, 0xdf, 0xee, 0x02, 0x21, 0xa6, 0x75, 0xe6, 0xd6, 0x9f, 0x54, 0x72,
+ 0x61, 0xe6, 0x5c, 0x1e, 0x6e, 0x16, 0xf6, 0x8e, 0xb8, 0xfc, 0x47, 0x80,
+ 0x05, 0x4b, 0xf7, 0x2d, 0x02, 0xee, 0x50, 0x26, 0xd1, 0x48, 0x01, 0x60,
+ 0xdc, 0x3c, 0xa7, 0xdb, 0xeb, 0xca, 0x8b, 0xa6, 0xff, 0x9e, 0x47, 0x5d,
+ 0x87, 0x40, 0xf8, 0xd2, 0x82, 0xd7, 0x13, 0x64, 0x0e, 0xd4, 0xb3, 0x29,
+ 0x22, 0xa7, 0xe0, 0xc8, 0xcd, 0x8c, 0x4d, 0xf5, 0x11, 0x21, 0x26, 0x02,
+ 0x43, 0x33, 0x8e, 0xa9, 0x3f, 0x91, 0xd4, 0x05, 0x97, 0xc9, 0xd3, 0x42,
+ 0x6b, 0x05, 0x99, 0xf6, 0x16, 0x71, 0x67, 0x65, 0xc7, 0x96, 0xdf, 0x2a,
+ 0xd7, 0x54, 0x63, 0x25, 0xc0, 0x28, 0xf7, 0x1c, 0xee, 0xcd, 0x8b, 0xe4,
+ 0x9d, 0x32, 0xa3, 0x81, 0x55
+};
+
+// A certificate for www.paypal.com with a NULL byte in the common name.
+// From http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/70363
+unsigned char VARIABLE_IS_NOT_USED paypal_null_der[] = {
+ 0x30, 0x82, 0x06, 0x44, 0x30, 0x82, 0x05, 0xad, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x03, 0x00, 0xf0, 0x9b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x82, 0x01,
+ 0x12, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+ 0x45, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x09, 0x42, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x42, 0x61, 0x72,
+ 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x50, 0x53, 0x20, 0x43, 0x65, 0x72,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x73, 0x2e, 0x6c,
+ 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x25,
+ 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x43, 0x2e, 0x49, 0x2e, 0x46, 0x2e,
+ 0x20, 0x20, 0x42, 0x2d, 0x42, 0x36, 0x32, 0x32, 0x31, 0x30, 0x36, 0x39,
+ 0x35, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x25,
+ 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25,
+ 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
+ 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
+ 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30,
+ 0x34, 0x31, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x32, 0x32, 0x34,
+ 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a, 0x30, 0x81, 0x94, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x43, 0x61,
+ 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14,
+ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x53, 0x61, 0x6e, 0x20, 0x46,
+ 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72,
+ 0x69, 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
+ 0x13, 0x0b, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x55, 0x6e, 0x69,
+ 0x74, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26,
+ 0x77, 0x77, 0x77, 0x2e, 0x70, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x00, 0x73, 0x73, 0x6c, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72,
+ 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
+ 0x63, 0x63, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd2, 0x69, 0xfa, 0x6f, 0x3a,
+ 0x00, 0xb4, 0x21, 0x1b, 0xc8, 0xb1, 0x02, 0xd7, 0x3f, 0x19, 0xb2, 0xc4,
+ 0x6d, 0xb4, 0x54, 0xf8, 0x8b, 0x8a, 0xcc, 0xdb, 0x72, 0xc2, 0x9e, 0x3c,
+ 0x60, 0xb9, 0xc6, 0x91, 0x3d, 0x82, 0xb7, 0x7d, 0x99, 0xff, 0xd1, 0x29,
+ 0x84, 0xc1, 0x73, 0x53, 0x9c, 0x82, 0xdd, 0xfc, 0x24, 0x8c, 0x77, 0xd5,
+ 0x41, 0xf3, 0xe8, 0x1e, 0x42, 0xa1, 0xad, 0x2d, 0x9e, 0xff, 0x5b, 0x10,
+ 0x26, 0xce, 0x9d, 0x57, 0x17, 0x73, 0x16, 0x23, 0x38, 0xc8, 0xd6, 0xf1,
+ 0xba, 0xa3, 0x96, 0x5b, 0x16, 0x67, 0x4a, 0x4f, 0x73, 0x97, 0x3a, 0x4d,
+ 0x14, 0xa4, 0xf4, 0xe2, 0x3f, 0x8b, 0x05, 0x83, 0x42, 0xd1, 0xd0, 0xdc,
+ 0x2f, 0x7a, 0xe5, 0xb6, 0x10, 0xb2, 0x11, 0xc0, 0xdc, 0x21, 0x2a, 0x90,
+ 0xff, 0xae, 0x97, 0x71, 0x5a, 0x49, 0x81, 0xac, 0x40, 0xf3, 0x3b, 0xb8,
+ 0x59, 0xb2, 0x4f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03, 0x21,
+ 0x30, 0x82, 0x03, 0x1d, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
+ 0x02, 0x30, 0x00, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40, 0x30, 0x0b,
+ 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x03, 0xf8, 0x30,
+ 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d, 0x06, 0x03,
+ 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x61, 0x8f, 0x61, 0x34, 0x43,
+ 0x55, 0x14, 0x7f, 0x27, 0x09, 0xce, 0x4c, 0x8b, 0xea, 0x9b, 0x7b, 0x19,
+ 0x25, 0xbc, 0x6e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0x0e, 0x07, 0x60, 0xd4, 0x39, 0xc9, 0x1b, 0x5b,
+ 0x5d, 0x90, 0x7b, 0x23, 0xc8, 0xd2, 0x34, 0x9d, 0x4a, 0x9a, 0x46, 0x39,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x02, 0x30, 0x00, 0x30,
+ 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x12, 0x04, 0x15, 0x30, 0x13, 0x81, 0x11,
+ 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x72, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x65, 0x16, 0x63, 0x4f, 0x72,
+ 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49,
+ 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e,
+ 0x4f, 0x54, 0x20, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, 0x44,
+ 0x2e, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20,
+ 0x62, 0x79, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
+ 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x30, 0x2f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42,
+ 0x01, 0x02, 0x04, 0x22, 0x16, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30,
+ 0x32, 0x2f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+ 0x42, 0x01, 0x04, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73,
+ 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30,
+ 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32,
+ 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30,
+ 0x46, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x03,
+ 0x04, 0x39, 0x16, 0x37, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+ 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f,
+ 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x4c,
+ 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3f, 0x30,
+ 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x07,
+ 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+ 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f,
+ 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x43, 0x4c, 0x41, 0x53, 0x45,
+ 0x41, 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3f, 0x30, 0x41, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x34, 0x16,
+ 0x32, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68,
+ 0x74, 0x6d, 0x6c, 0x30, 0x81, 0x83, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
+ 0x7c, 0x30, 0x7a, 0x30, 0x39, 0xa0, 0x37, 0xa0, 0x35, 0x86, 0x33, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32,
+ 0x30, 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x3d, 0xa0, 0x3b, 0xa0, 0x39, 0x86, 0x37, 0x68, 0x74,
+ 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x62, 0x61, 0x63, 0x6b,
+ 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73,
+ 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+ 0x03, 0x81, 0x81, 0x00, 0x68, 0xee, 0x79, 0x97, 0x97, 0xdd, 0x3b, 0xef,
+ 0x16, 0x6a, 0x06, 0xf2, 0x14, 0x9a, 0x6e, 0xcd, 0x9e, 0x12, 0xf7, 0xaa,
+ 0x83, 0x10, 0xbd, 0xd1, 0x7c, 0x98, 0xfa, 0xc7, 0xae, 0xd4, 0x0e, 0x2c,
+ 0x9e, 0x38, 0x05, 0x9d, 0x52, 0x60, 0xa9, 0x99, 0x0a, 0x81, 0xb4, 0x98,
+ 0x90, 0x1d, 0xae, 0xbb, 0x4a, 0xd7, 0xb9, 0xdc, 0x88, 0x9e, 0x37, 0x78,
+ 0x41, 0x5b, 0xf7, 0x82, 0xa5, 0xf2, 0xba, 0x41, 0x25, 0x5a, 0x90, 0x1a,
+ 0x1e, 0x45, 0x38, 0xa1, 0x52, 0x58, 0x75, 0x94, 0x26, 0x44, 0xfb, 0x20,
+ 0x07, 0xba, 0x44, 0xcc, 0xe5, 0x4a, 0x2d, 0x72, 0x3f, 0x98, 0x47, 0xf6,
+ 0x26, 0xdc, 0x05, 0x46, 0x05, 0x07, 0x63, 0x21, 0xab, 0x46, 0x9b, 0x9c,
+ 0x78, 0xd5, 0x54, 0x5b, 0x3d, 0x0c, 0x1e, 0xc8, 0x64, 0x8c, 0xb5, 0x50,
+ 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43, 0x96, 0x07, 0xa8, 0xbb
+};
+
+// DER-encoded X.509 DistinguishedNames.
+//
+// To output the subject or issuer of a certificate:
+//
+// openssl asn1parse -i -inform DER -in <cert>
+//
+// The output will contain
+// SEQUENCE [This is the issuer name]
+// ...
+// SEQUENCE [This is the validity period]
+// UTCTIME (or GENERALTIME)
+// UTCTIME
+// SEQUENCE [This is the subject]
+// ...
+//
+// The OFFSET is the first column before the column, e.g. for '21:d=2', the
+// offset is 21 for the SEQUENCE you're interested in.
+// The LENGTH is 'hl + l'.
+//
+// To generate the table, then use the following for a DER-encoded
+// certificate:
+//
+// xxd -i -s $OFFSET -l $LENGTH <cert>
+//
+// For PEM certificates, convert them to DER before, as in:
+//
+// openssl x509 -inform PEM -outform DER -in <cert> |
+// xxd -i -s $OFFSET -l $LENGTH
+//
+
+// 0:d=0 hl=2 l= 95 cons: SEQUENCE
+// 2:d=1 hl=2 l= 11 cons: SET
+// 4:d=2 hl=2 l= 9 cons: SEQUENCE
+// 6:d=3 hl=2 l= 3 prim: OBJECT :countryName
+// 11:d=3 hl=2 l= 2 prim: PRINTABLESTRING :US
+// 15:d=1 hl=2 l= 23 cons: SET
+// 17:d=2 hl=2 l= 21 cons: SEQUENCE
+// 19:d=3 hl=2 l= 3 prim: OBJECT :organizationName
+// 24:d=3 hl=2 l= 14 prim: PRINTABLESTRING :VeriSign, Inc.
+// 40:d=1 hl=2 l= 55 cons: SET
+// 42:d=2 hl=2 l= 53 cons: SEQUENCE
+// 44:d=3 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+// 49:d=3 hl=2 l= 46 prim: PRINTABLESTRING :
+// Class 1 Public Primary Certification Authority
+const uint8 VARIABLE_IS_NOT_USED VerisignDN[] = {
+ 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20,
+ 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04,
+ 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x31, 0x20, 0x50,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72,
+ 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79
+};
+
+// 0:d=0 hl=2 l= 125 cons: SEQUENCE
+// 2:d=1 hl=2 l= 11 cons: SET
+// 4:d=2 hl=2 l= 9 cons: SEQUENCE
+// 6:d=3 hl=2 l= 3 prim: OBJECT :countryName
+// 11:d=3 hl=2 l= 2 prim: PRINTABLESTRING :IL
+// 15:d=1 hl=2 l= 22 cons: SET
+// 17:d=2 hl=2 l= 20 cons: SEQUENCE
+// 19:d=3 hl=2 l= 3 prim: OBJECT :organizationName
+// 24:d=3 hl=2 l= 13 prim: PRINTABLESTRING :StartCom Ltd.
+// 39:d=1 hl=2 l= 43 cons: SET
+// 41:d=2 hl=2 l= 41 cons: SEQUENCE
+// 43:d=3 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+// 48:d=3 hl=2 l= 34 prim: PRINTABLESTRING :
+// Secure Digital Certificate Signing
+// 84:d=1 hl=2 l= 41 cons: SET
+// 86:d=2 hl=2 l= 39 cons: SEQUENCE
+// 88:d=3 hl=2 l= 3 prim: OBJECT :commonName
+// 93:d=3 hl=2 l= 32 prim: PRINTABLESTRING :
+// StartCom Certification Authority
+const uint8 VARIABLE_IS_NOT_USED StartComDN[] = {
+ 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x0d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c,
+ 0x74, 0x64, 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b,
+ 0x13, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67,
+ 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67,
+ 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x53,
+ 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79
+};
+
+// 0:d=0 hl=3 l= 174 cons: SEQUENCE
+// 3:d=1 hl=2 l= 11 cons: SET
+// 5:d=2 hl=2 l= 9 cons: SEQUENCE
+// 7:d=3 hl=2 l= 3 prim: OBJECT :countryName
+// 12:d=3 hl=2 l= 2 prim: PRINTABLESTRING :US
+// 16:d=1 hl=2 l= 11 cons: SET
+// 18:d=2 hl=2 l= 9 cons: SEQUENCE
+// 20:d=3 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
+// 25:d=3 hl=2 l= 2 prim: PRINTABLESTRING :UT
+// 29:d=1 hl=2 l= 23 cons: SET
+// 31:d=2 hl=2 l= 21 cons: SEQUENCE
+// 33:d=3 hl=2 l= 3 prim: OBJECT :localityName
+// 38:d=3 hl=2 l= 14 prim: PRINTABLESTRING :Salt Lake City
+// 54:d=1 hl=2 l= 30 cons: SET
+// 56:d=2 hl=2 l= 28 cons: SEQUENCE
+// 58:d=3 hl=2 l= 3 prim: OBJECT :organizationName
+// 63:d=3 hl=2 l= 21 prim: PRINTABLESTRING :The USERTRUST Network
+// 86:d=1 hl=2 l= 33 cons: SET
+// 88:d=2 hl=2 l= 31 cons: SEQUENCE
+// 90:d=3 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+// 95:d=3 hl=2 l= 24 prim: PRINTABLESTRING :http://www.usertrust.com
+//121:d=1 hl=2 l= 54 cons: SET
+//123:d=2 hl=2 l= 52 cons: SEQUENCE
+//125:d=3 hl=2 l= 3 prim: OBJECT :commonName
+//130:d=3 hl=2 l= 45 prim: PRINTABLESTRING :
+// UTN-USERFirst-Client Authentication and Email
+const uint8 VARIABLE_IS_NOT_USED UserTrustDN[] = {
+ 0x30, 0x81, 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+ 0x04, 0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b,
+ 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45,
+ 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f,
+ 0x72, 0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+ 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
+ 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d,
+ 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
+ 0x74, 0x2d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x41, 0x75, 0x74,
+ 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x45, 0x6d, 0x61, 0x69, 0x6c
+};
+
+// 0:d=0 hl=3 l= 190 cons: SEQUENCE
+// 3:d=1 hl=2 l= 63 cons: SET
+// 5:d=2 hl=2 l= 61 cons: SEQUENCE
+// 7:d=3 hl=2 l= 3 prim: OBJECT :commonName
+// 12:d=3 hl=2 l= 54 prim: UTF8STRING :
+// TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
+// 68:d=1 hl=2 l= 11 cons: SET
+// 70:d=2 hl=2 l= 9 cons: SEQUENCE
+// 72:d=3 hl=2 l= 3 prim: OBJECT :countryName
+// 77:d=3 hl=2 l= 2 prim: PRINTABLESTRING :TR
+// 81:d=1 hl=2 l= 15 cons: SET
+// 83:d=2 hl=2 l= 13 cons: SEQUENCE
+// 85:d=3 hl=2 l= 3 prim: OBJECT :localityName
+// 90:d=3 hl=2 l= 6 prim: UTF8STRING :Ankara
+// 98:d=1 hl=2 l= 93 cons: SET
+//100:d=2 hl=2 l= 91 cons: SEQUENCE
+//102:d=3 hl=2 l= 3 prim: OBJECT :organizationName
+//107:d=3 hl=2 l= 84 prim: UTF8STRING :
+// TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
+// (c) Kasım 2005
+const uint8 VARIABLE_IS_NOT_USED TurkTrustDN[] = {
+ 0x30, 0x81, 0xbe, 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x0c, 0x36, 0x54, 0xc3, 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
+ 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x6b, 0x20,
+ 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
+ 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4, 0x9f, 0x6c, 0x61, 0x79,
+ 0xc4, 0xb1, 0x63, 0xc4, 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x52, 0x31, 0x0f, 0x30,
+ 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61,
+ 0x72, 0x61, 0x31, 0x5d, 0x30, 0x5b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+ 0x54, 0x54, 0xc3, 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
+ 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4, 0xb0, 0x6c, 0x65, 0x74, 0x69,
+ 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
+ 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3, 0xbc, 0x76, 0x65, 0x6e, 0x6c,
+ 0x69, 0xc4, 0x9f, 0x69, 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
+ 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e, 0x2e, 0x20, 0x28, 0x63,
+ 0x29, 0x20, 0x4b, 0x61, 0x73, 0xc4, 0xb1, 0x6d, 0x20, 0x32, 0x30, 0x30,
+ 0x35, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x35, 0x31, 0x31, 0x30, 0x37, 0x31,
+ 0x30, 0x30, 0x37, 0x35, 0x37
+};
+
+// 33:d=2 hl=3 l= 207 cons: SEQUENCE
+// 36:d=3 hl=2 l= 11 cons: SET
+// 38:d=4 hl=2 l= 9 cons: SEQUENCE
+// 40:d=5 hl=2 l= 3 prim: OBJECT :countryName
+// 45:d=5 hl=2 l= 2 prim: PRINTABLESTRING :AT
+// 49:d=3 hl=3 l= 139 cons: SET
+// 52:d=4 hl=3 l= 136 cons: SEQUENCE
+// 55:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+// 60:d=5 hl=3 l= 128 prim: BMPSTRING :
+// A-Trust Ges. für Sicherheitssysteme im elektr. Datenverkehr GmbH
+//191:d=3 hl=2 l= 24 cons: SET
+//193:d=4 hl=2 l= 22 cons: SEQUENCE
+//195:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+//200:d=5 hl=2 l= 15 prim: PRINTABLESTRING :A-Trust-Qual-01
+//217:d=3 hl=2 l= 24 cons: SET
+//219:d=4 hl=2 l= 22 cons: SEQUENCE
+//221:d=5 hl=2 l= 3 prim: OBJECT :commonName
+//226:d=5 hl=2 l= 15 prim: PRINTABLESTRING :A-Trust-Qual-01
+const uint8 VARIABLE_IS_NOT_USED ATrustQual01DN[] = {
+ 0x30, 0x81, 0xcf, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x54, 0x31, 0x81, 0x8b, 0x30, 0x81, 0x88, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x1e, 0x81, 0x80, 0x00, 0x41, 0x00, 0x2d, 0x00, 0x54,
+ 0x00, 0x72, 0x00, 0x75, 0x00, 0x73, 0x00, 0x74, 0x00, 0x20, 0x00, 0x47,
+ 0x00, 0x65, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x66, 0x00, 0xfc,
+ 0x00, 0x72, 0x00, 0x20, 0x00, 0x53, 0x00, 0x69, 0x00, 0x63, 0x00, 0x68,
+ 0x00, 0x65, 0x00, 0x72, 0x00, 0x68, 0x00, 0x65, 0x00, 0x69, 0x00, 0x74,
+ 0x00, 0x73, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65,
+ 0x00, 0x6d, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x20,
+ 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x72,
+ 0x00, 0x2e, 0x00, 0x20, 0x00, 0x44, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65,
+ 0x00, 0x6e, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x65,
+ 0x00, 0x68, 0x00, 0x72, 0x00, 0x20, 0x00, 0x47, 0x00, 0x6d, 0x00, 0x62,
+ 0x00, 0x48, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+ 0x0f, 0x41, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x51, 0x75, 0x61,
+ 0x6c, 0x2d, 0x30, 0x31, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x0f, 0x41, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x51,
+ 0x75, 0x61, 0x6c, 0x2d, 0x30, 0x31, 0x30, 0x1e, 0x17
+};
+
+// 34:d=2 hl=3 l= 180 cons: SEQUENCE
+// 37:d=3 hl=2 l= 20 cons: SET
+// 39:d=4 hl=2 l= 18 cons: SEQUENCE
+// 41:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+// 46:d=5 hl=2 l= 11 prim: PRINTABLESTRING :Entrust.net
+// 59:d=3 hl=2 l= 64 cons: SET
+// 61:d=4 hl=2 l= 62 cons: SEQUENCE
+// 63:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+// 68:d=5 hl=2 l= 55 prim: T61STRING :
+// www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)
+//125:d=3 hl=2 l= 37 cons: SET
+//127:d=4 hl=2 l= 35 cons: SEQUENCE
+//129:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+//134:d=5 hl=2 l= 28 prim: PRINTABLESTRING :
+// (c) 1999 Entrust.net Limited
+//164:d=3 hl=2 l= 51 cons: SET
+//166:d=4 hl=2 l= 49 cons: SEQUENCE
+//168:d=5 hl=2 l= 3 prim: OBJECT :commonName
+//173:d=5 hl=2 l= 42 prim: PRINTABLESTRING :
+// Entrust.net Certification Authority (2048)
+const uint8 VARIABLE_IS_NOT_USED EntrustDN[] = {
+ 0x30, 0x81, 0xb4, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x0b, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65,
+ 0x74, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x14, 0x37,
+ 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e,
+ 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38,
+ 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20,
+ 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73,
+ 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x31, 0x25, 0x30, 0x23, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39,
+ 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e,
+ 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x33,
+ 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74,
+ 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30,
+ 0x34, 0x38, 0x29
+};
+
+// 46:d=2 hl=2 l= 76 cons: SEQUENCE
+// 48:d=3 hl=2 l= 11 cons: SET
+// 50:d=4 hl=2 l= 9 cons: SEQUENCE
+// 52:d=5 hl=2 l= 3 prim: OBJECT :countryName
+// 57:d=5 hl=2 l= 2 prim: PRINTABLESTRING :ZA
+// 61:d=3 hl=2 l= 37 cons: SET
+// 63:d=4 hl=2 l= 35 cons: SEQUENCE
+// 65:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+// 70:d=5 hl=2 l= 28 prim: PRINTABLESTRING :
+// Thawte Consulting (Pty) Ltd.
+// 100:d=3 hl=2 l= 22 cons: SET
+// 102:d=4 hl=2 l= 20 cons: SEQUENCE
+// 104:d=5 hl=2 l= 3 prim: OBJECT :commonName
+// 109:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Thawte SGC CA
+const uint8 VARIABLE_IS_NOT_USED ThawteDN[] = {
+ 0x30, 0x4C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x5A, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A,
+ 0x13, 0x1C, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6F, 0x6E,
+ 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79,
+ 0x29, 0x20, 0x4C, 0x74, 0x64, 0x2E, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x0D, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+ 0x53, 0x47, 0x43, 0x20, 0x43, 0x41
+};
+
+// 47:d=2 hl=2 l= 108 cons: SEQUENCE
+// 49:d=3 hl=2 l= 11 cons: SET
+// 51:d=4 hl=2 l= 9 cons: SEQUENCE
+// 53:d=5 hl=2 l= 3 prim: OBJECT :countryName
+// 58:d=5 hl=2 l= 2 prim: PRINTABLESTRING :US
+// 62:d=3 hl=2 l= 22 cons: SET
+// 64:d=4 hl=2 l= 20 cons: SEQUENCE
+// 66:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
+// 71:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Massachusetts
+// 86:d=3 hl=2 l= 46 cons: SET
+// 88:d=4 hl=2 l= 44 cons: SEQUENCE
+// 90:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+// 95:d=5 hl=2 l= 37 prim: PRINTABLESTRING :
+// Massachusetts Institute of Technology
+// 134:d=3 hl=2 l= 21 cons: SET
+// 136:d=4 hl=2 l= 19 cons: SEQUENCE
+// 138:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+// 143:d=5 hl=2 l= 12 prim: PRINTABLESTRING :Client CA v1
+const uint8 VARIABLE_IS_NOT_USED MITDN[] = {
+ 0x30, 0x6C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0D, 0x4D, 0x61, 0x73, 0x73, 0x61, 0x63, 0x68, 0x75, 0x73, 0x65,
+ 0x74, 0x74, 0x73, 0x31, 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x0A,
+ 0x13, 0x25, 0x4D, 0x61, 0x73, 0x73, 0x61, 0x63, 0x68, 0x75, 0x73, 0x65,
+ 0x74, 0x74, 0x73, 0x20, 0x49, 0x6E, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74,
+ 0x65, 0x20, 0x6F, 0x66, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 0x6F, 0x6C,
+ 0x6F, 0x67, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0B,
+ 0x13, 0x0C, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x43, 0x41, 0x20,
+ 0x76, 0x31
+};
+
+} // namespace