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

Side by Side Diff: net/tools/testserver/testserver.py

Issue 5104004: Spin up XMPP server for testservers of type sync. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 10 years, 1 month 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 | net/tools/testserver/xmppserver.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/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 sys.version_info < (2, 6): 33 if sys.version_info < (2, 6):
31 import simplejson as json 34 import simplejson as json
32 else: 35 else:
33 import json 36 import json
(...skipping 17 matching lines...) Expand all
51 54
52 SERVER_HTTP = 0 55 SERVER_HTTP = 0
53 SERVER_FTP = 1 56 SERVER_FTP = 1
54 SERVER_SYNC = 2 57 SERVER_SYNC = 2
55 58
56 debug_output = sys.stderr 59 debug_output = sys.stderr
57 def debug(str): 60 def debug(str):
58 debug_output.write(str + "\n") 61 debug_output.write(str + "\n")
59 debug_output.flush() 62 debug_output.flush()
60 63
64 class Error(Exception):
65 """Error class for this module."""
66 pass
67
68 class UnexpectedSocketType(Error):
69 """Raised when a value of a socket map is of unknown type."""
70 pass
71
61 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): 72 class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
62 """This is a specialization of of BaseHTTPServer to allow it 73 """This is a specialization of of BaseHTTPServer to allow it
63 to be exited cleanly (by setting its "stop" member to True).""" 74 to be exited cleanly (by setting its "stop" member to True)."""
64 75
65 def serve_forever(self): 76 def serve_forever(self):
66 self.stop = False 77 self.stop = False
67 self.nonce_time = None 78 self.nonce_time = None
68 while not self.stop: 79 while not self.stop:
69 self.handle_request() 80 self.handle_request()
70 self.socket.close() 81 self.socket.close()
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 return False 124 return False
114 125
115 126
116 class SyncHTTPServer(StoppableHTTPServer): 127 class SyncHTTPServer(StoppableHTTPServer):
117 """An HTTP server that handles sync commands.""" 128 """An HTTP server that handles sync commands."""
118 129
119 def __init__(self, server_address, request_handler_class): 130 def __init__(self, server_address, request_handler_class):
120 # We import here to avoid pulling in chromiumsync's dependencies 131 # We import here to avoid pulling in chromiumsync's dependencies
121 # unless strictly necessary. 132 # unless strictly necessary.
122 import chromiumsync 133 import chromiumsync
134 import xmppserver
135 StoppableHTTPServer.__init__(self, server_address, request_handler_class)
123 self._sync_handler = chromiumsync.TestServer() 136 self._sync_handler = chromiumsync.TestServer()
124 StoppableHTTPServer.__init__(self, server_address, request_handler_class) 137 self._socket_map = { self.fileno(): self }
138 self._xmpp_server = xmppserver.XmppServer(
cbentzel 2010/11/18 11:59:09 Should xmpp_server be run a separate thread so you
akalin 2010/11/18 23:32:58 I think the complexity of this select loop (especi
139 self._socket_map, ('localhost', 0))
140 self.xmpp_port = self._xmpp_server.getsockname()[1]
125 141
126 def HandleCommand(self, query, raw_request): 142 def HandleCommand(self, query, raw_request):
127 return self._sync_handler.HandleCommand(query, raw_request) 143 return self._sync_handler.HandleCommand(query, raw_request)
128 144
145 def serve_forever(self):
146 """This is a merge of asyncore.loop() and SocketServer.serve_forever().
147 """
148
149 def HandleSocketServerRequestNoBlock(socket_server):
150 """Handles a single request for a SocketServer.BaseServer.
151
152 Copied from SocketServer._handle_request_noblock().
153 """
154 try:
155 request, client_address = socket_server.get_request()
156 except socket.error:
157 return
158 if socket_server.verify_request(request, client_address):
159 try:
160 socket_server.process_request(request, client_address)
161 except:
162 socket_server.handle_error(request, client_address)
163 socket_server.close_request(request)
164
165 def RunDispatcherHandler(dispatcher, handler):
166 """Handles a single event for an asyncore.dispatcher.
167
168 Adapted from asyncore.read() et al.
169 """
170 try:
171 handler(dispatcher)
172 except (asyncore.ExitNow, KeyboardInterrupt, SystemExit):
173 raise
174 except:
175 dispatcher.handle_error()
176
177 poll_interval = 0.5
178
179 while map:
180 r = []; w = []; e = []
181 for fd, obj in self._socket_map.items():
182 if isinstance(obj, SocketServer.BaseServer):
183 r.append(fd)
184 elif isinstance(obj, asyncore.dispatcher):
185 is_r = obj.readable()
186 is_w = obj.writable()
187 if is_r:
188 r.append(fd)
189 if is_w:
190 w.append(fd)
191 if is_r or is_w:
192 e.append(fd)
193 else:
194 raise UnexpectedSocketType()
195
196 if [] == r == w == e:
197 time.sleep(poll_interval)
Paweł Hajdan Jr. 2010/11/18 11:58:45 hmmm, why? Can we wait for an event that would mak
akalin 2010/11/18 23:32:58 Actually, this case should never happen. Removed
198 continue
199
200 try:
201 r, w, e = select.select(r, w, e, poll_interval)
202 except select.error, err:
203 if err.args[0] != errno.EINTR:
204 raise
205 else:
206 continue
207
208 for fd in r:
209 obj = self._socket_map.get(fd)
210 if obj is None:
211 continue
212 if isinstance(obj, SocketServer.BaseServer):
213 HandleSocketServerRequestNoBlock(obj)
214 elif isinstance(obj, asyncore.dispatcher):
215 RunDispatcherHandler(obj, asyncore.dispatcher.handle_read_event)
216 else:
217 raise UnexpectedSocketType()
218
219 for fd in w:
220 obj = self._socket_map.get(fd)
221 if obj is None:
222 continue
223 if isinstance(obj, asyncore.dispatcher):
224 RunDispatcherHandler(obj, asyncore.dispatcher.handle_write_event)
225 else:
226 raise UnexpectedSocketType()
227
228 for fd in e:
229 obj = self._socket_map.get(fd)
230 if obj is None:
231 continue
232 if isinstance(obj, asyncore.dispatcher):
233 RunDispatcherHandler(obj, asyncore.dispatcher.handle_expt_event)
234 else:
235 raise UnexpectedSocketType()
236
129 237
130 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): 238 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
131 239
132 def __init__(self, request, client_address, socket_server, 240 def __init__(self, request, client_address, socket_server,
133 connect_handlers, get_handlers, post_handlers, put_handlers): 241 connect_handlers, get_handlers, post_handlers, put_handlers):
134 self._connect_handlers = connect_handlers 242 self._connect_handlers = connect_handlers
135 self._get_handlers = get_handlers 243 self._get_handlers = get_handlers
136 self._post_handlers = post_handlers 244 self._post_handlers = post_handlers
137 self._put_handlers = put_handlers 245 self._put_handlers = put_handlers
138 BaseHTTPServer.BaseHTTPRequestHandler.__init__( 246 BaseHTTPServer.BaseHTTPRequestHandler.__init__(
(...skipping 1103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1242 self.__fd1.flush() 1350 self.__fd1.flush()
1243 self.__fd2.flush() 1351 self.__fd2.flush()
1244 1352
1245 def main(options, args): 1353 def main(options, args):
1246 logfile = open('testserver.log', 'w') 1354 logfile = open('testserver.log', 'w')
1247 sys.stdout = FileMultiplexer(sys.stdout, logfile) 1355 sys.stdout = FileMultiplexer(sys.stdout, logfile)
1248 sys.stderr = FileMultiplexer(sys.stderr, logfile) 1356 sys.stderr = FileMultiplexer(sys.stderr, logfile)
1249 1357
1250 port = options.port 1358 port = options.port
1251 1359
1360 server_data = {}
1361
1252 if options.server_type == SERVER_HTTP: 1362 if options.server_type == SERVER_HTTP:
1253 if options.cert: 1363 if options.cert:
1254 # let's make sure the cert file exists. 1364 # let's make sure the cert file exists.
1255 if not os.path.isfile(options.cert): 1365 if not os.path.isfile(options.cert):
1256 print 'specified server cert file not found: ' + options.cert + \ 1366 print 'specified server cert file not found: ' + options.cert + \
1257 ' exiting...' 1367 ' exiting...'
1258 return 1368 return
1259 for ca_cert in options.ssl_client_ca: 1369 for ca_cert in options.ssl_client_ca:
1260 if not os.path.isfile(ca_cert): 1370 if not os.path.isfile(ca_cert):
1261 print 'specified trusted client CA file not found: ' + ca_cert + \ 1371 print 'specified trusted client CA file not found: ' + ca_cert + \
1262 ' exiting...' 1372 ' exiting...'
1263 return 1373 return
1264 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, 1374 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert,
1265 options.ssl_client_auth, options.ssl_client_ca, 1375 options.ssl_client_auth, options.ssl_client_ca,
1266 options.ssl_bulk_cipher) 1376 options.ssl_bulk_cipher)
1267 print 'HTTPS server started on port %d...' % server.server_port 1377 print 'HTTPS server started on port %d...' % server.server_port
1268 else: 1378 else:
1269 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) 1379 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler)
1270 print 'HTTP server started on port %d...' % server.server_port 1380 print 'HTTP server started on port %d...' % server.server_port
1271 1381
1272 server.data_dir = MakeDataDir() 1382 server.data_dir = MakeDataDir()
1273 server.file_root_url = options.file_root_url 1383 server.file_root_url = options.file_root_url
1274 listen_port = server.server_port 1384 server_data['port'] = server.server_port
cbentzel 2010/11/18 11:59:09 Should this move to unique key per server type?
akalin 2010/11/18 23:32:58 Hmm I don't think so. Then run_testserver would h
1275 server._device_management_handler = None 1385 server._device_management_handler = None
1276 elif options.server_type == SERVER_SYNC: 1386 elif options.server_type == SERVER_SYNC:
1277 server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler) 1387 server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler)
1278 print 'Sync HTTP server started on port %d...' % server.server_port 1388 print 'Sync HTTP server started on port %d...' % server.server_port
1279 listen_port = server.server_port 1389 print 'Sync XMPP server started on port %d...' % server.xmpp_port
1390 server_data['port'] = server.server_port
1391 server_data['xmpp_port'] = server.xmpp_port
1280 # means FTP Server 1392 # means FTP Server
1281 else: 1393 else:
1282 my_data_dir = MakeDataDir() 1394 my_data_dir = MakeDataDir()
1283 1395
1284 # Instantiate a dummy authorizer for managing 'virtual' users 1396 # Instantiate a dummy authorizer for managing 'virtual' users
1285 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() 1397 authorizer = pyftpdlib.ftpserver.DummyAuthorizer()
1286 1398
1287 # Define a new user having full r/w permissions and a read-only 1399 # Define a new user having full r/w permissions and a read-only
1288 # anonymous user 1400 # anonymous user
1289 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') 1401 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw')
1290 1402
1291 authorizer.add_anonymous(my_data_dir) 1403 authorizer.add_anonymous(my_data_dir)
1292 1404
1293 # Instantiate FTP handler class 1405 # Instantiate FTP handler class
1294 ftp_handler = pyftpdlib.ftpserver.FTPHandler 1406 ftp_handler = pyftpdlib.ftpserver.FTPHandler
1295 ftp_handler.authorizer = authorizer 1407 ftp_handler.authorizer = authorizer
1296 1408
1297 # Define a customized banner (string returned when client connects) 1409 # Define a customized banner (string returned when client connects)
1298 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % 1410 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." %
1299 pyftpdlib.ftpserver.__ver__) 1411 pyftpdlib.ftpserver.__ver__)
1300 1412
1301 # Instantiate FTP server class and listen to 127.0.0.1:port 1413 # Instantiate FTP server class and listen to 127.0.0.1:port
1302 address = ('127.0.0.1', port) 1414 address = ('127.0.0.1', port)
1303 server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler) 1415 server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler)
1304 listen_port = server.socket.getsockname()[1] 1416 server_data['port'] = server.socket.getsockname()[1]
1305 print 'FTP server started on port %d...' % listen_port 1417 print 'FTP server started on port %d...' % server_data['port']
1306 1418
1307 # Notify the parent that we've started. (BaseServer subclasses 1419 # Notify the parent that we've started. (BaseServer subclasses
1308 # bind their sockets on construction.) 1420 # bind their sockets on construction.)
1309 if options.startup_pipe is not None: 1421 if options.startup_pipe is not None:
1310 server_data = {
1311 'port': listen_port
1312 }
1313 server_data_json = json.dumps(server_data) 1422 server_data_json = json.dumps(server_data)
1314 print 'sending server_data: %s' % server_data_json 1423 print 'sending server_data: %s' % server_data_json
1315 server_data_len = len(server_data_json) 1424 server_data_len = len(server_data_json)
1316 if sys.platform == 'win32': 1425 if sys.platform == 'win32':
1317 fd = msvcrt.open_osfhandle(options.startup_pipe, 0) 1426 fd = msvcrt.open_osfhandle(options.startup_pipe, 0)
1318 else: 1427 else:
1319 fd = options.startup_pipe 1428 fd = options.startup_pipe
1320 startup_pipe = os.fdopen(fd, "w") 1429 startup_pipe = os.fdopen(fd, "w")
1321 # First write the data length as an unsigned 4-byte value. This 1430 # First write the data length as an unsigned 4-byte value. This
1322 # is _not_ using network byte ordering since the other end of the 1431 # is _not_ using network byte ordering since the other end of the
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 'option may appear multiple times, indicating ' 1476 'option may appear multiple times, indicating '
1368 'multiple algorithms should be enabled.'); 1477 'multiple algorithms should be enabled.');
1369 option_parser.add_option('', '--file-root-url', default='/files/', 1478 option_parser.add_option('', '--file-root-url', default='/files/',
1370 help='Specify a root URL for files served.') 1479 help='Specify a root URL for files served.')
1371 option_parser.add_option('', '--startup-pipe', type='int', 1480 option_parser.add_option('', '--startup-pipe', type='int',
1372 dest='startup_pipe', 1481 dest='startup_pipe',
1373 help='File handle of pipe to parent process') 1482 help='File handle of pipe to parent process')
1374 options, args = option_parser.parse_args() 1483 options, args = option_parser.parse_args()
1375 1484
1376 sys.exit(main(options, args)) 1485 sys.exit(main(options, args))
OLDNEW
« no previous file with comments | « no previous file | net/tools/testserver/xmppserver.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698