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 |