Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2010 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 """This is a simple HTTP server used for testing Chrome. | 6 """This is a simple HTTP server used for testing Chrome. |
| 7 | 7 |
| 8 It supports several test URLs, as specified by the handlers in TestPageHandler. | 8 It supports several test URLs, as specified by the handlers in TestPageHandler. |
| 9 By default, it listens on an ephemeral port and sends the port number back to | 9 By default, it listens on an ephemeral port and sends the port number back to |
| 10 the originating process over a pipe. The originating process can specify an | 10 the originating process over a pipe. The originating process can specify an |
| 11 explicit port if necessary. | 11 explicit port if necessary. |
| 12 It can use https if you specify the flag --https=CERT where CERT is the path | 12 It can use https if you specify the flag --https=CERT where CERT is the path |
| 13 to a pem file containing the certificate and private key that should be used. | 13 to a pem file containing the certificate and private key that should be used. |
| 14 """ | 14 """ |
| 15 | 15 |
| 16 import asyncore | |
| 16 import base64 | 17 import base64 |
| 17 import BaseHTTPServer | 18 import BaseHTTPServer |
| 18 import cgi | 19 import cgi |
| 20 import errno | |
| 19 import optparse | 21 import optparse |
| 20 import os | 22 import os |
| 21 import re | 23 import re |
| 22 import shutil | 24 import select |
| 23 import SocketServer | 25 import SocketServer |
| 26 import socket | |
| 24 import sys | 27 import sys |
| 25 import struct | 28 import struct |
| 26 import time | 29 import time |
| 27 import urlparse | 30 import urlparse |
| 28 import warnings | 31 import warnings |
| 29 | 32 |
| 30 # If we use simplejson always, we get some warnings when we run under | 33 # If we use simplejson always, we get some warnings when we run under |
| 31 # 2.6. | 34 # 2.6. |
| 32 if sys.version_info < (2, 6): | 35 if sys.version_info < (2, 6): |
| 33 import simplejson as json | 36 import simplejson as json |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 return False | 118 return False |
| 116 | 119 |
| 117 | 120 |
| 118 class SyncHTTPServer(StoppableHTTPServer): | 121 class SyncHTTPServer(StoppableHTTPServer): |
| 119 """An HTTP server that handles sync commands.""" | 122 """An HTTP server that handles sync commands.""" |
| 120 | 123 |
| 121 def __init__(self, server_address, request_handler_class): | 124 def __init__(self, server_address, request_handler_class): |
| 122 # We import here to avoid pulling in chromiumsync's dependencies | 125 # We import here to avoid pulling in chromiumsync's dependencies |
| 123 # unless strictly necessary. | 126 # unless strictly necessary. |
| 124 import chromiumsync | 127 import chromiumsync |
| 128 import xmppserver | |
| 129 StoppableHTTPServer.__init__(self, server_address, request_handler_class) | |
| 125 self._sync_handler = chromiumsync.TestServer() | 130 self._sync_handler = chromiumsync.TestServer() |
| 126 StoppableHTTPServer.__init__(self, server_address, request_handler_class) | 131 self._xmpp_socket_map = {} |
| 132 self._xmpp_server = xmppserver.XmppServer( | |
| 133 self._xmpp_socket_map, ('localhost', 0)) | |
| 134 self.xmpp_port = self._xmpp_server.getsockname()[1] | |
| 127 | 135 |
| 128 def HandleCommand(self, query, raw_request): | 136 def HandleCommand(self, query, raw_request): |
| 129 return self._sync_handler.HandleCommand(query, raw_request) | 137 return self._sync_handler.HandleCommand(query, raw_request) |
| 130 | 138 |
| 139 def HandleRequestNoBlock(self): | |
| 140 """Handles a single request. | |
| 141 | |
| 142 Copied from SocketServer._handle_request_noblock(). | |
| 143 """ | |
| 144 try: | |
| 145 request, client_address = self.get_request() | |
| 146 except socket.error: | |
| 147 return | |
| 148 if self.verify_request(request, client_address): | |
| 149 try: | |
| 150 self.process_request(request, client_address) | |
| 151 except: | |
| 152 self.handle_error(request, client_address) | |
| 153 self.close_request(request) | |
| 154 | |
| 155 def serve_forever(self): | |
| 156 """This is a merge of asyncore.loop() and SocketServer.serve_forever(). | |
| 157 """ | |
| 158 | |
| 159 def RunDispatcherHandler(dispatcher, handler): | |
| 160 """Handles a single event for an asyncore.dispatcher. | |
| 161 | |
| 162 Adapted from asyncore.read() et al. | |
| 163 """ | |
| 164 try: | |
| 165 handler(dispatcher) | |
| 166 except (asyncore.ExitNow, KeyboardInterrupt, SystemExit): | |
| 167 raise | |
| 168 except: | |
| 169 dispatcher.handle_error() | |
| 170 | |
| 171 while True: | |
| 172 r = [ self.fileno() ] | |
|
cbentzel
2010/11/19 15:39:29
Nit: are r,w,e too short? [maybe at least r,w,x si
akalin
2010/11/19 18:06:17
Done.
| |
| 173 w = [] | |
| 174 e = [] | |
| 175 | |
| 176 for fd, obj in self._xmpp_socket_map.items(): | |
|
cbentzel
2010/11/19 15:39:29
xmpp_connection instead of obj?
akalin
2010/11/19 18:06:17
Done.
| |
| 177 is_r = obj.readable() | |
| 178 is_w = obj.writable() | |
| 179 if is_r: | |
| 180 r.append(fd) | |
| 181 if is_w: | |
| 182 w.append(fd) | |
| 183 if is_r or is_w: | |
| 184 e.append(fd) | |
| 185 | |
| 186 select_timeout = 0.5 | |
| 187 try: | |
| 188 r, w, e = select.select(r, w, e, select_timeout) | |
|
cbentzel
2010/11/19 15:39:29
Why do you need a timeout here? The tests that spa
akalin
2010/11/19 18:06:17
Done.
| |
| 189 except select.error, err: | |
| 190 if err.args[0] != errno.EINTR: | |
| 191 raise | |
| 192 else: | |
| 193 continue | |
| 194 | |
| 195 for fd in r: | |
| 196 if fd == self.fileno(): | |
| 197 self.HandleRequestNoBlock() | |
| 198 continue | |
| 199 obj = self._xmpp_socket_map.get(fd) | |
| 200 RunDispatcherHandler(obj, asyncore.dispatcher.handle_read_event) | |
| 201 | |
| 202 for fd in w: | |
| 203 obj = self._xmpp_socket_map.get(fd) | |
| 204 RunDispatcherHandler(obj, asyncore.dispatcher.handle_write_event) | |
| 205 | |
| 206 for fd in e: | |
| 207 obj = self._xmpp_socket_map.get(fd) | |
| 208 RunDispatcherHandler(obj, asyncore.dispatcher.handle_expt_event) | |
| 209 | |
| 131 | 210 |
| 132 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): | 211 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
| 133 | 212 |
| 134 def __init__(self, request, client_address, socket_server, | 213 def __init__(self, request, client_address, socket_server, |
| 135 connect_handlers, get_handlers, post_handlers, put_handlers): | 214 connect_handlers, get_handlers, post_handlers, put_handlers): |
| 136 self._connect_handlers = connect_handlers | 215 self._connect_handlers = connect_handlers |
| 137 self._get_handlers = get_handlers | 216 self._get_handlers = get_handlers |
| 138 self._post_handlers = post_handlers | 217 self._post_handlers = post_handlers |
| 139 self._put_handlers = put_handlers | 218 self._put_handlers = put_handlers |
| 140 BaseHTTPServer.BaseHTTPRequestHandler.__init__( | 219 BaseHTTPServer.BaseHTTPRequestHandler.__init__( |
| (...skipping 1122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1263 self.__fd1.flush() | 1342 self.__fd1.flush() |
| 1264 self.__fd2.flush() | 1343 self.__fd2.flush() |
| 1265 | 1344 |
| 1266 def main(options, args): | 1345 def main(options, args): |
| 1267 logfile = open('testserver.log', 'w') | 1346 logfile = open('testserver.log', 'w') |
| 1268 sys.stdout = FileMultiplexer(sys.stdout, logfile) | 1347 sys.stdout = FileMultiplexer(sys.stdout, logfile) |
| 1269 sys.stderr = FileMultiplexer(sys.stderr, logfile) | 1348 sys.stderr = FileMultiplexer(sys.stderr, logfile) |
| 1270 | 1349 |
| 1271 port = options.port | 1350 port = options.port |
| 1272 | 1351 |
| 1352 server_data = {} | |
|
cbentzel
2010/11/19 15:39:29
Maybe server_ports instead of server_data?
akalin
2010/11/19 18:06:17
Hmm, it's a JSON grab-bag, so I think we shouldn't
| |
| 1353 | |
| 1273 if options.server_type == SERVER_HTTP: | 1354 if options.server_type == SERVER_HTTP: |
| 1274 if options.cert: | 1355 if options.cert: |
| 1275 # let's make sure the cert file exists. | 1356 # let's make sure the cert file exists. |
| 1276 if not os.path.isfile(options.cert): | 1357 if not os.path.isfile(options.cert): |
| 1277 print 'specified server cert file not found: ' + options.cert + \ | 1358 print 'specified server cert file not found: ' + options.cert + \ |
| 1278 ' exiting...' | 1359 ' exiting...' |
| 1279 return | 1360 return |
| 1280 for ca_cert in options.ssl_client_ca: | 1361 for ca_cert in options.ssl_client_ca: |
| 1281 if not os.path.isfile(ca_cert): | 1362 if not os.path.isfile(ca_cert): |
| 1282 print 'specified trusted client CA file not found: ' + ca_cert + \ | 1363 print 'specified trusted client CA file not found: ' + ca_cert + \ |
| 1283 ' exiting...' | 1364 ' exiting...' |
| 1284 return | 1365 return |
| 1285 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, | 1366 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, |
| 1286 options.ssl_client_auth, options.ssl_client_ca, | 1367 options.ssl_client_auth, options.ssl_client_ca, |
| 1287 options.ssl_bulk_cipher) | 1368 options.ssl_bulk_cipher) |
| 1288 print 'HTTPS server started on port %d...' % server.server_port | 1369 print 'HTTPS server started on port %d...' % server.server_port |
| 1289 else: | 1370 else: |
| 1290 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) | 1371 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) |
| 1291 print 'HTTP server started on port %d...' % server.server_port | 1372 print 'HTTP server started on port %d...' % server.server_port |
| 1292 | 1373 |
| 1293 server.data_dir = MakeDataDir() | 1374 server.data_dir = MakeDataDir() |
| 1294 server.file_root_url = options.file_root_url | 1375 server.file_root_url = options.file_root_url |
| 1295 listen_port = server.server_port | 1376 server_data['port'] = server.server_port |
| 1296 server._device_management_handler = None | 1377 server._device_management_handler = None |
| 1297 elif options.server_type == SERVER_SYNC: | 1378 elif options.server_type == SERVER_SYNC: |
| 1298 server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler) | 1379 server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler) |
| 1299 print 'Sync HTTP server started on port %d...' % server.server_port | 1380 print 'Sync HTTP server started on port %d...' % server.server_port |
| 1300 listen_port = server.server_port | 1381 print 'Sync XMPP server started on port %d...' % server.xmpp_port |
| 1382 server_data['port'] = server.server_port | |
| 1383 server_data['xmpp_port'] = server.xmpp_port | |
| 1301 # means FTP Server | 1384 # means FTP Server |
| 1302 else: | 1385 else: |
| 1303 my_data_dir = MakeDataDir() | 1386 my_data_dir = MakeDataDir() |
| 1304 | 1387 |
| 1305 # Instantiate a dummy authorizer for managing 'virtual' users | 1388 # Instantiate a dummy authorizer for managing 'virtual' users |
| 1306 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() | 1389 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() |
| 1307 | 1390 |
| 1308 # Define a new user having full r/w permissions and a read-only | 1391 # Define a new user having full r/w permissions and a read-only |
| 1309 # anonymous user | 1392 # anonymous user |
| 1310 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') | 1393 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') |
| 1311 | 1394 |
| 1312 authorizer.add_anonymous(my_data_dir) | 1395 authorizer.add_anonymous(my_data_dir) |
| 1313 | 1396 |
| 1314 # Instantiate FTP handler class | 1397 # Instantiate FTP handler class |
| 1315 ftp_handler = pyftpdlib.ftpserver.FTPHandler | 1398 ftp_handler = pyftpdlib.ftpserver.FTPHandler |
| 1316 ftp_handler.authorizer = authorizer | 1399 ftp_handler.authorizer = authorizer |
| 1317 | 1400 |
| 1318 # Define a customized banner (string returned when client connects) | 1401 # Define a customized banner (string returned when client connects) |
| 1319 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % | 1402 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % |
| 1320 pyftpdlib.ftpserver.__ver__) | 1403 pyftpdlib.ftpserver.__ver__) |
| 1321 | 1404 |
| 1322 # Instantiate FTP server class and listen to 127.0.0.1:port | 1405 # Instantiate FTP server class and listen to 127.0.0.1:port |
| 1323 address = ('127.0.0.1', port) | 1406 address = ('127.0.0.1', port) |
| 1324 server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler) | 1407 server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler) |
| 1325 listen_port = server.socket.getsockname()[1] | 1408 server_data['port'] = server.socket.getsockname()[1] |
| 1326 print 'FTP server started on port %d...' % listen_port | 1409 print 'FTP server started on port %d...' % server_data['port'] |
| 1327 | 1410 |
| 1328 # Notify the parent that we've started. (BaseServer subclasses | 1411 # Notify the parent that we've started. (BaseServer subclasses |
| 1329 # bind their sockets on construction.) | 1412 # bind their sockets on construction.) |
| 1330 if options.startup_pipe is not None: | 1413 if options.startup_pipe is not None: |
| 1331 server_data = { | |
| 1332 'port': listen_port | |
| 1333 } | |
| 1334 server_data_json = json.dumps(server_data) | 1414 server_data_json = json.dumps(server_data) |
| 1335 debug('sending server_data: %s' % server_data_json) | 1415 debug('sending server_data: %s' % server_data_json) |
| 1336 server_data_len = len(server_data_json) | 1416 server_data_len = len(server_data_json) |
| 1337 if sys.platform == 'win32': | 1417 if sys.platform == 'win32': |
| 1338 fd = msvcrt.open_osfhandle(options.startup_pipe, 0) | 1418 fd = msvcrt.open_osfhandle(options.startup_pipe, 0) |
| 1339 else: | 1419 else: |
| 1340 fd = options.startup_pipe | 1420 fd = options.startup_pipe |
| 1341 startup_pipe = os.fdopen(fd, "w") | 1421 startup_pipe = os.fdopen(fd, "w") |
| 1342 # First write the data length as an unsigned 4-byte value. This | 1422 # First write the data length as an unsigned 4-byte value. This |
| 1343 # is _not_ using network byte ordering since the other end of the | 1423 # is _not_ using network byte ordering since the other end of the |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1388 'option may appear multiple times, indicating ' | 1468 'option may appear multiple times, indicating ' |
| 1389 'multiple algorithms should be enabled.'); | 1469 'multiple algorithms should be enabled.'); |
| 1390 option_parser.add_option('', '--file-root-url', default='/files/', | 1470 option_parser.add_option('', '--file-root-url', default='/files/', |
| 1391 help='Specify a root URL for files served.') | 1471 help='Specify a root URL for files served.') |
| 1392 option_parser.add_option('', '--startup-pipe', type='int', | 1472 option_parser.add_option('', '--startup-pipe', type='int', |
| 1393 dest='startup_pipe', | 1473 dest='startup_pipe', |
| 1394 help='File handle of pipe to parent process') | 1474 help='File handle of pipe to parent process') |
| 1395 options, args = option_parser.parse_args() | 1475 options, args = option_parser.parse_args() |
| 1396 | 1476 |
| 1397 sys.exit(main(options, args)) | 1477 sys.exit(main(options, args)) |
| OLD | NEW |