Switch DomAutomationController to be a RenderFrameObserver.
[chromium-blink-merge.git] / build / android / lighttpd_server.py
blob11ae794d4ade6a9d7fdbbbb286b8e724377f26fb
1 #!/usr/bin/env python
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 """Provides a convenient wrapper for spawning a test lighttpd instance.
9 Usage:
10 lighttpd_server PATH_TO_DOC_ROOT
11 """
13 import codecs
14 import contextlib
15 import httplib
16 import os
17 import random
18 import shutil
19 import socket
20 import subprocess
21 import sys
22 import tempfile
23 import time
25 from pylib import constants
26 from pylib import pexpect
28 class LighttpdServer(object):
29 """Wraps lighttpd server, providing robust startup.
31 Args:
32 document_root: Path to root of this server's hosted files.
33 port: TCP port on the _host_ machine that the server will listen on. If
34 ommitted it will attempt to use 9000, or if unavailable it will find
35 a free port from 8001 - 8999.
36 lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries.
37 base_config_path: If supplied this file will replace the built-in default
38 lighttpd config file.
39 extra_config_contents: If specified, this string will be appended to the
40 base config (default built-in, or from base_config_path).
41 config_path, error_log, access_log: Optional paths where the class should
42 place temprary files for this session.
43 """
45 def __init__(self, document_root, port=None,
46 lighttpd_path=None, lighttpd_module_path=None,
47 base_config_path=None, extra_config_contents=None,
48 config_path=None, error_log=None, access_log=None):
49 self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android')
50 self.document_root = os.path.abspath(document_root)
51 self.fixed_port = port
52 self.port = port or constants.LIGHTTPD_DEFAULT_PORT
53 self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999))
54 self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd'
55 self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd'
56 self.base_config_path = base_config_path
57 self.extra_config_contents = extra_config_contents
58 self.config_path = config_path or self._Mktmp('config')
59 self.error_log = error_log or self._Mktmp('error_log')
60 self.access_log = access_log or self._Mktmp('access_log')
61 self.pid_file = self._Mktmp('pid_file')
62 self.process = None
64 def _Mktmp(self, name):
65 return os.path.join(self.temp_dir, name)
67 def _GetRandomPort(self):
68 # The ports of test server is arranged in constants.py.
69 return random.randint(constants.LIGHTTPD_RANDOM_PORT_FIRST,
70 constants.LIGHTTPD_RANDOM_PORT_LAST)
72 def StartupHttpServer(self):
73 """Starts up a http server with specified document root and port."""
74 # If we want a specific port, make sure no one else is listening on it.
75 if self.fixed_port:
76 self._KillProcessListeningOnPort(self.fixed_port)
77 while True:
78 if self.base_config_path:
79 # Read the config
80 with codecs.open(self.base_config_path, 'r', 'utf-8') as f:
81 config_contents = f.read()
82 else:
83 config_contents = self._GetDefaultBaseConfig()
84 if self.extra_config_contents:
85 config_contents += self.extra_config_contents
86 # Write out the config, filling in placeholders from the members of |self|
87 with codecs.open(self.config_path, 'w', 'utf-8') as f:
88 f.write(config_contents % self.__dict__)
89 if (not os.path.exists(self.lighttpd_path) or
90 not os.access(self.lighttpd_path, os.X_OK)):
91 raise EnvironmentError(
92 'Could not find lighttpd at %s.\n'
93 'It may need to be installed (e.g. sudo apt-get install lighttpd)'
94 % self.lighttpd_path)
95 self.process = pexpect.spawn(self.lighttpd_path,
96 ['-D', '-f', self.config_path,
97 '-m', self.lighttpd_module_path],
98 cwd=self.temp_dir)
99 client_error, server_error = self._TestServerConnection()
100 if not client_error:
101 assert int(open(self.pid_file, 'r').read()) == self.process.pid
102 break
103 self.process.close()
105 if self.fixed_port or not 'in use' in server_error:
106 print 'Client error:', client_error
107 print 'Server error:', server_error
108 return False
109 self.port = self._GetRandomPort()
110 return True
112 def ShutdownHttpServer(self):
113 """Shuts down our lighttpd processes."""
114 if self.process:
115 self.process.terminate()
116 shutil.rmtree(self.temp_dir, ignore_errors=True)
118 def _TestServerConnection(self):
119 # Wait for server to start
120 server_msg = ''
121 for timeout in xrange(1, 5):
122 client_error = None
123 try:
124 with contextlib.closing(httplib.HTTPConnection(
125 '127.0.0.1', self.port, timeout=timeout)) as http:
126 http.set_debuglevel(timeout > 3)
127 http.request('HEAD', '/')
128 r = http.getresponse()
129 r.read()
130 if (r.status == 200 and r.reason == 'OK' and
131 r.getheader('Server') == self.server_tag):
132 return (None, server_msg)
133 client_error = ('Bad response: %s %s version %s\n ' %
134 (r.status, r.reason, r.version) +
135 '\n '.join([': '.join(h) for h in r.getheaders()]))
136 except (httplib.HTTPException, socket.error) as client_error:
137 pass # Probably too quick connecting: try again
138 # Check for server startup error messages
139 ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'],
140 timeout=timeout)
141 if ix == 2: # stdout spew from the server
142 server_msg += self.process.match.group(0)
143 elif ix == 1: # EOF -- server has quit so giveup.
144 client_error = client_error or 'Server exited'
145 break
146 return (client_error or 'Timeout', server_msg)
148 def _KillProcessListeningOnPort(self, port):
149 """Checks if there is a process listening on port number |port| and
150 terminates it if found.
152 Args:
153 port: Port number to check.
155 if subprocess.call(['fuser', '-kv', '%d/tcp' % port]) == 0:
156 # Give the process some time to terminate and check that it is gone.
157 time.sleep(2)
158 assert subprocess.call(['fuser', '-v', '%d/tcp' % port]) != 0, \
159 'Unable to kill process listening on port %d.' % port
161 def _GetDefaultBaseConfig(self):
162 return """server.tag = "%(server_tag)s"
163 server.modules = ( "mod_access",
164 "mod_accesslog",
165 "mod_alias",
166 "mod_cgi",
167 "mod_rewrite" )
169 # default document root required
170 #server.document-root = "."
172 # files to check for if .../ is requested
173 index-file.names = ( "index.php", "index.pl", "index.cgi",
174 "index.html", "index.htm", "default.htm" )
175 # mimetype mapping
176 mimetype.assign = (
177 ".gif" => "image/gif",
178 ".jpg" => "image/jpeg",
179 ".jpeg" => "image/jpeg",
180 ".png" => "image/png",
181 ".svg" => "image/svg+xml",
182 ".css" => "text/css",
183 ".html" => "text/html",
184 ".htm" => "text/html",
185 ".xhtml" => "application/xhtml+xml",
186 ".xhtmlmp" => "application/vnd.wap.xhtml+xml",
187 ".js" => "application/x-javascript",
188 ".log" => "text/plain",
189 ".conf" => "text/plain",
190 ".text" => "text/plain",
191 ".txt" => "text/plain",
192 ".dtd" => "text/xml",
193 ".xml" => "text/xml",
194 ".manifest" => "text/cache-manifest",
197 # Use the "Content-Type" extended attribute to obtain mime type if possible
198 mimetype.use-xattr = "enable"
201 # which extensions should not be handle via static-file transfer
203 # .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
204 static-file.exclude-extensions = ( ".php", ".pl", ".cgi" )
206 server.bind = "127.0.0.1"
207 server.port = %(port)s
209 ## virtual directory listings
210 dir-listing.activate = "enable"
211 #dir-listing.encoding = "iso-8859-2"
212 #dir-listing.external-css = "style/oldstyle.css"
214 ## enable debugging
215 #debug.log-request-header = "enable"
216 #debug.log-response-header = "enable"
217 #debug.log-request-handling = "enable"
218 #debug.log-file-not-found = "enable"
220 #### SSL engine
221 #ssl.engine = "enable"
222 #ssl.pemfile = "server.pem"
224 # Autogenerated test-specific config follows.
226 cgi.assign = ( ".cgi" => "/usr/bin/env",
227 ".pl" => "/usr/bin/env",
228 ".asis" => "/bin/cat",
229 ".php" => "/usr/bin/php-cgi" )
231 server.errorlog = "%(error_log)s"
232 accesslog.filename = "%(access_log)s"
233 server.upload-dirs = ( "/tmp" )
234 server.pid-file = "%(pid_file)s"
235 server.document-root = "%(document_root)s"
240 def main(argv):
241 server = LighttpdServer(*argv[1:])
242 try:
243 if server.StartupHttpServer():
244 raw_input('Server running at http://127.0.0.1:%s -'
245 ' press Enter to exit it.' % server.port)
246 else:
247 print 'Server exit code:', server.process.exitstatus
248 finally:
249 server.ShutdownHttpServer()
252 if __name__ == '__main__':
253 sys.exit(main(sys.argv))