OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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/SYNC/TCP/UDP/ 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 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 SERVER_SYNC = 2 | 61 SERVER_SYNC = 2 |
62 SERVER_TCP_ECHO = 3 | 62 SERVER_TCP_ECHO = 3 |
63 SERVER_UDP_ECHO = 4 | 63 SERVER_UDP_ECHO = 4 |
64 | 64 |
65 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . | 65 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . |
66 debug_output = sys.stderr | 66 debug_output = sys.stderr |
67 def debug(str): | 67 def debug(str): |
68 debug_output.write(str + "\n") | 68 debug_output.write(str + "\n") |
69 debug_output.flush() | 69 debug_output.flush() |
70 | 70 |
71 class RecordingSessionCache(object): | |
wtc
2011/12/10 01:22:37
I suggest renaming
SessionCache => SSLSessionCa
agl
2011/12/12 22:18:20
Done.
| |
72 """RecordingSessionCache acts as a TLS session cache and maintains a log of | |
73 lookups and inserts in order to test session cache behaviours.""" | |
74 | |
75 def __init__(self): | |
76 self.log = [] | |
77 | |
78 def __getitem__(self, sessionID): | |
79 self.log.append(('lookup', sessionID)) | |
80 raise KeyError() | |
81 | |
82 def __setitem__(self, sessionID, session): | |
83 self.log.append(('insert', sessionID)) | |
84 | |
71 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): | 85 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): |
72 """This is a specialization of of BaseHTTPServer to allow it | 86 """This is a specialization of of BaseHTTPServer to allow it |
73 to be exited cleanly (by setting its "stop" member to True).""" | 87 to be exited cleanly (by setting its "stop" member to True).""" |
74 | 88 |
75 def serve_forever(self): | 89 def serve_forever(self): |
76 self.stop = False | 90 self.stop = False |
77 self.nonce_time = None | 91 self.nonce_time = None |
78 while not self.stop: | 92 while not self.stop: |
79 self.handle_request() | 93 self.handle_request() |
80 self.socket.close() | 94 self.socket.close() |
81 | 95 |
82 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): | 96 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): |
83 """This is a specialization of StoppableHTTPerver that add https support.""" | 97 """This is a specialization of StoppableHTTPerver that add https support.""" |
84 | 98 |
85 def __init__(self, server_address, request_hander_class, cert_path, | 99 def __init__(self, server_address, request_hander_class, cert_path, |
86 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers): | 100 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
101 record_resume_info): | |
87 s = open(cert_path).read() | 102 s = open(cert_path).read() |
88 x509 = tlslite.api.X509() | 103 x509 = tlslite.api.X509() |
89 x509.parse(s) | 104 x509.parse(s) |
90 self.cert_chain = tlslite.api.X509CertChain([x509]) | 105 self.cert_chain = tlslite.api.X509CertChain([x509]) |
91 s = open(cert_path).read() | 106 s = open(cert_path).read() |
92 self.private_key = tlslite.api.parsePEMKey(s, private=True) | 107 self.private_key = tlslite.api.parsePEMKey(s, private=True) |
93 self.ssl_client_auth = ssl_client_auth | 108 self.ssl_client_auth = ssl_client_auth |
94 self.ssl_client_cas = [] | 109 self.ssl_client_cas = [] |
95 for ca_file in ssl_client_cas: | 110 for ca_file in ssl_client_cas: |
96 s = open(ca_file).read() | 111 s = open(ca_file).read() |
97 x509 = tlslite.api.X509() | 112 x509 = tlslite.api.X509() |
98 x509.parse(s) | 113 x509.parse(s) |
99 self.ssl_client_cas.append(x509.subject) | 114 self.ssl_client_cas.append(x509.subject) |
100 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() | 115 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() |
101 if ssl_bulk_ciphers is not None: | 116 if ssl_bulk_ciphers is not None: |
102 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers | 117 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers |
103 | 118 |
104 self.session_cache = tlslite.api.SessionCache() | 119 if record_resume_info: |
120 # If record_resume_info is true then we'll replace the session cache with | |
121 # an object that records the lookups and inserts that it sees. | |
122 self.session_cache = RecordingSessionCache() | |
123 else: | |
124 self.session_cache = tlslite.api.SessionCache() | |
105 StoppableHTTPServer.__init__(self, server_address, request_hander_class) | 125 StoppableHTTPServer.__init__(self, server_address, request_hander_class) |
106 | 126 |
107 def handshake(self, tlsConnection): | 127 def handshake(self, tlsConnection): |
108 """Creates the SSL connection.""" | 128 """Creates the SSL connection.""" |
109 try: | 129 try: |
110 tlsConnection.handshakeServer(certChain=self.cert_chain, | 130 tlsConnection.handshakeServer(certChain=self.cert_chain, |
111 privateKey=self.private_key, | 131 privateKey=self.private_key, |
112 sessionCache=self.session_cache, | 132 sessionCache=self.session_cache, |
113 reqCert=self.ssl_client_auth, | 133 reqCert=self.ssl_client_auth, |
114 settings=self.ssl_handshake_settings, | 134 settings=self.ssl_handshake_settings, |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
350 self.AuthBasicHandler, | 370 self.AuthBasicHandler, |
351 self.AuthDigestHandler, | 371 self.AuthDigestHandler, |
352 self.SlowServerHandler, | 372 self.SlowServerHandler, |
353 self.ChunkedServerHandler, | 373 self.ChunkedServerHandler, |
354 self.ContentTypeHandler, | 374 self.ContentTypeHandler, |
355 self.NoContentHandler, | 375 self.NoContentHandler, |
356 self.ServerRedirectHandler, | 376 self.ServerRedirectHandler, |
357 self.ClientRedirectHandler, | 377 self.ClientRedirectHandler, |
358 self.MultipartHandler, | 378 self.MultipartHandler, |
359 self.MultipartSlowHandler, | 379 self.MultipartSlowHandler, |
380 self.GetSessionCacheHandler, | |
360 self.DefaultResponseHandler] | 381 self.DefaultResponseHandler] |
361 post_handlers = [ | 382 post_handlers = [ |
362 self.EchoTitleHandler, | 383 self.EchoTitleHandler, |
363 self.EchoHandler, | 384 self.EchoHandler, |
364 self.DeviceManagementHandler] + get_handlers | 385 self.DeviceManagementHandler] + get_handlers |
365 put_handlers = [ | 386 put_handlers = [ |
366 self.EchoTitleHandler, | 387 self.EchoTitleHandler, |
367 self.EchoHandler] + get_handlers | 388 self.EchoHandler] + get_handlers |
368 head_handlers = [ | 389 head_handlers = [ |
369 self.FileHandler, | 390 self.FileHandler, |
(...skipping 1003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1373 time.sleep(0.25) | 1394 time.sleep(0.25) |
1374 if i == 2: | 1395 if i == 2: |
1375 self.wfile.write('<title>PASS</title>') | 1396 self.wfile.write('<title>PASS</title>') |
1376 else: | 1397 else: |
1377 self.wfile.write('<title>page ' + str(i) + '</title>') | 1398 self.wfile.write('<title>page ' + str(i) + '</title>') |
1378 self.wfile.write('page ' + str(i) + '<!-- ' + ('x' * 2048) + '-->') | 1399 self.wfile.write('page ' + str(i) + '<!-- ' + ('x' * 2048) + '-->') |
1379 | 1400 |
1380 self.wfile.write('--' + bound + '--') | 1401 self.wfile.write('--' + bound + '--') |
1381 return True | 1402 return True |
1382 | 1403 |
1404 def GetSessionCacheHandler(self): | |
1405 """Send a reply containing a log of the session cache operations.""" | |
1406 | |
1407 if not self._ShouldHandleRequest('/session-cache'): | |
wtc
2011/12/10 01:22:37
/session-cache => /ssl-session-cache
also on line
agl
2011/12/12 22:18:20
Done.
| |
1408 return False | |
1409 | |
1410 self.send_response(200) | |
1411 self.send_header('Content-Type', 'text/plain') | |
1412 self.end_headers() | |
1413 try: | |
1414 for (action, sessionID) in self.server.session_cache.log: | |
1415 self.wfile.write('%s\t%s\n' % (action, sessionID.encode('hex'))) | |
1416 except AttributeError, e: | |
1417 self.wfile.write('Pass --https-record-resume in order to use' + | |
1418 ' this request') | |
1419 return True | |
1420 | |
1383 def DefaultResponseHandler(self): | 1421 def DefaultResponseHandler(self): |
1384 """This is the catch-all response handler for requests that aren't handled | 1422 """This is the catch-all response handler for requests that aren't handled |
1385 by one of the special handlers above. | 1423 by one of the special handlers above. |
1386 Note that we specify the content-length as without it the https connection | 1424 Note that we specify the content-length as without it the https connection |
1387 is not closed properly (and the browser keeps expecting data).""" | 1425 is not closed properly (and the browser keeps expecting data).""" |
1388 | 1426 |
1389 contents = "Default response given for path: " + self.path | 1427 contents = "Default response given for path: " + self.path |
1390 self.send_response(200) | 1428 self.send_response(200) |
1391 self.send_header('Content-Type', 'text/html') | 1429 self.send_header('Content-Type', 'text/html') |
1392 self.send_header('Content-Length', len(contents)) | 1430 self.send_header('Content-Length', len(contents)) |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1798 print 'specified server cert file not found: ' + options.cert + \ | 1836 print 'specified server cert file not found: ' + options.cert + \ |
1799 ' exiting...' | 1837 ' exiting...' |
1800 return | 1838 return |
1801 for ca_cert in options.ssl_client_ca: | 1839 for ca_cert in options.ssl_client_ca: |
1802 if not os.path.isfile(ca_cert): | 1840 if not os.path.isfile(ca_cert): |
1803 print 'specified trusted client CA file not found: ' + ca_cert + \ | 1841 print 'specified trusted client CA file not found: ' + ca_cert + \ |
1804 ' exiting...' | 1842 ' exiting...' |
1805 return | 1843 return |
1806 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, | 1844 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, |
1807 options.ssl_client_auth, options.ssl_client_ca, | 1845 options.ssl_client_auth, options.ssl_client_ca, |
1808 options.ssl_bulk_cipher) | 1846 options.ssl_bulk_cipher, options.record_resume) |
1809 print 'HTTPS server started on port %d...' % server.server_port | 1847 print 'HTTPS server started on port %d...' % server.server_port |
1810 else: | 1848 else: |
1811 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) | 1849 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) |
1812 print 'HTTP server started on port %d...' % server.server_port | 1850 print 'HTTP server started on port %d...' % server.server_port |
1813 | 1851 |
1814 server.data_dir = MakeDataDir() | 1852 server.data_dir = MakeDataDir() |
1815 server.file_root_url = options.file_root_url | 1853 server.file_root_url = options.file_root_url |
1816 server_data['port'] = server.server_port | 1854 server_data['port'] = server.server_port |
1817 server._device_management_handler = None | 1855 server._device_management_handler = None |
1818 server.policy_keys = options.policy_keys | 1856 server.policy_keys = options.policy_keys |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1914 'the console.') | 1952 'the console.') |
1915 option_parser.add_option('', '--port', default='0', type='int', | 1953 option_parser.add_option('', '--port', default='0', type='int', |
1916 help='Port used by the server. If unspecified, the ' | 1954 help='Port used by the server. If unspecified, the ' |
1917 'server will listen on an ephemeral port.') | 1955 'server will listen on an ephemeral port.') |
1918 option_parser.add_option('', '--data-dir', dest='data_dir', | 1956 option_parser.add_option('', '--data-dir', dest='data_dir', |
1919 help='Directory from which to read the files.') | 1957 help='Directory from which to read the files.') |
1920 option_parser.add_option('', '--https', dest='cert', | 1958 option_parser.add_option('', '--https', dest='cert', |
1921 help='Specify that https should be used, specify ' | 1959 help='Specify that https should be used, specify ' |
1922 'the path to the cert containing the private key ' | 1960 'the path to the cert containing the private key ' |
1923 'the server should use.') | 1961 'the server should use.') |
1962 option_parser.add_option('', '--https-record-resume', dest='record_resume', | |
1963 const=True, default=False, action='store_const', | |
1964 help='Record resumption cache events rather than' | |
1965 ' resuming as normal. Allows the use of the' | |
1966 ' /session-cache request') | |
1924 option_parser.add_option('', '--ssl-client-auth', action='store_true', | 1967 option_parser.add_option('', '--ssl-client-auth', action='store_true', |
1925 help='Require SSL client auth on every connection.') | 1968 help='Require SSL client auth on every connection.') |
1926 option_parser.add_option('', '--ssl-client-ca', action='append', default=[], | 1969 option_parser.add_option('', '--ssl-client-ca', action='append', default=[], |
1927 help='Specify that the client certificate request ' | 1970 help='Specify that the client certificate request ' |
1928 'should include the CA named in the subject of ' | 1971 'should include the CA named in the subject of ' |
1929 'the DER-encoded certificate contained in the ' | 1972 'the DER-encoded certificate contained in the ' |
1930 'specified file. This option may appear multiple ' | 1973 'specified file. This option may appear multiple ' |
1931 'times, indicating multiple CA names should be ' | 1974 'times, indicating multiple CA names should be ' |
1932 'sent in the request.') | 1975 'sent in the request.') |
1933 option_parser.add_option('', '--ssl-bulk-cipher', action='append', | 1976 option_parser.add_option('', '--ssl-bulk-cipher', action='append', |
(...skipping 19 matching lines...) Expand all Loading... | |
1953 'random key if none is specified on the command ' | 1996 'random key if none is specified on the command ' |
1954 'line.') | 1997 'line.') |
1955 option_parser.add_option('', '--policy-user', default='user@example.com', | 1998 option_parser.add_option('', '--policy-user', default='user@example.com', |
1956 dest='policy_user', | 1999 dest='policy_user', |
1957 help='Specify the user name the server should ' | 2000 help='Specify the user name the server should ' |
1958 'report back to the client as the user owning the ' | 2001 'report back to the client as the user owning the ' |
1959 'token used for making the policy request.') | 2002 'token used for making the policy request.') |
1960 options, args = option_parser.parse_args() | 2003 options, args = option_parser.parse_args() |
1961 | 2004 |
1962 sys.exit(main(options, args)) | 2005 sys.exit(main(options, args)) |
OLD | NEW |