Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1405)

Side by Side Diff: native_client_sdk/src/tools/httpd.py

Issue 351963003: [NaCl SDK] Simplify httpd.py (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | native_client_sdk/src/tools/run.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import BaseHTTPServer 6 import BaseHTTPServer
7 import imp
8 import logging 7 import logging
9 import multiprocessing 8 import multiprocessing
10 import optparse 9 import optparse
11 import os 10 import os
12 import SimpleHTTPServer # pylint: disable=W0611 11 import SimpleHTTPServer # pylint: disable=W0611
13 import socket 12 import socket
14 import sys 13 import sys
15 import time 14 import time
16 import urlparse 15 import urlparse
17 16
(...skipping 17 matching lines...) Expand all
35 # Verify we don't serve anywhere above NACL_SDK_ROOT. 34 # Verify we don't serve anywhere above NACL_SDK_ROOT.
36 if abs_serve_dir[:len(NACL_SDK_ROOT)] == NACL_SDK_ROOT: 35 if abs_serve_dir[:len(NACL_SDK_ROOT)] == NACL_SDK_ROOT:
37 return 36 return
38 logging.error('For security, httpd.py should only be run from within the') 37 logging.error('For security, httpd.py should only be run from within the')
39 logging.error('example directory tree.') 38 logging.error('example directory tree.')
40 logging.error('Attempting to serve from %s.' % abs_serve_dir) 39 logging.error('Attempting to serve from %s.' % abs_serve_dir)
41 logging.error('Run with --no-dir-check to bypass this check.') 40 logging.error('Run with --no-dir-check to bypass this check.')
42 sys.exit(1) 41 sys.exit(1)
43 42
44 43
45 class PluggableHTTPServer(BaseHTTPServer.HTTPServer): 44 class HTTPServer(BaseHTTPServer.HTTPServer):
46 def __init__(self, *args, **kwargs): 45 def __init__(self, *args, **kwargs):
47 BaseHTTPServer.HTTPServer.__init__(self, *args) 46 BaseHTTPServer.HTTPServer.__init__(self, *args)
48 self.serve_dir = kwargs.get('serve_dir', '.')
49 self.test_mode = kwargs.get('test_mode', False)
50 self.delegate_map = {}
51 self.running = True 47 self.running = True
52 self.result = 0 48 self.result = 0
53 49
54 def Shutdown(self, result=0): 50 def Shutdown(self, result=0):
55 self.running = False 51 self.running = False
56 self.result = result 52 self.result = result
57 53
58 54
59 class PluggableHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 55 class HTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
60 def _FindDelegateAtPath(self, dirname):
61 # First check the cache...
62 logging.debug('Looking for cached delegate in %s...' % dirname)
63 handler_script = os.path.join(dirname, 'handler.py')
64
65 if dirname in self.server.delegate_map:
66 result = self.server.delegate_map[dirname]
67 if result is None:
68 logging.debug('Found None.')
69 else:
70 logging.debug('Found delegate.')
71 return result
72
73 # Don't have one yet, look for one.
74 delegate = None
75 logging.debug('Testing file %s for existence...' % handler_script)
76 if os.path.exists(handler_script):
77 logging.debug(
78 'File %s exists, looking for HTTPRequestHandlerDelegate.' %
79 handler_script)
80
81 module = imp.load_source('handler', handler_script)
82 delegate_class = getattr(module, 'HTTPRequestHandlerDelegate', None)
83 delegate = delegate_class()
84 if not delegate:
85 logging.warn(
86 'Unable to find symbol HTTPRequestHandlerDelegate in module %s.' %
87 handler_script)
88
89 return delegate
90
91 def _FindDelegateForURLRecurse(self, cur_dir, abs_root):
92 delegate = self._FindDelegateAtPath(cur_dir)
93 if not delegate:
94 # Didn't find it, try the parent directory, but stop if this is the server
95 # root.
96 if cur_dir != abs_root:
97 parent_dir = os.path.dirname(cur_dir)
98 delegate = self._FindDelegateForURLRecurse(parent_dir, abs_root)
99
100 logging.debug('Adding delegate to cache for %s.' % cur_dir)
101 self.server.delegate_map[cur_dir] = delegate
102 return delegate
103
104 def _FindDelegateForURL(self, url_path):
105 path = self.translate_path(url_path)
106 if os.path.isdir(path):
107 dirname = path
108 else:
109 dirname = os.path.dirname(path)
110
111 abs_serve_dir = os.path.abspath(self.server.serve_dir)
112 delegate = self._FindDelegateForURLRecurse(dirname, abs_serve_dir)
113 if not delegate:
114 logging.info('No handler found for path %s. Using default.' % url_path)
115 return delegate
116
117 def _SendNothingAndDie(self, result=0): 56 def _SendNothingAndDie(self, result=0):
118 self.send_response(200, 'OK') 57 self.send_response(200, 'OK')
119 self.send_header('Content-type', 'text/html') 58 self.send_header('Content-type', 'text/html')
120 self.send_header('Content-length', '0') 59 self.send_header('Content-length', '0')
121 self.end_headers() 60 self.end_headers()
122 self.server.Shutdown(result) 61 self.server.Shutdown(result)
123 62
124 def send_head(self):
125 delegate = self._FindDelegateForURL(self.path)
126 if delegate:
127 return delegate.send_head(self)
128 return self.base_send_head()
129
130 def base_send_head(self):
131 return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
132
133 def do_GET(self): 63 def do_GET(self):
134 # TODO(binji): pyauto tests use the ?quit=1 method to kill the server. 64 # Browsing to ?quit=1 will kill the server cleanly.
135 # Remove this when we kill the pyauto tests.
136 _, _, _, query, _ = urlparse.urlsplit(self.path) 65 _, _, _, query, _ = urlparse.urlsplit(self.path)
137 if query: 66 if query:
138 params = urlparse.parse_qs(query) 67 params = urlparse.parse_qs(query)
139 if '1' in params.get('quit', []): 68 if '1' in params.get('quit', []):
140 self._SendNothingAndDie() 69 self._SendNothingAndDie()
141 return 70 return
142 71
143 delegate = self._FindDelegateForURL(self.path)
144 if delegate:
145 return delegate.do_GET(self)
146 return self.base_do_GET()
147
148 def base_do_GET(self):
149 return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) 72 return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
150 73
151 def do_POST(self):
152 delegate = self._FindDelegateForURL(self.path)
153 if delegate:
154 return delegate.do_POST(self)
155 return self.base_do_POST()
156
157 def base_do_POST(self):
158 if self.server.test_mode:
159 if self.path == '/ok':
160 self._SendNothingAndDie(0)
161 elif self.path == '/fail':
162 self._SendNothingAndDie(1)
163
164 74
165 class LocalHTTPServer(object): 75 class LocalHTTPServer(object):
166 """Class to start a local HTTP server as a child process.""" 76 """Class to start a local HTTP server as a child process."""
167 77
168 def __init__(self, dirname, port, test_mode): 78 def __init__(self, dirname, port):
169 parent_conn, child_conn = multiprocessing.Pipe() 79 parent_conn, child_conn = multiprocessing.Pipe()
170 self.process = multiprocessing.Process( 80 self.process = multiprocessing.Process(
171 target=_HTTPServerProcess, 81 target=_HTTPServerProcess,
172 args=(child_conn, dirname, port, { 82 args=(child_conn, dirname, port, {}))
173 'serve_dir': dirname,
174 'test_mode': test_mode,
175 }))
176 self.process.start() 83 self.process.start()
177 if parent_conn.poll(10): # wait 10 seconds 84 if parent_conn.poll(10): # wait 10 seconds
178 self.port = parent_conn.recv() 85 self.port = parent_conn.recv()
179 else: 86 else:
180 raise Exception('Unable to launch HTTP server.') 87 raise Exception('Unable to launch HTTP server.')
181 88
182 self.conn = parent_conn 89 self.conn = parent_conn
183 90
184 def ServeForever(self): 91 def ServeForever(self):
185 """Serve until the child HTTP process tells us to stop. 92 """Serve until the child HTTP process tells us to stop.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 the local port, and waits for a message from the parent to 155 the local port, and waits for a message from the parent to
249 stop serving. It also sends a "result" back to the parent -- this can 156 stop serving. It also sends a "result" back to the parent -- this can
250 be used to allow a client-side test to notify the server of results. 157 be used to allow a client-side test to notify the server of results.
251 dirname: The directory to serve. All files are accessible through 158 dirname: The directory to serve. All files are accessible through
252 http://localhost:<port>/path/to/filename. 159 http://localhost:<port>/path/to/filename.
253 port: The port to serve on. If 0, an ephemeral port will be chosen. 160 port: The port to serve on. If 0, an ephemeral port will be chosen.
254 server_kwargs: A dict that will be passed as kwargs to the server. 161 server_kwargs: A dict that will be passed as kwargs to the server.
255 """ 162 """
256 try: 163 try:
257 os.chdir(dirname) 164 os.chdir(dirname)
258 httpd = PluggableHTTPServer(('', port), PluggableHTTPRequestHandler, 165 httpd = HTTPServer(('', port), HTTPRequestHandler, **server_kwargs)
259 **server_kwargs)
260 except socket.error as e: 166 except socket.error as e:
261 sys.stderr.write('Error creating HTTPServer: %s\n' % e) 167 sys.stderr.write('Error creating HTTPServer: %s\n' % e)
262 sys.exit(1) 168 sys.exit(1)
263 169
264 try: 170 try:
265 conn.send(httpd.server_address[1]) # the chosen port number 171 conn.send(httpd.server_address[1]) # the chosen port number
266 httpd.timeout = 0.5 # seconds 172 httpd.timeout = 0.5 # seconds
267 while httpd.running: 173 while httpd.running:
268 # Flush output for MSVS Add-In. 174 # Flush output for MSVS Add-In.
269 sys.stdout.flush() 175 sys.stdout.flush()
(...skipping 11 matching lines...) Expand all
281 def main(args): 187 def main(args):
282 parser = optparse.OptionParser() 188 parser = optparse.OptionParser()
283 parser.add_option('-C', '--serve-dir', 189 parser.add_option('-C', '--serve-dir',
284 help='Serve files out of this directory.', 190 help='Serve files out of this directory.',
285 default=os.path.abspath('.')) 191 default=os.path.abspath('.'))
286 parser.add_option('-p', '--port', 192 parser.add_option('-p', '--port',
287 help='Run server on this port.', default=5103) 193 help='Run server on this port.', default=5103)
288 parser.add_option('--no-dir-check', '--no_dir_check', 194 parser.add_option('--no-dir-check', '--no_dir_check',
289 help='No check to ensure serving from safe directory.', 195 help='No check to ensure serving from safe directory.',
290 dest='do_safe_check', action='store_false', default=True) 196 dest='do_safe_check', action='store_false', default=True)
291 parser.add_option('--test-mode',
292 help='Listen for posts to /ok or /fail and shut down the server with '
293 ' errorcodes 0 and 1 respectively.',
294 action='store_true')
295 197
296 # To enable bash completion for this command first install optcomplete 198 # To enable bash completion for this command first install optcomplete
297 # and then add this line to your .bashrc: 199 # and then add this line to your .bashrc:
298 # complete -F _optcomplete httpd.py 200 # complete -F _optcomplete httpd.py
299 try: 201 try:
300 import optcomplete 202 import optcomplete
301 optcomplete.autocomplete(parser) 203 optcomplete.autocomplete(parser)
302 except ImportError: 204 except ImportError:
303 pass 205 pass
304 206
305 options, args = parser.parse_args(args) 207 options, args = parser.parse_args(args)
306 if options.do_safe_check: 208 if options.do_safe_check:
307 SanityCheckDirectory(options.serve_dir) 209 SanityCheckDirectory(options.serve_dir)
308 210
309 server = LocalHTTPServer(options.serve_dir, int(options.port), 211 server = LocalHTTPServer(options.serve_dir, int(options.port))
310 options.test_mode)
311 212
312 # Serve until the client tells us to stop. When it does, it will give us an 213 # Serve until the client tells us to stop. When it does, it will give us an
313 # errorcode. 214 # errorcode.
314 print 'Serving %s on %s...' % (options.serve_dir, server.GetURL('')) 215 print 'Serving %s on %s...' % (options.serve_dir, server.GetURL(''))
315 return server.ServeForever() 216 return server.ServeForever()
316 217
317 if __name__ == '__main__': 218 if __name__ == '__main__':
318 sys.exit(main(sys.argv[1:])) 219 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | native_client_sdk/src/tools/run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698