• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4from contextlib import contextmanager
5
6import logging
7import multiprocessing
8import os
9import shutil
10import tempfile
11import SocketServer
12import SimpleHTTPServer
13
14import common
15from autotest_lib.client.bin import utils
16from autotest_lib.client.common_lib import error
17from autotest_lib.site_utils.lxc import constants
18
19
20@contextmanager
21def serve_locally(file_path):
22    """Starts an http server on the localhost, to serve the given file.
23
24    Copies the given file to a temporary location, then starts a local http
25    server to serve that file.  Intended for use with unit tests that require
26    some URL to download a file (see testInstallSsp as an example).
27
28    @param file_path: The path of the file to serve.
29
30    @return The URL at which the file will be served.
31    """
32    p = None
33    try:
34        # Copy the target file into a tmpdir for serving.
35        tmpdir = tempfile.mkdtemp()
36        shutil.copy(file_path, tmpdir)
37
38        httpd = SocketServer.TCPServer(
39                ('', 0), SimpleHTTPServer.SimpleHTTPRequestHandler)
40        port = httpd.socket.getsockname()[1]
41
42        # Start the http daemon in the tmpdir to serve the file.
43        def serve():
44            """Serves the tmpdir."""
45            os.chdir(tmpdir)
46            httpd.serve_forever()
47        p = multiprocessing.Process(target=serve)
48        p.daemon = True
49        p.start()
50
51        utils.poll_for_condition(
52                condition=lambda: http_up(port),
53                timeout=constants.NETWORK_INIT_TIMEOUT,
54                sleep_interval=constants.NETWORK_INIT_CHECK_INTERVAL)
55        url = 'http://127.0.0.1:{port}/{filename}'.format(
56                port=port, filename=os.path.basename(file_path))
57        logging.debug('Serving %s as %s', file_path, url)
58        yield url
59    finally:
60        if p is not None:
61            p.terminate()
62        shutil.rmtree(tmpdir)
63
64
65def http_up(port):
66    """Checks for an http server on localhost:port.
67
68    @param port: The port to check.
69    """
70    try:
71        utils.run('curl --head http://127.0.0.1:%d' % port)
72        return True
73    except error.CmdError:
74        return False
75