1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/build/android/lighttpd_server.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,253 @@ 1.4 +#!/usr/bin/env python 1.5 +# 1.6 +# Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.7 +# Use of this source code is governed by a BSD-style license that can be 1.8 +# found in the LICENSE file. 1.9 + 1.10 +"""Provides a convenient wrapper for spawning a test lighttpd instance. 1.11 + 1.12 +Usage: 1.13 + lighttpd_server PATH_TO_DOC_ROOT 1.14 +""" 1.15 + 1.16 +import codecs 1.17 +import contextlib 1.18 +import httplib 1.19 +import os 1.20 +import random 1.21 +import shutil 1.22 +import socket 1.23 +import subprocess 1.24 +import sys 1.25 +import tempfile 1.26 +import time 1.27 + 1.28 +from pylib import constants 1.29 +from pylib import pexpect 1.30 + 1.31 +class LighttpdServer(object): 1.32 + """Wraps lighttpd server, providing robust startup. 1.33 + 1.34 + Args: 1.35 + document_root: Path to root of this server's hosted files. 1.36 + port: TCP port on the _host_ machine that the server will listen on. If 1.37 + ommitted it will attempt to use 9000, or if unavailable it will find 1.38 + a free port from 8001 - 8999. 1.39 + lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries. 1.40 + base_config_path: If supplied this file will replace the built-in default 1.41 + lighttpd config file. 1.42 + extra_config_contents: If specified, this string will be appended to the 1.43 + base config (default built-in, or from base_config_path). 1.44 + config_path, error_log, access_log: Optional paths where the class should 1.45 + place temprary files for this session. 1.46 + """ 1.47 + 1.48 + def __init__(self, document_root, port=None, 1.49 + lighttpd_path=None, lighttpd_module_path=None, 1.50 + base_config_path=None, extra_config_contents=None, 1.51 + config_path=None, error_log=None, access_log=None): 1.52 + self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android') 1.53 + self.document_root = os.path.abspath(document_root) 1.54 + self.fixed_port = port 1.55 + self.port = port or constants.LIGHTTPD_DEFAULT_PORT 1.56 + self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999)) 1.57 + self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd' 1.58 + self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd' 1.59 + self.base_config_path = base_config_path 1.60 + self.extra_config_contents = extra_config_contents 1.61 + self.config_path = config_path or self._Mktmp('config') 1.62 + self.error_log = error_log or self._Mktmp('error_log') 1.63 + self.access_log = access_log or self._Mktmp('access_log') 1.64 + self.pid_file = self._Mktmp('pid_file') 1.65 + self.process = None 1.66 + 1.67 + def _Mktmp(self, name): 1.68 + return os.path.join(self.temp_dir, name) 1.69 + 1.70 + def _GetRandomPort(self): 1.71 + # The ports of test server is arranged in constants.py. 1.72 + return random.randint(constants.LIGHTTPD_RANDOM_PORT_FIRST, 1.73 + constants.LIGHTTPD_RANDOM_PORT_LAST) 1.74 + 1.75 + def StartupHttpServer(self): 1.76 + """Starts up a http server with specified document root and port.""" 1.77 + # If we want a specific port, make sure no one else is listening on it. 1.78 + if self.fixed_port: 1.79 + self._KillProcessListeningOnPort(self.fixed_port) 1.80 + while True: 1.81 + if self.base_config_path: 1.82 + # Read the config 1.83 + with codecs.open(self.base_config_path, 'r', 'utf-8') as f: 1.84 + config_contents = f.read() 1.85 + else: 1.86 + config_contents = self._GetDefaultBaseConfig() 1.87 + if self.extra_config_contents: 1.88 + config_contents += self.extra_config_contents 1.89 + # Write out the config, filling in placeholders from the members of |self| 1.90 + with codecs.open(self.config_path, 'w', 'utf-8') as f: 1.91 + f.write(config_contents % self.__dict__) 1.92 + if (not os.path.exists(self.lighttpd_path) or 1.93 + not os.access(self.lighttpd_path, os.X_OK)): 1.94 + raise EnvironmentError( 1.95 + 'Could not find lighttpd at %s.\n' 1.96 + 'It may need to be installed (e.g. sudo apt-get install lighttpd)' 1.97 + % self.lighttpd_path) 1.98 + self.process = pexpect.spawn(self.lighttpd_path, 1.99 + ['-D', '-f', self.config_path, 1.100 + '-m', self.lighttpd_module_path], 1.101 + cwd=self.temp_dir) 1.102 + client_error, server_error = self._TestServerConnection() 1.103 + if not client_error: 1.104 + assert int(open(self.pid_file, 'r').read()) == self.process.pid 1.105 + break 1.106 + self.process.close() 1.107 + 1.108 + if self.fixed_port or not 'in use' in server_error: 1.109 + print 'Client error:', client_error 1.110 + print 'Server error:', server_error 1.111 + return False 1.112 + self.port = self._GetRandomPort() 1.113 + return True 1.114 + 1.115 + def ShutdownHttpServer(self): 1.116 + """Shuts down our lighttpd processes.""" 1.117 + if self.process: 1.118 + self.process.terminate() 1.119 + shutil.rmtree(self.temp_dir, ignore_errors=True) 1.120 + 1.121 + def _TestServerConnection(self): 1.122 + # Wait for server to start 1.123 + server_msg = '' 1.124 + for timeout in xrange(1, 5): 1.125 + client_error = None 1.126 + try: 1.127 + with contextlib.closing(httplib.HTTPConnection( 1.128 + '127.0.0.1', self.port, timeout=timeout)) as http: 1.129 + http.set_debuglevel(timeout > 3) 1.130 + http.request('HEAD', '/') 1.131 + r = http.getresponse() 1.132 + r.read() 1.133 + if (r.status == 200 and r.reason == 'OK' and 1.134 + r.getheader('Server') == self.server_tag): 1.135 + return (None, server_msg) 1.136 + client_error = ('Bad response: %s %s version %s\n ' % 1.137 + (r.status, r.reason, r.version) + 1.138 + '\n '.join([': '.join(h) for h in r.getheaders()])) 1.139 + except (httplib.HTTPException, socket.error) as client_error: 1.140 + pass # Probably too quick connecting: try again 1.141 + # Check for server startup error messages 1.142 + ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'], 1.143 + timeout=timeout) 1.144 + if ix == 2: # stdout spew from the server 1.145 + server_msg += self.process.match.group(0) 1.146 + elif ix == 1: # EOF -- server has quit so giveup. 1.147 + client_error = client_error or 'Server exited' 1.148 + break 1.149 + return (client_error or 'Timeout', server_msg) 1.150 + 1.151 + def _KillProcessListeningOnPort(self, port): 1.152 + """Checks if there is a process listening on port number |port| and 1.153 + terminates it if found. 1.154 + 1.155 + Args: 1.156 + port: Port number to check. 1.157 + """ 1.158 + if subprocess.call(['fuser', '-kv', '%d/tcp' % port]) == 0: 1.159 + # Give the process some time to terminate and check that it is gone. 1.160 + time.sleep(2) 1.161 + assert subprocess.call(['fuser', '-v', '%d/tcp' % port]) != 0, \ 1.162 + 'Unable to kill process listening on port %d.' % port 1.163 + 1.164 + def _GetDefaultBaseConfig(self): 1.165 + return """server.tag = "%(server_tag)s" 1.166 +server.modules = ( "mod_access", 1.167 + "mod_accesslog", 1.168 + "mod_alias", 1.169 + "mod_cgi", 1.170 + "mod_rewrite" ) 1.171 + 1.172 +# default document root required 1.173 +#server.document-root = "." 1.174 + 1.175 +# files to check for if .../ is requested 1.176 +index-file.names = ( "index.php", "index.pl", "index.cgi", 1.177 + "index.html", "index.htm", "default.htm" ) 1.178 +# mimetype mapping 1.179 +mimetype.assign = ( 1.180 + ".gif" => "image/gif", 1.181 + ".jpg" => "image/jpeg", 1.182 + ".jpeg" => "image/jpeg", 1.183 + ".png" => "image/png", 1.184 + ".svg" => "image/svg+xml", 1.185 + ".css" => "text/css", 1.186 + ".html" => "text/html", 1.187 + ".htm" => "text/html", 1.188 + ".xhtml" => "application/xhtml+xml", 1.189 + ".xhtmlmp" => "application/vnd.wap.xhtml+xml", 1.190 + ".js" => "application/x-javascript", 1.191 + ".log" => "text/plain", 1.192 + ".conf" => "text/plain", 1.193 + ".text" => "text/plain", 1.194 + ".txt" => "text/plain", 1.195 + ".dtd" => "text/xml", 1.196 + ".xml" => "text/xml", 1.197 + ".manifest" => "text/cache-manifest", 1.198 + ) 1.199 + 1.200 +# Use the "Content-Type" extended attribute to obtain mime type if possible 1.201 +mimetype.use-xattr = "enable" 1.202 + 1.203 +## 1.204 +# which extensions should not be handle via static-file transfer 1.205 +# 1.206 +# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi 1.207 +static-file.exclude-extensions = ( ".php", ".pl", ".cgi" ) 1.208 + 1.209 +server.bind = "127.0.0.1" 1.210 +server.port = %(port)s 1.211 + 1.212 +## virtual directory listings 1.213 +dir-listing.activate = "enable" 1.214 +#dir-listing.encoding = "iso-8859-2" 1.215 +#dir-listing.external-css = "style/oldstyle.css" 1.216 + 1.217 +## enable debugging 1.218 +#debug.log-request-header = "enable" 1.219 +#debug.log-response-header = "enable" 1.220 +#debug.log-request-handling = "enable" 1.221 +#debug.log-file-not-found = "enable" 1.222 + 1.223 +#### SSL engine 1.224 +#ssl.engine = "enable" 1.225 +#ssl.pemfile = "server.pem" 1.226 + 1.227 +# Autogenerated test-specific config follows. 1.228 + 1.229 +cgi.assign = ( ".cgi" => "/usr/bin/env", 1.230 + ".pl" => "/usr/bin/env", 1.231 + ".asis" => "/bin/cat", 1.232 + ".php" => "/usr/bin/php-cgi" ) 1.233 + 1.234 +server.errorlog = "%(error_log)s" 1.235 +accesslog.filename = "%(access_log)s" 1.236 +server.upload-dirs = ( "/tmp" ) 1.237 +server.pid-file = "%(pid_file)s" 1.238 +server.document-root = "%(document_root)s" 1.239 + 1.240 +""" 1.241 + 1.242 + 1.243 +def main(argv): 1.244 + server = LighttpdServer(*argv[1:]) 1.245 + try: 1.246 + if server.StartupHttpServer(): 1.247 + raw_input('Server running at http://127.0.0.1:%s -' 1.248 + ' press Enter to exit it.' % server.port) 1.249 + else: 1.250 + print 'Server exit code:', server.process.exitstatus 1.251 + finally: 1.252 + server.ShutdownHttpServer() 1.253 + 1.254 + 1.255 +if __name__ == '__main__': 1.256 + sys.exit(main(sys.argv))