1# Copyright 2013 The Chromium 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. 4 5import atexit 6import os 7import socket 8import subprocess 9import time 10import urllib2 11 12 13class Server(object): 14 """A running ChromeDriver server.""" 15 16 def __init__(self, exe_path, log_path=None): 17 """Starts the ChromeDriver server and waits for it to be ready. 18 19 Args: 20 exe_path: path to the ChromeDriver executable 21 log_path: path to the log file 22 Raises: 23 RuntimeError if ChromeDriver fails to start 24 """ 25 if not os.path.exists(exe_path): 26 raise RuntimeError('ChromeDriver exe not found at: ' + exe_path) 27 28 port = self._FindOpenPort() 29 chromedriver_args = [exe_path, '--port=%d' % port] 30 if log_path: 31 chromedriver_args.extend(['--verbose', '--log-path=%s' % log_path]) 32 self._process = subprocess.Popen(chromedriver_args) 33 self._url = 'http://127.0.0.1:%d' % port 34 if self._process is None: 35 raise RuntimeError('ChromeDriver server cannot be started') 36 37 max_time = time.time() + 10 38 while not self.IsRunning(): 39 if time.time() > max_time: 40 self._process.terminate() 41 raise RuntimeError('ChromeDriver server did not start') 42 time.sleep(0.1) 43 44 atexit.register(self.Kill) 45 46 def _FindOpenPort(self): 47 for port in range(9500, 10000): 48 try: 49 socket.create_connection(('127.0.0.1', port), 0.2).close() 50 except socket.error: 51 return port 52 raise RuntimeError('Cannot find open port to launch ChromeDriver') 53 54 def GetUrl(self): 55 return self._url 56 57 def IsRunning(self): 58 """Returns whether the server is up and running.""" 59 try: 60 urllib2.urlopen(self.GetUrl() + '/status') 61 return True 62 except urllib2.URLError: 63 return False 64 65 def Kill(self): 66 """Kills the ChromeDriver server, if it is running.""" 67 if self._process is None: 68 return 69 70 try: 71 urllib2.urlopen(self.GetUrl() + '/shutdown', timeout=10).close() 72 except: 73 self._process.terminate() 74 self._process.wait() 75 self._process = None 76