OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 def __init__(self): | 75 def __init__(self): |
76 self.log = [] | 76 self.log = [] |
77 | 77 |
78 def __getitem__(self, sessionID): | 78 def __getitem__(self, sessionID): |
79 self.log.append(('lookup', sessionID)) | 79 self.log.append(('lookup', sessionID)) |
80 raise KeyError() | 80 raise KeyError() |
81 | 81 |
82 def __setitem__(self, sessionID, session): | 82 def __setitem__(self, sessionID, session): |
83 self.log.append(('insert', sessionID)) | 83 self.log.append(('insert', sessionID)) |
84 | 84 |
85 | |
86 class ClientRestrictingServerMixIn: | |
87 """Implements verify_request to limit connections to our configured IP | |
88 address.""" | |
89 | |
90 def verify_request(self, request, client_address): | |
91 return client_address[0] == self.server_address[0] | |
92 | |
93 | |
85 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): | 94 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): |
86 """This is a specialization of of BaseHTTPServer to allow it | 95 """This is a specialization of BaseHTTPServer to allow it |
87 to be exited cleanly (by setting its "stop" member to True).""" | 96 to be exited cleanly (by setting its "stop" member to True).""" |
88 | 97 |
89 def serve_forever(self): | 98 def serve_forever(self): |
90 self.stop = False | 99 self.stop = False |
91 self.nonce_time = None | 100 self.nonce_time = None |
92 while not self.stop: | 101 while not self.stop: |
93 self.handle_request() | 102 self.handle_request() |
94 self.socket.close() | 103 self.socket.close() |
95 | 104 |
96 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): | 105 |
97 """This is a specialization of StoppableHTTPerver that add https support.""" | 106 class HTTPServer(ClientRestrictingServerMixIn, StoppableHTTPServer): |
107 """This is a specialization of StoppableHTTPerver that adds client | |
108 verification.""" | |
109 | |
110 pass | |
111 | |
112 | |
113 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, | |
114 ClientRestrictingServerMixIn, | |
115 StoppableHTTPServer): | |
116 """This is a specialization of StoppableHTTPerver that add https support and | |
117 client verification.""" | |
98 | 118 |
99 def __init__(self, server_address, request_hander_class, cert_path, | 119 def __init__(self, server_address, request_hander_class, cert_path, |
100 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, | 120 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
101 record_resume_info): | 121 record_resume_info): |
102 s = open(cert_path).read() | 122 s = open(cert_path).read() |
103 x509 = tlslite.api.X509() | 123 x509 = tlslite.api.X509() |
104 x509.parse(s) | 124 x509.parse(s) |
105 self.cert_chain = tlslite.api.X509CertChain([x509]) | 125 self.cert_chain = tlslite.api.X509CertChain([x509]) |
106 s = open(cert_path).read() | 126 s = open(cert_path).read() |
107 self.private_key = tlslite.api.parsePEMKey(s, private=True) | 127 self.private_key = tlslite.api.parsePEMKey(s, private=True) |
(...skipping 28 matching lines...) Expand all Loading... | |
136 tlsConnection.ignoreAbruptClose = True | 156 tlsConnection.ignoreAbruptClose = True |
137 return True | 157 return True |
138 except tlslite.api.TLSAbruptCloseError: | 158 except tlslite.api.TLSAbruptCloseError: |
139 # Ignore abrupt close. | 159 # Ignore abrupt close. |
140 return True | 160 return True |
141 except tlslite.api.TLSError, error: | 161 except tlslite.api.TLSError, error: |
142 print "Handshake failure:", str(error) | 162 print "Handshake failure:", str(error) |
143 return False | 163 return False |
144 | 164 |
145 | 165 |
146 class SyncHTTPServer(StoppableHTTPServer): | 166 class SyncHTTPServer(ClientRestrictingServerMixIn, StoppableHTTPServer): |
147 """An HTTP server that handles sync commands.""" | 167 """An HTTP server that handles sync commands.""" |
148 | 168 |
149 def __init__(self, server_address, request_handler_class): | 169 def __init__(self, server_address, request_handler_class): |
150 # We import here to avoid pulling in chromiumsync's dependencies | 170 # We import here to avoid pulling in chromiumsync's dependencies |
151 # unless strictly necessary. | 171 # unless strictly necessary. |
152 import chromiumsync | 172 import chromiumsync |
153 import xmppserver | 173 import xmppserver |
154 StoppableHTTPServer.__init__(self, server_address, request_handler_class) | 174 StoppableHTTPServer.__init__(self, server_address, request_handler_class) |
155 self._sync_handler = chromiumsync.TestServer() | 175 self._sync_handler = chromiumsync.TestServer() |
156 self._xmpp_socket_map = {} | 176 self._xmpp_socket_map = {} |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 | 261 |
242 for fd in write_fds: | 262 for fd in write_fds: |
243 HandleXmppSocket(fd, self._xmpp_socket_map, | 263 HandleXmppSocket(fd, self._xmpp_socket_map, |
244 asyncore.dispatcher.handle_write_event) | 264 asyncore.dispatcher.handle_write_event) |
245 | 265 |
246 for fd in exceptional_fds: | 266 for fd in exceptional_fds: |
247 HandleXmppSocket(fd, self._xmpp_socket_map, | 267 HandleXmppSocket(fd, self._xmpp_socket_map, |
248 asyncore.dispatcher.handle_expt_event) | 268 asyncore.dispatcher.handle_expt_event) |
249 | 269 |
250 | 270 |
251 class TCPEchoServer(SocketServer.TCPServer): | 271 class FTPServer(ClientRestrictingServerMixIn, pyftpdlib.ftpserver.FTPServer): |
272 """This is a specialization of FTPServer that adds client verification.""" | |
273 | |
274 pass | |
275 | |
276 | |
277 class TCPEchoServer(ClientRestrictingServerMixIn, SocketServer.TCPServer): | |
252 """A TCP echo server that echoes back what it has received.""" | 278 """A TCP echo server that echoes back what it has received.""" |
253 | 279 |
254 def server_bind(self): | 280 def server_bind(self): |
255 """Override server_bind to store the server name.""" | 281 """Override server_bind to store the server name.""" |
256 SocketServer.TCPServer.server_bind(self) | 282 SocketServer.TCPServer.server_bind(self) |
257 host, port = self.socket.getsockname()[:2] | 283 host, port = self.socket.getsockname()[:2] |
258 self.server_name = socket.getfqdn(host) | 284 self.server_name = socket.getfqdn(host) |
259 self.server_port = port | 285 self.server_port = port |
260 | 286 |
261 def serve_forever(self): | 287 def serve_forever(self): |
262 self.stop = False | 288 self.stop = False |
263 self.nonce_time = None | 289 self.nonce_time = None |
264 while not self.stop: | 290 while not self.stop: |
265 self.handle_request() | 291 self.handle_request() |
266 self.socket.close() | 292 self.socket.close() |
267 | 293 |
268 | 294 |
269 class UDPEchoServer(SocketServer.UDPServer): | 295 class UDPEchoServer(ClientRestrictingServerMixIn, SocketServer.UDPServer): |
270 """A UDP echo server that echoes back what it has received.""" | 296 """A UDP echo server that echoes back what it has received.""" |
271 | 297 |
272 def server_bind(self): | 298 def server_bind(self): |
273 """Override server_bind to store the server name.""" | 299 """Override server_bind to store the server name.""" |
274 SocketServer.UDPServer.server_bind(self) | 300 SocketServer.UDPServer.server_bind(self) |
275 host, port = self.socket.getsockname()[:2] | 301 host, port = self.socket.getsockname()[:2] |
276 self.server_name = socket.getfqdn(host) | 302 self.server_name = socket.getfqdn(host) |
277 self.server_port = port | 303 self.server_port = port |
278 | 304 |
279 def serve_forever(self): | 305 def serve_forever(self): |
(...skipping 1335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1615 test_name = "/chromiumsync/command" | 1641 test_name = "/chromiumsync/command" |
1616 if not self._ShouldHandleRequest(test_name): | 1642 if not self._ShouldHandleRequest(test_name): |
1617 return False | 1643 return False |
1618 | 1644 |
1619 length = int(self.headers.getheader('content-length')) | 1645 length = int(self.headers.getheader('content-length')) |
1620 raw_request = self.rfile.read(length) | 1646 raw_request = self.rfile.read(length) |
1621 http_response = 200 | 1647 http_response = 200 |
1622 raw_reply = None | 1648 raw_reply = None |
1623 if not self.server.GetAuthenticated(): | 1649 if not self.server.GetAuthenticated(): |
1624 http_response = 401 | 1650 http_response = 401 |
1625 challenge = 'GoogleLogin realm="http://127.0.0.1", service="chromiumsync"' | 1651 challenge = 'GoogleLogin realm="http://%s", service="chromiumsync"' % ( |
1652 self.server.server_address[0]) | |
1626 else: | 1653 else: |
1627 http_response, raw_reply = self.server.HandleCommand( | 1654 http_response, raw_reply = self.server.HandleCommand( |
1628 self.path, raw_request) | 1655 self.path, raw_request) |
1629 | 1656 |
1630 ### Now send the response to the client. ### | 1657 ### Now send the response to the client. ### |
1631 self.send_response(http_response) | 1658 self.send_response(http_response) |
1632 if http_response == 401: | 1659 if http_response == 401: |
1633 self.send_header('www-Authenticate', challenge) | 1660 self.send_header('www-Authenticate', challenge) |
1634 self.end_headers() | 1661 self.end_headers() |
1635 self.wfile.write(raw_reply) | 1662 self.wfile.write(raw_reply) |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1862 | 1889 |
1863 def main(options, args): | 1890 def main(options, args): |
1864 logfile = open('testserver.log', 'w') | 1891 logfile = open('testserver.log', 'w') |
1865 sys.stderr = FileMultiplexer(sys.stderr, logfile) | 1892 sys.stderr = FileMultiplexer(sys.stderr, logfile) |
1866 if options.log_to_console: | 1893 if options.log_to_console: |
1867 sys.stdout = FileMultiplexer(sys.stdout, logfile) | 1894 sys.stdout = FileMultiplexer(sys.stdout, logfile) |
1868 else: | 1895 else: |
1869 sys.stdout = logfile | 1896 sys.stdout = logfile |
1870 | 1897 |
1871 port = options.port | 1898 port = options.port |
1899 host = options.host | |
1872 | 1900 |
1873 server_data = {} | 1901 server_data = {} |
1902 server_data['host'] = host | |
1874 | 1903 |
1875 if options.server_type == SERVER_HTTP: | 1904 if options.server_type == SERVER_HTTP: |
1876 if options.cert: | 1905 if options.cert: |
1877 # let's make sure the cert file exists. | 1906 # let's make sure the cert file exists. |
1878 if not os.path.isfile(options.cert): | 1907 if not os.path.isfile(options.cert): |
1879 print 'specified server cert file not found: ' + options.cert + \ | 1908 print 'specified server cert file not found: ' + options.cert + \ |
1880 ' exiting...' | 1909 ' exiting...' |
1881 return | 1910 return |
1882 for ca_cert in options.ssl_client_ca: | 1911 for ca_cert in options.ssl_client_ca: |
1883 if not os.path.isfile(ca_cert): | 1912 if not os.path.isfile(ca_cert): |
1884 print 'specified trusted client CA file not found: ' + ca_cert + \ | 1913 print 'specified trusted client CA file not found: ' + ca_cert + \ |
1885 ' exiting...' | 1914 ' exiting...' |
1886 return | 1915 return |
1887 server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, | 1916 server = HTTPSServer((host, port), TestPageHandler, options.cert, |
1888 options.ssl_client_auth, options.ssl_client_ca, | 1917 options.ssl_client_auth, options.ssl_client_ca, |
1889 options.ssl_bulk_cipher, options.record_resume) | 1918 options.ssl_bulk_cipher, options.record_resume) |
1890 print 'HTTPS server started on port %d...' % server.server_port | 1919 print 'HTTPS server started on %s:%d...' % (host, server.server_port) |
eroman
2012/02/23 20:51:44
note that if host is an IPv6 literal, this host:po
| |
1891 else: | 1920 else: |
1892 server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) | 1921 server = HTTPServer((host, port), TestPageHandler) |
1893 print 'HTTP server started on port %d...' % server.server_port | 1922 print 'HTTP server started on %s:%d...' % (host, server.server_port) |
1894 | 1923 |
1895 server.data_dir = MakeDataDir() | 1924 server.data_dir = MakeDataDir() |
1896 server.file_root_url = options.file_root_url | 1925 server.file_root_url = options.file_root_url |
1897 server_data['port'] = server.server_port | 1926 server_data['port'] = server.server_port |
1898 server._device_management_handler = None | 1927 server._device_management_handler = None |
1899 server.policy_keys = options.policy_keys | 1928 server.policy_keys = options.policy_keys |
1900 server.policy_user = options.policy_user | 1929 server.policy_user = options.policy_user |
1901 elif options.server_type == SERVER_SYNC: | 1930 elif options.server_type == SERVER_SYNC: |
1902 server = SyncHTTPServer(('127.0.0.1', port), SyncPageHandler) | 1931 server = SyncHTTPServer((host, port), SyncPageHandler) |
1903 print 'Sync HTTP server started on port %d...' % server.server_port | 1932 print 'Sync HTTP server started on port %d...' % server.server_port |
1904 print 'Sync XMPP server started on port %d...' % server.xmpp_port | 1933 print 'Sync XMPP server started on port %d...' % server.xmpp_port |
1905 server_data['port'] = server.server_port | 1934 server_data['port'] = server.server_port |
1906 server_data['xmpp_port'] = server.xmpp_port | 1935 server_data['xmpp_port'] = server.xmpp_port |
1907 elif options.server_type == SERVER_TCP_ECHO: | 1936 elif options.server_type == SERVER_TCP_ECHO: |
1908 # Used for generating the key (randomly) that encodes the "echo request" | 1937 # Used for generating the key (randomly) that encodes the "echo request" |
1909 # message. | 1938 # message. |
1910 random.seed() | 1939 random.seed() |
1911 server = TCPEchoServer(('127.0.0.1', port), TCPEchoHandler) | 1940 server = TCPEchoServer((host, port), TCPEchoHandler) |
1912 print 'Echo TCP server started on port %d...' % server.server_port | 1941 print 'Echo TCP server started on port %d...' % server.server_port |
1913 server_data['port'] = server.server_port | 1942 server_data['port'] = server.server_port |
1914 elif options.server_type == SERVER_UDP_ECHO: | 1943 elif options.server_type == SERVER_UDP_ECHO: |
1915 # Used for generating the key (randomly) that encodes the "echo request" | 1944 # Used for generating the key (randomly) that encodes the "echo request" |
1916 # message. | 1945 # message. |
1917 random.seed() | 1946 random.seed() |
1918 server = UDPEchoServer(('127.0.0.1', port), UDPEchoHandler) | 1947 server = UDPEchoServer((host, port), UDPEchoHandler) |
1919 print 'Echo UDP server started on port %d...' % server.server_port | 1948 print 'Echo UDP server started on port %d...' % server.server_port |
1920 server_data['port'] = server.server_port | 1949 server_data['port'] = server.server_port |
1921 # means FTP Server | 1950 # means FTP Server |
1922 else: | 1951 else: |
1923 my_data_dir = MakeDataDir() | 1952 my_data_dir = MakeDataDir() |
1924 | 1953 |
1925 # Instantiate a dummy authorizer for managing 'virtual' users | 1954 # Instantiate a dummy authorizer for managing 'virtual' users |
1926 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() | 1955 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() |
1927 | 1956 |
1928 # Define a new user having full r/w permissions and a read-only | 1957 # Define a new user having full r/w permissions and a read-only |
1929 # anonymous user | 1958 # anonymous user |
1930 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') | 1959 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') |
1931 | 1960 |
1932 authorizer.add_anonymous(my_data_dir) | 1961 authorizer.add_anonymous(my_data_dir) |
1933 | 1962 |
1934 # Instantiate FTP handler class | 1963 # Instantiate FTP handler class |
1935 ftp_handler = pyftpdlib.ftpserver.FTPHandler | 1964 ftp_handler = pyftpdlib.ftpserver.FTPHandler |
1936 ftp_handler.authorizer = authorizer | 1965 ftp_handler.authorizer = authorizer |
1937 | 1966 |
1938 # Define a customized banner (string returned when client connects) | 1967 # Define a customized banner (string returned when client connects) |
1939 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % | 1968 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % |
1940 pyftpdlib.ftpserver.__ver__) | 1969 pyftpdlib.ftpserver.__ver__) |
1941 | 1970 |
1942 # Instantiate FTP server class and listen to 127.0.0.1:port | 1971 # Instantiate FTP server class and listen to address:port |
1943 address = ('127.0.0.1', port) | 1972 server = pyftpdlib.ftpserver.FTPServer((host, port), ftp_handler) |
1944 server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler) | |
1945 server_data['port'] = server.socket.getsockname()[1] | 1973 server_data['port'] = server.socket.getsockname()[1] |
1946 print 'FTP server started on port %d...' % server_data['port'] | 1974 print 'FTP server started on port %d...' % server_data['port'] |
1947 | 1975 |
1948 # Notify the parent that we've started. (BaseServer subclasses | 1976 # Notify the parent that we've started. (BaseServer subclasses |
1949 # bind their sockets on construction.) | 1977 # bind their sockets on construction.) |
1950 if options.startup_pipe is not None: | 1978 if options.startup_pipe is not None: |
1951 server_data_json = json.dumps(server_data) | 1979 server_data_json = json.dumps(server_data) |
1952 server_data_len = len(server_data_json) | 1980 server_data_len = len(server_data_json) |
1953 print 'sending server_data: %s (%d bytes)' % ( | 1981 print 'sending server_data: %s (%d bytes)' % ( |
1954 server_data_json, server_data_len) | 1982 server_data_json, server_data_len) |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2036 'the server. If ther server has multiple keys, it ' | 2064 'the server. If ther server has multiple keys, it ' |
2037 'will rotate through them in at each request a ' | 2065 'will rotate through them in at each request a ' |
2038 'round-robin fashion. The server will generate a ' | 2066 'round-robin fashion. The server will generate a ' |
2039 'random key if none is specified on the command ' | 2067 'random key if none is specified on the command ' |
2040 'line.') | 2068 'line.') |
2041 option_parser.add_option('', '--policy-user', default='user@example.com', | 2069 option_parser.add_option('', '--policy-user', default='user@example.com', |
2042 dest='policy_user', | 2070 dest='policy_user', |
2043 help='Specify the user name the server should ' | 2071 help='Specify the user name the server should ' |
2044 'report back to the client as the user owning the ' | 2072 'report back to the client as the user owning the ' |
2045 'token used for making the policy request.') | 2073 'token used for making the policy request.') |
2074 option_parser.add_option('', '--host', default='127.0.0.1', | |
2075 dest='host', | |
2076 help='Hostname or IP upon which the server will ' | |
2077 'listen. Client connections will also only be ' | |
2078 'allowed from this address.') | |
2046 options, args = option_parser.parse_args() | 2079 options, args = option_parser.parse_args() |
2047 | 2080 |
2048 sys.exit(main(options, args)) | 2081 sys.exit(main(options, args)) |
OLD | NEW |