# Copyright 2017 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. from contextlib import contextmanager import logging import multiprocessing import os import shutil import tempfile import SocketServer import SimpleHTTPServer import common from autotest_lib.client.bin import utils from autotest_lib.client.common_lib import error from autotest_lib.site_utils.lxc import constants @contextmanager def serve_locally(file_path): """Starts an http server on the localhost, to serve the given file. Copies the given file to a temporary location, then starts a local http server to serve that file. Intended for use with unit tests that require some URL to download a file (see testInstallSsp as an example). @param file_path: The path of the file to serve. @return The URL at which the file will be served. """ p = None try: # Copy the target file into a tmpdir for serving. tmpdir = tempfile.mkdtemp() shutil.copy(file_path, tmpdir) httpd = SocketServer.TCPServer( ('', 0), SimpleHTTPServer.SimpleHTTPRequestHandler) port = httpd.socket.getsockname()[1] # Start the http daemon in the tmpdir to serve the file. def serve(): """Serves the tmpdir.""" os.chdir(tmpdir) httpd.serve_forever() p = multiprocessing.Process(target=serve) p.daemon = True p.start() utils.poll_for_condition( condition=lambda: http_up(port), timeout=constants.NETWORK_INIT_TIMEOUT, sleep_interval=constants.NETWORK_INIT_CHECK_INTERVAL) url = 'http://127.0.0.1:{port}/{filename}'.format( port=port, filename=os.path.basename(file_path)) logging.debug('Serving %s as %s', file_path, url) yield url finally: if p is not None: p.terminate() shutil.rmtree(tmpdir) def http_up(port): """Checks for an http server on localhost:port. @param port: The port to check. """ try: utils.run('curl --head http://127.0.0.1:%d' % port) return True except error.CmdError: return False