autotest: Remove test_Recall and associated infrastructure

The test is unused.

BUG=chromium:356414
TEST=trybot on lumpy-release
CQ-DEPEND=CL:203107

Change-Id: Iaf06e727b4ee6fae9225d4f6a778d4f551d7874d
Reviewed-on: https://chromium-review.googlesource.com/203106
Reviewed-by: Scott James Remnant <keybuk@chromium.org>
Reviewed-by: Alex Miller <milleral@chromium.org>
Tested-by: Gaurav Shah <gauravsh@chromium.org>
Commit-Queue: Gaurav Shah <gauravsh@chromium.org>
diff --git a/client/cros/constants.py b/client/cros/constants.py
index 07c2423..f7a5068 100644
--- a/client/cros/constants.py
+++ b/client/cros/constants.py
@@ -136,9 +136,6 @@
 PENDING_SHUTDOWN_PATH = '/var/lib/crash_reporter/pending_clean_shutdown'
 UNCLEAN_SHUTDOWN_DETECTED_PATH = '/var/run/unclean-shutdown-detected'
 
-FAKE_ROOT_CA_DIR = '/etc/fake_root_ca'
-FAKE_NSSDB_DIR = FAKE_ROOT_CA_DIR + '/nssdb'
-
 INTERACTIVE_XMLRPC_SERVER_PORT = 9980
 INTERACTIVE_XMLRPC_SERVER_COMMAND = (
         'cd /usr/local/autotest/common_lib/cros; '
diff --git a/client/cros/recall.py b/client/cros/recall.py
deleted file mode 100644
index 859510d..0000000
--- a/client/cros/recall.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Context Manager for using Recall in autotest tests.
-
-Recall is a server-side system that intercepts DNS, HTTP and HTTPS
-traffic from clients for either recording or playback. This allows
-tests to be run in labs without Internet access by playing back
-pre-recorded copies of websites, allows tests to be run that use
-recorded copies of sites known to exhibit errors or many iterations
-of the same test to be run with the same data.
-
-Recall is intended to be completely transparent to the client tests,
-this context manager takes care of adjusting the client's configuration
-to redirect the traffic to the recall server (in the case it's not the
-network's default gateway already) and install a root certificate
-for HTTPS man-in-the-middling.
-
-It's instantiated as part of the control file sent from the autotest
-server when invoking the client tests.
-"""
-
-import logging, os, re, stat, subprocess, urllib2
-
-import common, constants
-from autotest_lib.client.common_lib import error
-
-
-class RecallServer(object):
-    """Context manager for adjusting client configuration for Recall.
-
-    Use this in a control file to wrap a client test to run against a
-    server using Recall:
-
-      with RecallServer(recall_server_ip):
-          job.run_test(...)
-
-    This is intended to be included in the control file passed from the
-    autotest server to the client to be run.
-    """
-
-    def __init__(self, recall_server_ip):
-        self._recall_server_ip = recall_server_ip
-
-    def __enter__(self):
-        certificate_url = ("http://%s/GetRootCertificate"
-                           % self._recall_server_ip)
-        self._InstallRootCertificate(certificate_url)
-        self._InstallDnsServer(self._recall_server_ip)
-        self._InstallDefaultRoute(self._recall_server_ip)
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self._UninstallRootCertificate()
-        self._UninstallDnsServer()
-        self._UninstallDefaultRoute()
-        return False
-
-    def _InstallRootCertificate(self, certificate_url):
-        """Download fake root cert from server and install.
-
-        Mounts a tmpfs filesystem over the location that Chromium will
-        look for an additional nssdb, downloads a root certificate from
-        the given URL and creates an nssdb containing it.
-
-        Args:
-            certificate_url: URL of certificate to download.
-        """
-        logging.debug("Obtaining certificate from %s", certificate_url)
-        f = urllib2.urlopen(certificate_url)
-        try:
-            certificate = f.read()
-        finally:
-            f.close()
-
-        logging.debug("Mounting tmpfs on %s", constants.FAKE_ROOT_CA_DIR)
-        cmd = ( 'mount', '-t', 'tmpfs', '-o', 'mode=0755', 'none',
-                constants.FAKE_ROOT_CA_DIR )
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to mount tmpfs")
-
-        logging.debug("Creating NSS database in %s", constants.FAKE_NSSDB_DIR)
-        os.mkdir(constants.FAKE_NSSDB_DIR, 0755)
-
-        cmd = ( 'certutil', '-d', 'sql:' + constants.FAKE_NSSDB_DIR,
-                '-N', '-f', '/dev/fd/0' )
-        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-        proc.communicate('\n')
-        if proc.returncode != 0:
-            raise error.TestError("Failed to create nssdb")
-
-        logging.debug("Adding certificate to database")
-        cmd = ( 'certutil', '-d', 'sql:' + constants.FAKE_NSSDB_DIR,
-                '-A', '-n', "Chromium OS Test Server", '-t', 'C,,', '-a' )
-        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-        proc.communicate(certificate)
-        if proc.returncode != 0:
-            raise error.TestError("Failed to add certificate to nssdb")
-
-        logging.debug("Fixing permissions")
-        for filename in os.listdir(constants.FAKE_NSSDB_DIR):
-            os.chmod(os.path.join(constants.FAKE_NSSDB_DIR, filename), 0644)
-
-    def _UninstallRootCertificate(self):
-        """Uninstall fake root cert.
-
-        Unmounts the tmpfs created by _InstallRootCertificate().
-        """
-        logging.info("Unmounting tmpfs from %s", constants.FAKE_ROOT_CA_DIR)
-        cmd = ( 'umount', '-l', constants.FAKE_ROOT_CA_DIR )
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to umount tmpfs")
-
-    def _InstallDnsServer(self, nameserver):
-        """Change the system DNS server.
-
-        Backs up and writes out an alternate /etc/resolv.conf pointing
-        at the nameserver given.
-
-        Args:
-            nameserver: IP address of server to use.
-        """
-        resolv_conf = os.path.realpath(constants.RESOLV_CONF_FILE)
-        resolv_conf_bak = resolv_conf + '.recallbak'
-        resolv_dir = os.path.dirname(resolv_conf)
-
-        logging.info("Changing nameserver to %s", nameserver)
-        os.rename(resolv_conf, resolv_conf_bak)
-        with open(resolv_conf, 'w') as resolv:
-            self._resolv_dir_mode = os.stat(resolv_dir).st_mode
-            os.chmod(resolv_dir, self._resolv_dir_mode & ~ (stat.S_IWUSR |
-                                                            stat.S_IWGRP |
-                                                            stat.S_IWOTH))
-
-            print >>resolv, "nameserver %s" % nameserver
-
-    def _UninstallDnsServer(self):
-        """Restore the system DNS server.
-
-        Restores the original /etc/resolv.conf from before calling
-        _InstallDnsServer().
-        """
-        resolv_conf = os.path.realpath(constants.RESOLV_CONF_FILE)
-        resolv_conf_bak = resolv_conf + '.recallbak'
-        resolv_dir = os.path.dirname(resolv_conf)
-
-        logging.info("Restoring original nameserver")
-        os.chmod(resolv_dir, self._resolv_dir_mode)
-        os.rename(resolv_conf_bak, resolv_conf)
-
-    def _GetDefaultRouteGateway(self):
-        """Return the gateway of the default route."""
-        cmd = ( 'ip', 'route', 'show' )
-        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-        data, errdata = proc.communicate()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to obtain routing table")
-
-        for line in data.splitlines():
-            if not line.startswith("default "):
-                continue
-
-            match = re.search(r'via ([^ ]*)', line)
-            if not match:
-                continue
-
-            return match.group(1)
-        else:
-            raise error.TestError("Failed to obtain default route gateway")
-
-    def _InstallDefaultRoute(self, gateway):
-        """Change the gateway of the default route.
-
-        Adjusts the system routing table so that the gateway of the
-        default route points to the IP address given.
-
-        Args:
-            gateway: IP address of new default route gateway.
-        """
-        self._original_gateway = self._GetDefaultRouteGateway()
-
-        logging.info("Changing default route gateway to %s", gateway)
-        cmd = ( 'ip', 'route', 'change', 'default', 'via', gateway )
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to change default route gateway")
-
-        cmd = ( 'ip', 'route', 'flush', 'cache')
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        # Discard return code, it doesn't matter so much if this fails
-
-    def _UninstallDefaultRoute(self):
-        """Restore the gateway of the default route.
-
-        Restores the gateway of the default route to that which existed
-        before calling _InstallDefaultRoute().
-        """
-        logging.info("Restoring original default route gateway")
-        cmd = ( 'ip', 'route', 'change', 'default', 'via',
-                self._original_gateway )
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to change default route gateway")
-
-        cmd = ( 'ip', 'route', 'flush', 'cache')
-        proc = subprocess.Popen(cmd)
-        proc.wait()
-        # Discard return code, it doesn't matter so much if this fails
diff --git a/client/site_tests/test_Recall/control b/client/site_tests/test_Recall/control
deleted file mode 100644
index 81e1dfd..0000000
--- a/client/site_tests/test_Recall/control
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-AUTHOR = "Chromium OS Project"
-NAME = "test_Recall"
-PURPOSE = "Verify the Recall client-side helper"
-CRITERIA = """
-This test will succeed as long as the RecallServer class adjusts the
-default route and DNS server of the client, and installs a root
-certificate.
-"""
-TIME = "SHORT"
-TEST_CATEGORY = "General"
-TEST_CLASS = "test"
-TEST_TYPE = "client"
-
-DOC = """
-This is a test to verify the autotest infrastructure for supporting
-Recall. It's implemented as a client test and not as a unit test because
-the RecallServer class makes changes to the system it's running on, and
-we don't want that to happen to the buildbots/your desktop.
-"""
-
-job.run_test('test_Recall')
diff --git a/client/site_tests/test_Recall/test_Recall.py b/client/site_tests/test_Recall/test_Recall.py
deleted file mode 100644
index 8fd3d9b..0000000
--- a/client/site_tests/test_Recall/test_Recall.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import httplib
-import os
-import re
-import stat
-import subprocess
-
-from autotest_lib.client.bin import test
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.cros import constants, httpd
-from autotest_lib.client.cros.recall import RecallServer
-
-class test_Recall(test.test):
-    version = 1
-
-    _certificate = """\
------BEGIN CERTIFICATE-----
-MIICejCCAeOgAwIBAgIJAJAMlNbcSCFeMA0GCSqGSIb3DQEBBQUAMDMxDzANBgNV
-BAoTBkdvb2dsZTEgMB4GA1UECxMXQ2hyb21pdW0gT1MgVGVzdCBTZXJ2ZXIwHhcN
-MTExMTEwMTk0NTQ0WhcNMTExMTExMTk0NTQ0WjAzMQ8wDQYDVQQKEwZHb29nbGUx
-IDAeBgNVBAsTF0Nocm9taXVtIE9TIFRlc3QgU2VydmVyMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQCc+gTR3R/OiY+AtZCsRI3CtHr+/7q8VRuci/rJU1R58OrX
-qEPZx/rck1fpAA3rpCkfv/T7tXbmzyTVJ8cPh9scC22hM8OKppZeZSlX2hA8uocW
-iheMkuUHcP+ya4z02GXNgUdLUiWSBfyme3cdHc5+Ugp1wrAOUkLG0Ya2x01I0QID
-AQABo4GVMIGSMB0GA1UdDgQWBBQtD9gOLzc5O9aW+74nZL/VGQHRDDBjBgNVHSME
-XDBagBQtD9gOLzc5O9aW+74nZL/VGQHRDKE3pDUwMzEPMA0GA1UEChMGR29vZ2xl
-MSAwHgYDVQQLExdDaHJvbWl1bSBPUyBUZXN0IFNlcnZlcoIJAJAMlNbcSCFeMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEACNNJsaj/lMlmbu+tQe67GUwl
-Cy68yHMFUmY6B2jBBhQLQlCVvB1HF3Tg0YGy9+OFBx00N2ysPRNhcuE2Hwv0mM4C
-UMfRd7zhQDCEKDqqsJFOOrgu/MJKo3qkJBoreE4lmlnrIyhYpkN1TwAz4jVUCklV
-7ZKxlI+3hii+ifNCPdU=
------END CERTIFICATE-----
-"""
-
-    def _respond_with_certificate(self, handler, url_args):
-        self._requested_certificate = True
-
-        handler.send_response(httplib.OK)
-        handler.send_header('Content-Type', 'text/plain')
-        handler.send_header('Content-Length', str(len(self._certificate)))
-        handler.end_headers()
-        handler.wfile.write(self._certificate)
-        handler.wfile.flush()
-
-    def initialize(self):
-        # Start a local web server (for the certificate fetch)
-        self._listener = httpd.HTTPListener(80, docroot=self.srcdir)
-        self._listener.add_url_handler('/GetRootCertificate',
-                                       self._respond_with_certificate)
-        self._listener.run()
-
-    def run_once(self):
-        self._requested_certificate = False
-
-        # Get the current state of things
-        orig_stat = os.stat(constants.FAKE_ROOT_CA_DIR)
-        orig_resolv = open(constants.RESOLV_CONF_FILE).read()
-
-        cmd = ( 'ip', 'route', 'show' )
-        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-        orig_routing_table, errdata = proc.communicate()
-        if proc.returncode != 0:
-            raise error.TestFail('Could not retrieve routing table')
-
-        # Run the test with the recall wrapper
-        with RecallServer('127.0.0.1'):
-            # Certificate much have been fetched from our http server
-            if not self._requested_certificate:
-                raise error.TestFail('Never requested certificate.')
-
-            # tmpfs must have been mounted over the root ca directory
-            test_stat = os.stat(constants.FAKE_ROOT_CA_DIR)
-            if (test_stat.st_ino, test_stat.st_dev) \
-                    == (orig_stat.st_ino, orig_stat.st_dev):
-                raise error.TestFail('Did not mount tmpfs over %s',
-                                     constants.FAKE_ROOT_CA_DIR)
-
-            # Certificate must be in the nssdb
-            cmd = ( 'certutil', '-d', 'sql:' + constants.FAKE_NSSDB_DIR,
-                    '-L', '-a', '-n', 'Chromium OS Test Server' )
-            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-            data, errdata = proc.communicate()
-            if proc.returncode != 0:
-                raise error.TestFail('Did not find certificate in nssdb')
-            if data.replace('\r', '') != self._certificate:
-                raise error.TestFail('Incorrect certificate in nssdb')
-
-            # DNS server must be changed to our IP
-            if open('/etc/resolv.conf').read() != 'nameserver 127.0.0.1\n':
-                raise error.TestFail('Nameserver not changed')
-
-            # Default route must have been changed
-            cmd = ( 'ip', 'route', 'show' )
-            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-            data, errdata = proc.communicate()
-            if proc.returncode != 0:
-                raise error.TestFail('Could not retrieve routing table')
-            for line in data.splitlines():
-                if not line.startswith("default "):
-                    continue
-                match = re.search(r'via ([^ ]*)', line)
-                if not match:
-                    continue
-                if match.group(1) != '127.0.0.1':
-                    raise error.TestFail('Default route gateway not changed')
-                break
-            else:
-                raise error.TestFail('No default route found')
-
-        # Mounted tmpfs must have been unmounted again
-        test_stat = os.stat(constants.FAKE_ROOT_CA_DIR)
-        if (test_stat.st_ino, test_stat.st_dev) \
-                != (orig_stat.st_ino, orig_stat.st_dev):
-            raise error.TestFail('Did not unmount tmpfs from %s',
-                                  constants.FAKE_ROOT_CA_DIR)
-
-        # DNS Resolver must have been restored
-        if open('/etc/resolv.conf').read() != orig_resolv:
-            raise error.TestFail('Nameserver settings not restored')
-
-        # Routing table must have been restored
-        cmd = ( 'ip', 'route', 'show' )
-        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-        data, errdata = proc.communicate()
-        if proc.returncode != 0:
-            raise error.TestFail('Could not retrieve routing table')
-        if data != orig_routing_table:
-            raise error.TestFail('Routing table not restored')
-
-    def cleanup(self):
-        self._listener.stop()
diff --git a/server/cros/recall/__init__.py b/server/cros/recall/__init__.py
deleted file mode 100644
index 0fb4020..0000000
--- a/server/cros/recall/__init__.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Recall server infrastructure.
-
-Recall is a server-side system that intercepts DNS, HTTP and HTTPS
-traffic from clients for recording, manipulation and playback. This
-allows tests to be run in labs without Internet access by playing back
-pre-recorded copies of websites, allows tests to be run that use
-recorded copies of sites known to exhibit errors or many iterations
-of the same test to be run with the same data.
-
-The server infrastructure consists of DNS, HTTP and HTTPS servers and
-a Certificate Authority that is used by the HTTPS server to generate
-certificates on the fly as needed.
-
-It also consists of DNS and HTTP clients, which are built in the
-middleware pattern. Each server has an associated client that it will
-use to fetch the necessary response. Clients can be stacked to build
-functionality, for example:
-
-    from autotest_lib.server.cros import recall
-    c = recall.ArchivingHTTPClient(
-          recall.DeterministicScriptInjector(
-              recall.HTTPClient()))
-
-This would create a client that after fetching the response from the
-Internet modifies it to inject JavaScript code to wrap Math.random()
-and Date() before finally archiving it. The order is important, since
-this means the archived response is already pre-mutated.
-
-To run an autotest client test on a remote machine wrapped in a
-Recall server instance for the most common use cases you only need use
-the pre-written test_RecallServer test.
-
-If you need to create a custom type of autotest server test, you can
-subclass that test from RecallServerTest to deal with the heavy lifting
-of reconfiguring the server to redirect traffic from the client.
-
-Finally, the classes in this module on their own are useful for building
-a standalone Recall server on a preconfigured system, perhaps with a DHCP
-server that already directs clients to it.
-"""
-
-# The code is split amongst multiple files for maintainability, this is
-# not intended to be exposed to other Python code, instead they should
-# treat it as a single module.
-#
-# This is correct:
-#   from autotest_lib.server.cros import recall
-# so is this:
-#   import autotest_lib.server.cros.recall
-#
-# But this is NOT:
-#   from autotest_lib.server.cros.recall import dns_server
-#
-# We use __all__ in each of the files so that the following only imports
-# the public API. This is a minor sprain of the coding style, but one that
-# aids usability of this package.
-from certificate_authority import *
-from dns_client import *
-from dns_server import *
-from http_client import *
-from http_server import *
-from middleware import *
diff --git a/server/cros/recall/certificate_authority.py b/server/cros/recall/certificate_authority.py
deleted file mode 100644
index 4019def..0000000
--- a/server/cros/recall/certificate_authority.py
+++ /dev/null
@@ -1,417 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Certificate Authority for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["CertificateAuthority"]
-
-import ConfigParser
-import logging
-import os
-import Queue
-import shutil
-import subprocess
-import tempfile
-import threading
-
-from cStringIO import StringIO
-
-
-class CertificateAuthority(threading.Thread):
-  """Certificate Authority for Recall server.
-
-  This class implements an OpenSSL Certificate Authority for use with
-  Recall, in particular the HTTPS server that utilises this class to
-  generate needed certificates on the fly.
-
-  Certificate Authority instances are picklable, the pickle will contain
-  the set of requested and completed hostnames and restoring the instance
-  from the pickle will create a new CA directory layout and generate
-  certificates asynchronously for them.
-
-  The authority must be initialized with a subject for the root
-  certificate, e.g. "/O=Google/OU=Test". The following member variables
-  are available:
-
-    directory: location on disk of the certificate authority.
-    private_key_file: location on disk of the CA private key file.
-    certificate_file: location on disk of the CA certificate file.
-
-  Certificates may be requested synchronously or asynchronously, using
-  ca.GetCertificateAndPrivateKey() issues a synchronous request and the
-  function will return the certificate and private keys when the
-  generation is complete.
-
-  Alternatively ca.RequestCertificateAndPrivateKey() merely begins
-  generation in the background, a later call to the former method is
-  required to obtain the keys by which point they will hopefully be
-  generated (if not, that call blocks until they are).
-
-  A typical use for this would be a DNSClient requesting certificate
-  generation so that by the time HTTPSServer gets the files, they are
-  already generated and it need not block.
-
-  The shutdown() method of the CA must be called to clean up.
-  """
-  logger = logging.getLogger("CertificateAuthority")
-
-  def __init__(self, subject, default_days=365):
-    super(CertificateAuthority, self).__init__()
-    self._subject = subject
-    self._default_days = default_days
-
-    self._SetupDirectory()
-    self._GenerateAuthorityCertificateAndPrivateKey(self._subject)
-
-    # We use a Queue to store the set of hostnames requested and also
-    # duplicate them in the _requested set so we can quickly lookup
-    # whether we need to block or queue a new incoming hostname.
-    #
-    # The _completed hash stores the set of generated certificates and
-    # private keys, when a new certificate is added to this hash the
-    # _changed Event is triggered to wake up the blockers.
-    #
-    # All of these structures are protected by a single lock.
-    self._queue = Queue.Queue()
-    self._requested = set()
-    self._completed = {}
-    self._lock = threading.Lock()
-    self._changed = threading.Event()
-
-    self.logger.info("Starting")
-    self.daemon = True
-    self.start()
-
-  def shutdown(self):
-    """Shut down the server.
-
-    This method must be called to clean up the CA directory and shut down
-    the worker thread.
-    """
-    # Place None in the queue to inform the thread to shutdown, and join
-    # to wait for it to do so.
-    self.logger.info("Shutting down")
-    self._queue.put(None)
-    self._queue.join()
-
-    if hasattr(self, 'directory'):
-      self._CleanupDirectory()
-    else:
-      self.logger.info("No directory to clean up")
-
-  def __getstate__(self):
-    state = {}
-    state['subject'] = self._subject
-    state['default_days'] = self._default_days
-    with self._lock:
-      state['certificates'] = set()
-      state['certificates'].update(self._completed.keys())
-      state['certificates'].update(self._requested)
-    return state
-
-  def __setstate__(self, state):
-    self.__init__(state['subject'], state['default_days'])
-
-    for hostname in state['certificates']:
-      self.GetCertificateAndPrivateKey(hostname)
-
-  def run(self):
-    """Worker thread method.
-
-    This is called by threading.Thread, it loops continuously taking new
-    requests from the queue and processing them.
-
-    Call shutdown() to stop the thread and exit.
-    """
-    while True:
-      # Queue.get() blocks forever, we place None in the queue in
-      # shutdown() to break out.
-      hostname = self._queue.get(block=True)
-      if hostname is None:
-        self._queue.task_done()
-        return
-
-      try:
-        self._ProcessRequest(hostname)
-      except:
-        self.logger.exception("Certificate generation failed")
-      finally:
-        self._queue.task_done()
-
-  def _SetupDirectory(self):
-    """Setup OpenSSL CA directory.
-
-    Create an OpenSSL Certificate Authority directory layout, including
-    the configuration file.
-    """
-    self.directory = tempfile.mkdtemp(prefix='CertificateAuthority')
-    self.logger.info("Creating certificate authority in %s", self.directory)
-
-    config = ConfigParser.RawConfigParser()
-    config.optionxform = str
-
-    config.add_section('ca')
-    config.set('ca', 'default_ca', 'CA_default')
-
-    config.add_section('CA_default')
-    config.set('CA_default', 'dir', self.directory)
-
-    self._certificate_dir = os.path.join(self.directory, 'certs')
-    os.mkdir(self._certificate_dir, 0700)
-    config.set('CA_default', 'certs', self._certificate_dir)
-
-    crl_dir = os.path.join(self.directory, 'crl')
-    os.mkdir(crl_dir, 0700)
-    config.set('CA_default', 'crl_dir', crl_dir)
-
-    newcerts_dir = os.path.join(self.directory, 'newcerts')
-    os.mkdir(newcerts_dir, 0700)
-    config.set('CA_default', 'new_certs_dir', newcerts_dir)
-
-    self._private_key_dir = os.path.join(self.directory, 'private')
-    os.mkdir(self._private_key_dir, 0700)
-
-    database_file = os.path.join(self.directory, 'index.txt')
-    open(database_file, 'w').close()
-    config.set('CA_default', 'database', database_file)
-
-    serial_file = os.path.join(self.directory, 'serial')
-    with open(serial_file, 'w') as serialfile:
-      print >>serialfile, '01'
-    config.set('CA_default', 'serial', serial_file)
-
-    self.certificate_file = os.path.join(self._certificate_dir, 'CA.pem')
-    config.set('CA_default', 'certificate', self.certificate_file)
-
-    self.private_key_file = os.path.join(self._private_key_dir, 'CA.key')
-    config.set('CA_default', 'private_key', self.private_key_file)
-
-    config.set('CA_default', 'name_opt', 'ca_default')
-    config.set('CA_default', 'cert_opt', 'ca_default')
-
-    config.set('CA_default', 'default_md', 'sha1')
-
-    config.set('CA_default', 'policy', 'policy_anything')
-
-    config.add_section('policy_anything')
-    config.set('policy_anything', 'countryName', 'optional')
-    config.set('policy_anything', 'stateOrProvinceName', 'optional')
-    config.set('policy_anything', 'localityName', 'optional')
-    config.set('policy_anything', 'organizationName', 'optional')
-    config.set('policy_anything', 'commonName', 'supplied')
-    config.set('policy_anything', 'emailAddress', 'optional')
-
-    self._config_file = os.path.join(self.directory, 'openssl.cnf')
-    with open(self._config_file, 'w') as configfile:
-      config.write(configfile)
-
-  def _CleanupDirectory(self):
-    """Cleanup OpenSSL directory
-
-    Remove the CA directory from the disk, undoes _SetupDirectory()
-    """
-    self.logger.info("Removing certificate authority directory")
-    shutil.rmtree(self.directory)
-
-  def _GenerateAuthorityCertificateAndPrivateKey(self, subject, days=None):
-    """Generate the CA certificate and private key.
-
-    Args:
-        subject: subject for the CA key request.
-        days: days key should be valid, defaults to that passed to constructor.
-
-    Returns:
-        tuple of certificate and private key filenames.
-    """
-    self.logger.info("Generating CA certificate and key for %s", subject)
-
-    cmd = ('openssl', 'req', '-x509', '-newkey', 'rsa:1024', '-nodes',
-           '-subj', subject,
-           '-days', '%d' % (days or self._default_days),
-           '-keyout', self.private_key_file,
-           '-out', self.certificate_file)
-    with tempfile.TemporaryFile() as output:
-      try:
-        subprocess.check_call(cmd, cwd=self.directory,
-                              stdout=output, stderr=output)
-      except subprocess.CalledProcessError:
-        output.seek(0)
-        self.logger.debug("openssl output:\n%s", output.read())
-        raise test.TestError("Failed to generate CA certificate and key")
-
-    os.chmod(self.private_key_file, 0400)
-
-    return self.certificate_file, self.private_key_file
-
-  def _GenerateCertificateRequestAndPrivateKey(self, basename, subject,
-                                               days=None):
-    """Generate a certificate request and private key.
-
-    Args:
-        basename: base for the filename (usually the hostname).
-        subject: subject for the certificate request.
-        days: days key should be valid, defaults to that passed to constructor.
-
-    Returns:
-        tuple of certificate request and private key filenames.
-    """
-    self.logger.info("Generate certificate request and key for %s in %s",
-                     subject, basename)
-    private_key_file = os.path.join(self._private_key_dir, '%s.key' % basename)
-    certificate_request_file = os.path.join(self.directory, '%s.csr' % basename)
-
-    cmd = ('openssl', 'req', '-new', '-newkey', 'rsa:1024', '-nodes',
-           '-subj', subject,
-           '-days', '%d' % (days or self._default_days),
-           '-keyout', private_key_file,
-           '-out', certificate_request_file)
-    with tempfile.TemporaryFile() as output:
-      try:
-        subprocess.check_call(cmd, cwd=self.directory,
-                              stdout=output, stderr=output)
-      except subprocess.CalledProcessError:
-        output.seek(0)
-        self.logger.debug("openssl output:\n%s", output.read())
-        raise test.TestError("Failed to generate certificate request for %s",
-                             subject)
-
-    os.chmod(self.private_key_file, 0400)
-
-    return certificate_request_file, private_key_file
-
-  def _SignCertificateRequest(self, certificate_request_file, days=None):
-    """Sign certificate request file.
-
-    Args:
-        certificate_request_file: filename of certificate request.
-        days: days certificate should be valid, defaults to that passed to
-              constructor.
-
-    Returns:
-        filename of certificate.
-    """
-    basename = os.path.splitext(os.path.basename(certificate_request_file))[0]
-    self.logger.info("Signing certificate request for %s", basename)
-
-    certificate_file = os.path.join(self._certificate_dir, '%s.pem' % basename)
-
-    cmd = ('openssl', 'ca', '-config', self._config_file, '-batch',
-           '-days', '%d' % (days or self._default_days),
-           '-out', certificate_file,
-           '-in', certificate_request_file)
-    with tempfile.TemporaryFile() as output:
-      try:
-        subprocess.check_call(cmd, cwd=self.directory,
-                              stdout=output, stderr=output)
-      except subprocess.CalledProcessError:
-        output.seek(0)
-        self.logger.debug("openssl output:\n%s", output.read())
-        raise test.TestError("Failed to sign certificate for %s", basename)
-
-    return certificate_file
-
-  def _GenerateCertificateAndPrivateKey(self, basename, subject, days=None):
-    """Generate a certificate and private key.
-
-    Args:
-        basename: base for the filename (usually the hostname).
-        subject: subject for the certificate.
-        days: days key should be valid, defaults to that passed to constructor.
-
-    Returns:
-        tuple of certificate and private key filenames.
-    """
-    certificate_request_file, private_key_file = \
-        self._GenerateCertificateRequestAndPrivateKey(basename, subject,
-                                                      days=days)
-    try:
-      certificate_file = self._SignCertificateRequest(
-          certificate_request_file, days=days)
-    except:
-      os.unlink(private_key_file)
-      raise
-    finally:
-      os.unlink(certificate_request_file)
-
-    return certificate_file, private_key_file
-
-  def RequestCertificateAndPrivateKey(self, hostname):
-    """Asynchronously request generation of certificate and private key.
-
-    This method returns immediately while the certificate and private key
-    are generated in the background by the worker thread, or if a
-    certificate and private key already exist for the hostname given.
-
-    To request the filenames, call GetCertificateAndPrivateKey()
-
-    Args:
-        hostname: hostname required.
-    """
-    with self._lock:
-      if hostname in self._requested \
-            or hostname in self._completed:
-        return
-
-      self._requested.add(hostname)
-      self._queue.put(hostname)
-
-  def GetCertificateAndPrivateKey(self, hostname):
-    """Retrieve certificate and private key.
-
-    Makes a synchronous request to obtain a certificate and private key
-    for the hostname given. If they have already been generated, for
-    example by a prior call to this method or to the
-    RequestCertificateAndPrivateKey() method, this returns immediately.
-
-    Otherwise this function will block until the worker thread has
-    generated the necessary keys, which may take some time depending
-    on available entropy.
-
-    Args:
-        hostname: hostname required.
-
-    Returns:
-        tuple of certificate and private key filenames.
-    """
-    while True:
-      with self._lock:
-        if hostname in self._completed:
-          certificate_file, private_key_file = self._completed[hostname]
-          return certificate_file, private_key_file
-        elif hostname not in self._requested:
-          self._requested.add(hostname)
-          self._queue.put(hostname)
-
-      # Wait for the _completed hash to change, and clear the event when
-      # it does. All threads are woken up simultaneously for each change.
-      self._changed.wait()
-      self._changed.clear()
-
-  def _ProcessRequest(self, hostname):
-    """Process a request.
-
-    Called from the worker thread to process a request, generates the
-    certificate request and private key, and then signs the request,
-    before placing the respective keys into the _completed hash and
-    waking up all threads.
-
-    Args:
-        hostname: hostname requested.
-    """
-    self.logger.debug("Received request for %s", hostname)
-    subject = "/CN=%s" % hostname
-
-    (certificate_file, private_key_file) \
-        = self._GenerateCertificateAndPrivateKey(hostname, subject)
-
-    with self._lock:
-      self._completed[hostname] = (certificate_file, private_key_file)
-      self._requested.remove(hostname)
-
-    self.logger.debug("Request for %s completed", hostname)
-    self._changed.set()
diff --git a/server/cros/recall/dns_client.py b/server/cros/recall/dns_client.py
deleted file mode 100644
index 93d1093..0000000
--- a/server/cros/recall/dns_client.py
+++ /dev/null
@@ -1,488 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""DNS Client classes for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["DNSRequest", "DNSResponse", "DNSClient", "DNSMiddleware",
-           "ArchivingDNSClient", "SymmetricDNSClient"]
-
-import logging
-import socket
-import struct
-import threading
-
-import dns.rdataclass
-import dns.rdatatype
-import dns.resolver
-
-
-class DNSMessage(object):
-  """Simple DNS Message object base class.
-
-  This class encapsulates the relatively complicated API of dnspython
-  into an instance that holds the relevant parts of a message together
-  and implements matching and hashing.
-
-  DNS Message objects are picklable.
-
-  Generally you instantiate either the DNSRequest or DNSResponse objects
-  rather than this base class.
-  """
-  def __init__(self, text, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN):
-    """Create a DNS Message.
-
-    Args:
-        text: text content of the record, e.g. IP address or hostname.
-        rdtype: data type of record, use a dns.rdatatype.* constant.
-        rdclass: data class of record, use a dns.rdataclass.* constant.
-    """
-    try:
-      self.text = text.to_text()
-    except AttributeError:
-      self.text = text
-    self.rdtype = rdtype
-    self.rdclass = rdclass
-
-  def __str__(self):
-    return "%s %s %s" % (dns.rdataclass.to_text(self.rdclass),
-                         dns.rdatatype.to_text(self.rdtype),
-                         self.text)
-
-  def __repr__(self):
-    return "<%s: %s>" % (self.__class__.__name__, str(self))
-
-  def __hash__(self):
-    return hash(repr((self.text, self.rdtype, self.rdclass)))
-
-  def __eq__(self, other):
-    if other.text != self.text:
-      return False
-    elif other.rdtype != self.rdtype:
-      return False
-    elif other.rdclass != self.rdclass:
-      return False
-    else:
-      return True
-
-  def IsAddress(self):
-    """Return whether this is an address message.
-
-    Returns:
-        True if the data class/type is IN A; for a Request that means this
-        is True for a request for an IP Address (ie. a hostname lookup),
-        for a Response that means this is True for a response containing
-        an IP Address for a hostname.
-
-        False otherwise.
-    """
-    return self.rdclass == dns.rdataclass.IN \
-        and self.rdtype == dns.rdatatype.A
-
-  def IsName(self):
-    """Return whether this is a name message.
-
-    Returns:
-        True if the data class/type is IN PTR; for a Request that means this
-        is True for a request for a hostname (ie. a reverse lookup), for a
-        Response that means this is True for a response containing a
-        hostname for an IP Address.
-
-        False otherwise.
-    """
-    return self.rdclass == dns.rdataclass.IN \
-        and self.rdtype == dns.rdatatype.PTR
-
-
-class DNSRequest(DNSMessage):
-  """Simple DNS Request object.
-
-  Encapsulates a DNS Request.
-  """
-  @classmethod
-  def ReverseLookup(cls, address):
-    """Create a DNS Request for a reverse lookup.
-
-    This class method constructor creates a DNSRequest object for a
-    given IP address that results in a reverse lookup.
-
-    i.e. DNSRequest.ReverseLookup('192.168.1.1') results in an instance
-    of <DNSRequest IN PTR 1.1.168.192.in-addr.arpa>
-
-    Args:
-        address: IP address in usual dotted form.
-
-    Returns:
-        newly created DNSRequest object.
-    """
-    text = '.'.join(reversed(address.split('.'))) + '.in-addr.arpa'
-    return cls(text, dns.rdatatype.PTR, dns.rdataclass.IN)
-
-
-class DNSResponse(DNSMessage):
-  """Simple DNS Response object.
-
-  Encapsulates a DNS Response.
-  """
-  pass
-
-
-class DNSClient(object):
-  """DNS Client for system resolver.
-
-  This class implements a DNS Client that uses the system resolver to
-  lookup the responses for DNSRequest objects. DNS Client objects are
-  picklable.
-
-  Example:
-      client = DNSClient()
-      request = DNSRequest('www.google.com')
-      for response in client(request):
-        ...
-  """
-  def __init__(self):
-    self._resolver = dns.resolver.get_default_resolver()
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    del state['_resolver']
-    return state
-
-  def __setstate__(self):
-    self.__dict__.update(state)
-
-    self._resolver = dns.resolver.get_default_resolver()
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        DNSResponse for each reply. No responses are yielded for NXDOMAIN.
-    """
-    try:
-      for answer in self._resolver.query(request.text,
-                                         request.rdtype, request.rdclass):
-        if answer.rdclass == dns.rdataclass.IN \
-              and answer.rdtype == dns.rdatatype.A:
-          text = answer.address
-        elif answer.rdtype == dns.rdatatype.PTR:
-          text = answer.target.to_text()
-        else:
-          continue
-
-        yield DNSResponse(text, answer.rdtype, answer.rdclass)
-    except dns.resolver.NXDOMAIN:
-      return
-
-
-class DNSMiddleware(object):
-  """Base class for DNS Client middleware.
-
-  This class is a base class for DNSClient-compatible classes that
-  accept a DNSClient argument to their constructor and surround it
-  with their own processing.
-
-  DNS Middleware options are picklable.
-
-  When creating your subclass, if it will work without a DNS Client
-  you can set the client_optional class member to True; an instance
-  may raise KeyError in the case where it cannot proceed further
-  without one.
-  """
-  client_optional = False
-
-  def __init__(self, dns_client=DNSClient()):
-    """Create the client middleware instance.
-
-    Args:
-        dns_client: DNS Client object to wrap, defaults to plain DNSClient()
-            and may be None if client_optional is True for the class.
-    """
-    self.dns_client = dns_client
-
-  @property
-  def dns_client(self):
-    return self._dns_client
-
-  @dns_client.setter
-  def dns_client(self, dns_client):
-    assert dns_client is not None or self.client_optional
-    self._dns_client = dns_client
-
-  @dns_client.deleter
-  def dns_client(self):
-    assert self.client_optional
-    self._dns_client = None
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Returns an archived response if one exists, otherwise uses the next
-    DNS Client in the middleware stack to resolve it, throwing KeyError
-    if no further client exists.
-
-    Subclasses should override this function replacing it with their
-    own, there is no need to call the superclass version.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        DNSResponse for each reply. No responses are yielded for NXDOMAIN.
-    """
-    if not self._dns_client:
-      raise KeyError
-
-    responses = self._dns_client(request)
-    for response in responses:
-      yield response
-
-
-class ArchivingDNSClient(DNSMiddleware):
-  """Archiving DNS Client middleware.
-
-  This DNS Client middleware wraps a DNS Client and archives all of its
-  responses. If a request is found in the archive, that is returned in
-  place of using the DNS Client given to the constructor.
-
-  The archive may be initialised with None as the DNS Client in which
-  case KeyError will be raised if the request is not found in the archive.
-
-  When using an HTTPS Server you should use SymmetricDNSClient instead.
-  """
-  client_optional = True
-
-  logger = logging.getLogger("ArchivingDNSClient")
-
-  def __init__(self, dns_client=DNSClient()):
-    super(ArchivingDNSClient, self).__init__(dns_client)
-
-    self._responses = {}
-    self._lock = threading.Lock()
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    del state['_lock']
-    return state
-
-  def __setstate__(self, state):
-    self.__dict__.update(state)
-
-    self._lock = threading.Lock()
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Returns an archived response if one exists, otherwise uses the next
-    DNS Client in the middleware stack to resolve it, throwing KeyError
-    if no further client exists.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        DNSResponse for each reply. No responses are yielded for NXDOMAIN.
-    """
-    try:
-      with self._lock:
-        for response in self._responses[request]:
-          yield response
-      self.logger.info("HIT  %s", request)
-    except KeyError:
-      self.logger.info("MISS %s", request)
-      if not self._dns_client:
-        raise
-
-      responses = self._dns_client(request)
-      with self._lock:
-        self._responses[request] = []
-        for response in responses:
-          self._responses[request].append(response)
-          yield response
-
-
-class SymmetricDNSClient(DNSMiddleware):
-  """Symmetric DNS Client middleware.
-
-  This DNS Client middleware wraps a DNS Client and ensures that all
-  responses are symmetric. I.e. a request for www.google.com will always
-  return the same IP Address, eliding any multiple responses, and
-  conversely no other request will return that same IP Address even if
-  it could potentially resolve.
-
-  The symmetricness allows the HTTPS Server to translate a destination
-  IP Address to only one possible hostname for certificate generation.
-
-  In the case where two hostnames resolve to only one IP Address, the
-  second to be looked up is given a fake IP Address in the 10/8 range.
-
-  An archive is kept of all responses and the class may be initialised
-  with None as the DNS Client in which case KeyError will be raised if
-  the request is not found in the archive.
-  """
-  client_optional = True
-
-  logger = logging.getLogger("SymmetricDNSClient")
-
-  def __init__(self, dns_client=DNSClient()):
-    super(SymmetricDNSClient, self).__init__(dns_client)
-
-    self._hostnames = {}
-    self._addresses = {}
-    self._reserve_addr = 0x0a000000
-    self._lock = threading.Lock()
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    del state['_lock']
-    return state
-
-  def __setstate__(self, state):
-    self.__dict__.update(state)
-
-    self._lock = threading.Lock()
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Returns an archived response if one exists, otherwise uses the next
-    DNS Client in the middleware stack to resolve it, throwing KeyError
-    if no further client exists.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        Single DNSResponse for the reply.
-        No responses are yielded for NXDOMAIN.
-    """
-    if request.IsAddress():
-      responses = self._LookupAddress(request)
-    elif request.IsName():
-      responses = self._LookupName(request)
-    else:
-      if not self._dns_client:
-        raise KeyError
-
-      self.logger.info("Fallback for request %s", request)
-      responses = self._dns_client(request)
-
-    for response in responses:
-      yield response
-
-  def _LookupAddress(self, request):
-    """Lookup an address request.
-
-    Translates a hostname into an IP Address, where this is the first
-    lookup for either, uses the next DNS Client in the stack to obtain
-    a real answer.
-
-    Ideally the first IP Address from the real answer that has not already
-    been returned for a different hostname is used. In the case where all
-    addresses from the real reply have been returned for other hostnames,
-    a fake IP address in the 10/8 range is returned.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        Single DNSResponse for the reply.
-        No responses are yielded for NXDOMAIN.
-    """
-    hostname = request.text.rstrip('.')
-
-    try:
-      with self._lock:
-        address = self._addresses[hostname]
-      self.logger.info("HIT  %s -> %s", hostname, address)
-    except KeyError:
-      if not self._dns_client:
-        self.logger.info("MISS  %s -> (no record)", hostname)
-        raise
-
-      responses = self._dns_client(request)
-      with self._lock:
-        nxdomain = True
-        for response in responses:
-          nxdomain = False
-
-          if response.IsAddress():
-            address = response.text
-            if address not in self._hostnames:
-              self.logger.info("MISS  %s -> %s (using client)",
-                               hostname, address)
-              break
-        else:
-          if nxdomain:
-            address = None
-            self.logger.info("MISS  %s -> NXDOMAIN", hostname)
-          else:
-            addr = self._reserve_addr = self._reserve_addr + 1
-            address = socket.inet_ntoa(struct.pack('!I', addr))
-            self.logger.info("MISS  %s -> %s (synthesised)", hostname, address)
-
-        self._addresses[hostname] = address
-        if address is not None:
-          self._hostnames[address] = hostname
-    if address is not None:
-      yield DNSResponse(address, dns.rdatatype.A, dns.rdataclass.IN)
-
-  def _LookupName(self, request):
-    """Lookup a hostname request.
-
-    Translates an IP Address into a hostname, where this is the first
-    lookup for either, uses the next DNS Client in the stack to obtain
-    a real answer.
-
-    The hostname/address pair is recorded so that a forward lookup for
-    the address of the hostname always returns the same result. If the
-    hostname has returned a different address previously, NXDOMAIN is
-    simulated for this lookup.
-
-    Args:
-        request: DNSRequest to lookup.
-
-    Yields:
-        Single DNSResponse for the reply.
-        No responses are yielded for NXDOMAIN.
-    """
-    in_addr = '.in-addr.arpa'
-    self.logger.debug('LookupName %r', request)
-    assert request.text.rstrip('.').endswith(in_addr)
-    address = '.'.join(
-        reversed(request.text.rstrip('.')[:-len(in_addr)].split('.')))
-
-    try:
-      with self._lock:
-        hostname = self._hostnames[address]
-      self.logger.info("HIT  %s -> %s", address, hostname)
-    except KeyError:
-      if not self._dns_client:
-        self.logger.info("MISS  %s -> (no record)", address)
-        raise
-
-      responses = self._dns_client(request)
-      with self._lock:
-        for response in responses:
-          if response.IsName():
-            hostname = response.text.rstrip('.')
-            if hostname not in self._addresses:
-              self.logger.info("MISS  %s -> %s (using client)",
-                               address, hostname)
-              break
-        else:
-          hostname = None
-          self.logger.info("MISS  %s -> NXDOMAIN", address)
-
-        self._hostnames[address] = hostname
-        if hostname is not None:
-          self._addresses[hostname] = address
-    if hostname is not None:
-      yield DNSResponse(hostname + '.', dns.rdatatype.PTR, dns.rdataclass.IN)
diff --git a/server/cros/recall/dns_server.py b/server/cros/recall/dns_server.py
deleted file mode 100644
index 134f223..0000000
--- a/server/cros/recall/dns_server.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""DNS Server classes for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["DNSServer", "DNSRequestHandler"]
-
-import logging
-import SocketServer
-import threading
-
-import dns.flags
-import dns.message
-import dns.opcode
-import dns.rdataclass
-import dns.rdatatype
-import dns.rrset
-
-from dns_client import DNSRequest, DNSClient
-
-
-class DNSServer(SocketServer.ThreadingUDPServer,
-                threading.Thread):
-  """Simple multithreaded DNS Server.
-
-  This class implements a multithreaded DNS Server that uses the DNS Client
-  passed to the constructor to resolve requests.
-
-  The shutdown() method must be called to clean up.
-  """
-  logger = logging.getLogger("DNSServer")
-
-  def __init__(self, server_address,
-               dns_client=DNSClient()):
-    SocketServer.ThreadingUDPServer.__init__(self, server_address,
-                                             DNSRequestHandler)
-    self.request_queue_size = 128
-
-    threading.Thread.__init__(self, target=self.serve_forever)
-
-    self.dns_client = dns_client
-
-    self.logger.info("Starting on %s", self.server_address)
-    self.daemon = True
-    self.start()
-
-  def shutdown(self):
-    """Shutdown the server."""
-    self.logger.info("Shutting down")
-    super(DNSServer, self).shutdown()
-
-
-class DNSRequestHandler(SocketServer.DatagramRequestHandler):
-  """Request handler for DNS Server.
-
-  Handles incoming DNS requests on behalf of DNSServer; the request
-  is converted to a DNSRequest object and a response obtained from the
-  DNSServer's dns_client member before being converted back to a
-  dnspython object and written to the client.
-  """
-  logger = logging.getLogger("DNSRequestHandler")
-
-  def _Error(self, query, opcode=dns.rcode.NOTIMP):
-    """Generate an Error response.
-
-    Generates and writes back an error response.
-
-    Args:
-        query: query to respond to.
-        opcode: dns.rcode.* member for error type.
-    """
-    response = dns.message.make_response(query)
-    response.flags |= dns.flags.RA | dns.flags.AA
-    response.set_rcode(opcode)
-    self.wfile.write(response.to_wire())
-
-  def handle(self):
-    """Handle the request."""
-    query = dns.message.from_wire(self.rfile.read())
-
-    if query.opcode() != dns.opcode.QUERY:
-      self.logger.debug("Ignored unhandled DNS message type: %s",
-                        dns.opcode.to_text(query.opcode))
-      return self._Error(query)
-
-    if len(query.question) > 1:
-      self.logger.debug("Ignored additional questions in DNS message")
-    if query.question[0].rdclass != dns.rdataclass.IN:
-      self.logger.debug("Ignored unhandled DNS query class: %s",
-                        dns.rdataclass.to_text(query.question[0].rdlcass))
-      return self._Error(query)
-    if query.question[0].rdtype != dns.rdatatype.A \
-          and query.question[0].rdtype != dns.rdatatype.PTR:
-      if query.question[0].rdtype != dns.rdatatype.AAAA: # IPv6 is hard
-        self.logger.debug("Ignored unhandled DNS query type: %s",
-                          dns.rdatatype.to_text(query.question[0].rdtype))
-
-      return self._Error(query)
-
-    reply = dns.message.make_response(query)
-    reply.flags |= dns.flags.RA | dns.flags.AA
-
-    request = DNSRequest(query.question[0].name,
-                         query.question[0].rdtype, query.question[0].rdclass)
-
-    try:
-      for response in self.server.dns_client(request):
-        reply.answer.append(dns.rrset.from_text(
-            query.question[0].name,
-            3600,
-            query.question[0].rdclass,
-            query.question[0].rdtype,
-            response.text))
-      if not len(reply.answer):
-        reply.set_rcode(dns.rcode.NXDOMAIN)
-    except KeyError:
-      reply.set_rcode(dns.rcode.NXDOMAIN)
-
-    self.wfile.write(reply.to_wire())
diff --git a/server/cros/recall/http_client.py b/server/cros/recall/http_client.py
deleted file mode 100644
index 88b079b..0000000
--- a/server/cros/recall/http_client.py
+++ /dev/null
@@ -1,578 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""HTTP Client classes for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["HTTPConnection", "HTTPSConnection", "HTTPRequest", "HTTPResponse",
-           "HTTPClient", "HTTPMiddleware", "ArchivingHTTPClient"]
-
-import httplib
-import logging
-import struct
-import threading
-import time
-import zlib
-
-
-class HTTPResponse(httplib.HTTPResponse):
-  """Recordable HTTP Response.
-
-  Subclasses the httplib.HTTPResponse class to add the ability to record
-  the data received from the server, the delay between chunks, modify data
-  recevied and pickle for later playback.
-  """
-
-  logger = logging.getLogger("HTTPResponse")
-
-  def __init__(self, *args, **kwds):
-    httplib.HTTPResponse.__init__(self, *args, **kwds)
-    self._mutate_functions = []
-    self._decompressor = None
-    self._compressor = None
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    if 'fp' in state:
-      del state['fp']
-    del state['_mutate_functions']
-    del state['_decompressor']
-    del state['_compressor']
-    return state
-
-  def __setstate__(self, state):
-    self.__dict__.update(state)
-
-    self._mutate_functions = []
-    self._decompressor = None
-    self._compressor = None
-
-  @property
-  def headers(self):
-    """List of (header, value) tuples.
-
-    Unlike the superclass, this doesn't merge duplicate headers since that
-    breaks cookies.
-    """
-    if self.msg is None:
-      raise httplib.ResponseNotReady()
-
-    self._headers = []
-    for line in self.msg.headers:
-      sep = line.index(':')
-      header = line[:sep].rstrip()
-      value = line[sep+1:].lstrip().rstrip('\r\n')
-      self._headers.append((header, value))
-
-    return self._headers
-
-  def _read_status(self):
-    """Read status line from server.
-
-    Wrapped to set the time we received the status line, which gets converted
-    to a delay by HTTPConnection.getresponse()
-    """
-    ret = httplib.HTTPResponse._read_status(self)
-    self._status_receive_time = time.time()
-    return ret
-
-  def AddMutateFunction(self, function):
-    """Add a function to mutate data chunks.
-
-    Must be called before the chunks property is accessed and before any
-    headers are sent.
-
-    Performing mutation on an HTTP Request drops the Content-Length
-    header from the request, requiring the server to generate it if
-    necessary. It also enforces on-the-fly decompression and
-    compression of the incoming chunks,
-    """
-    self._mutate_functions.append(function)
-    # Mutate functions means the length of the content may change;
-    # server must recalculate on the fly
-    del self.msg['Content-Length']
-
-    # It also means we have to decompress and compress again after
-    content_encoding = self.getheader('Content-Encoding')
-    if content_encoding in ('gzip', 'deflate'):
-      self.logger.debug("Will decompresss data in order to mutate")
-      if content_encoding == 'gzip':
-        self._decompressor = zlib.decompressobj(16 + zlib.MAX_WBITS)
-        self._compressor = HTTPGzipCompressor()
-      elif content_encoding == 'deflate':
-        self._decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
-        self._compressor = zlib.compressobj()
-
-  def _RecordChunk(self, chunk, last=False):
-    """Record and mutate chunk received from the server.
-
-    This method handles the decompression and recompression of chunks.
-    """
-    delay = time.time() - self.start_time
-    if self._decompressor:
-      chunk = self._decompressor.decompress(chunk)
-    for mutate_function in self._mutate_functions:
-      chunk = mutate_function(chunk)
-    if self._compressor:
-      chunk = self._compressor.compress(chunk)
-      if last:
-        chunk += self._compressor.flush(zlib.Z_FULL_FLUSH)
-        chunk += self._compressor.flush()
-      else:
-        chunk += self._compressor.flush(zlib.Z_SYNC_FLUSH)
-
-    self._chunks.append((delay, chunk))
-    return chunk
-
-  @property
-  def chunks(self):
-    """Read data chunks from server.
-
-    This yields each chunk, including the final empty chunk in the case of
-    chunked transfer-encoding and may sleep between calls to simulate the
-    delay between chunk receive times.
-    """
-    try:
-      # TODO(keybuk): this should probably record the time of the last call
-      # rather than just the delay
-      last_delay = 0.0
-      for delay, chunk in self._chunks:
-        time.sleep(delay - last_delay)
-        last_delay = delay
-        yield chunk
-    except AttributeError:
-      self._chunks = []
-
-      # (keybuk) non-chunked we just read the entire document as one chunk;
-      # this means that for streaming, there's a bit of a wait the first time
-      # since it has to reach the server first, but not when playing back
-      if not self.chunked:
-        yield self._RecordChunk(self.read(), last=True)
-        return
-
-      # (keybuk) this code is basically _read_chunked() from the superclass,
-      # simplified to always read everything, and to yield the final empty
-      # chunk since we need to send it to the client ourselves
-      chunk_len = None
-      while chunk_len != 0:
-        line = self.fp.readline()
-        i = line.find(';')
-        if i >= 0:
-          line = line[:i] # strip chunk-extensions
-        try:
-          chunk_len = int(line, 16)
-        except ValueError:
-          # close the connection as protocol synchronisation is
-          # probably lost
-          self.close()
-          raise httplib.IncompleteRead(''.join(value))
-
-        # (keybuk) we always want to yield the final empty chunk since we
-        # need to send it to the client anyway
-        yield self._RecordChunk(self._safe_read(chunk_len), last=(chunk_len==0))
-        self._safe_read(2)      # toss the CRLF at the end of the chunk
-
-      # we read everything; close the "file"
-      self.close()
-
-
-class HTTPGzipCompressor(object):
-  """Wrapper around zlib.Decompress to handle HTTP gzip compression.
-
-  We can't use the Python gzip module for this since it only encapsulates
-  files, and we can't subclass zlib.Decompress itself because that object
-  is "hidden".
-
-  This wrapper only implements the compress() and flush() methods, so
-  is equivalent to Python 2.4-era zlib
-  """
-
-  # see gzip.py _write_gzip_header() in the Python distribution
-  GZIP_HEADER = (
-    '\037\213'             # magic header
-    '\010'                 # compression method
-    '\000'                 # flags (none)
-    '\000\000\000\000'     # packed time (use zero)
-    '\002'
-    '\377')
-
-  def __init__(self):
-    # see gzip.py in the Python distribution
-    self._compressor = zlib.compressobj(
-        6, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)
-    self._crc = zlib.crc32('') & 0xffffffffL
-    self._size = 0
-    self._sent_header = False
-
-  def compress(self, string):
-    """Compress string, returning at least part of it.
-
-    Wraps zlib.Decompress.compress() prepending the gzip header for the
-    first chunk, and keeping track of the CRC and size of the compressed
-    data.
-
-    Args:
-        string: string to be compressed;
-    Returns:
-        string of compressed data forming at least part of string
-    """
-    chunk = self._compressor.compress(string)
-    if not self._sent_header:
-      chunk = self.GZIP_HEADER + chunk
-      self._sent_header = True
-
-    self._crc = zlib.crc32(string, self._crc) & 0xffffffffL
-    self._size += len(string)
-    return chunk
-
-  def flush(self, mode=zlib.Z_FINISH):
-    """Flush all pending input.
-
-    Wraps zlib.Decompress.flush(), when called without arguments or
-    with zlib.Z_FINISH, appends the CRC and size of the compressed data
-    as required for gzip files.
-
-    Args:
-        mode: see zlib.py documentation
-    Returns:
-        string of remaining compressed data;
-    """
-    chunk = self._compressor.flush(mode)
-    if mode == zlib.Z_FINISH:
-      chunk += struct.pack('<LL', long(self._crc), long(self._size))
-    return chunk
-
-
-class HTTPConnectionMixIn: # HTTPConnection is not an object
-  response_class = HTTPResponse
-
-  def getresponse(self):
-    """Get the response from the server.
-
-    Wraps httplib.HTTPConnection to set the response's start_time variable
-    used to caclulate the delay between chunks being received, and ensures
-    that status_delay is the time it took to receive the status code line.
-    """
-    start_time = time.time()
-    response = httplib.HTTPConnection.getresponse(self)
-    response.start_time = start_time
-    # calculate here since we can't set start_time before getresponse
-    response.status_delay = response._status_receive_time - start_time
-    return response
-
-class HTTPConnection(HTTPConnectionMixIn, httplib.HTTPConnection):
-  pass
-
-class HTTPSConnection(HTTPConnectionMixIn, httplib.HTTPSConnection):
-  pass
-
-
-class HTTPRequest(object):
-  """Recordable HTTP Request.
-
-  Companion request object for HTTPResponse that is picklable and hashable
-  so it can be used as a key to find the appropriate HTTPResponse object;
-  implements smart matching since some headers change, and some order
-  changes.
-
-  Because of this smart matching, one HTTPRequest object may in fact match
-  several recorded ones. You should therefore use an indirect lookup where
-  hashing an HTTPRequest in fact yields an array of matching requests and
-  their responses, and compare the request you're looking for with those
-  using MatchScore()
-  """
-
-  logger = logging.getLogger("HTTPRequest")
-
-  unmatchable_headers = [
-      'Accept',
-      'Accept-Charset',
-      'Accept-Encoding',
-      'Accept-Language',
-      'Cache-Control',
-      'Cookie', # special matching
-      'Connection',
-      'Keep-Alive',
-      'Pragma',
-      'Referer', # special matching
-      'User-Agent',
-      ]
-
-  def __init__(self, host, command, path, headers=[], body=None, ssl=False):
-    self.host = host
-    self.command = command
-    self.path = path
-    self.headers = headers
-    self.body = body
-    self.ssl = ssl
-
-    self._match_headers = self._MatchHeaders(self.headers)
-
-  def __str__(self):
-    return "%s %s://%s%s" % (self.command,
-                             self.ssl and 'https' or 'http',
-                             self.host, self.path)
-
-  def __repr__(self):
-    return "<%s: %s%r %s %r>" % (self.__class__.__name__,
-                                 self.ssl and '(SSL) ' or '',
-                                 self.host, self.command, self.path)
-
-  def __hash__(self):
-    return hash(repr((self.host, self.command, self.path, self._match_headers,
-                      self.body, self.ssl)))
-
-  def __eq__(self, other):
-    if other.host != self.host:
-      return False
-    elif other.command != self.command:
-      return False
-    elif other.ssl != self.ssl:
-      return False
-    elif other.path != self.path:
-      return False
-    elif other.body != self.body:
-      return False
-    elif other._match_headers != self._match_headers:
-      return False
-    else:
-      return True
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    del state['_match_headers']
-    return state
-
-  def __setstate__(self, state):
-    self.__dict__.update(state)
-    self._match_headers = self._MatchHeaders(state['headers'])
-
-  @classmethod
-  def _MatchHeaders(cls, headers):
-    match_headers = set()
-    for header, value in headers:
-      header = header.title()
-      if header in cls.unmatchable_headers:
-        continue
-      match_headers.add((header, value))
-    return match_headers
-
-  @property
-  def _cookies(self):
-    """Values of all cookies present in the request.
-
-    Returns all values from all Cookie headers, including those that provide
-    multiple values.
-    """
-    cookies = set()
-    for header, value in self.headers:
-      if header.title() == 'Cookie':
-        for cookie in value.split(';'):
-          cookies.add(cookie.strip())
-    return cookies
-
-  def getheader(self, name, default=None):
-    """Retrieve value of header."""
-    for header, value in self.headers:
-      if header.title() == name.title():
-        return value
-    else:
-      return default
-
-  def MatchScore(self, other):
-    """Compare request with another and return a match score.
-
-    The hash of an HTTPRequest object may match multiple other HTTPRequest
-    objects, in which case you should calculate the MatchScore of the request
-    you're seeking against those present and pick the highest one.
-    """
-    # These numbers are randomly picked and seem to work ok for now
-    score = len(self._cookies.intersection(other._cookies)) * 10
-    if self.getheader('referer') == other.getheader('referer'):
-      score += 1000
-    return score
-
-
-class HTTPClient(object):
-  """Generic HTTP Client.
-
-  This class implements an HTTP Client that fetches the results using
-  the Python httplib library. HTTP Client objects are picklable.
-
-  Example:
-      client = HTTPClient()
-      request = HTTPRequest('www.google.com', 'GET', '/')
-      response = client(request)
-  """
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Args:
-        request: HTTPRequest to lookup.
-
-    Returns:
-        HTTPResponse reply, which may include an error response.
-    """
-    if request.ssl:
-      connection = HTTPSConnection(request.host)
-    else:
-      connection = HTTPConnection(request.host)
-
-    connection.putrequest(request.command, request.path,
-                          skip_host=True,
-                          skip_accept_encoding=True)
-
-    send_host = True
-    send_accept_encoding = True
-
-    for header, value in request.headers:
-      if header.title() == 'Host':
-        send_host = False
-      elif header.title() == 'Accept-Encoding':
-        send_accept_encoding = False
-
-      connection.putheader(header, value)
-
-    if send_host:
-      connection.putheader('Host', request.host)
-    if send_accept_encoding:
-      connection.putheader('Accept-Encoding', '')
-
-    connection.endheaders()
-
-    if request.body is not None:
-      connection.send(request.body)
-
-    return connection.getresponse()
-
-
-class HTTPMiddleware(object):
-  """Base class for HTTP Client middleware.
-
-  This class is a base class for HTTPClient-compatible classes that
-  accept a HTTPClient argument to their constructor and surround it
-  with their own processing.
-
-  HTTP Middleware objects are picklable.
-
-  When creating your subclass, if it will work without a HTTP Client
-  you can set the client_optional class member to True; an instance
-  may raise KeyError in the case where it cannot proceed further
-  without one.
-  """
-  client_optional = False
-
-  def __init__(self, http_client=HTTPClient()):
-    """Create the client middleware instance.
-
-    Args:
-        http_client: HTTP Client object to wrap, defaults to plain HTTPClient()
-            and may be None if client_optional is True for the class.
-    """
-    self.http_client = http_client
-
-  @property
-  def http_client(self):
-    return self._http_client
-
-  @http_client.setter
-  def http_client(self, http_client):
-    assert http_client is not None or self.client_optional
-    self._http_client = http_client
-
-  @http_client.deleter
-  def http_client(self):
-    assert self.client_optional
-    self._http_client = None
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Subclasses should override this function replacing it with their
-    own, there is no need to call the superclass version.
-
-    Args:
-        request: HTTPRequest to lookup.
-
-    Returns:
-        HTTPResponse reply, which may include an error response.
-    """
-    if not self._http_client:
-      raise KeyError
-
-    response = self._http_client(request)
-    return response
-
-
-class ArchivingHTTPClient(HTTPMiddleware):
-  """Archiving HTTP Client middleware.
-
-  This HTTP Client middleware wraps an HTTP Client and archives all of its
-  responses. If a request is found in the archive, that is returned in
-  place of using the HTTP Client given to the constructor.
-
-  The archive may be initialised with None as the HTTP Client in which
-  case KeyError will be raised if the request is not found in the archive.
-
-  Matching is done using HTTPRequest smart matching.
-  """
-  client_optional = True
-
-  logger = logging.getLogger("ArchivingHTTPClient")
-
-  def __init__(self, http_client=HTTPClient()):
-    super(ArchivingHTTPClient, self).__init__(http_client)
-
-    self._responses = {}
-    self._lock = threading.Lock()
-
-  def __getstate__(self):
-    state = self.__dict__.copy()
-    del state['_lock']
-    return state
-
-  def __setstate__(self, state):
-    self.__dict__.update(state)
-
-    self._lock = threading.Lock()
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Returns an archived response if one exists, otherwise uses the next
-    HTTP Client in the middleware stack to resolve it, throwing KeyError
-    if no further client exists.
-
-    Args:
-        request: HTTPRequest to lookup.
-
-    Returns:
-        HTTPResponse reply, which may include an error response.
-    """
-    try:
-      with self._lock:
-        best_response, best_score = None, 0
-        for original_request, response in self._responses[request]:
-          score = request.MatchScore(original_request)
-          if score >= best_score:
-            best_response, best_score = response, score
-
-      self.logger.info("HIT  %s", request)
-      return best_response
-    except KeyError:
-      self.logger.info("MISS %s", request)
-      if not self._http_client:
-        raise
-
-      response = self._http_client(request)
-      with self._lock:
-        try:
-          self._responses[request].append((request, response))
-        except KeyError:
-          self._responses[request] = [ (request, response) ]
-      return response
diff --git a/server/cros/recall/http_server.py b/server/cros/recall/http_server.py
deleted file mode 100644
index a347f55..0000000
--- a/server/cros/recall/http_server.py
+++ /dev/null
@@ -1,328 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""HTTP Server classes for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["HTTPServer", "HTTPSServer", "HTTPRequestHandler"]
-
-import BaseHTTPServer
-import fnmatch
-import httplib
-import logging
-import SocketServer
-import ssl
-import tempfile
-import threading
-
-import socket_util
-from certificate_authority import CertificateAuthority
-from dns_client import DNSRequest, DNSClient
-from http_client import HTTPRequest, HTTPClient
-
-
-def _GetHostnameForAddress(dns_client, address):
-  """Get the hostname for an address.
-
-  Utility function that uses a DNS Client to perform a reverse lookup
-  and returns the hostname without trailing periods.
-  """
-  for hostname in dns_client(DNSRequest.ReverseLookup(address)):
-    return hostname.text.rstrip('.')
-  else:
-    return None
-
-
-class HTTPServer(SocketServer.ThreadingMixIn,
-                 BaseHTTPServer.HTTPServer,
-                 threading.Thread):
-  """Simple multithreaded HTTP Server.
-
-  This class implements a multithreaded HTTP Server that uses the HTTP Client
-  passed to the constructor to resolve requests. For consistency with the
-  HTTPSServer class, the constructor also accepts DNS Client and
-  Certificate Authority arguments, though these will not be used.
-
-  The shutdown() method must be called to clean up.
-  """
-  logger = logging.getLogger("HTTPServer")
-
-  ssl = False
-
-  def __init__(self, server_address,
-               http_client=HTTPClient(),
-               dns_client=DNSClient(),
-               certificate_authority=None):
-    BaseHTTPServer.HTTPServer.__init__(self, server_address, HTTPRequestHandler)
-    self.request_queue_size = 128
-
-    threading.Thread.__init__(self, target=self.serve_forever)
-
-    self.http_client = http_client
-    self.dns_client = dns_client
-    self.certificate_authority = certificate_authority
-
-    self.logger.info("Starting on %s", self.server_address)
-    self.daemon = True
-    self.start()
-
-  def shutdown(self):
-    """Shutdown the server."""
-    self.logger.info("Shutting down")
-    super(HTTPServer, self).shutdown()
-
-
-class HTTPSServer(SocketServer.ThreadingMixIn,
-                  BaseHTTPServer.HTTPServer,
-                  threading.Thread):
-  """Multithreaded HTTPS Server.
-
-  This class implements a multithreaded HTTPS Server that uses the HTTP Client
-  passed to the constructor to resolve requests. The original destination
-  address of incoming connections is resolved to a hostname using the passed
-  DNS Client, and a certificate generated using the passed Certificate
-  Authority.
-
-  For best results, the DNS Client should be the SymmetricDNSClient class.
-
-  The shutdown() method must be called to clean up.
-  """
-  logger = logging.getLogger("HTTPSServer")
-
-  ssl = True
-
-  def __init__(self, server_address,
-               http_client=HTTPClient(),
-               dns_client=DNSClient(),
-               certificate_authority=None):
-    BaseHTTPServer.HTTPServer.__init__(self, server_address, HTTPRequestHandler)
-    self.request_queue_size = 128
-
-    threading.Thread.__init__(self, target=self.serve_forever)
-
-    self.http_client = http_client
-    self.dns_client = dns_client
-    self.certificate_authority = certificate_authority
-
-    self.logger.info("Starting on %s", self.server_address)
-    self.daemon = True
-    self.start()
-
-  def shutdown(self):
-    """Shutdown the server."""
-    self.logger.info("Shutting down")
-    super(HTTPSServer, self).shutdown()
-
-  def get_request(self):
-    """Accept incoming request.
-
-    Looks up the original destination of the address and resolves that to
-    a hostname using the DNS Client passed to the constructor. Certificates
-    and Private Keys are obtained from the class Certificate Authority,
-    and each connection is individually wrapped through SSL.
-    """
-    (conn, address) = self.socket.accept()
-    self.logger.debug("Accepted request from %s:%d", address[0], address[1])
-
-    try:
-      original_address, original_port \
-          = socket_util.GetOriginalDestinationAddress(conn)
-
-      certificate_hostname = _GetHostnameForAddress(self.dns_client,
-                                                    original_address)
-      if certificate_hostname is None:
-        certificate_hostname = original_address
-
-      self.logger.debug("Original destination %s:%d; using certificate for %s",
-                        original_address, original_port, certificate_hostname)
-    except (TypeError, KeyError):
-      certificate_hostname = self.server_name
-      self.logger.warn("Using our own certificate for this request")
-
-    (certificate_file, private_key_file) = \
-        self.certificate_authority.GetCertificateAndPrivateKey(
-            certificate_hostname)
-
-    return (ssl.wrap_socket(conn, server_side=True,
-                            certfile=certificate_file,
-                            keyfile=private_key_file),
-            address)
-
-
-class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-  """Request handler for HTTP and HTTPS Servers.
-
-  Handles incoming HTTP requests on behalf of HTTPServer and HTTPSServer
-  (distinguished by their ssl members). The request is converted to an
-  HTTPRequest object and a response obtained from the server's http_client
-  member before being sent back to the client.
-
-  Additionally if the incoming request is directed at the server itself,
-  the first element of the path may be a function local to this class in
-  which case it is run to generate the response.
-  """
-
-  protocol_version = 'HTTP/1.1'
-
-  # Turn on buffering, we explicitly flush where we need to
-  wbufsize = -1
-
-  def __init__(self, request, client_address, server):
-    self.logger = logging.getLogger("HTTPRequestHandler:%s:%d"
-                                   % (client_address[0], client_address[1]))
-
-    BaseHTTPServer.BaseHTTPRequestHandler.__init__(
-        self, request, client_address, server)
-
-  def log_request(self, code='-', size='-'):
-    # we do our own request logging
-    pass
-
-  # reformat other log messages to our own logger
-  def log_error(self, format, *args):
-    self.logger.error(format, *args)
-  def log_message(self, format, *args):
-    self.logger.info(format, *args)
-
-  # handle all methods the same way
-  def do_HEAD(self):
-    self._HandleRequest()
-  def do_GET(self):
-    self._HandleRequest()
-  def do_POST(self):
-    self._HandleRequest()
-
-  def _RequestIsForSelf(self):
-    """Check whether the request is for our server name or IP Address.
-
-    Returns:
-        True if request is for us, False otherwise.
-    """
-    server_aliases = [ self.server.server_name, self.request.getsockname()[0] ]
-    try:
-      sep = self.server.server_name.index('.')
-      server_aliases.append(self.server.server_name[:sep])
-    except ValueError:
-      pass
-
-    return self.host.split(':')[0] in server_aliases
-
-  def _HandleRequest(self):
-    """Handle the request."""
-    # Lookup the hostname
-    self.host = self.headers.get('host', None)
-    if not self.host:
-      try:
-        original_address, original_port \
-            = socket_util.GetOriginalDestinationAddress(self.request)
-
-        hostname = _GetHostnameForAddress(self.server.dns_client,
-                                          original_address)
-        if hostname:
-          self.host = '%s:%d' % (hostname, original_port)
-        else:
-          self.host = '%s:%d' % (original_address, original_port)
-
-        self.logger.debug("Missing Host header in request, used %s", self.host)
-      except TypeError:
-        return self._Error("Missing Host header in request, "
-                           "and can't obtain original destination")
-
-    # Handle requests for our own host
-    if self._RequestIsForSelf():
-      command = self.path[1:].split('/')
-      try:
-        return getattr(self, command[0])(*command[1:])
-      except AttributeError:
-        return self._Error("Unknown command %s" % command[0])
-      except TypeError, e:
-        return self._Error(str(e))
-
-    content_length = int(self.headers.get('Content-Length', 0))
-    if content_length:
-      body = self.rfile.read(content_length)
-    else:
-      body = None
-
-    request = HTTPRequest(self.host, self.command, self.path,
-                          self.headers.items(), body,
-                          self.server.ssl)
-
-    try:
-      response = self.server.http_client(request)
-    except KeyError:
-      return self._Error("Not found in archive", 404)
-
-    if response.version == 10:
-      self.protocol_version = 'HTTP/1.0'
-    self.send_response(response.status, response.reason)
-
-    sent_content_length = False
-    for header, value in response.headers:
-      self.send_header(header, value)
-      if header.title() == 'Content-Length':
-        sent_content_length = True
-
-    # Sometimes we need to send the content-length header ourselves; in those
-    # cases delay ending the headers until we receive the data from the server
-    if response.chunked or sent_content_length:
-      self.end_headers()
-      self.wfile.flush()
-    else:
-      self.logger.debug("Will send Content-Length later")
-
-    for chunk in response.chunks:
-      if response.chunked:
-        self.wfile.write('%x\r\n%s\r\n' % (len(chunk), chunk))
-      else:
-        if not sent_content_length:
-          self.send_header('Content-Length', str(len(chunk)))
-          self.end_headers()
-          sent_content_length = True
-        self.wfile.write(chunk)
-      self.wfile.flush()
-
-    # Should never happen, but let's be careful
-    if not response.chunked and not sent_content_length:
-      self.logger.debug("Handled empty request")
-      self.send_header('Content-Length', '0')
-      self.end_headers()
-      self.wfile.flush()
-
-    if response.version == 10:
-      self.close_connection = 1
-
-  def GetRootCertificate(self):
-    """Generate a response with the CA's certificate.
-
-    Command intended for use by clients, writes back the attached CA's
-    root certificate.
-    """
-    with open(self.server.certificate_authority.certificate_file) \
-          as cert:
-      certificate = cert.read()
-
-    self.send_response(httplib.OK)
-    self.send_header('Content-Type', 'text/plain')
-    self.send_header('Content-Length', str(len(certificate)))
-    self.end_headers()
-    self.wfile.write(certificate)
-    self.wfile.flush()
-
-  def _Error(self, message, code=httplib.INTERNAL_SERVER_ERROR):
-    """Reply with an error.
-
-    Generates an error reply and returns it to the client.
-    """
-    self.logger.warn(message)
-
-    self.send_response(code)
-    self.send_header('Content-Type', 'text/plain')
-    self.send_header('Content-Length', str(len(message)))
-    self.end_headers()
-    self.wfile.write(message)
-    self.wfile.flush()
diff --git a/server/cros/recall/middleware.py b/server/cros/recall/middleware.py
deleted file mode 100644
index 13341a9..0000000
--- a/server/cros/recall/middleware.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Middleware classes for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["DeterministicScriptInjector"]
-
-import logging
-import re
-
-from http_client import HTTPClient, HTTPMiddleware
-
-
-class DeterministicScriptInjector(HTTPMiddleware):
-  """Mutate HTTP Requests to inject Deterministic JavaScript code.
-
-  Implements HTTP Client middleware that alters text/html responses,
-  inserting a <script> block to the top of the page that replaces the
-  JavaScript Math.random() and Date() functions for deterministic
-  behaviour.
-
-  The Date() replacement uses the original request time as the returned
-  value, to avoid issues where scripts loop while the date remains the
-  same, the date is incremented between calls. However since scripts may
-  be executed out of order, the date is only incremented every
-  date_count_threshold calls.
-  """
-  logger = logging.getLogger("DeterministicScriptInjector")
-
-  _html_re = re.compile(r'<html[^>]*>', re.IGNORECASE)
-  _head_re = re.compile(r'<head[^>]*>', re.IGNORECASE)
-  _body_re = re.compile(r'<body[^>]*>', re.IGNORECASE)
-
-  _deterministic_script = """\
-<script>
-  (function () {
-    var orig_date = Date;
-    var random_count = 0;
-    var date_count = 0;
-    var random_seed = 0.462;
-    var time_seed = @@START_TIME@@;
-    var random_count_threshold = 25;
-    var date_count_threshold = 25;
-    Math.random = function() {
-      random_count++;
-      if (random_count > random_count_threshold){
-        random_seed += 0.1;
-        random_count = 1;
-      }
-      return (random_seed % 1);
-    };
-    Date = function() {
-      if (this instanceof Date) {
-        date_count++;
-        if (date_count > date_count_threshold){
-          time_seed += 50;
-          date_count = 1;
-        }
-        switch (arguments.length) {
-        case 0: return new orig_date(time_seed);
-        case 1: return new orig_date(arguments[0]);
-        default: return new orig_date(arguments[0], arguments[1],
-           arguments.length >= 3 ? arguments[2] : 1,
-           arguments.length >= 4 ? arguments[3] : 0,
-           arguments.length >= 5 ? arguments[4] : 0,
-           arguments.length >= 6 ? arguments[5] : 0,
-           arguments.length >= 7 ? arguments[6] : 0);
-        }
-      }
-      return new Date().toString();
-    };
-    Date.__proto__ = orig_date;
-    Date.prototype.constructor = Date;
-    orig_date.now = function() {
-      return new Date().getTime();
-    };
-  })();
-</script>
-"""
-
-  def __call__(self, request):
-    """Lookup the request.
-
-    Args:
-        request: HTTPRequest to lookup.
-
-    Returns:
-        HTTPResponse reply, which may include an error response.
-    """
-    response = self.http_client(request)
-
-    content_type = response.getheader('Content-Type')
-    if content_type and content_type.startswith('text/html'):
-      self.logger.debug("Will inject script into %r for %s", response, request)
-
-      start_time = int(response.start_time * 1000)
-      self._inject_script = self._deterministic_script.replace(
-          '@@START_TIME@@', str(start_time))
-      response.AddMutateFunction(self._MutateChunk)
-
-    return response
-
-  def _InjectScriptAfter(self, match):
-    return match.group(0) + self._inject_script
-
-  def _MutateChunk(self, chunk):
-    if self._inject_script:
-      count = 0
-      if chunk:
-        chunk, count = self._head_re.subn(self._InjectScriptAfter, chunk, 1)
-        if count:
-          self.logger.debug("Injected script into HEAD")
-          self._inject_script = None
-        else:
-          chunk, count = self._body_re.subn(self._InjectScriptAfter, chunk, 1)
-          if count:
-            self.logger.debug("Injected script into BODY")
-            self._inject_script = None
-
-    return chunk
diff --git a/server/cros/recall/socket_util.py b/server/cros/recall/socket_util.py
deleted file mode 100644
index 558dcac..0000000
--- a/server/cros/recall/socket_util.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Socket utilities for Recall server.
-
-This module should not be imported directly, instead the public classes
-are imported directly into the top-level recall package.
-"""
-
-__all__ = ["GetOriginalDestinationAddress"]
-
-import socket
-import struct
-
-
-SO_ORIGINAL_DST = 80
-SOCKADDR_IN = "!2xH4s8x"
-SOCKADDR_IN_LEN = 16
-
-def GetOriginalDestinationAddress(conn):
-  """Get the original destination address of a connection.
-
-  When connections undergo iptables redirection, the kernel stores the
-  original destination address and port as a socket option. This method
-  retrieves that.
-
-  Args:
-      conn: Socket to lookup.
-
-  Returns:
-      tuple of original address as string and port as integer
-      or None if no original destination was found.
-  """
-  try:
-    original_dst_addr \
-        = conn.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, SOCKADDR_IN_LEN)
-    original_port, original_in_addr \
-        = struct.unpack(SOCKADDR_IN, original_dst_addr)
-    original_addr = socket.inet_ntoa(original_in_addr)
-
-    return original_addr, original_port
-  except Exception, e:
-    return None
diff --git a/server/cros/recall_test.py b/server/cros/recall_test.py
deleted file mode 100644
index 2d53784..0000000
--- a/server/cros/recall_test.py
+++ /dev/null
@@ -1,291 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Base class for Recall tests.
-
-Recall provides an infrastructure for proxying, recording, altering and
-playing back DNS, HTTP and HTTPS requests.
-
-This requires that an autotest server test be run, with some configuration
-changes to the server, and then the desired client test run on the client
-wrapped with the Recall context manager.
-
-The server test base class provided handles most of the heavy lifting for
-you. For an example server test, see test_RecallServer that implements the
-common case of recording and playback.
-"""
-
-import errno
-import logging
-import os
-import re
-import subprocess
-
-from autotest_lib.client.common_lib import error
-from autotest_lib.server import test, autotest
-from autotest_lib.server.cros import recall
-
-
-class RecallServerTest(test.test):
-    """AutoTest test class for Recall tests.
-
-    This base class handles adjusting the autotest server configuration
-    to allow redirection of traffic from the remote client to it, and
-    cleaning up afterwards.
-
-    Subclasses should override the initialize method and setup the
-    following members before calling the superclass method:
-
-        certificate_authority: instance of recall.CertificateAuthority to
-            use to generate or retrieve certificates.
-        dns_client: instance of recall.DNSClient or compatible class to
-            lookup DNS results.
-        http_client: instance of recall.HTTPClient or compatible class to
-            lookup HTTP results.
-
-    If these are left as None, no appropriate server will be created by
-    this method. The subclass may then choose to set up servers of its
-    own and use InstallPortRedirect() to redirect traffic to them.
-
-    Members available for use by subclasses:
-
-        ANY_ADDRESS: pass to SocketServer instances to get a random port.
-
-        source_address: local IP address that will likely be used to
-            communicate with the remote client.
-        source_interface: local interface of source_address.
-
-        dns_server: recall.DNSServer created using dns_client.
-        http_server: recall.HTTPServer created using http_client.
-        https_server: recall.HTTPSServer created using http_client.
-
-    Finally to run the client test on the remote client the subclass
-    should call RunTestOnHost() in its run_once() function.
-    """
-    version = 1
-
-    # Pass as server_address to SocketServer classes to get a random port
-    ANY_ADDRESS = ('', 0)
-
-    _send_redirects_sysctl_pattern = "net.ipv4.conf.%s.send_redirects"
-
-    def __init__(self, job, bindir, outputdir):
-        test.test.__init__(self, job, bindir, outputdir)
-
-        # To be set by subclass initialize
-        self.certificate_authority = None
-        self.dns_client = None
-        self.http_client = None
-
-        # Set by our initialize
-        self.dns_server = None
-        self.http_server = None
-        self.https_server = None
-
-        self._send_redirects = None
-        self._port_redirects = []
-
-    def initialize(self, host):
-        """Initialize the Recall server.
-
-        Override in your subclass to setup the certificate_authority,
-        dns_client and http_client members before calling the superclass
-        method.
-
-        You may also leave those as None and setup your own server
-        instances if you prefer.
-
-        This method sets the source_address and source_interface members
-        to the local address and interface that would be used to reach
-        the given host.
-
-        Args:
-            host: autotest host object for remote client.
-        """
-        if host.ip == '127.0.0.1':
-            raise error.TestError("Recall server tests cannot be run against "
-                                  "the autotest server or a VM running on it.")
-
-        self._host = host
-        self.source_address, self.source_interface = \
-            self._GetAddressAndInterfaceForAddress(self._host.ip)
-        logging.debug("Source address and interface for %s are %s, %s",
-                      self._host.ip,
-                      self.source_address, self.source_interface)
-
-        # Disable ICMP redirects for the interface we use for the client
-        self._send_redirects_sysctl = self._send_redirects_sysctl_pattern \
-            % self.source_interface
-        try:
-            self._send_redirects = \
-                self._GetAndSetSysctl(self._send_redirects_sysctl, '0')
-        except IOError as e:
-            if e.errno == errno.EACCES:
-                raise error.TestError("Recall server tests must be run as root")
-            else:
-                raise
-
-        # Setup the servers using the client classes provided
-        if self.dns_client is not None:
-            logging.info("Setting up DNS Server")
-            self.dns_server = recall.DNSServer(self.ANY_ADDRESS,
-                                               self.dns_client)
-            self.InstallPortRedirect('udp', 53,
-                                     self.dns_server.server_address[-1])
-            self.InstallPortRedirect('tcp', 53,
-                                     self.dns_server.server_address[-1])
-        if self.http_client is not None:
-            logging.info("Setting up HTTP and HTTPS Server")
-            self.http_server = recall.HTTPServer(
-                self.ANY_ADDRESS, self.http_client, self.dns_client,
-                self.certificate_authority)
-            self.InstallPortRedirect('tcp', 80,
-                                     self.http_server.server_address[-1])
-
-            if self.certificate_authority is not None:
-                self.https_server = recall.HTTPSServer(
-                    self.ANY_ADDRESS, self.http_client, self.dns_client,
-                    self.certificate_authority)
-                self.InstallPortRedirect('tcp', 443,
-                                     self.https_server.server_address[-1])
-
-    def cleanup(self):
-        """Cleanup.
-
-        If you override in your subclass, be sure to call the superclass
-        method.
-        """
-        self._UninstallPortRedirects()
-
-        if self._send_redirects is not None:
-          self._GetAndSetSysctl(self._send_redirects_sysctl,
-                                self._send_redirects)
-
-        if self.dns_server is not None:
-            self.dns_server.shutdown()
-        if self.http_server is not None:
-            self.http_server.shutdown()
-        if self.https_server is not None:
-            self.https_server.shutdown()
-
-    def _GetAddressAndInterfaceForAddress(self, ip_address):
-        """Return the local address and interface to reach an address.
-
-        Given the IP address of a remote machine, returns the local
-        source address and interface that may be used to reach that
-        machine.
-
-        This may not be the actual return IP address the remote machine
-        sees if a NAT or similar redirection is in the way, but if
-        they are on the same local network, it should resolve cases of
-        multiple interfaces.
-
-        Args:
-            ip_address: address of remote machine as string.
-
-        Returns:
-            tuple of local address and interface names as strings.
-        """
-        cmd = ( '/sbin/ip', 'route', 'get', ip_address )
-        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-        data, errdata = proc.communicate()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to obtain local address for remote")
-
-        match = re.search(r'src ([^ ]*)', data)
-        if not match:
-            raise error.TestError("Missing source address for remote")
-        source = match.group(1)
-
-        match = re.search(r'dev ([^ ]*)', data)
-        if not match:
-            raise error.TestError("Missing source device for remote")
-        interface = match.group(1)
-
-        return source, interface
-
-    def _GetAndSetSysctl(self, sysctl_name, new_value=None):
-        """Sets a sysctl, returning the old value.
-
-        Args:
-            sysctl_name: dotted-notation name of sysctl.
-            new_value: new value, if None, only returns current value.
-        """
-        sysctl_path = os.path.join('/proc/sys', sysctl_name.replace('.', '/'))
-        with open(sysctl_path, 'r+') as sysctl:
-            old_value = sysctl.read()
-            if new_value is not None:
-                print >>sysctl, new_value
-
-        return old_value
-
-    def InstallPortRedirect(self, protocol, port, to_port):
-        """Install a port redirection.
-
-        Installs a port direction so that requests from the client for the
-        given protocol and port are redirected to the local port given.
-
-        Can be removed with _UninstallPortRedirects().
-
-        Args:
-            protocol: protocol to redirect ('tcp' or 'udp').
-            port: integer port to redirect, or tuple of range to redirect.
-            to_port: integer port to redirect to on current machine.
-        """
-        try:
-            port_spec = ':'.join(str(p) for p in port)
-        except TypeError:
-            port_spec = str(port)
-
-        logging.debug("Installing port redirection for %s %s -> %d",
-                      protocol, port_spec, to_port)
-        cmd = ( '/sbin/iptables', '-t', 'nat', '-A', 'PREROUTING',
-                '-p', protocol, '-s', self._host.ip,
-                '--dport', port_spec, '-j', 'REDIRECT',
-                '--to-ports', '%d' % to_port )
-        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-        proc.wait()
-        if proc.returncode != 0:
-            raise error.TestError("Failed to install port redirection")
-
-        self._port_redirects.append((protocol, port_spec, to_port))
-
-    def _UninstallPortRedirects(self):
-        """Uninstall port redirections.
-
-        Removes all port redirects installed with _InstallPortRedirect().
-        """
-        for protocol, port_spec, to_port in self._port_redirects:
-            cmd = ( '/sbin/iptables', '-t', 'nat', '-D', 'PREROUTING',
-                    '-p', protocol, '-s', self._host.ip,
-                    '--dport', port_spec, '-j', 'REDIRECT',
-                    '--to-ports', '%d' % to_port )
-            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-            proc.wait()
-            if proc.returncode != 0:
-                raise error.TestError("Failed to uninstall port redirection")
-
-    def RunTestOnHost(self, test, host, **args):
-        """Run client test on host using this Recall server.
-
-        Args:
-            test: name of test to run.
-            host: host object to run test on.
-
-        Additional keyword arguments are passed as arguments to the test
-        being run.
-        """
-        # (keybuk) don't hurt me, I copied this code from autotest itself
-        opts = ["%s=%s" % (o[0], repr(o[1])) for o in args.items()]
-        cmd = ", ".join([repr(test)] + opts)
-        control = """\
-from autotest_lib.client.cros.recall import RecallServer
-with RecallServer(%r):
-    job.run_test(%s)
-""" % (self.source_address, cmd)
-
-        logging.debug("Running control file %s", control)
-
-        client_autotest = autotest.Autotest(host)
-        return client_autotest.run(control)
diff --git a/server/site_tests/test_RecallServer/control b/server/site_tests/test_RecallServer/control
deleted file mode 100644
index ef68223..0000000
--- a/server/site_tests/test_RecallServer/control
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-AUTHOR = "Chromium OS Project"
-NAME = "test_RecallServer"
-PURPOSE = "Run a client test using a Recall server"
-CRITERIA = """
-This test will succeed if the client test specified succeeds.
-"""
-TIME = "SHORT"
-TEST_CATEGORY = "General"
-TEST_CLASS = "test"
-TEST_TYPE = "server"
-
-DOC = """
-This test creates a Recall server instance, and runs a specified client
-test on the client machine intercepting DNS, HTTP and HTTPS traffic for
-recording, manipulation and later playback.
-
-Sample usage:
-
-  # Run desktopui_UrlFetch on the client, record results which can
-  # be found as <RESULTS DIR>/pickle
-  ./run_remote_tests.sh --remote=<DEVICE IP> test_RecallServer \
-    -a 'desktopui_UrlFetch'
-
-  # Run desktopui_UrlFetch on the client, only returning results
-  # found in the given pickle file created from a previous recording
-  ./run_remote_tests.sh --remote=<DEVICE IP> test_RecallServer \
-    -a 'desktopui_UrlFetch /path/to/pickle'
-
-  # Run desktopui_UrlFetch on the client 100 times, the first time
-  # will be recorded, the subsequent 99 will use the playback only
-  ./run_remote_tests.sh --remote=<DEVICE IP> test_RecallServer \
-    -a 'desktopui_UrlFetch num_iterations=100'
-
-  # Run desktopui_UrlFetch on the client using a simple proxy server
-  # that doesn't record (mostly for infrastructure testing)
-  ./run_remote_tests.sh --remote=<DEVICE IP> test_RecallServer \
-    -a 'desktopui_UrlFetch proxy_only=1'
-
-Infrastructure restrictions mean that this test must always be run as
-root (or with sudo), and may not be run against the 127.0.0.1 address.
-"""
-
-dict_args = {}
-if args:
-    if args and '=' not in args[0]:
-        dict_args['test'] = args.pop(0)
-    if args and '=' not in args[0]:
-        dict_args['pickle_file'] = args.pop(0)
-    dict_args.update(x.split('=') for x in args)
-
-def run(machine):
-    host = hosts.create_host(machine)
-    job.run_test("test_RecallServer", host=host, **dict_args)
-
-parallel_simple(run, machines)
diff --git a/server/site_tests/test_RecallServer/test_RecallServer.py b/server/site_tests/test_RecallServer/test_RecallServer.py
deleted file mode 100644
index 0a7df11..0000000
--- a/server/site_tests/test_RecallServer/test_RecallServer.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import cPickle as pickle
-import logging
-import os
-
-from autotest_lib.client.common_lib import error
-from autotest_lib.server import test, autotest
-from autotest_lib.server.cros import recall_test, recall
-
-class test_RecallServer(recall_test.RecallServerTest):
-    version = 1
-
-    _certificate_authority_subject = "/O=Google/OU=Chromium OS Test Server"
-
-    def initialize(self, host, pickle_file=None, proxy_only=False):
-        if pickle_file is not None:
-            logging.info("Restoring from pickle %s", pickle_file)
-            self.certificate_authority, self.dns_client, self.http_client \
-                = pickle.load(open(pickle_file))
-        else:
-            logging.info("Setting up recall server")
-            self.certificate_authority = recall.CertificateAuthority(
-                subject=self._certificate_authority_subject,
-                default_days=1)
-
-            if proxy_only:
-                self.dns_client = recall.DNSClient()
-                self.http_client = recall.HTTPClient()
-            else:
-                self.dns_client = recall.SymmetricDNSClient()
-                self.http_client = recall.ArchivingHTTPClient(
-                    recall.DeterministicScriptInjector())
-
-        recall_test.RecallServerTest.initialize(self, host)
-
-    def run_once(self, host, test, proxy_only=False, num_iterations=1, **args):
-        logging.info("Running test %s on remote client %s", test, host.ip)
-        self.RunTestOnHost(test, host, **args)
-
-        # Remove the second-level client so further iterations, including
-        # later runs with the pickle we write out, don't proxy
-        del self.dns_client.dns_client
-        del self.http_client.http_client
-        logging.info("Recording/proxying disabled")
-
-        if not proxy_only:
-            dump_file = os.path.join(self.resultsdir, 'pickle')
-            logging.debug("Saving results to %s", dump_file)
-            pickle.dump((self.certificate_authority,
-                         self.dns_client, self.http_client),
-                        open(dump_file, 'w'))
-
-        # Repeat test for subsequent iterations now proxying is disabled
-        if isinstance(num_iterations, str):
-            num_iterations = int(num_iterations)
-        if num_iterations > 1:
-            logging.info("Running %d more iterations", num_iterations - 1)
-            self.RunTestOnHost(test, host, iterations=(num_iterations - 1),
-                               **args)