media/webrtc/trunk/build/android/lighttpd_server.py

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:965f8c5eb11d
1 #!/usr/bin/env python
2 #
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.
6
7 """Provides a convenient wrapper for spawning a test lighttpd instance.
8
9 Usage:
10 lighttpd_server PATH_TO_DOC_ROOT
11 """
12
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
24
25 from pylib import constants
26 from pylib import pexpect
27
28 class LighttpdServer(object):
29 """Wraps lighttpd server, providing robust startup.
30
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 """
44
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
63
64 def _Mktmp(self, name):
65 return os.path.join(self.temp_dir, name)
66
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)
71
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()
104
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
111
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)
117
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)
147
148 def _KillProcessListeningOnPort(self, port):
149 """Checks if there is a process listening on port number |port| and
150 terminates it if found.
151
152 Args:
153 port: Port number to check.
154 """
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
160
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" )
168
169 # default document root required
170 #server.document-root = "."
171
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",
195 )
196
197 # Use the "Content-Type" extended attribute to obtain mime type if possible
198 mimetype.use-xattr = "enable"
199
200 ##
201 # which extensions should not be handle via static-file transfer
202 #
203 # .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
204 static-file.exclude-extensions = ( ".php", ".pl", ".cgi" )
205
206 server.bind = "127.0.0.1"
207 server.port = %(port)s
208
209 ## virtual directory listings
210 dir-listing.activate = "enable"
211 #dir-listing.encoding = "iso-8859-2"
212 #dir-listing.external-css = "style/oldstyle.css"
213
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"
219
220 #### SSL engine
221 #ssl.engine = "enable"
222 #ssl.pemfile = "server.pem"
223
224 # Autogenerated test-specific config follows.
225
226 cgi.assign = ( ".cgi" => "/usr/bin/env",
227 ".pl" => "/usr/bin/env",
228 ".asis" => "/bin/cat",
229 ".php" => "/usr/bin/php-cgi" )
230
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"
236
237 """
238
239
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()
250
251
252 if __name__ == '__main__':
253 sys.exit(main(sys.argv))

mercurial