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