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 | |
43 import testserver_base | |
44 | |
45 # Append at the end of sys.path, it's fine to use the system library. | 42 # 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')) | 43 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 | 44 import pyftpdlib.ftpserver |
Ryan Sleevi
2014/04/08 20:45:36
Should this be moved down, as you did lines 42/43?
davidben
2014/04/08 23:30:36
Rearranged this considerably. Hopefully this order
| |
49 import tlslite | 45 |
50 import tlslite.api | 46 # Temporary hack to deal with tlslite 0.3.8 -> 0.4.0 upgrade. |
47 # | |
48 # TODO(davidben): Remove this when it has landed and cycled through all the | |
49 # bots. | |
davidben
2014/04/08 01:11:42
This should read
# Temporary hack to deal with tl
davidben
2014/04/08 23:30:36
Done.
| |
50 try: | |
51 os.remove(os.path.join(ROOT_DIR, 'third_party', 'tlslite', | |
52 'tlslite', 'utils', 'hmac.pyc')) | |
53 except Exception: | |
54 pass | |
Ryan Sleevi
2014/04/08 20:45:36
Why do you do this here, rather than line 41?
davidben
2014/04/08 23:30:36
I think it made more sense before I had to move te
| |
51 | 55 |
52 # Insert at the beginning of the path, we want this to be used | 56 # Insert at the beginning of the path, we want this to be used |
wtc
2014/04/08 22:41:17
Nit: this => these
or rephrase to be more specifi
davidben
2014/04/08 23:30:36
Done.
| |
53 # unconditionally. | 57 # unconditionally. |
54 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', 'pywebsocket', 'src')) |
59 sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'tlslite')) | |
60 import tlslite | |
61 import tlslite.api | |
wtc
2014/04/08 22:29:09
These are sandwiched between two lines (line 58 an
davidben
2014/04/08 23:30:36
Rearranged this considerably. Hopefully this order
| |
55 import mod_pywebsocket.standalone | 62 import mod_pywebsocket.standalone |
56 from mod_pywebsocket.standalone import WebSocketServer | 63 from mod_pywebsocket.standalone import WebSocketServer |
57 # import manually | 64 # import manually |
58 mod_pywebsocket.standalone.ssl = ssl | 65 mod_pywebsocket.standalone.ssl = ssl |
59 | 66 |
67 import echo_message | |
68 import testserver_base | |
69 | |
60 SERVER_HTTP = 0 | 70 SERVER_HTTP = 0 |
61 SERVER_FTP = 1 | 71 SERVER_FTP = 1 |
62 SERVER_TCP_ECHO = 2 | 72 SERVER_TCP_ECHO = 2 |
63 SERVER_UDP_ECHO = 3 | 73 SERVER_UDP_ECHO = 3 |
64 SERVER_BASIC_AUTH_PROXY = 4 | 74 SERVER_BASIC_AUTH_PROXY = 4 |
65 SERVER_WEBSOCKET = 5 | 75 SERVER_WEBSOCKET = 5 |
66 | 76 |
67 # Default request queue size for WebSocketServer. | 77 # Default request queue size for WebSocketServer. |
68 _DEFAULT_REQUEST_QUEUE_SIZE = 128 | 78 _DEFAULT_REQUEST_QUEUE_SIZE = 128 |
69 | 79 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 testserver_base.ClientRestrictingServerMixIn, | 145 testserver_base.ClientRestrictingServerMixIn, |
136 testserver_base.BrokenPipeHandlerMixIn, | 146 testserver_base.BrokenPipeHandlerMixIn, |
137 testserver_base.StoppableHTTPServer): | 147 testserver_base.StoppableHTTPServer): |
138 """This is a specialization of StoppableHTTPServer that add https support and | 148 """This is a specialization of StoppableHTTPServer that add https support and |
139 client verification.""" | 149 client verification.""" |
140 | 150 |
141 def __init__(self, server_address, request_hander_class, pem_cert_and_key, | 151 def __init__(self, server_address, request_hander_class, pem_cert_and_key, |
142 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, | 152 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
143 record_resume_info, tls_intolerant, signed_cert_timestamps, | 153 record_resume_info, tls_intolerant, signed_cert_timestamps, |
144 fallback_scsv_enabled, ocsp_response): | 154 fallback_scsv_enabled, ocsp_response): |
145 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) | 155 self.cert_chain = tlslite.api.X509CertChain() |
156 self.cert_chain.parsePemList(pem_cert_and_key) | |
146 # Force using only python implementation - otherwise behavior is different | 157 # Force using only python implementation - otherwise behavior is different |
147 # depending on whether m2crypto Python module is present (error is thrown | 158 # depending on whether m2crypto Python module is present (error is thrown |
148 # when it is). m2crypto uses a C (based on OpenSSL) implementation under | 159 # when it is). m2crypto uses a C (based on OpenSSL) implementation under |
149 # the hood. | 160 # the hood. |
150 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, | 161 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, |
151 private=True, | 162 private=True, |
152 implementations=['python']) | 163 implementations=['python']) |
153 self.ssl_client_auth = ssl_client_auth | 164 self.ssl_client_auth = ssl_client_auth |
154 self.ssl_client_cas = [] | 165 self.ssl_client_cas = [] |
155 self.tls_intolerant = tls_intolerant | 166 if tls_intolerant == 0: |
167 self.tls_intolerant = None | |
168 else: | |
169 self.tls_intolerant = (3, tls_intolerant) | |
156 self.signed_cert_timestamps = signed_cert_timestamps | 170 self.signed_cert_timestamps = signed_cert_timestamps |
157 self.fallback_scsv_enabled = fallback_scsv_enabled | 171 self.fallback_scsv_enabled = fallback_scsv_enabled |
158 self.ocsp_response = ocsp_response | 172 self.ocsp_response = ocsp_response |
159 | 173 |
160 for ca_file in ssl_client_cas: | 174 for ca_file in ssl_client_cas: |
161 s = open(ca_file).read() | 175 s = open(ca_file).read() |
162 x509 = tlslite.api.X509() | 176 x509 = tlslite.api.X509() |
163 x509.parse(s) | 177 x509.parse(s) |
164 self.ssl_client_cas.append(x509.subject) | 178 self.ssl_client_cas.append(x509.subject) |
165 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() | 179 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() |
(...skipping 1263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1429 def GetSSLSessionCacheHandler(self): | 1443 def GetSSLSessionCacheHandler(self): |
1430 """Send a reply containing a log of the session cache operations.""" | 1444 """Send a reply containing a log of the session cache operations.""" |
1431 | 1445 |
1432 if not self._ShouldHandleRequest('/ssl-session-cache'): | 1446 if not self._ShouldHandleRequest('/ssl-session-cache'): |
1433 return False | 1447 return False |
1434 | 1448 |
1435 self.send_response(200) | 1449 self.send_response(200) |
1436 self.send_header('Content-Type', 'text/plain') | 1450 self.send_header('Content-Type', 'text/plain') |
1437 self.end_headers() | 1451 self.end_headers() |
1438 try: | 1452 try: |
1439 for (action, sessionID) in self.server.session_cache.log: | 1453 log = self.server.session_cache.log |
1440 self.wfile.write('%s\t%s\n' % (action, sessionID.encode('hex'))) | |
1441 except AttributeError: | 1454 except AttributeError: |
1442 self.wfile.write('Pass --https-record-resume in order to use' + | 1455 self.wfile.write('Pass --https-record-resume in order to use' + |
1443 ' this request') | 1456 ' this request') |
1457 return True | |
wtc
2014/04/08 22:29:09
Should we return False here?
davidben
2014/04/08 23:30:36
Hrm, I don't think so? The old code returns True.
| |
1458 | |
1459 for (action, sessionID) in log: | |
1460 self.wfile.write('%s\t%s\n' % (action, bytes(sessionID).encode('hex'))) | |
Ryan Sleevi
2014/04/08 20:45:36
Curious why you shuffled this around?
davidben
2014/04/08 23:30:36
So, the actual change was to do a bytes(sessionID)
| |
1444 return True | 1461 return True |
1445 | 1462 |
1446 def SSLManySmallRecords(self): | 1463 def SSLManySmallRecords(self): |
1447 """Sends a reply consisting of a variety of small writes. These will be | 1464 """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 | 1465 translated into a series of small SSL records when used over an HTTPS |
1449 server.""" | 1466 server.""" |
1450 | 1467 |
1451 if not self._ShouldHandleRequest('/ssl-many-small-records'): | 1468 if not self._ShouldHandleRequest('/ssl-many-small-records'): |
1452 return False | 1469 return False |
1453 | 1470 |
1454 self.send_response(200) | 1471 self.send_response(200) |
1455 self.send_header('Content-Type', 'text/plain') | 1472 self.send_header('Content-Type', 'text/plain') |
1456 self.end_headers() | 1473 self.end_headers() |
1457 | 1474 |
1458 # Write ~26K of data, in 1350 byte chunks | 1475 # Write ~26K of data, in 1350 byte chunks |
1459 for i in xrange(20): | 1476 for i in xrange(20): |
1460 self.wfile.write('*' * 1350) | 1477 self.wfile.write('*' * 1350) |
1461 self.wfile.flush() | 1478 self.wfile.flush() |
1462 return True | 1479 return True |
1463 | 1480 |
1464 def GetChannelID(self): | 1481 def GetChannelID(self): |
1465 """Send a reply containing the hashed ChannelID that the client provided.""" | 1482 """Send a reply containing the hashed ChannelID that the client provided.""" |
1466 | 1483 |
1467 if not self._ShouldHandleRequest('/channel-id'): | 1484 if not self._ShouldHandleRequest('/channel-id'): |
1468 return False | 1485 return False |
1469 | 1486 |
1470 self.send_response(200) | 1487 self.send_response(200) |
1471 self.send_header('Content-Type', 'text/plain') | 1488 self.send_header('Content-Type', 'text/plain') |
1472 self.end_headers() | 1489 self.end_headers() |
1473 channel_id = self.server.tlsConnection.channel_id.tostring() | 1490 channel_id = bytes(self.server.tlsConnection.channel_id) |
1474 self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) | 1491 self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) |
1475 return True | 1492 return True |
1476 | 1493 |
1477 def CloseSocketHandler(self): | 1494 def CloseSocketHandler(self): |
1478 """Closes the socket without sending anything.""" | 1495 """Closes the socket without sending anything.""" |
1479 | 1496 |
1480 if not self._ShouldHandleRequest('/close-socket'): | 1497 if not self._ShouldHandleRequest('/close-socket'): |
1481 return False | 1498 return False |
1482 | 1499 |
1483 self.wfile.close() | 1500 self.wfile.close() |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2149 '"aes128", "3des", "rc4". If omitted, all ' | 2166 '"aes128", "3des", "rc4". If omitted, all ' |
2150 'algorithms will be used. This option may ' | 2167 'algorithms will be used. This option may ' |
2151 'appear multiple times, indicating ' | 2168 'appear multiple times, indicating ' |
2152 'multiple algorithms should be enabled.'); | 2169 'multiple algorithms should be enabled.'); |
2153 self.option_parser.add_option('--file-root-url', default='/files/', | 2170 self.option_parser.add_option('--file-root-url', default='/files/', |
2154 help='Specify a root URL for files served.') | 2171 help='Specify a root URL for files served.') |
2155 | 2172 |
2156 | 2173 |
2157 if __name__ == '__main__': | 2174 if __name__ == '__main__': |
2158 sys.exit(ServerRunner().main()) | 2175 sys.exit(ServerRunner().main()) |
OLD | NEW |