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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 import simplejson as json | 57 import simplejson as json |
58 | 58 |
59 if sys.platform == 'win32': | 59 if sys.platform == 'win32': |
60 import msvcrt | 60 import msvcrt |
61 | 61 |
62 SERVER_HTTP = 0 | 62 SERVER_HTTP = 0 |
63 SERVER_FTP = 1 | 63 SERVER_FTP = 1 |
64 SERVER_SYNC = 2 | 64 SERVER_SYNC = 2 |
65 SERVER_TCP_ECHO = 3 | 65 SERVER_TCP_ECHO = 3 |
66 SERVER_UDP_ECHO = 4 | 66 SERVER_UDP_ECHO = 4 |
| 67 SERVER_BASIC_AUTH_PROXY = 5 |
67 | 68 |
68 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . | 69 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . |
69 debug_output = sys.stderr | 70 debug_output = sys.stderr |
70 def debug(str): | 71 def debug(str): |
71 debug_output.write(str + "\n") | 72 debug_output.write(str + "\n") |
72 debug_output.flush() | 73 debug_output.flush() |
73 | 74 |
74 class RecordingSSLSessionCache(object): | 75 class RecordingSSLSessionCache(object): |
75 """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of | 76 """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of |
76 lookups and inserts in order to test session cache behaviours.""" | 77 lookups and inserts in order to test session cache behaviours.""" |
(...skipping 28 matching lines...) Expand all Loading... |
105 self.handle_request() | 106 self.handle_request() |
106 self.socket.close() | 107 self.socket.close() |
107 | 108 |
108 | 109 |
109 class HTTPServer(ClientRestrictingServerMixIn, StoppableHTTPServer): | 110 class HTTPServer(ClientRestrictingServerMixIn, StoppableHTTPServer): |
110 """This is a specialization of StoppableHTTPServer that adds client | 111 """This is a specialization of StoppableHTTPServer that adds client |
111 verification.""" | 112 verification.""" |
112 | 113 |
113 pass | 114 pass |
114 | 115 |
| 116 class ThreadingHTTPServer(ClientRestrictingServerMixIn, |
| 117 SocketServer.ThreadingMixIn, |
| 118 StoppableHTTPServer): |
| 119 """This is a specialization of StoppableHTTPServer that creates |
| 120 a dedicated thread for each request.""" |
| 121 |
| 122 pass |
| 123 |
| 124 |
115 class OCSPServer(ClientRestrictingServerMixIn, BaseHTTPServer.HTTPServer): | 125 class OCSPServer(ClientRestrictingServerMixIn, BaseHTTPServer.HTTPServer): |
116 """This is a specialization of HTTPServer that serves an | 126 """This is a specialization of HTTPServer that serves an |
117 OCSP response""" | 127 OCSP response""" |
118 | 128 |
119 def serve_forever_on_thread(self): | 129 def serve_forever_on_thread(self): |
120 self.thread = threading.Thread(target = self.serve_forever, | 130 self.thread = threading.Thread(target = self.serve_forever, |
121 name = "OCSPServerThread") | 131 name = "OCSPServerThread") |
122 self.thread.start() | 132 self.thread.start() |
123 | 133 |
124 def stop_serving(self): | 134 def stop_serving(self): |
(...skipping 1887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2012 # "echo response" message if "echo request" message is valid. | 2022 # "echo response" message if "echo request" message is valid. |
2013 try: | 2023 try: |
2014 return_data = echo_message.GetEchoResponseData(data) | 2024 return_data = echo_message.GetEchoResponseData(data) |
2015 if not return_data: | 2025 if not return_data: |
2016 return | 2026 return |
2017 except ValueError: | 2027 except ValueError: |
2018 return | 2028 return |
2019 socket.sendto(return_data, self.client_address) | 2029 socket.sendto(return_data, self.client_address) |
2020 | 2030 |
2021 | 2031 |
| 2032 class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
| 2033 """A request handler that behaves as a proxy server which requires |
| 2034 basic authentication. Only CONNECT, GET and HEAD is supported for now. |
| 2035 """ |
| 2036 |
| 2037 _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar |
| 2038 |
| 2039 def parse_request(self): |
| 2040 """Overrides parse_request to check credential.""" |
| 2041 |
| 2042 if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self): |
| 2043 return False |
| 2044 |
| 2045 auth = self.headers.getheader('Proxy-Authorization') |
| 2046 if auth != self._AUTH_CREDENTIAL: |
| 2047 self.send_response(407) |
| 2048 self.send_header('Proxy-Authenticate', 'Basic realm="MyRealm1"') |
| 2049 self.end_headers() |
| 2050 return False |
| 2051 |
| 2052 return True |
| 2053 |
| 2054 def _start_read_write(self, sock): |
| 2055 sock.setblocking(0) |
| 2056 self.request.setblocking(0) |
| 2057 rlist = [self.request, sock] |
| 2058 while True: |
| 2059 ready_sockets, unused, errors = select.select(rlist, [], []) |
| 2060 if errors: |
| 2061 self.send_response(500) |
| 2062 self.end_headers() |
| 2063 return |
| 2064 for s in ready_sockets: |
| 2065 received = s.recv(1024) |
| 2066 if len(received) == 0: |
| 2067 return |
| 2068 if s == self.request: |
| 2069 other = sock |
| 2070 else: |
| 2071 other = self.request |
| 2072 other.send(received) |
| 2073 |
| 2074 def _do_common_method(self): |
| 2075 url = urlparse.urlparse(self.path) |
| 2076 port = url.port |
| 2077 if not port: |
| 2078 if url.scheme == 'http': |
| 2079 port = 80 |
| 2080 elif url.scheme == 'https': |
| 2081 port = 443 |
| 2082 if not url.hostname or not port: |
| 2083 self.send_response(400) |
| 2084 self.end_headers() |
| 2085 return |
| 2086 |
| 2087 if len(url.path) == 0: |
| 2088 path = '/' |
| 2089 else: |
| 2090 path = url.path |
| 2091 if len(url.query) > 0: |
| 2092 path = '%s?%s' % (url.path, url.query) |
| 2093 |
| 2094 try: |
| 2095 sock = socket.create_connection((url.hostname, port)) |
| 2096 sock.send('%s %s %s\r\n' % ( |
| 2097 self.command, path, self.protocol_version)) |
| 2098 for header in self.headers.headers: |
| 2099 header = header.strip() |
| 2100 if (header.lower().startswith('connection') or |
| 2101 header.lower().startswith('proxy')): |
| 2102 continue |
| 2103 sock.send('%s\r\n' % header) |
| 2104 sock.send('\r\n') |
| 2105 self._start_read_write(sock) |
| 2106 except: |
| 2107 self.send_response(500) |
| 2108 self.end_headers() |
| 2109 finally: |
| 2110 sock.close() |
| 2111 |
| 2112 def do_CONNECT(self): |
| 2113 try: |
| 2114 pos = self.path.rfind(':') |
| 2115 host = self.path[:pos] |
| 2116 port = int(self.path[pos+1:]) |
| 2117 except: |
| 2118 self.send_response(400) |
| 2119 self.end_headers() |
| 2120 |
| 2121 try: |
| 2122 sock = socket.create_connection((host, port)) |
| 2123 self.send_response(200, 'Connection established') |
| 2124 self.end_headers() |
| 2125 self._start_read_write(sock) |
| 2126 except: |
| 2127 self.send_response(500) |
| 2128 self.end_headers() |
| 2129 finally: |
| 2130 sock.close() |
| 2131 |
| 2132 def do_GET(self): |
| 2133 self._do_common_method() |
| 2134 |
| 2135 def do_HEAD(self): |
| 2136 self._do_common_method() |
| 2137 |
| 2138 |
2022 class FileMultiplexer: | 2139 class FileMultiplexer: |
2023 def __init__(self, fd1, fd2) : | 2140 def __init__(self, fd1, fd2) : |
2024 self.__fd1 = fd1 | 2141 self.__fd1 = fd1 |
2025 self.__fd2 = fd2 | 2142 self.__fd2 = fd2 |
2026 | 2143 |
2027 def __del__(self) : | 2144 def __del__(self) : |
2028 if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: | 2145 if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: |
2029 self.__fd1.close() | 2146 self.__fd1.close() |
2030 if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: | 2147 if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: |
2031 self.__fd2.close() | 2148 self.__fd2.close() |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2130 server = TCPEchoServer((host, port), TCPEchoHandler) | 2247 server = TCPEchoServer((host, port), TCPEchoHandler) |
2131 print 'Echo TCP server started on port %d...' % server.server_port | 2248 print 'Echo TCP server started on port %d...' % server.server_port |
2132 server_data['port'] = server.server_port | 2249 server_data['port'] = server.server_port |
2133 elif options.server_type == SERVER_UDP_ECHO: | 2250 elif options.server_type == SERVER_UDP_ECHO: |
2134 # Used for generating the key (randomly) that encodes the "echo request" | 2251 # Used for generating the key (randomly) that encodes the "echo request" |
2135 # message. | 2252 # message. |
2136 random.seed() | 2253 random.seed() |
2137 server = UDPEchoServer((host, port), UDPEchoHandler) | 2254 server = UDPEchoServer((host, port), UDPEchoHandler) |
2138 print 'Echo UDP server started on port %d...' % server.server_port | 2255 print 'Echo UDP server started on port %d...' % server.server_port |
2139 server_data['port'] = server.server_port | 2256 server_data['port'] = server.server_port |
| 2257 elif options.server_type == SERVER_BASIC_AUTH_PROXY: |
| 2258 server = ThreadingHTTPServer((host, port), BasicAuthProxyRequestHandler) |
| 2259 print 'BasicAuthProxy server started on port %d...' % server.server_port |
| 2260 server_data['port'] = server.server_port |
2140 # means FTP Server | 2261 # means FTP Server |
2141 else: | 2262 else: |
2142 my_data_dir = MakeDataDir() | 2263 my_data_dir = MakeDataDir() |
2143 | 2264 |
2144 # Instantiate a dummy authorizer for managing 'virtual' users | 2265 # Instantiate a dummy authorizer for managing 'virtual' users |
2145 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() | 2266 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() |
2146 | 2267 |
2147 # Define a new user having full r/w permissions and a read-only | 2268 # Define a new user having full r/w permissions and a read-only |
2148 # anonymous user | 2269 # anonymous user |
2149 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') | 2270 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2204 dest='server_type', | 2325 dest='server_type', |
2205 help='start up a sync server.') | 2326 help='start up a sync server.') |
2206 option_parser.add_option('', '--tcp-echo', action='store_const', | 2327 option_parser.add_option('', '--tcp-echo', action='store_const', |
2207 const=SERVER_TCP_ECHO, default=SERVER_HTTP, | 2328 const=SERVER_TCP_ECHO, default=SERVER_HTTP, |
2208 dest='server_type', | 2329 dest='server_type', |
2209 help='start up a tcp echo server.') | 2330 help='start up a tcp echo server.') |
2210 option_parser.add_option('', '--udp-echo', action='store_const', | 2331 option_parser.add_option('', '--udp-echo', action='store_const', |
2211 const=SERVER_UDP_ECHO, default=SERVER_HTTP, | 2332 const=SERVER_UDP_ECHO, default=SERVER_HTTP, |
2212 dest='server_type', | 2333 dest='server_type', |
2213 help='start up a udp echo server.') | 2334 help='start up a udp echo server.') |
| 2335 option_parser.add_option('', '--basic-auth-proxy', action='store_const', |
| 2336 const=SERVER_BASIC_AUTH_PROXY, default=SERVER_HTTP, |
| 2337 dest='server_type', |
| 2338 help='start up a proxy server which requires basic ' |
| 2339 'authentication.') |
2214 option_parser.add_option('', '--log-to-console', action='store_const', | 2340 option_parser.add_option('', '--log-to-console', action='store_const', |
2215 const=True, default=False, | 2341 const=True, default=False, |
2216 dest='log_to_console', | 2342 dest='log_to_console', |
2217 help='Enables or disables sys.stdout logging to ' | 2343 help='Enables or disables sys.stdout logging to ' |
2218 'the console.') | 2344 'the console.') |
2219 option_parser.add_option('', '--port', default='0', type='int', | 2345 option_parser.add_option('', '--port', default='0', type='int', |
2220 help='Port used by the server. If unspecified, the ' | 2346 help='Port used by the server. If unspecified, the ' |
2221 'server will listen on an ephemeral port.') | 2347 'server will listen on an ephemeral port.') |
2222 option_parser.add_option('', '--xmpp-port', default='0', type='int', | 2348 option_parser.add_option('', '--xmpp-port', default='0', type='int', |
2223 help='Port used by the XMPP server. If unspecified, ' | 2349 help='Port used by the XMPP server. If unspecified, ' |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2286 dest='host', | 2412 dest='host', |
2287 help='Hostname or IP upon which the server will ' | 2413 help='Hostname or IP upon which the server will ' |
2288 'listen. Client connections will also only be ' | 2414 'listen. Client connections will also only be ' |
2289 'allowed from this address.') | 2415 'allowed from this address.') |
2290 option_parser.add_option('', '--auth-token', dest='auth_token', | 2416 option_parser.add_option('', '--auth-token', dest='auth_token', |
2291 help='Specify the auth token which should be used' | 2417 help='Specify the auth token which should be used' |
2292 'in the authorization header for GData.') | 2418 'in the authorization header for GData.') |
2293 options, args = option_parser.parse_args() | 2419 options, args = option_parser.parse_args() |
2294 | 2420 |
2295 sys.exit(main(options, args)) | 2421 sys.exit(main(options, args)) |
OLD | NEW |