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

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

Issue 11971025: [sync] Divorce python sync test server chromiumsync.py from testserver.py (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 11 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 | « net/tools/testserver/run_testserver.cc ('k') | net/tools/testserver/testserver_base.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 2013 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/FTP/SYNC/TCP/UDP/ server used for testing Chrome. 6 """This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for
7 testing Chrome.
7 8
8 It supports several test URLs, as specified by the handlers in TestPageHandler. 9 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 10 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 11 the originating process over a pipe. The originating process can specify an
11 explicit port if necessary. 12 explicit port if necessary.
12 It can use https if you specify the flag --https=CERT where CERT is the path 13 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. 14 to a pem file containing the certificate and private key that should be used.
14 """ 15 """
15 16
16 import asyncore
17 import base64 17 import base64
18 import BaseHTTPServer 18 import BaseHTTPServer
19 import cgi 19 import cgi
20 import errno
21 import hashlib 20 import hashlib
22 import json
23 import logging 21 import logging
24 import minica 22 import minica
25 import os 23 import os
26 import random 24 import random
27 import re 25 import re
28 import select 26 import select
29 import socket 27 import socket
30 import SocketServer 28 import SocketServer
31 import struct 29 import struct
32 import sys 30 import sys
33 import threading 31 import threading
34 import time 32 import time
35 import urllib 33 import urllib
36 import urlparse 34 import urlparse
37 import zlib 35 import zlib
38 36
39 import echo_message 37 import echo_message
40 import pyftpdlib.ftpserver 38 import pyftpdlib.ftpserver
41 import testserver_base 39 import testserver_base
42 import tlslite 40 import tlslite
43 import tlslite.api 41 import tlslite.api
44 42
45 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 43 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
46 sys.path.insert( 44 sys.path.insert(
47 0, os.path.join(BASE_DIR, '..', '..', '..', 'third_party/pywebsocket/src')) 45 0, os.path.join(BASE_DIR, '..', '..', '..', 'third_party/pywebsocket/src'))
48 from mod_pywebsocket.standalone import WebSocketServer 46 from mod_pywebsocket.standalone import WebSocketServer
49 47
50 SERVER_HTTP = 0 48 SERVER_HTTP = 0
51 SERVER_FTP = 1 49 SERVER_FTP = 1
52 SERVER_SYNC = 2 50 SERVER_TCP_ECHO = 2
53 SERVER_TCP_ECHO = 3 51 SERVER_UDP_ECHO = 3
54 SERVER_UDP_ECHO = 4 52 SERVER_BASIC_AUTH_PROXY = 4
55 SERVER_BASIC_AUTH_PROXY = 5 53 SERVER_WEBSOCKET = 5
56 SERVER_WEBSOCKET = 6
57 54
58 # Default request queue size for WebSocketServer. 55 # Default request queue size for WebSocketServer.
59 _DEFAULT_REQUEST_QUEUE_SIZE = 128 56 _DEFAULT_REQUEST_QUEUE_SIZE = 128
60 57
61 58
62 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 .
63 debug_output = sys.stderr
64 def debug(string):
65 debug_output.write(string + "\n")
66 debug_output.flush()
67
68
69 class WebSocketOptions: 59 class WebSocketOptions:
70 """Holds options for WebSocketServer.""" 60 """Holds options for WebSocketServer."""
71 61
72 def __init__(self, host, port, data_dir): 62 def __init__(self, host, port, data_dir):
73 self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE 63 self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE
74 self.server_host = host 64 self.server_host = host
75 self.port = port 65 self.port = port
76 self.websock_handlers = data_dir 66 self.websock_handlers = data_dir
77 self.scan_dir = None 67 self.scan_dir = None
78 self.allow_handlers_outside_root_dir = False 68 self.allow_handlers_outside_root_dir = False
(...skipping 19 matching lines...) Expand all
98 self.log = [] 88 self.log = []
99 89
100 def __getitem__(self, sessionID): 90 def __getitem__(self, sessionID):
101 self.log.append(('lookup', sessionID)) 91 self.log.append(('lookup', sessionID))
102 raise KeyError() 92 raise KeyError()
103 93
104 def __setitem__(self, sessionID, session): 94 def __setitem__(self, sessionID, session):
105 self.log.append(('insert', sessionID)) 95 self.log.append(('insert', sessionID))
106 96
107 97
108 class ClientRestrictingServerMixIn: 98 class HTTPServer(testserver_base.ClientRestrictingServerMixIn,
109 """Implements verify_request to limit connections to our configured IP 99 testserver_base.BrokenPipeHandlerMixIn,
110 address.""" 100 testserver_base.StoppableHTTPServer):
111
112 def verify_request(self, _request, client_address):
113 return client_address[0] == self.server_address[0]
114
115
116 class BrokenPipeHandlerMixIn:
117 """Allows the server to deal with "broken pipe" errors (which happen if the
118 browser quits with outstanding requests, like for the favicon). This mix-in
119 requires the class to derive from SocketServer.BaseServer and not override its
120 handle_error() method. """
121
122 def handle_error(self, request, client_address):
123 value = sys.exc_info()[1]
124 if isinstance(value, socket.error):
125 err = value.args[0]
126 if sys.platform in ('win32', 'cygwin'):
127 # "An established connection was aborted by the software in your host."
128 pipe_err = 10053
129 else:
130 pipe_err = errno.EPIPE
131 if err == pipe_err:
132 print "testserver.py: Broken pipe"
133 return
134 SocketServer.BaseServer.handle_error(self, request, client_address)
135
136
137 class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
138 """This is a specialization of BaseHTTPServer to allow it
139 to be exited cleanly (by setting its "stop" member to True)."""
140
141 def serve_forever(self):
142 self.stop = False
143 self.nonce_time = None
144 while not self.stop:
145 self.handle_request()
146 self.socket.close()
147
148
149 class HTTPServer(ClientRestrictingServerMixIn,
150 BrokenPipeHandlerMixIn,
151 StoppableHTTPServer):
152 """This is a specialization of StoppableHTTPServer that adds client 101 """This is a specialization of StoppableHTTPServer that adds client
153 verification.""" 102 verification."""
154 103
155 pass 104 pass
156 105
157 class OCSPServer(ClientRestrictingServerMixIn, 106 class OCSPServer(testserver_base.ClientRestrictingServerMixIn,
158 BrokenPipeHandlerMixIn, 107 testserver_base.BrokenPipeHandlerMixIn,
159 BaseHTTPServer.HTTPServer): 108 BaseHTTPServer.HTTPServer):
160 """This is a specialization of HTTPServer that serves an 109 """This is a specialization of HTTPServer that serves an
161 OCSP response""" 110 OCSP response"""
162 111
163 def serve_forever_on_thread(self): 112 def serve_forever_on_thread(self):
164 self.thread = threading.Thread(target = self.serve_forever, 113 self.thread = threading.Thread(target = self.serve_forever,
165 name = "OCSPServerThread") 114 name = "OCSPServerThread")
166 self.thread.start() 115 self.thread.start()
167 116
168 def stop_serving(self): 117 def stop_serving(self):
169 self.shutdown() 118 self.shutdown()
170 self.thread.join() 119 self.thread.join()
171 120
172 121
173 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, 122 class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
174 ClientRestrictingServerMixIn, 123 testserver_base.ClientRestrictingServerMixIn,
175 BrokenPipeHandlerMixIn, 124 testserver_base.BrokenPipeHandlerMixIn,
176 StoppableHTTPServer): 125 testserver_base.StoppableHTTPServer):
177 """This is a specialization of StoppableHTTPServer that add https support and 126 """This is a specialization of StoppableHTTPServer that add https support and
178 client verification.""" 127 client verification."""
179 128
180 def __init__(self, server_address, request_hander_class, pem_cert_and_key, 129 def __init__(self, server_address, request_hander_class, pem_cert_and_key,
181 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, 130 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers,
182 record_resume_info, tls_intolerant): 131 record_resume_info, tls_intolerant):
183 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) 132 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key)
184 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True) 133 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True)
185 self.ssl_client_auth = ssl_client_auth 134 self.ssl_client_auth = ssl_client_auth
186 self.ssl_client_cas = [] 135 self.ssl_client_cas = []
187 self.tls_intolerant = tls_intolerant 136 self.tls_intolerant = tls_intolerant
188 137
189 for ca_file in ssl_client_cas: 138 for ca_file in ssl_client_cas:
190 s = open(ca_file).read() 139 s = open(ca_file).read()
191 x509 = tlslite.api.X509() 140 x509 = tlslite.api.X509()
192 x509.parse(s) 141 x509.parse(s)
193 self.ssl_client_cas.append(x509.subject) 142 self.ssl_client_cas.append(x509.subject)
194 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() 143 self.ssl_handshake_settings = tlslite.api.HandshakeSettings()
195 if ssl_bulk_ciphers is not None: 144 if ssl_bulk_ciphers is not None:
196 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers 145 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers
197 146
198 if record_resume_info: 147 if record_resume_info:
199 # If record_resume_info is true then we'll replace the session cache with 148 # If record_resume_info is true then we'll replace the session cache with
200 # an object that records the lookups and inserts that it sees. 149 # an object that records the lookups and inserts that it sees.
201 self.session_cache = RecordingSSLSessionCache() 150 self.session_cache = RecordingSSLSessionCache()
202 else: 151 else:
203 self.session_cache = tlslite.api.SessionCache() 152 self.session_cache = tlslite.api.SessionCache()
204 StoppableHTTPServer.__init__(self, server_address, request_hander_class) 153 testserver_base.StoppableHTTPServer.__init__(self,
154 server_address,
155 request_hander_class)
205 156
206 def handshake(self, tlsConnection): 157 def handshake(self, tlsConnection):
207 """Creates the SSL connection.""" 158 """Creates the SSL connection."""
208 159
209 try: 160 try:
210 tlsConnection.handshakeServer(certChain=self.cert_chain, 161 tlsConnection.handshakeServer(certChain=self.cert_chain,
211 privateKey=self.private_key, 162 privateKey=self.private_key,
212 sessionCache=self.session_cache, 163 sessionCache=self.session_cache,
213 reqCert=self.ssl_client_auth, 164 reqCert=self.ssl_client_auth,
214 settings=self.ssl_handshake_settings, 165 settings=self.ssl_handshake_settings,
215 reqCAs=self.ssl_client_cas, 166 reqCAs=self.ssl_client_cas,
216 tlsIntolerant=self.tls_intolerant) 167 tlsIntolerant=self.tls_intolerant)
217 tlsConnection.ignoreAbruptClose = True 168 tlsConnection.ignoreAbruptClose = True
218 return True 169 return True
219 except tlslite.api.TLSAbruptCloseError: 170 except tlslite.api.TLSAbruptCloseError:
220 # Ignore abrupt close. 171 # Ignore abrupt close.
221 return True 172 return True
222 except tlslite.api.TLSError, error: 173 except tlslite.api.TLSError, error:
223 print "Handshake failure:", str(error) 174 print "Handshake failure:", str(error)
224 return False 175 return False
225 176
226 177
227 class SyncHTTPServer(ClientRestrictingServerMixIn, 178 class FTPServer(testserver_base.ClientRestrictingServerMixIn,
228 BrokenPipeHandlerMixIn, 179 pyftpdlib.ftpserver.FTPServer):
229 StoppableHTTPServer):
230 """An HTTP server that handles sync commands."""
231
232 def __init__(self, server_address, xmpp_port, request_handler_class):
233 # We import here to avoid pulling in chromiumsync's dependencies
234 # unless strictly necessary.
235 import chromiumsync
236 import xmppserver
237 StoppableHTTPServer.__init__(self, server_address, request_handler_class)
238 self._sync_handler = chromiumsync.TestServer()
239 self._xmpp_socket_map = {}
240 self._xmpp_server = xmppserver.XmppServer(
241 self._xmpp_socket_map, ('localhost', xmpp_port))
242 self.xmpp_port = self._xmpp_server.getsockname()[1]
243 self.authenticated = True
244
245 def GetXmppServer(self):
246 return self._xmpp_server
247
248 def HandleCommand(self, query, raw_request):
249 return self._sync_handler.HandleCommand(query, raw_request)
250
251 def HandleRequestNoBlock(self):
252 """Handles a single request.
253
254 Copied from SocketServer._handle_request_noblock().
255 """
256
257 try:
258 request, client_address = self.get_request()
259 except socket.error:
260 return
261 if self.verify_request(request, client_address):
262 try:
263 self.process_request(request, client_address)
264 except Exception:
265 self.handle_error(request, client_address)
266 self.close_request(request)
267
268 def SetAuthenticated(self, auth_valid):
269 self.authenticated = auth_valid
270
271 def GetAuthenticated(self):
272 return self.authenticated
273
274 def serve_forever(self):
275 """This is a merge of asyncore.loop() and SocketServer.serve_forever().
276 """
277
278 def HandleXmppSocket(fd, socket_map, handler):
279 """Runs the handler for the xmpp connection for fd.
280
281 Adapted from asyncore.read() et al.
282 """
283
284 xmpp_connection = socket_map.get(fd)
285 # This could happen if a previous handler call caused fd to get
286 # removed from socket_map.
287 if xmpp_connection is None:
288 return
289 try:
290 handler(xmpp_connection)
291 except (asyncore.ExitNow, KeyboardInterrupt, SystemExit):
292 raise
293 except:
294 xmpp_connection.handle_error()
295
296 while True:
297 read_fds = [ self.fileno() ]
298 write_fds = []
299 exceptional_fds = []
300
301 for fd, xmpp_connection in self._xmpp_socket_map.items():
302 is_r = xmpp_connection.readable()
303 is_w = xmpp_connection.writable()
304 if is_r:
305 read_fds.append(fd)
306 if is_w:
307 write_fds.append(fd)
308 if is_r or is_w:
309 exceptional_fds.append(fd)
310
311 try:
312 read_fds, write_fds, exceptional_fds = (
313 select.select(read_fds, write_fds, exceptional_fds))
314 except select.error, err:
315 if err.args[0] != errno.EINTR:
316 raise
317 else:
318 continue
319
320 for fd in read_fds:
321 if fd == self.fileno():
322 self.HandleRequestNoBlock()
323 continue
324 HandleXmppSocket(fd, self._xmpp_socket_map,
325 asyncore.dispatcher.handle_read_event)
326
327 for fd in write_fds:
328 HandleXmppSocket(fd, self._xmpp_socket_map,
329 asyncore.dispatcher.handle_write_event)
330
331 for fd in exceptional_fds:
332 HandleXmppSocket(fd, self._xmpp_socket_map,
333 asyncore.dispatcher.handle_expt_event)
334
335
336 class FTPServer(ClientRestrictingServerMixIn, pyftpdlib.ftpserver.FTPServer):
337 """This is a specialization of FTPServer that adds client verification.""" 180 """This is a specialization of FTPServer that adds client verification."""
338 181
339 pass 182 pass
340 183
341 184
342 class TCPEchoServer(ClientRestrictingServerMixIn, SocketServer.TCPServer): 185 class TCPEchoServer(testserver_base.ClientRestrictingServerMixIn,
186 SocketServer.TCPServer):
343 """A TCP echo server that echoes back what it has received.""" 187 """A TCP echo server that echoes back what it has received."""
344 188
345 def server_bind(self): 189 def server_bind(self):
346 """Override server_bind to store the server name.""" 190 """Override server_bind to store the server name."""
347 191
348 SocketServer.TCPServer.server_bind(self) 192 SocketServer.TCPServer.server_bind(self)
349 host, port = self.socket.getsockname()[:2] 193 host, port = self.socket.getsockname()[:2]
350 self.server_name = socket.getfqdn(host) 194 self.server_name = socket.getfqdn(host)
351 self.server_port = port 195 self.server_port = port
352 196
353 def serve_forever(self): 197 def serve_forever(self):
354 self.stop = False 198 self.stop = False
355 self.nonce_time = None 199 self.nonce_time = None
356 while not self.stop: 200 while not self.stop:
357 self.handle_request() 201 self.handle_request()
358 self.socket.close() 202 self.socket.close()
359 203
360 204
361 class UDPEchoServer(ClientRestrictingServerMixIn, SocketServer.UDPServer): 205 class UDPEchoServer(testserver_base.ClientRestrictingServerMixIn,
206 SocketServer.UDPServer):
362 """A UDP echo server that echoes back what it has received.""" 207 """A UDP echo server that echoes back what it has received."""
363 208
364 def server_bind(self): 209 def server_bind(self):
365 """Override server_bind to store the server name.""" 210 """Override server_bind to store the server name."""
366 211
367 SocketServer.UDPServer.server_bind(self) 212 SocketServer.UDPServer.server_bind(self)
368 host, port = self.socket.getsockname()[:2] 213 host, port = self.socket.getsockname()[:2]
369 self.server_name = socket.getfqdn(host) 214 self.server_name = socket.getfqdn(host)
370 self.server_port = port 215 self.server_port = port
371 216
372 def serve_forever(self): 217 def serve_forever(self):
373 self.stop = False 218 self.stop = False
374 self.nonce_time = None 219 self.nonce_time = None
375 while not self.stop: 220 while not self.stop:
376 self.handle_request() 221 self.handle_request()
377 self.socket.close() 222 self.socket.close()
378 223
379 224
380 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): 225 class TestPageHandler(testserver_base.BasePageHandler):
381
382 def __init__(self, request, client_address, socket_server,
383 connect_handlers, get_handlers, head_handlers, post_handlers,
384 put_handlers):
385 self._connect_handlers = connect_handlers
386 self._get_handlers = get_handlers
387 self._head_handlers = head_handlers
388 self._post_handlers = post_handlers
389 self._put_handlers = put_handlers
390 BaseHTTPServer.BaseHTTPRequestHandler.__init__(
391 self, request, client_address, socket_server)
392
393 def log_request(self, *args, **kwargs):
394 # Disable request logging to declutter test log output.
395 pass
396
397 def _ShouldHandleRequest(self, handler_name):
398 """Determines if the path can be handled by the handler.
399
400 We consider a handler valid if the path begins with the
401 handler name. It can optionally be followed by "?*", "/*".
402 """
403
404 pattern = re.compile('%s($|\?|/).*' % handler_name)
405 return pattern.match(self.path)
406
407 def do_CONNECT(self):
408 for handler in self._connect_handlers:
409 if handler():
410 return
411
412 def do_GET(self):
413 for handler in self._get_handlers:
414 if handler():
415 return
416
417 def do_HEAD(self):
418 for handler in self._head_handlers:
419 if handler():
420 return
421
422 def do_POST(self):
423 for handler in self._post_handlers:
424 if handler():
425 return
426
427 def do_PUT(self):
428 for handler in self._put_handlers:
429 if handler():
430 return
431
432
433 class TestPageHandler(BasePageHandler):
434 226
435 def __init__(self, request, client_address, socket_server): 227 def __init__(self, request, client_address, socket_server):
436 connect_handlers = [ 228 connect_handlers = [
437 self.RedirectConnectHandler, 229 self.RedirectConnectHandler,
438 self.ServerAuthConnectHandler, 230 self.ServerAuthConnectHandler,
439 self.DefaultConnectResponseHandler] 231 self.DefaultConnectResponseHandler]
440 get_handlers = [ 232 get_handlers = [
441 self.NoCacheMaxAgeTimeHandler, 233 self.NoCacheMaxAgeTimeHandler,
442 self.NoCacheTimeHandler, 234 self.NoCacheTimeHandler,
443 self.CacheTimeHandler, 235 self.CacheTimeHandler,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 'gif': 'image/gif', 286 'gif': 'image/gif',
495 'jpeg' : 'image/jpeg', 287 'jpeg' : 'image/jpeg',
496 'jpg' : 'image/jpeg', 288 'jpg' : 'image/jpeg',
497 'json': 'application/json', 289 'json': 'application/json',
498 'pdf' : 'application/pdf', 290 'pdf' : 'application/pdf',
499 'wav' : 'audio/wav', 291 'wav' : 'audio/wav',
500 'xml' : 'text/xml' 292 'xml' : 'text/xml'
501 } 293 }
502 self._default_mime_type = 'text/html' 294 self._default_mime_type = 'text/html'
503 295
504 BasePageHandler.__init__(self, request, client_address, socket_server, 296 testserver_base.BasePageHandler.__init__(self, request, client_address,
505 connect_handlers, get_handlers, head_handlers, 297 socket_server, connect_handlers,
506 post_handlers, put_handlers) 298 get_handlers, head_handlers,
299 post_handlers, put_handlers)
507 300
508 def GetMIMETypeFromName(self, file_name): 301 def GetMIMETypeFromName(self, file_name):
509 """Returns the mime type for the specified file_name. So far it only looks 302 """Returns the mime type for the specified file_name. So far it only looks
510 at the file extension.""" 303 at the file extension."""
511 304
512 (_shortname, extension) = os.path.splitext(file_name.split("?")[0]) 305 (_shortname, extension) = os.path.splitext(file_name.split("?")[0])
513 if len(extension) == 0: 306 if len(extension) == 0:
514 # no extension. 307 # no extension.
515 return self._default_mime_type 308 return self._default_mime_type
516 309
(...skipping 1306 matching lines...) Expand 10 before | Expand all | Expand 10 after
1823 self.wfile.write('</body></html>') 1616 self.wfile.write('</body></html>')
1824 1617
1825 # called by chunked handling function 1618 # called by chunked handling function
1826 def sendChunkHelp(self, chunk): 1619 def sendChunkHelp(self, chunk):
1827 # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF 1620 # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF
1828 self.wfile.write('%X\r\n' % len(chunk)) 1621 self.wfile.write('%X\r\n' % len(chunk))
1829 self.wfile.write(chunk) 1622 self.wfile.write(chunk)
1830 self.wfile.write('\r\n') 1623 self.wfile.write('\r\n')
1831 1624
1832 1625
1833 class SyncPageHandler(BasePageHandler): 1626 class OCSPHandler(testserver_base.BasePageHandler):
1834 """Handler for the main HTTP sync server."""
1835
1836 def __init__(self, request, client_address, sync_http_server):
1837 get_handlers = [self.ChromiumSyncTimeHandler,
1838 self.ChromiumSyncMigrationOpHandler,
1839 self.ChromiumSyncCredHandler,
1840 self.ChromiumSyncXmppCredHandler,
1841 self.ChromiumSyncDisableNotificationsOpHandler,
1842 self.ChromiumSyncEnableNotificationsOpHandler,
1843 self.ChromiumSyncSendNotificationOpHandler,
1844 self.ChromiumSyncBirthdayErrorOpHandler,
1845 self.ChromiumSyncTransientErrorOpHandler,
1846 self.ChromiumSyncErrorOpHandler,
1847 self.ChromiumSyncSyncTabFaviconsOpHandler,
1848 self.ChromiumSyncCreateSyncedBookmarksOpHandler,
1849 self.ChromiumSyncEnableKeystoreEncryptionOpHandler,
1850 self.ChromiumSyncRotateKeystoreKeysOpHandler]
1851
1852 post_handlers = [self.ChromiumSyncCommandHandler,
1853 self.ChromiumSyncTimeHandler]
1854 BasePageHandler.__init__(self, request, client_address,
1855 sync_http_server, [], get_handlers, [],
1856 post_handlers, [])
1857
1858
1859 def ChromiumSyncTimeHandler(self):
1860 """Handle Chromium sync .../time requests.
1861
1862 The syncer sometimes checks server reachability by examining /time.
1863 """
1864
1865 test_name = "/chromiumsync/time"
1866 if not self._ShouldHandleRequest(test_name):
1867 return False
1868
1869 # Chrome hates it if we send a response before reading the request.
1870 if self.headers.getheader('content-length'):
1871 length = int(self.headers.getheader('content-length'))
1872 _raw_request = self.rfile.read(length)
1873
1874 self.send_response(200)
1875 self.send_header('Content-Type', 'text/plain')
1876 self.end_headers()
1877 self.wfile.write('0123456789')
1878 return True
1879
1880 def ChromiumSyncCommandHandler(self):
1881 """Handle a chromiumsync command arriving via http.
1882
1883 This covers all sync protocol commands: authentication, getupdates, and
1884 commit.
1885 """
1886
1887 test_name = "/chromiumsync/command"
1888 if not self._ShouldHandleRequest(test_name):
1889 return False
1890
1891 length = int(self.headers.getheader('content-length'))
1892 raw_request = self.rfile.read(length)
1893 http_response = 200
1894 raw_reply = None
1895 if not self.server.GetAuthenticated():
1896 http_response = 401
1897 challenge = 'GoogleLogin realm="http://%s", service="chromiumsync"' % (
1898 self.server.server_address[0])
1899 else:
1900 http_response, raw_reply = self.server.HandleCommand(
1901 self.path, raw_request)
1902
1903 ### Now send the response to the client. ###
1904 self.send_response(http_response)
1905 if http_response == 401:
1906 self.send_header('www-Authenticate', challenge)
1907 self.end_headers()
1908 self.wfile.write(raw_reply)
1909 return True
1910
1911 def ChromiumSyncMigrationOpHandler(self):
1912 test_name = "/chromiumsync/migrate"
1913 if not self._ShouldHandleRequest(test_name):
1914 return False
1915
1916 http_response, raw_reply = self.server._sync_handler.HandleMigrate(
1917 self.path)
1918 self.send_response(http_response)
1919 self.send_header('Content-Type', 'text/html')
1920 self.send_header('Content-Length', len(raw_reply))
1921 self.end_headers()
1922 self.wfile.write(raw_reply)
1923 return True
1924
1925 def ChromiumSyncCredHandler(self):
1926 test_name = "/chromiumsync/cred"
1927 if not self._ShouldHandleRequest(test_name):
1928 return False
1929 try:
1930 query = urlparse.urlparse(self.path)[4]
1931 cred_valid = urlparse.parse_qs(query)['valid']
1932 if cred_valid[0] == 'True':
1933 self.server.SetAuthenticated(True)
1934 else:
1935 self.server.SetAuthenticated(False)
1936 except Exception:
1937 self.server.SetAuthenticated(False)
1938
1939 http_response = 200
1940 raw_reply = 'Authenticated: %s ' % self.server.GetAuthenticated()
1941 self.send_response(http_response)
1942 self.send_header('Content-Type', 'text/html')
1943 self.send_header('Content-Length', len(raw_reply))
1944 self.end_headers()
1945 self.wfile.write(raw_reply)
1946 return True
1947
1948 def ChromiumSyncXmppCredHandler(self):
1949 test_name = "/chromiumsync/xmppcred"
1950 if not self._ShouldHandleRequest(test_name):
1951 return False
1952 xmpp_server = self.server.GetXmppServer()
1953 try:
1954 query = urlparse.urlparse(self.path)[4]
1955 cred_valid = urlparse.parse_qs(query)['valid']
1956 if cred_valid[0] == 'True':
1957 xmpp_server.SetAuthenticated(True)
1958 else:
1959 xmpp_server.SetAuthenticated(False)
1960 except:
1961 xmpp_server.SetAuthenticated(False)
1962
1963 http_response = 200
1964 raw_reply = 'XMPP Authenticated: %s ' % xmpp_server.GetAuthenticated()
1965 self.send_response(http_response)
1966 self.send_header('Content-Type', 'text/html')
1967 self.send_header('Content-Length', len(raw_reply))
1968 self.end_headers()
1969 self.wfile.write(raw_reply)
1970 return True
1971
1972 def ChromiumSyncDisableNotificationsOpHandler(self):
1973 test_name = "/chromiumsync/disablenotifications"
1974 if not self._ShouldHandleRequest(test_name):
1975 return False
1976 self.server.GetXmppServer().DisableNotifications()
1977 result = 200
1978 raw_reply = ('<html><title>Notifications disabled</title>'
1979 '<H1>Notifications disabled</H1></html>')
1980 self.send_response(result)
1981 self.send_header('Content-Type', 'text/html')
1982 self.send_header('Content-Length', len(raw_reply))
1983 self.end_headers()
1984 self.wfile.write(raw_reply)
1985 return True
1986
1987 def ChromiumSyncEnableNotificationsOpHandler(self):
1988 test_name = "/chromiumsync/enablenotifications"
1989 if not self._ShouldHandleRequest(test_name):
1990 return False
1991 self.server.GetXmppServer().EnableNotifications()
1992 result = 200
1993 raw_reply = ('<html><title>Notifications enabled</title>'
1994 '<H1>Notifications enabled</H1></html>')
1995 self.send_response(result)
1996 self.send_header('Content-Type', 'text/html')
1997 self.send_header('Content-Length', len(raw_reply))
1998 self.end_headers()
1999 self.wfile.write(raw_reply)
2000 return True
2001
2002 def ChromiumSyncSendNotificationOpHandler(self):
2003 test_name = "/chromiumsync/sendnotification"
2004 if not self._ShouldHandleRequest(test_name):
2005 return False
2006 query = urlparse.urlparse(self.path)[4]
2007 query_params = urlparse.parse_qs(query)
2008 channel = ''
2009 data = ''
2010 if 'channel' in query_params:
2011 channel = query_params['channel'][0]
2012 if 'data' in query_params:
2013 data = query_params['data'][0]
2014 self.server.GetXmppServer().SendNotification(channel, data)
2015 result = 200
2016 raw_reply = ('<html><title>Notification sent</title>'
2017 '<H1>Notification sent with channel "%s" '
2018 'and data "%s"</H1></html>'
2019 % (channel, data))
2020 self.send_response(result)
2021 self.send_header('Content-Type', 'text/html')
2022 self.send_header('Content-Length', len(raw_reply))
2023 self.end_headers()
2024 self.wfile.write(raw_reply)
2025 return True
2026
2027 def ChromiumSyncBirthdayErrorOpHandler(self):
2028 test_name = "/chromiumsync/birthdayerror"
2029 if not self._ShouldHandleRequest(test_name):
2030 return False
2031 result, raw_reply = self.server._sync_handler.HandleCreateBirthdayError()
2032 self.send_response(result)
2033 self.send_header('Content-Type', 'text/html')
2034 self.send_header('Content-Length', len(raw_reply))
2035 self.end_headers()
2036 self.wfile.write(raw_reply)
2037 return True
2038
2039 def ChromiumSyncTransientErrorOpHandler(self):
2040 test_name = "/chromiumsync/transienterror"
2041 if not self._ShouldHandleRequest(test_name):
2042 return False
2043 result, raw_reply = self.server._sync_handler.HandleSetTransientError()
2044 self.send_response(result)
2045 self.send_header('Content-Type', 'text/html')
2046 self.send_header('Content-Length', len(raw_reply))
2047 self.end_headers()
2048 self.wfile.write(raw_reply)
2049 return True
2050
2051 def ChromiumSyncErrorOpHandler(self):
2052 test_name = "/chromiumsync/error"
2053 if not self._ShouldHandleRequest(test_name):
2054 return False
2055 result, raw_reply = self.server._sync_handler.HandleSetInducedError(
2056 self.path)
2057 self.send_response(result)
2058 self.send_header('Content-Type', 'text/html')
2059 self.send_header('Content-Length', len(raw_reply))
2060 self.end_headers()
2061 self.wfile.write(raw_reply)
2062 return True
2063
2064 def ChromiumSyncSyncTabFaviconsOpHandler(self):
2065 test_name = "/chromiumsync/synctabfavicons"
2066 if not self._ShouldHandleRequest(test_name):
2067 return False
2068 result, raw_reply = self.server._sync_handler.HandleSetSyncTabFavicons()
2069 self.send_response(result)
2070 self.send_header('Content-Type', 'text/html')
2071 self.send_header('Content-Length', len(raw_reply))
2072 self.end_headers()
2073 self.wfile.write(raw_reply)
2074 return True
2075
2076 def ChromiumSyncCreateSyncedBookmarksOpHandler(self):
2077 test_name = "/chromiumsync/createsyncedbookmarks"
2078 if not self._ShouldHandleRequest(test_name):
2079 return False
2080 result, raw_reply = self.server._sync_handler.HandleCreateSyncedBookmarks()
2081 self.send_response(result)
2082 self.send_header('Content-Type', 'text/html')
2083 self.send_header('Content-Length', len(raw_reply))
2084 self.end_headers()
2085 self.wfile.write(raw_reply)
2086 return True
2087
2088 def ChromiumSyncEnableKeystoreEncryptionOpHandler(self):
2089 test_name = "/chromiumsync/enablekeystoreencryption"
2090 if not self._ShouldHandleRequest(test_name):
2091 return False
2092 result, raw_reply = (
2093 self.server._sync_handler.HandleEnableKeystoreEncryption())
2094 self.send_response(result)
2095 self.send_header('Content-Type', 'text/html')
2096 self.send_header('Content-Length', len(raw_reply))
2097 self.end_headers()
2098 self.wfile.write(raw_reply)
2099 return True
2100
2101 def ChromiumSyncRotateKeystoreKeysOpHandler(self):
2102 test_name = "/chromiumsync/rotatekeystorekeys"
2103 if not self._ShouldHandleRequest(test_name):
2104 return False
2105 result, raw_reply = (
2106 self.server._sync_handler.HandleRotateKeystoreKeys())
2107 self.send_response(result)
2108 self.send_header('Content-Type', 'text/html')
2109 self.send_header('Content-Length', len(raw_reply))
2110 self.end_headers()
2111 self.wfile.write(raw_reply)
2112 return True
2113
2114
2115 class OCSPHandler(BasePageHandler):
2116 def __init__(self, request, client_address, socket_server): 1627 def __init__(self, request, client_address, socket_server):
2117 handlers = [self.OCSPResponse] 1628 handlers = [self.OCSPResponse]
2118 self.ocsp_response = socket_server.ocsp_response 1629 self.ocsp_response = socket_server.ocsp_response
2119 BasePageHandler.__init__(self, request, client_address, socket_server, 1630 testserver_base.BasePageHandler.__init__(self, request, client_address,
2120 [], handlers, [], handlers, []) 1631 socket_server, [], handlers, [],
1632 handlers, [])
2121 1633
2122 def OCSPResponse(self): 1634 def OCSPResponse(self):
2123 self.send_response(200) 1635 self.send_response(200)
2124 self.send_header('Content-Type', 'application/ocsp-response') 1636 self.send_header('Content-Type', 'application/ocsp-response')
2125 self.send_header('Content-Length', str(len(self.ocsp_response))) 1637 self.send_header('Content-Length', str(len(self.ocsp_response)))
2126 self.end_headers() 1638 self.end_headers()
2127 1639
2128 self.wfile.write(self.ocsp_response) 1640 self.wfile.write(self.ocsp_response)
2129 1641
2130 1642
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
2389 raise testserver_base.OptionError( 1901 raise testserver_base.OptionError(
2390 'one trusted client CA file should be specified') 1902 'one trusted client CA file should be specified')
2391 if not os.path.isfile(self.options.ssl_client_ca[0]): 1903 if not os.path.isfile(self.options.ssl_client_ca[0]):
2392 raise testserver_base.OptionError( 1904 raise testserver_base.OptionError(
2393 'specified trusted client CA file not found: ' + 1905 'specified trusted client CA file not found: ' +
2394 self.options.ssl_client_ca[0] + ' exiting...') 1906 self.options.ssl_client_ca[0] + ' exiting...')
2395 websocket_options.tls_client_ca = self.options.ssl_client_ca[0] 1907 websocket_options.tls_client_ca = self.options.ssl_client_ca[0]
2396 server = WebSocketServer(websocket_options) 1908 server = WebSocketServer(websocket_options)
2397 print 'WebSocket server started on %s:%d...' % (host, server.server_port) 1909 print 'WebSocket server started on %s:%d...' % (host, server.server_port)
2398 server_data['port'] = server.server_port 1910 server_data['port'] = server.server_port
2399 elif self.options.server_type == SERVER_SYNC:
2400 xmpp_port = self.options.xmpp_port
2401 server = SyncHTTPServer((host, port), xmpp_port, SyncPageHandler)
2402 print 'Sync HTTP server started on port %d...' % server.server_port
2403 print 'Sync XMPP server started on port %d...' % server.xmpp_port
2404 server_data['port'] = server.server_port
2405 server_data['xmpp_port'] = server.xmpp_port
2406 elif self.options.server_type == SERVER_TCP_ECHO: 1911 elif self.options.server_type == SERVER_TCP_ECHO:
2407 # Used for generating the key (randomly) that encodes the "echo request" 1912 # Used for generating the key (randomly) that encodes the "echo request"
2408 # message. 1913 # message.
2409 random.seed() 1914 random.seed()
2410 server = TCPEchoServer((host, port), TCPEchoHandler) 1915 server = TCPEchoServer((host, port), TCPEchoHandler)
2411 print 'Echo TCP server started on port %d...' % server.server_port 1916 print 'Echo TCP server started on port %d...' % server.server_port
2412 server_data['port'] = server.server_port 1917 server_data['port'] = server.server_port
2413 elif self.options.server_type == SERVER_UDP_ECHO: 1918 elif self.options.server_type == SERVER_UDP_ECHO:
2414 # Used for generating the key (randomly) that encodes the "echo request" 1919 # Used for generating the key (randomly) that encodes the "echo request"
2415 # message. 1920 # message.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
2459 1964
2460 if self.__ocsp_server: 1965 if self.__ocsp_server:
2461 self.__ocsp_server.stop_serving() 1966 self.__ocsp_server.stop_serving()
2462 1967
2463 def add_options(self): 1968 def add_options(self):
2464 testserver_base.TestServerRunner.add_options(self) 1969 testserver_base.TestServerRunner.add_options(self)
2465 self.option_parser.add_option('-f', '--ftp', action='store_const', 1970 self.option_parser.add_option('-f', '--ftp', action='store_const',
2466 const=SERVER_FTP, default=SERVER_HTTP, 1971 const=SERVER_FTP, default=SERVER_HTTP,
2467 dest='server_type', 1972 dest='server_type',
2468 help='start up an FTP server.') 1973 help='start up an FTP server.')
2469 self.option_parser.add_option('--sync', action='store_const',
2470 const=SERVER_SYNC, default=SERVER_HTTP,
2471 dest='server_type',
2472 help='start up a sync server.')
2473 self.option_parser.add_option('--tcp-echo', action='store_const', 1974 self.option_parser.add_option('--tcp-echo', action='store_const',
2474 const=SERVER_TCP_ECHO, default=SERVER_HTTP, 1975 const=SERVER_TCP_ECHO, default=SERVER_HTTP,
2475 dest='server_type', 1976 dest='server_type',
2476 help='start up a tcp echo server.') 1977 help='start up a tcp echo server.')
2477 self.option_parser.add_option('--udp-echo', action='store_const', 1978 self.option_parser.add_option('--udp-echo', action='store_const',
2478 const=SERVER_UDP_ECHO, default=SERVER_HTTP, 1979 const=SERVER_UDP_ECHO, default=SERVER_HTTP,
2479 dest='server_type', 1980 dest='server_type',
2480 help='start up a udp echo server.') 1981 help='start up a udp echo server.')
2481 self.option_parser.add_option('--basic-auth-proxy', action='store_const', 1982 self.option_parser.add_option('--basic-auth-proxy', action='store_const',
2482 const=SERVER_BASIC_AUTH_PROXY, 1983 const=SERVER_BASIC_AUTH_PROXY,
2483 default=SERVER_HTTP, dest='server_type', 1984 default=SERVER_HTTP, dest='server_type',
2484 help='start up a proxy server which requires ' 1985 help='start up a proxy server which requires '
2485 'basic authentication.') 1986 'basic authentication.')
2486 self.option_parser.add_option('--websocket', action='store_const', 1987 self.option_parser.add_option('--websocket', action='store_const',
2487 const=SERVER_WEBSOCKET, default=SERVER_HTTP, 1988 const=SERVER_WEBSOCKET, default=SERVER_HTTP,
2488 dest='server_type', 1989 dest='server_type',
2489 help='start up a WebSocket server.') 1990 help='start up a WebSocket server.')
2490 self.option_parser.add_option('--xmpp-port', default='0', type='int',
2491 help='Port used by the XMPP server. If '
2492 'unspecified, the XMPP server will listen on '
2493 'an ephemeral port.')
2494 self.option_parser.add_option('--data-dir', dest='data_dir',
2495 help='Directory from which to read the '
2496 'files.')
2497 self.option_parser.add_option('--https', action='store_true', 1991 self.option_parser.add_option('--https', action='store_true',
2498 dest='https', help='Specify that https ' 1992 dest='https', help='Specify that https '
2499 'should be used.') 1993 'should be used.')
2500 self.option_parser.add_option('--cert-and-key-file', 1994 self.option_parser.add_option('--cert-and-key-file',
2501 dest='cert_and_key_file', help='specify the ' 1995 dest='cert_and_key_file', help='specify the '
2502 'path to the file containing the certificate ' 1996 'path to the file containing the certificate '
2503 'and private key for the server in PEM ' 1997 'and private key for the server in PEM '
2504 'format') 1998 'format')
2505 self.option_parser.add_option('--ocsp', dest='ocsp', default='ok', 1999 self.option_parser.add_option('--ocsp', dest='ocsp', default='ok',
2506 help='The type of OCSP response generated ' 2000 help='The type of OCSP response generated '
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
2549 'load multipe keys into the server. If the ' 2043 'load multipe keys into the server. If the '
2550 'server has multiple keys, it will rotate ' 2044 'server has multiple keys, it will rotate '
2551 'through them in at each request a ' 2045 'through them in at each request a '
2552 'round-robin fashion. The server will ' 2046 'round-robin fashion. The server will '
2553 'generate a random key if none is specified ' 2047 'generate a random key if none is specified '
2554 'on the command line.') 2048 'on the command line.')
2555 2049
2556 2050
2557 if __name__ == '__main__': 2051 if __name__ == '__main__':
2558 sys.exit(ServerRunner().main()) 2052 sys.exit(ServerRunner().main())
OLDNEW
« no previous file with comments | « net/tools/testserver/run_testserver.cc ('k') | net/tools/testserver/testserver_base.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698