| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 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/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for | 6 """This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for |
| 7 testing Chrome. | 7 testing Chrome. |
| 8 | 8 |
| 9 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. |
| 10 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 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 import sys | 32 import sys |
| 33 import threading | 33 import threading |
| 34 import time | 34 import time |
| 35 import urllib | 35 import urllib |
| 36 import urlparse | 36 import urlparse |
| 37 import zlib | 37 import zlib |
| 38 | 38 |
| 39 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 39 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 40 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(BASE_DIR))) | 40 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(BASE_DIR))) |
| 41 | 41 |
| 42 import echo_message | 42 # Temporary hack to deal with tlslite 0.3.8 -> 0.4.6 upgrade. |
| 43 import testserver_base | 43 # |
| 44 # TODO(davidben): Remove this when it has cycled through all the bots and |
| 45 # developer checkouts or when http://crbug.com/356276 is resolved. |
| 46 try: |
| 47 os.remove(os.path.join(ROOT_DIR, 'third_party', 'tlslite', |
| 48 'tlslite', 'utils', 'hmac.pyc')) |
| 49 except Exception: |
| 50 pass |
| 44 | 51 |
| 45 # Append at the end of sys.path, it's fine to use the system library. | 52 # Append at the end of sys.path, it's fine to use the system library. |
| 46 sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'pyftpdlib', 'src')) | 53 sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'pyftpdlib', 'src')) |
| 47 sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'tlslite')) | |
| 48 import pyftpdlib.ftpserver | |
| 49 import tlslite | |
| 50 import tlslite.api | |
| 51 | 54 |
| 52 # Insert at the beginning of the path, we want this to be used | 55 # Insert at the beginning of the path, we want to use our copies of the library |
| 53 # unconditionally. | 56 # unconditionally. |
| 54 sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'pywebsocket', 'src')) | 57 sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'pywebsocket', 'src')) |
| 58 sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'tlslite')) |
| 59 |
| 55 import mod_pywebsocket.standalone | 60 import mod_pywebsocket.standalone |
| 56 from mod_pywebsocket.standalone import WebSocketServer | 61 from mod_pywebsocket.standalone import WebSocketServer |
| 57 # import manually | 62 # import manually |
| 58 mod_pywebsocket.standalone.ssl = ssl | 63 mod_pywebsocket.standalone.ssl = ssl |
| 59 | 64 |
| 65 import pyftpdlib.ftpserver |
| 66 |
| 67 import tlslite |
| 68 import tlslite.api |
| 69 |
| 70 import echo_message |
| 71 import testserver_base |
| 72 |
| 60 SERVER_HTTP = 0 | 73 SERVER_HTTP = 0 |
| 61 SERVER_FTP = 1 | 74 SERVER_FTP = 1 |
| 62 SERVER_TCP_ECHO = 2 | 75 SERVER_TCP_ECHO = 2 |
| 63 SERVER_UDP_ECHO = 3 | 76 SERVER_UDP_ECHO = 3 |
| 64 SERVER_BASIC_AUTH_PROXY = 4 | 77 SERVER_BASIC_AUTH_PROXY = 4 |
| 65 SERVER_WEBSOCKET = 5 | 78 SERVER_WEBSOCKET = 5 |
| 66 | 79 |
| 67 # Default request queue size for WebSocketServer. | 80 # Default request queue size for WebSocketServer. |
| 68 _DEFAULT_REQUEST_QUEUE_SIZE = 128 | 81 _DEFAULT_REQUEST_QUEUE_SIZE = 128 |
| 69 | 82 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 testserver_base.ClientRestrictingServerMixIn, | 148 testserver_base.ClientRestrictingServerMixIn, |
| 136 testserver_base.BrokenPipeHandlerMixIn, | 149 testserver_base.BrokenPipeHandlerMixIn, |
| 137 testserver_base.StoppableHTTPServer): | 150 testserver_base.StoppableHTTPServer): |
| 138 """This is a specialization of StoppableHTTPServer that add https support and | 151 """This is a specialization of StoppableHTTPServer that add https support and |
| 139 client verification.""" | 152 client verification.""" |
| 140 | 153 |
| 141 def __init__(self, server_address, request_hander_class, pem_cert_and_key, | 154 def __init__(self, server_address, request_hander_class, pem_cert_and_key, |
| 142 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, | 155 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
| 143 record_resume_info, tls_intolerant, signed_cert_timestamps, | 156 record_resume_info, tls_intolerant, signed_cert_timestamps, |
| 144 fallback_scsv_enabled, ocsp_response): | 157 fallback_scsv_enabled, ocsp_response): |
| 145 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) | 158 self.cert_chain = tlslite.api.X509CertChain() |
| 159 self.cert_chain.parsePemList(pem_cert_and_key) |
| 146 # Force using only python implementation - otherwise behavior is different | 160 # Force using only python implementation - otherwise behavior is different |
| 147 # depending on whether m2crypto Python module is present (error is thrown | 161 # depending on whether m2crypto Python module is present (error is thrown |
| 148 # when it is). m2crypto uses a C (based on OpenSSL) implementation under | 162 # when it is). m2crypto uses a C (based on OpenSSL) implementation under |
| 149 # the hood. | 163 # the hood. |
| 150 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, | 164 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, |
| 151 private=True, | 165 private=True, |
| 152 implementations=['python']) | 166 implementations=['python']) |
| 153 self.ssl_client_auth = ssl_client_auth | 167 self.ssl_client_auth = ssl_client_auth |
| 154 self.ssl_client_cas = [] | 168 self.ssl_client_cas = [] |
| 155 self.tls_intolerant = tls_intolerant | 169 if tls_intolerant == 0: |
| 170 self.tls_intolerant = None |
| 171 else: |
| 172 self.tls_intolerant = (3, tls_intolerant) |
| 156 self.signed_cert_timestamps = signed_cert_timestamps | 173 self.signed_cert_timestamps = signed_cert_timestamps |
| 157 self.fallback_scsv_enabled = fallback_scsv_enabled | 174 self.fallback_scsv_enabled = fallback_scsv_enabled |
| 158 self.ocsp_response = ocsp_response | 175 self.ocsp_response = ocsp_response |
| 159 | 176 |
| 160 for ca_file in ssl_client_cas: | 177 for ca_file in ssl_client_cas: |
| 161 s = open(ca_file).read() | 178 s = open(ca_file).read() |
| 162 x509 = tlslite.api.X509() | 179 x509 = tlslite.api.X509() |
| 163 x509.parse(s) | 180 x509.parse(s) |
| 164 self.ssl_client_cas.append(x509.subject) | 181 self.ssl_client_cas.append(x509.subject) |
| 165 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() | 182 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() |
| (...skipping 1263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1429 def GetSSLSessionCacheHandler(self): | 1446 def GetSSLSessionCacheHandler(self): |
| 1430 """Send a reply containing a log of the session cache operations.""" | 1447 """Send a reply containing a log of the session cache operations.""" |
| 1431 | 1448 |
| 1432 if not self._ShouldHandleRequest('/ssl-session-cache'): | 1449 if not self._ShouldHandleRequest('/ssl-session-cache'): |
| 1433 return False | 1450 return False |
| 1434 | 1451 |
| 1435 self.send_response(200) | 1452 self.send_response(200) |
| 1436 self.send_header('Content-Type', 'text/plain') | 1453 self.send_header('Content-Type', 'text/plain') |
| 1437 self.end_headers() | 1454 self.end_headers() |
| 1438 try: | 1455 try: |
| 1439 for (action, sessionID) in self.server.session_cache.log: | 1456 log = self.server.session_cache.log |
| 1440 self.wfile.write('%s\t%s\n' % (action, sessionID.encode('hex'))) | |
| 1441 except AttributeError: | 1457 except AttributeError: |
| 1442 self.wfile.write('Pass --https-record-resume in order to use' + | 1458 self.wfile.write('Pass --https-record-resume in order to use' + |
| 1443 ' this request') | 1459 ' this request') |
| 1460 return True |
| 1461 |
| 1462 for (action, sessionID) in log: |
| 1463 self.wfile.write('%s\t%s\n' % (action, bytes(sessionID).encode('hex'))) |
| 1444 return True | 1464 return True |
| 1445 | 1465 |
| 1446 def SSLManySmallRecords(self): | 1466 def SSLManySmallRecords(self): |
| 1447 """Sends a reply consisting of a variety of small writes. These will be | 1467 """Sends a reply consisting of a variety of small writes. These will be |
| 1448 translated into a series of small SSL records when used over an HTTPS | 1468 translated into a series of small SSL records when used over an HTTPS |
| 1449 server.""" | 1469 server.""" |
| 1450 | 1470 |
| 1451 if not self._ShouldHandleRequest('/ssl-many-small-records'): | 1471 if not self._ShouldHandleRequest('/ssl-many-small-records'): |
| 1452 return False | 1472 return False |
| 1453 | 1473 |
| 1454 self.send_response(200) | 1474 self.send_response(200) |
| 1455 self.send_header('Content-Type', 'text/plain') | 1475 self.send_header('Content-Type', 'text/plain') |
| 1456 self.end_headers() | 1476 self.end_headers() |
| 1457 | 1477 |
| 1458 # Write ~26K of data, in 1350 byte chunks | 1478 # Write ~26K of data, in 1350 byte chunks |
| 1459 for i in xrange(20): | 1479 for i in xrange(20): |
| 1460 self.wfile.write('*' * 1350) | 1480 self.wfile.write('*' * 1350) |
| 1461 self.wfile.flush() | 1481 self.wfile.flush() |
| 1462 return True | 1482 return True |
| 1463 | 1483 |
| 1464 def GetChannelID(self): | 1484 def GetChannelID(self): |
| 1465 """Send a reply containing the hashed ChannelID that the client provided.""" | 1485 """Send a reply containing the hashed ChannelID that the client provided.""" |
| 1466 | 1486 |
| 1467 if not self._ShouldHandleRequest('/channel-id'): | 1487 if not self._ShouldHandleRequest('/channel-id'): |
| 1468 return False | 1488 return False |
| 1469 | 1489 |
| 1470 self.send_response(200) | 1490 self.send_response(200) |
| 1471 self.send_header('Content-Type', 'text/plain') | 1491 self.send_header('Content-Type', 'text/plain') |
| 1472 self.end_headers() | 1492 self.end_headers() |
| 1473 channel_id = self.server.tlsConnection.channel_id.tostring() | 1493 channel_id = bytes(self.server.tlsConnection.channel_id) |
| 1474 self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) | 1494 self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) |
| 1475 return True | 1495 return True |
| 1476 | 1496 |
| 1477 def CloseSocketHandler(self): | 1497 def CloseSocketHandler(self): |
| 1478 """Closes the socket without sending anything.""" | 1498 """Closes the socket without sending anything.""" |
| 1479 | 1499 |
| 1480 if not self._ShouldHandleRequest('/close-socket'): | 1500 if not self._ShouldHandleRequest('/close-socket'): |
| 1481 return False | 1501 return False |
| 1482 | 1502 |
| 1483 self.wfile.close() | 1503 self.wfile.close() |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2149 '"aes128", "3des", "rc4". If omitted, all ' | 2169 '"aes128", "3des", "rc4". If omitted, all ' |
| 2150 'algorithms will be used. This option may ' | 2170 'algorithms will be used. This option may ' |
| 2151 'appear multiple times, indicating ' | 2171 'appear multiple times, indicating ' |
| 2152 'multiple algorithms should be enabled.'); | 2172 'multiple algorithms should be enabled.'); |
| 2153 self.option_parser.add_option('--file-root-url', default='/files/', | 2173 self.option_parser.add_option('--file-root-url', default='/files/', |
| 2154 help='Specify a root URL for files served.') | 2174 help='Specify a root URL for files served.') |
| 2155 | 2175 |
| 2156 | 2176 |
| 2157 if __name__ == '__main__': | 2177 if __name__ == '__main__': |
| 2158 sys.exit(ServerRunner().main()) | 2178 sys.exit(ServerRunner().main()) |
| OLD | NEW |