| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 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/SYNC/TCP/UDP/ server used for testing Chrome. | 6 """This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for |
| 7 testing Chrome. |
| 7 | 8 |
| 8 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. |
| 9 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 |
| 10 the originating process over a pipe. The originating process can specify an | 11 the originating process over a pipe. The originating process can specify an |
| 11 explicit port if necessary. | 12 explicit port if necessary. |
| 12 It can use https if you specify the flag --https=CERT where CERT is the path | 13 It can use https if you specify the flag --https=CERT where CERT is the path |
| 13 to a pem file containing the certificate and private key that should be used. | 14 to a pem file containing the certificate and private key that should be used. |
| 14 """ | 15 """ |
| 15 | 16 |
| 16 import asyncore | |
| 17 import base64 | 17 import base64 |
| 18 import BaseHTTPServer | 18 import BaseHTTPServer |
| 19 import cgi | 19 import cgi |
| 20 import errno | |
| 21 import hashlib | 20 import hashlib |
| 22 import json | |
| 23 import logging | 21 import logging |
| 24 import minica | 22 import minica |
| 25 import os | 23 import os |
| 26 import random | 24 import random |
| 27 import re | 25 import re |
| 28 import select | 26 import select |
| 29 import socket | 27 import socket |
| 30 import SocketServer | 28 import SocketServer |
| 31 import struct | 29 import struct |
| 32 import sys | 30 import sys |
| 33 import threading | 31 import threading |
| 34 import time | 32 import time |
| 35 import urllib | 33 import urllib |
| 36 import urlparse | 34 import urlparse |
| 37 import zlib | 35 import zlib |
| 38 | 36 |
| 39 import echo_message | 37 import echo_message |
| 40 import pyftpdlib.ftpserver | 38 import pyftpdlib.ftpserver |
| 41 import testserver_base | 39 import testserver_base |
| 42 import tlslite | 40 import tlslite |
| 43 import tlslite.api | 41 import tlslite.api |
| 44 | 42 |
| 45 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 43 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 46 sys.path.insert( | 44 sys.path.insert( |
| 47 0, os.path.join(BASE_DIR, '..', '..', '..', 'third_party/pywebsocket/src')) | 45 0, os.path.join(BASE_DIR, '..', '..', '..', 'third_party/pywebsocket/src')) |
| 48 from mod_pywebsocket.standalone import WebSocketServer | 46 from mod_pywebsocket.standalone import WebSocketServer |
| 49 | 47 |
| 50 SERVER_HTTP = 0 | 48 SERVER_HTTP = 0 |
| 51 SERVER_FTP = 1 | 49 SERVER_FTP = 1 |
| 52 SERVER_SYNC = 2 | 50 SERVER_TCP_ECHO = 2 |
| 53 SERVER_TCP_ECHO = 3 | 51 SERVER_UDP_ECHO = 3 |
| 54 SERVER_UDP_ECHO = 4 | 52 SERVER_BASIC_AUTH_PROXY = 4 |
| 55 SERVER_BASIC_AUTH_PROXY = 5 | 53 SERVER_WEBSOCKET = 5 |
| 56 SERVER_WEBSOCKET = 6 | |
| 57 | 54 |
| 58 # Default request queue size for WebSocketServer. | 55 # Default request queue size for WebSocketServer. |
| 59 _DEFAULT_REQUEST_QUEUE_SIZE = 128 | 56 _DEFAULT_REQUEST_QUEUE_SIZE = 128 |
| 60 | 57 |
| 61 | 58 |
| 62 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . | |
| 63 debug_output = sys.stderr | |
| 64 def debug(string): | |
| 65 debug_output.write(string + "\n") | |
| 66 debug_output.flush() | |
| 67 | |
| 68 | |
| 69 class WebSocketOptions: | 59 class WebSocketOptions: |
| 70 """Holds options for WebSocketServer.""" | 60 """Holds options for WebSocketServer.""" |
| 71 | 61 |
| 72 def __init__(self, host, port, data_dir): | 62 def __init__(self, host, port, data_dir): |
| 73 self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE | 63 self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE |
| 74 self.server_host = host | 64 self.server_host = host |
| 75 self.port = port | 65 self.port = port |
| 76 self.websock_handlers = data_dir | 66 self.websock_handlers = data_dir |
| 77 self.scan_dir = None | 67 self.scan_dir = None |
| 78 self.allow_handlers_outside_root_dir = False | 68 self.allow_handlers_outside_root_dir = False |
| (...skipping 19 matching lines...) Expand all Loading... |
| 98 self.log = [] | 88 self.log = [] |
| 99 | 89 |
| 100 def __getitem__(self, sessionID): | 90 def __getitem__(self, sessionID): |
| 101 self.log.append(('lookup', sessionID)) | 91 self.log.append(('lookup', sessionID)) |
| 102 raise KeyError() | 92 raise KeyError() |
| 103 | 93 |
| 104 def __setitem__(self, sessionID, session): | 94 def __setitem__(self, sessionID, session): |
| 105 self.log.append(('insert', sessionID)) | 95 self.log.append(('insert', sessionID)) |
| 106 | 96 |
| 107 | 97 |
| 108 class ClientRestrictingServerMixIn: | 98 class HTTPServer(testserver_base.ClientRestrictingServerMixIn, |
| 109 """Implements verify_request to limit connections to our configured IP | 99 testserver_base.BrokenPipeHandlerMixIn, |
| 110 address.""" | 100 testserver_base.StoppableHTTPServer): |
| 111 | |
| 112 def verify_request(self, _request, client_address): | |
| 113 return client_address[0] == self.server_address[0] | |
| 114 | |
| 115 | |
| 116 class BrokenPipeHandlerMixIn: | |
| 117 """Allows the server to deal with "broken pipe" errors (which happen if the | |
| 118 browser quits with outstanding requests, like for the favicon). This mix-in | |
| 119 requires the class to derive from SocketServer.BaseServer and not override its | |
| 120 handle_error() method. """ | |
| 121 | |
| 122 def handle_error(self, request, client_address): | |
| 123 value = sys.exc_info()[1] | |
| 124 if isinstance(value, socket.error): | |
| 125 err = value.args[0] | |
| 126 if sys.platform in ('win32', 'cygwin'): | |
| 127 # "An established connection was aborted by the software in your host." | |
| 128 pipe_err = 10053 | |
| 129 else: | |
| 130 pipe_err = errno.EPIPE | |
| 131 if err == pipe_err: | |
| 132 print "testserver.py: Broken pipe" | |
| 133 return | |
| 134 SocketServer.BaseServer.handle_error(self, request, client_address) | |
| 135 | |
| 136 | |
| 137 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): | |
| 138 """This is a specialization of BaseHTTPServer to allow it | |
| 139 to be exited cleanly (by setting its "stop" member to True).""" | |
| 140 | |
| 141 def serve_forever(self): | |
| 142 self.stop = False | |
| 143 self.nonce_time = None | |
| 144 while not self.stop: | |
| 145 self.handle_request() | |
| 146 self.socket.close() | |
| 147 | |
| 148 | |
| 149 class HTTPServer(ClientRestrictingServerMixIn, | |
| 150 BrokenPipeHandlerMixIn, | |
| 151 StoppableHTTPServer): | |
| 152 """This is a specialization of StoppableHTTPServer that adds client | 101 """This is a specialization of StoppableHTTPServer that adds client |
| 153 verification.""" | 102 verification.""" |
| 154 | 103 |
| 155 pass | 104 pass |
| 156 | 105 |
| 157 class OCSPServer(ClientRestrictingServerMixIn, | 106 class OCSPServer(testserver_base.ClientRestrictingServerMixIn, |
| 158 BrokenPipeHandlerMixIn, | 107 testserver_base.BrokenPipeHandlerMixIn, |
| 159 BaseHTTPServer.HTTPServer): | 108 BaseHTTPServer.HTTPServer): |
| 160 """This is a specialization of HTTPServer that serves an | 109 """This is a specialization of HTTPServer that serves an |
| 161 OCSP response""" | 110 OCSP response""" |
| 162 | 111 |
| 163 def serve_forever_on_thread(self): | 112 def serve_forever_on_thread(self): |
| 164 self.thread = threading.Thread(target = self.serve_forever, | 113 self.thread = threading.Thread(target = self.serve_forever, |
| 165 name = "OCSPServerThread") | 114 name = "OCSPServerThread") |
| 166 self.thread.start() | 115 self.thread.start() |
| 167 | 116 |
| 168 def stop_serving(self): | 117 def stop_serving(self): |
| 169 self.shutdown() | 118 self.shutdown() |
| 170 self.thread.join() | 119 self.thread.join() |
| 171 | 120 |
| 172 | 121 |
| 173 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, | 122 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, |
| 174 ClientRestrictingServerMixIn, | 123 testserver_base.ClientRestrictingServerMixIn, |
| 175 BrokenPipeHandlerMixIn, | 124 testserver_base.BrokenPipeHandlerMixIn, |
| 176 StoppableHTTPServer): | 125 testserver_base.StoppableHTTPServer): |
| 177 """This is a specialization of StoppableHTTPServer that add https support and | 126 """This is a specialization of StoppableHTTPServer that add https support and |
| 178 client verification.""" | 127 client verification.""" |
| 179 | 128 |
| 180 def __init__(self, server_address, request_hander_class, pem_cert_and_key, | 129 def __init__(self, server_address, request_hander_class, pem_cert_and_key, |
| 181 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, | 130 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
| 182 record_resume_info, tls_intolerant): | 131 record_resume_info, tls_intolerant): |
| 183 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) | 132 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) |
| 184 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True) | 133 self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True) |
| 185 self.ssl_client_auth = ssl_client_auth | 134 self.ssl_client_auth = ssl_client_auth |
| 186 self.ssl_client_cas = [] | 135 self.ssl_client_cas = [] |
| 187 self.tls_intolerant = tls_intolerant | 136 self.tls_intolerant = tls_intolerant |
| 188 | 137 |
| 189 for ca_file in ssl_client_cas: | 138 for ca_file in ssl_client_cas: |
| 190 s = open(ca_file).read() | 139 s = open(ca_file).read() |
| 191 x509 = tlslite.api.X509() | 140 x509 = tlslite.api.X509() |
| 192 x509.parse(s) | 141 x509.parse(s) |
| 193 self.ssl_client_cas.append(x509.subject) | 142 self.ssl_client_cas.append(x509.subject) |
| 194 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() | 143 self.ssl_handshake_settings = tlslite.api.HandshakeSettings() |
| 195 if ssl_bulk_ciphers is not None: | 144 if ssl_bulk_ciphers is not None: |
| 196 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers | 145 self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers |
| 197 | 146 |
| 198 if record_resume_info: | 147 if record_resume_info: |
| 199 # If record_resume_info is true then we'll replace the session cache with | 148 # If record_resume_info is true then we'll replace the session cache with |
| 200 # an object that records the lookups and inserts that it sees. | 149 # an object that records the lookups and inserts that it sees. |
| 201 self.session_cache = RecordingSSLSessionCache() | 150 self.session_cache = RecordingSSLSessionCache() |
| 202 else: | 151 else: |
| 203 self.session_cache = tlslite.api.SessionCache() | 152 self.session_cache = tlslite.api.SessionCache() |
| 204 StoppableHTTPServer.__init__(self, server_address, request_hander_class) | 153 testserver_base.StoppableHTTPServer.__init__(self, |
| 154 server_address, |
| 155 request_hander_class) |
| 205 | 156 |
| 206 def handshake(self, tlsConnection): | 157 def handshake(self, tlsConnection): |
| 207 """Creates the SSL connection.""" | 158 """Creates the SSL connection.""" |
| 208 | 159 |
| 209 try: | 160 try: |
| 210 tlsConnection.handshakeServer(certChain=self.cert_chain, | 161 tlsConnection.handshakeServer(certChain=self.cert_chain, |
| 211 privateKey=self.private_key, | 162 privateKey=self.private_key, |
| 212 sessionCache=self.session_cache, | 163 sessionCache=self.session_cache, |
| 213 reqCert=self.ssl_client_auth, | 164 reqCert=self.ssl_client_auth, |
| 214 settings=self.ssl_handshake_settings, | 165 settings=self.ssl_handshake_settings, |
| 215 reqCAs=self.ssl_client_cas, | 166 reqCAs=self.ssl_client_cas, |
| 216 tlsIntolerant=self.tls_intolerant) | 167 tlsIntolerant=self.tls_intolerant) |
| 217 tlsConnection.ignoreAbruptClose = True | 168 tlsConnection.ignoreAbruptClose = True |
| 218 return True | 169 return True |
| 219 except tlslite.api.TLSAbruptCloseError: | 170 except tlslite.api.TLSAbruptCloseError: |
| 220 # Ignore abrupt close. | 171 # Ignore abrupt close. |
| 221 return True | 172 return True |
| 222 except tlslite.api.TLSError, error: | 173 except tlslite.api.TLSError, error: |
| 223 print "Handshake failure:", str(error) | 174 print "Handshake failure:", str(error) |
| 224 return False | 175 return False |
| 225 | 176 |
| 226 | 177 |
| 227 class SyncHTTPServer(ClientRestrictingServerMixIn, | 178 class FTPServer(testserver_base.ClientRestrictingServerMixIn, |
| 228 BrokenPipeHandlerMixIn, | 179 pyftpdlib.ftpserver.FTPServer): |
| 229 StoppableHTTPServer): | |
| 230 """An HTTP server that handles sync commands.""" | |
| 231 | |
| 232 def __init__(self, server_address, xmpp_port, request_handler_class): | |
| 233 # We import here to avoid pulling in chromiumsync's dependencies | |
| 234 # unless strictly necessary. | |
| 235 import chromiumsync | |
| 236 import xmppserver | |
| 237 StoppableHTTPServer.__init__(self, server_address, request_handler_class) | |
| 238 self._sync_handler = chromiumsync.TestServer() | |
| 239 self._xmpp_socket_map = {} | |
| 240 self._xmpp_server = xmppserver.XmppServer( | |
| 241 self._xmpp_socket_map, ('localhost', xmpp_port)) | |
| 242 self.xmpp_port = self._xmpp_server.getsockname()[1] | |
| 243 self.authenticated = True | |
| 244 | |
| 245 def GetXmppServer(self): | |
| 246 return self._xmpp_server | |
| 247 | |
| 248 def HandleCommand(self, query, raw_request): | |
| 249 return self._sync_handler.HandleCommand(query, raw_request) | |
| 250 | |
| 251 def HandleRequestNoBlock(self): | |
| 252 """Handles a single request. | |
| 253 | |
| 254 Copied from SocketServer._handle_request_noblock(). | |
| 255 """ | |
| 256 | |
| 257 try: | |
| 258 request, client_address = self.get_request() | |
| 259 except socket.error: | |
| 260 return | |
| 261 if self.verify_request(request, client_address): | |
| 262 try: | |
| 263 self.process_request(request, client_address) | |
| 264 except Exception: | |
| 265 self.handle_error(request, client_address) | |
| 266 self.close_request(request) | |
| 267 | |
| 268 def SetAuthenticated(self, auth_valid): | |
| 269 self.authenticated = auth_valid | |
| 270 | |
| 271 def GetAuthenticated(self): | |
| 272 return self.authenticated | |
| 273 | |
| 274 def serve_forever(self): | |
| 275 """This is a merge of asyncore.loop() and SocketServer.serve_forever(). | |
| 276 """ | |
| 277 | |
| 278 def HandleXmppSocket(fd, socket_map, handler): | |
| 279 """Runs the handler for the xmpp connection for fd. | |
| 280 | |
| 281 Adapted from asyncore.read() et al. | |
| 282 """ | |
| 283 | |
| 284 xmpp_connection = socket_map.get(fd) | |
| 285 # This could happen if a previous handler call caused fd to get | |
| 286 # removed from socket_map. | |
| 287 if xmpp_connection is None: | |
| 288 return | |
| 289 try: | |
| 290 handler(xmpp_connection) | |
| 291 except (asyncore.ExitNow, KeyboardInterrupt, SystemExit): | |
| 292 raise | |
| 293 except: | |
| 294 xmpp_connection.handle_error() | |
| 295 | |
| 296 while True: | |
| 297 read_fds = [ self.fileno() ] | |
| 298 write_fds = [] | |
| 299 exceptional_fds = [] | |
| 300 | |
| 301 for fd, xmpp_connection in self._xmpp_socket_map.items(): | |
| 302 is_r = xmpp_connection.readable() | |
| 303 is_w = xmpp_connection.writable() | |
| 304 if is_r: | |
| 305 read_fds.append(fd) | |
| 306 if is_w: | |
| 307 write_fds.append(fd) | |
| 308 if is_r or is_w: | |
| 309 exceptional_fds.append(fd) | |
| 310 | |
| 311 try: | |
| 312 read_fds, write_fds, exceptional_fds = ( | |
| 313 select.select(read_fds, write_fds, exceptional_fds)) | |
| 314 except select.error, err: | |
| 315 if err.args[0] != errno.EINTR: | |
| 316 raise | |
| 317 else: | |
| 318 continue | |
| 319 | |
| 320 for fd in read_fds: | |
| 321 if fd == self.fileno(): | |
| 322 self.HandleRequestNoBlock() | |
| 323 continue | |
| 324 HandleXmppSocket(fd, self._xmpp_socket_map, | |
| 325 asyncore.dispatcher.handle_read_event) | |
| 326 | |
| 327 for fd in write_fds: | |
| 328 HandleXmppSocket(fd, self._xmpp_socket_map, | |
| 329 asyncore.dispatcher.handle_write_event) | |
| 330 | |
| 331 for fd in exceptional_fds: | |
| 332 HandleXmppSocket(fd, self._xmpp_socket_map, | |
| 333 asyncore.dispatcher.handle_expt_event) | |
| 334 | |
| 335 | |
| 336 class FTPServer(ClientRestrictingServerMixIn, pyftpdlib.ftpserver.FTPServer): | |
| 337 """This is a specialization of FTPServer that adds client verification.""" | 180 """This is a specialization of FTPServer that adds client verification.""" |
| 338 | 181 |
| 339 pass | 182 pass |
| 340 | 183 |
| 341 | 184 |
| 342 class TCPEchoServer(ClientRestrictingServerMixIn, SocketServer.TCPServer): | 185 class TCPEchoServer(testserver_base.ClientRestrictingServerMixIn, |
| 186 SocketServer.TCPServer): |
| 343 """A TCP echo server that echoes back what it has received.""" | 187 """A TCP echo server that echoes back what it has received.""" |
| 344 | 188 |
| 345 def server_bind(self): | 189 def server_bind(self): |
| 346 """Override server_bind to store the server name.""" | 190 """Override server_bind to store the server name.""" |
| 347 | 191 |
| 348 SocketServer.TCPServer.server_bind(self) | 192 SocketServer.TCPServer.server_bind(self) |
| 349 host, port = self.socket.getsockname()[:2] | 193 host, port = self.socket.getsockname()[:2] |
| 350 self.server_name = socket.getfqdn(host) | 194 self.server_name = socket.getfqdn(host) |
| 351 self.server_port = port | 195 self.server_port = port |
| 352 | 196 |
| 353 def serve_forever(self): | 197 def serve_forever(self): |
| 354 self.stop = False | 198 self.stop = False |
| 355 self.nonce_time = None | 199 self.nonce_time = None |
| 356 while not self.stop: | 200 while not self.stop: |
| 357 self.handle_request() | 201 self.handle_request() |
| 358 self.socket.close() | 202 self.socket.close() |
| 359 | 203 |
| 360 | 204 |
| 361 class UDPEchoServer(ClientRestrictingServerMixIn, SocketServer.UDPServer): | 205 class UDPEchoServer(testserver_base.ClientRestrictingServerMixIn, |
| 206 SocketServer.UDPServer): |
| 362 """A UDP echo server that echoes back what it has received.""" | 207 """A UDP echo server that echoes back what it has received.""" |
| 363 | 208 |
| 364 def server_bind(self): | 209 def server_bind(self): |
| 365 """Override server_bind to store the server name.""" | 210 """Override server_bind to store the server name.""" |
| 366 | 211 |
| 367 SocketServer.UDPServer.server_bind(self) | 212 SocketServer.UDPServer.server_bind(self) |
| 368 host, port = self.socket.getsockname()[:2] | 213 host, port = self.socket.getsockname()[:2] |
| 369 self.server_name = socket.getfqdn(host) | 214 self.server_name = socket.getfqdn(host) |
| 370 self.server_port = port | 215 self.server_port = port |
| 371 | 216 |
| 372 def serve_forever(self): | 217 def serve_forever(self): |
| 373 self.stop = False | 218 self.stop = False |
| 374 self.nonce_time = None | 219 self.nonce_time = None |
| 375 while not self.stop: | 220 while not self.stop: |
| 376 self.handle_request() | 221 self.handle_request() |
| 377 self.socket.close() | 222 self.socket.close() |
| 378 | 223 |
| 379 | 224 |
| 380 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): | 225 class TestPageHandler(testserver_base.BasePageHandler): |
| 381 | |
| 382 def __init__(self, request, client_address, socket_server, | |
| 383 connect_handlers, get_handlers, head_handlers, post_handlers, | |
| 384 put_handlers): | |
| 385 self._connect_handlers = connect_handlers | |
| 386 self._get_handlers = get_handlers | |
| 387 self._head_handlers = head_handlers | |
| 388 self._post_handlers = post_handlers | |
| 389 self._put_handlers = put_handlers | |
| 390 BaseHTTPServer.BaseHTTPRequestHandler.__init__( | |
| 391 self, request, client_address, socket_server) | |
| 392 | |
| 393 def log_request(self, *args, **kwargs): | |
| 394 # Disable request logging to declutter test log output. | |
| 395 pass | |
| 396 | |
| 397 def _ShouldHandleRequest(self, handler_name): | |
| 398 """Determines if the path can be handled by the handler. | |
| 399 | |
| 400 We consider a handler valid if the path begins with the | |
| 401 handler name. It can optionally be followed by "?*", "/*". | |
| 402 """ | |
| 403 | |
| 404 pattern = re.compile('%s($|\?|/).*' % handler_name) | |
| 405 return pattern.match(self.path) | |
| 406 | |
| 407 def do_CONNECT(self): | |
| 408 for handler in self._connect_handlers: | |
| 409 if handler(): | |
| 410 return | |
| 411 | |
| 412 def do_GET(self): | |
| 413 for handler in self._get_handlers: | |
| 414 if handler(): | |
| 415 return | |
| 416 | |
| 417 def do_HEAD(self): | |
| 418 for handler in self._head_handlers: | |
| 419 if handler(): | |
| 420 return | |
| 421 | |
| 422 def do_POST(self): | |
| 423 for handler in self._post_handlers: | |
| 424 if handler(): | |
| 425 return | |
| 426 | |
| 427 def do_PUT(self): | |
| 428 for handler in self._put_handlers: | |
| 429 if handler(): | |
| 430 return | |
| 431 | |
| 432 | |
| 433 class TestPageHandler(BasePageHandler): | |
| 434 | 226 |
| 435 def __init__(self, request, client_address, socket_server): | 227 def __init__(self, request, client_address, socket_server): |
| 436 connect_handlers = [ | 228 connect_handlers = [ |
| 437 self.RedirectConnectHandler, | 229 self.RedirectConnectHandler, |
| 438 self.ServerAuthConnectHandler, | 230 self.ServerAuthConnectHandler, |
| 439 self.DefaultConnectResponseHandler] | 231 self.DefaultConnectResponseHandler] |
| 440 get_handlers = [ | 232 get_handlers = [ |
| 441 self.NoCacheMaxAgeTimeHandler, | 233 self.NoCacheMaxAgeTimeHandler, |
| 442 self.NoCacheTimeHandler, | 234 self.NoCacheTimeHandler, |
| 443 self.CacheTimeHandler, | 235 self.CacheTimeHandler, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 'gif': 'image/gif', | 286 'gif': 'image/gif', |
| 495 'jpeg' : 'image/jpeg', | 287 'jpeg' : 'image/jpeg', |
| 496 'jpg' : 'image/jpeg', | 288 'jpg' : 'image/jpeg', |
| 497 'json': 'application/json', | 289 'json': 'application/json', |
| 498 'pdf' : 'application/pdf', | 290 'pdf' : 'application/pdf', |
| 499 'wav' : 'audio/wav', | 291 'wav' : 'audio/wav', |
| 500 'xml' : 'text/xml' | 292 'xml' : 'text/xml' |
| 501 } | 293 } |
| 502 self._default_mime_type = 'text/html' | 294 self._default_mime_type = 'text/html' |
| 503 | 295 |
| 504 BasePageHandler.__init__(self, request, client_address, socket_server, | 296 testserver_base.BasePageHandler.__init__(self, request, client_address, |
| 505 connect_handlers, get_handlers, head_handlers, | 297 socket_server, connect_handlers, |
| 506 post_handlers, put_handlers) | 298 get_handlers, head_handlers, |
| 299 post_handlers, put_handlers) |
| 507 | 300 |
| 508 def GetMIMETypeFromName(self, file_name): | 301 def GetMIMETypeFromName(self, file_name): |
| 509 """Returns the mime type for the specified file_name. So far it only looks | 302 """Returns the mime type for the specified file_name. So far it only looks |
| 510 at the file extension.""" | 303 at the file extension.""" |
| 511 | 304 |
| 512 (_shortname, extension) = os.path.splitext(file_name.split("?")[0]) | 305 (_shortname, extension) = os.path.splitext(file_name.split("?")[0]) |
| 513 if len(extension) == 0: | 306 if len(extension) == 0: |
| 514 # no extension. | 307 # no extension. |
| 515 return self._default_mime_type | 308 return self._default_mime_type |
| 516 | 309 |
| (...skipping 1306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1823 self.wfile.write('</body></html>') | 1616 self.wfile.write('</body></html>') |
| 1824 | 1617 |
| 1825 # called by chunked handling function | 1618 # called by chunked handling function |
| 1826 def sendChunkHelp(self, chunk): | 1619 def sendChunkHelp(self, chunk): |
| 1827 # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF | 1620 # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF |
| 1828 self.wfile.write('%X\r\n' % len(chunk)) | 1621 self.wfile.write('%X\r\n' % len(chunk)) |
| 1829 self.wfile.write(chunk) | 1622 self.wfile.write(chunk) |
| 1830 self.wfile.write('\r\n') | 1623 self.wfile.write('\r\n') |
| 1831 | 1624 |
| 1832 | 1625 |
| 1833 class SyncPageHandler(BasePageHandler): | 1626 class OCSPHandler(testserver_base.BasePageHandler): |
| 1834 """Handler for the main HTTP sync server.""" | |
| 1835 | |
| 1836 def __init__(self, request, client_address, sync_http_server): | |
| 1837 get_handlers = [self.ChromiumSyncTimeHandler, | |
| 1838 self.ChromiumSyncMigrationOpHandler, | |
| 1839 self.ChromiumSyncCredHandler, | |
| 1840 self.ChromiumSyncXmppCredHandler, | |
| 1841 self.ChromiumSyncDisableNotificationsOpHandler, | |
| 1842 self.ChromiumSyncEnableNotificationsOpHandler, | |
| 1843 self.ChromiumSyncSendNotificationOpHandler, | |
| 1844 self.ChromiumSyncBirthdayErrorOpHandler, | |
| 1845 self.ChromiumSyncTransientErrorOpHandler, | |
| 1846 self.ChromiumSyncErrorOpHandler, | |
| 1847 self.ChromiumSyncSyncTabFaviconsOpHandler, | |
| 1848 self.ChromiumSyncCreateSyncedBookmarksOpHandler, | |
| 1849 self.ChromiumSyncEnableKeystoreEncryptionOpHandler, | |
| 1850 self.ChromiumSyncRotateKeystoreKeysOpHandler] | |
| 1851 | |
| 1852 post_handlers = [self.ChromiumSyncCommandHandler, | |
| 1853 self.ChromiumSyncTimeHandler] | |
| 1854 BasePageHandler.__init__(self, request, client_address, | |
| 1855 sync_http_server, [], get_handlers, [], | |
| 1856 post_handlers, []) | |
| 1857 | |
| 1858 | |
| 1859 def ChromiumSyncTimeHandler(self): | |
| 1860 """Handle Chromium sync .../time requests. | |
| 1861 | |
| 1862 The syncer sometimes checks server reachability by examining /time. | |
| 1863 """ | |
| 1864 | |
| 1865 test_name = "/chromiumsync/time" | |
| 1866 if not self._ShouldHandleRequest(test_name): | |
| 1867 return False | |
| 1868 | |
| 1869 # Chrome hates it if we send a response before reading the request. | |
| 1870 if self.headers.getheader('content-length'): | |
| 1871 length = int(self.headers.getheader('content-length')) | |
| 1872 _raw_request = self.rfile.read(length) | |
| 1873 | |
| 1874 self.send_response(200) | |
| 1875 self.send_header('Content-Type', 'text/plain') | |
| 1876 self.end_headers() | |
| 1877 self.wfile.write('0123456789') | |
| 1878 return True | |
| 1879 | |
| 1880 def ChromiumSyncCommandHandler(self): | |
| 1881 """Handle a chromiumsync command arriving via http. | |
| 1882 | |
| 1883 This covers all sync protocol commands: authentication, getupdates, and | |
| 1884 commit. | |
| 1885 """ | |
| 1886 | |
| 1887 test_name = "/chromiumsync/command" | |
| 1888 if not self._ShouldHandleRequest(test_name): | |
| 1889 return False | |
| 1890 | |
| 1891 length = int(self.headers.getheader('content-length')) | |
| 1892 raw_request = self.rfile.read(length) | |
| 1893 http_response = 200 | |
| 1894 raw_reply = None | |
| 1895 if not self.server.GetAuthenticated(): | |
| 1896 http_response = 401 | |
| 1897 challenge = 'GoogleLogin realm="http://%s", service="chromiumsync"' % ( | |
| 1898 self.server.server_address[0]) | |
| 1899 else: | |
| 1900 http_response, raw_reply = self.server.HandleCommand( | |
| 1901 self.path, raw_request) | |
| 1902 | |
| 1903 ### Now send the response to the client. ### | |
| 1904 self.send_response(http_response) | |
| 1905 if http_response == 401: | |
| 1906 self.send_header('www-Authenticate', challenge) | |
| 1907 self.end_headers() | |
| 1908 self.wfile.write(raw_reply) | |
| 1909 return True | |
| 1910 | |
| 1911 def ChromiumSyncMigrationOpHandler(self): | |
| 1912 test_name = "/chromiumsync/migrate" | |
| 1913 if not self._ShouldHandleRequest(test_name): | |
| 1914 return False | |
| 1915 | |
| 1916 http_response, raw_reply = self.server._sync_handler.HandleMigrate( | |
| 1917 self.path) | |
| 1918 self.send_response(http_response) | |
| 1919 self.send_header('Content-Type', 'text/html') | |
| 1920 self.send_header('Content-Length', len(raw_reply)) | |
| 1921 self.end_headers() | |
| 1922 self.wfile.write(raw_reply) | |
| 1923 return True | |
| 1924 | |
| 1925 def ChromiumSyncCredHandler(self): | |
| 1926 test_name = "/chromiumsync/cred" | |
| 1927 if not self._ShouldHandleRequest(test_name): | |
| 1928 return False | |
| 1929 try: | |
| 1930 query = urlparse.urlparse(self.path)[4] | |
| 1931 cred_valid = urlparse.parse_qs(query)['valid'] | |
| 1932 if cred_valid[0] == 'True': | |
| 1933 self.server.SetAuthenticated(True) | |
| 1934 else: | |
| 1935 self.server.SetAuthenticated(False) | |
| 1936 except Exception: | |
| 1937 self.server.SetAuthenticated(False) | |
| 1938 | |
| 1939 http_response = 200 | |
| 1940 raw_reply = 'Authenticated: %s ' % self.server.GetAuthenticated() | |
| 1941 self.send_response(http_response) | |
| 1942 self.send_header('Content-Type', 'text/html') | |
| 1943 self.send_header('Content-Length', len(raw_reply)) | |
| 1944 self.end_headers() | |
| 1945 self.wfile.write(raw_reply) | |
| 1946 return True | |
| 1947 | |
| 1948 def ChromiumSyncXmppCredHandler(self): | |
| 1949 test_name = "/chromiumsync/xmppcred" | |
| 1950 if not self._ShouldHandleRequest(test_name): | |
| 1951 return False | |
| 1952 xmpp_server = self.server.GetXmppServer() | |
| 1953 try: | |
| 1954 query = urlparse.urlparse(self.path)[4] | |
| 1955 cred_valid = urlparse.parse_qs(query)['valid'] | |
| 1956 if cred_valid[0] == 'True': | |
| 1957 xmpp_server.SetAuthenticated(True) | |
| 1958 else: | |
| 1959 xmpp_server.SetAuthenticated(False) | |
| 1960 except: | |
| 1961 xmpp_server.SetAuthenticated(False) | |
| 1962 | |
| 1963 http_response = 200 | |
| 1964 raw_reply = 'XMPP Authenticated: %s ' % xmpp_server.GetAuthenticated() | |
| 1965 self.send_response(http_response) | |
| 1966 self.send_header('Content-Type', 'text/html') | |
| 1967 self.send_header('Content-Length', len(raw_reply)) | |
| 1968 self.end_headers() | |
| 1969 self.wfile.write(raw_reply) | |
| 1970 return True | |
| 1971 | |
| 1972 def ChromiumSyncDisableNotificationsOpHandler(self): | |
| 1973 test_name = "/chromiumsync/disablenotifications" | |
| 1974 if not self._ShouldHandleRequest(test_name): | |
| 1975 return False | |
| 1976 self.server.GetXmppServer().DisableNotifications() | |
| 1977 result = 200 | |
| 1978 raw_reply = ('<html><title>Notifications disabled</title>' | |
| 1979 '<H1>Notifications disabled</H1></html>') | |
| 1980 self.send_response(result) | |
| 1981 self.send_header('Content-Type', 'text/html') | |
| 1982 self.send_header('Content-Length', len(raw_reply)) | |
| 1983 self.end_headers() | |
| 1984 self.wfile.write(raw_reply) | |
| 1985 return True | |
| 1986 | |
| 1987 def ChromiumSyncEnableNotificationsOpHandler(self): | |
| 1988 test_name = "/chromiumsync/enablenotifications" | |
| 1989 if not self._ShouldHandleRequest(test_name): | |
| 1990 return False | |
| 1991 self.server.GetXmppServer().EnableNotifications() | |
| 1992 result = 200 | |
| 1993 raw_reply = ('<html><title>Notifications enabled</title>' | |
| 1994 '<H1>Notifications enabled</H1></html>') | |
| 1995 self.send_response(result) | |
| 1996 self.send_header('Content-Type', 'text/html') | |
| 1997 self.send_header('Content-Length', len(raw_reply)) | |
| 1998 self.end_headers() | |
| 1999 self.wfile.write(raw_reply) | |
| 2000 return True | |
| 2001 | |
| 2002 def ChromiumSyncSendNotificationOpHandler(self): | |
| 2003 test_name = "/chromiumsync/sendnotification" | |
| 2004 if not self._ShouldHandleRequest(test_name): | |
| 2005 return False | |
| 2006 query = urlparse.urlparse(self.path)[4] | |
| 2007 query_params = urlparse.parse_qs(query) | |
| 2008 channel = '' | |
| 2009 data = '' | |
| 2010 if 'channel' in query_params: | |
| 2011 channel = query_params['channel'][0] | |
| 2012 if 'data' in query_params: | |
| 2013 data = query_params['data'][0] | |
| 2014 self.server.GetXmppServer().SendNotification(channel, data) | |
| 2015 result = 200 | |
| 2016 raw_reply = ('<html><title>Notification sent</title>' | |
| 2017 '<H1>Notification sent with channel "%s" ' | |
| 2018 'and data "%s"</H1></html>' | |
| 2019 % (channel, data)) | |
| 2020 self.send_response(result) | |
| 2021 self.send_header('Content-Type', 'text/html') | |
| 2022 self.send_header('Content-Length', len(raw_reply)) | |
| 2023 self.end_headers() | |
| 2024 self.wfile.write(raw_reply) | |
| 2025 return True | |
| 2026 | |
| 2027 def ChromiumSyncBirthdayErrorOpHandler(self): | |
| 2028 test_name = "/chromiumsync/birthdayerror" | |
| 2029 if not self._ShouldHandleRequest(test_name): | |
| 2030 return False | |
| 2031 result, raw_reply = self.server._sync_handler.HandleCreateBirthdayError() | |
| 2032 self.send_response(result) | |
| 2033 self.send_header('Content-Type', 'text/html') | |
| 2034 self.send_header('Content-Length', len(raw_reply)) | |
| 2035 self.end_headers() | |
| 2036 self.wfile.write(raw_reply) | |
| 2037 return True | |
| 2038 | |
| 2039 def ChromiumSyncTransientErrorOpHandler(self): | |
| 2040 test_name = "/chromiumsync/transienterror" | |
| 2041 if not self._ShouldHandleRequest(test_name): | |
| 2042 return False | |
| 2043 result, raw_reply = self.server._sync_handler.HandleSetTransientError() | |
| 2044 self.send_response(result) | |
| 2045 self.send_header('Content-Type', 'text/html') | |
| 2046 self.send_header('Content-Length', len(raw_reply)) | |
| 2047 self.end_headers() | |
| 2048 self.wfile.write(raw_reply) | |
| 2049 return True | |
| 2050 | |
| 2051 def ChromiumSyncErrorOpHandler(self): | |
| 2052 test_name = "/chromiumsync/error" | |
| 2053 if not self._ShouldHandleRequest(test_name): | |
| 2054 return False | |
| 2055 result, raw_reply = self.server._sync_handler.HandleSetInducedError( | |
| 2056 self.path) | |
| 2057 self.send_response(result) | |
| 2058 self.send_header('Content-Type', 'text/html') | |
| 2059 self.send_header('Content-Length', len(raw_reply)) | |
| 2060 self.end_headers() | |
| 2061 self.wfile.write(raw_reply) | |
| 2062 return True | |
| 2063 | |
| 2064 def ChromiumSyncSyncTabFaviconsOpHandler(self): | |
| 2065 test_name = "/chromiumsync/synctabfavicons" | |
| 2066 if not self._ShouldHandleRequest(test_name): | |
| 2067 return False | |
| 2068 result, raw_reply = self.server._sync_handler.HandleSetSyncTabFavicons() | |
| 2069 self.send_response(result) | |
| 2070 self.send_header('Content-Type', 'text/html') | |
| 2071 self.send_header('Content-Length', len(raw_reply)) | |
| 2072 self.end_headers() | |
| 2073 self.wfile.write(raw_reply) | |
| 2074 return True | |
| 2075 | |
| 2076 def ChromiumSyncCreateSyncedBookmarksOpHandler(self): | |
| 2077 test_name = "/chromiumsync/createsyncedbookmarks" | |
| 2078 if not self._ShouldHandleRequest(test_name): | |
| 2079 return False | |
| 2080 result, raw_reply = self.server._sync_handler.HandleCreateSyncedBookmarks() | |
| 2081 self.send_response(result) | |
| 2082 self.send_header('Content-Type', 'text/html') | |
| 2083 self.send_header('Content-Length', len(raw_reply)) | |
| 2084 self.end_headers() | |
| 2085 self.wfile.write(raw_reply) | |
| 2086 return True | |
| 2087 | |
| 2088 def ChromiumSyncEnableKeystoreEncryptionOpHandler(self): | |
| 2089 test_name = "/chromiumsync/enablekeystoreencryption" | |
| 2090 if not self._ShouldHandleRequest(test_name): | |
| 2091 return False | |
| 2092 result, raw_reply = ( | |
| 2093 self.server._sync_handler.HandleEnableKeystoreEncryption()) | |
| 2094 self.send_response(result) | |
| 2095 self.send_header('Content-Type', 'text/html') | |
| 2096 self.send_header('Content-Length', len(raw_reply)) | |
| 2097 self.end_headers() | |
| 2098 self.wfile.write(raw_reply) | |
| 2099 return True | |
| 2100 | |
| 2101 def ChromiumSyncRotateKeystoreKeysOpHandler(self): | |
| 2102 test_name = "/chromiumsync/rotatekeystorekeys" | |
| 2103 if not self._ShouldHandleRequest(test_name): | |
| 2104 return False | |
| 2105 result, raw_reply = ( | |
| 2106 self.server._sync_handler.HandleRotateKeystoreKeys()) | |
| 2107 self.send_response(result) | |
| 2108 self.send_header('Content-Type', 'text/html') | |
| 2109 self.send_header('Content-Length', len(raw_reply)) | |
| 2110 self.end_headers() | |
| 2111 self.wfile.write(raw_reply) | |
| 2112 return True | |
| 2113 | |
| 2114 | |
| 2115 class OCSPHandler(BasePageHandler): | |
| 2116 def __init__(self, request, client_address, socket_server): | 1627 def __init__(self, request, client_address, socket_server): |
| 2117 handlers = [self.OCSPResponse] | 1628 handlers = [self.OCSPResponse] |
| 2118 self.ocsp_response = socket_server.ocsp_response | 1629 self.ocsp_response = socket_server.ocsp_response |
| 2119 BasePageHandler.__init__(self, request, client_address, socket_server, | 1630 testserver_base.BasePageHandler.__init__(self, request, client_address, |
| 2120 [], handlers, [], handlers, []) | 1631 socket_server, [], handlers, [], |
| 1632 handlers, []) |
| 2121 | 1633 |
| 2122 def OCSPResponse(self): | 1634 def OCSPResponse(self): |
| 2123 self.send_response(200) | 1635 self.send_response(200) |
| 2124 self.send_header('Content-Type', 'application/ocsp-response') | 1636 self.send_header('Content-Type', 'application/ocsp-response') |
| 2125 self.send_header('Content-Length', str(len(self.ocsp_response))) | 1637 self.send_header('Content-Length', str(len(self.ocsp_response))) |
| 2126 self.end_headers() | 1638 self.end_headers() |
| 2127 | 1639 |
| 2128 self.wfile.write(self.ocsp_response) | 1640 self.wfile.write(self.ocsp_response) |
| 2129 | 1641 |
| 2130 | 1642 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2389 raise testserver_base.OptionError( | 1901 raise testserver_base.OptionError( |
| 2390 'one trusted client CA file should be specified') | 1902 'one trusted client CA file should be specified') |
| 2391 if not os.path.isfile(self.options.ssl_client_ca[0]): | 1903 if not os.path.isfile(self.options.ssl_client_ca[0]): |
| 2392 raise testserver_base.OptionError( | 1904 raise testserver_base.OptionError( |
| 2393 'specified trusted client CA file not found: ' + | 1905 'specified trusted client CA file not found: ' + |
| 2394 self.options.ssl_client_ca[0] + ' exiting...') | 1906 self.options.ssl_client_ca[0] + ' exiting...') |
| 2395 websocket_options.tls_client_ca = self.options.ssl_client_ca[0] | 1907 websocket_options.tls_client_ca = self.options.ssl_client_ca[0] |
| 2396 server = WebSocketServer(websocket_options) | 1908 server = WebSocketServer(websocket_options) |
| 2397 print 'WebSocket server started on %s:%d...' % (host, server.server_port) | 1909 print 'WebSocket server started on %s:%d...' % (host, server.server_port) |
| 2398 server_data['port'] = server.server_port | 1910 server_data['port'] = server.server_port |
| 2399 elif self.options.server_type == SERVER_SYNC: | |
| 2400 xmpp_port = self.options.xmpp_port | |
| 2401 server = SyncHTTPServer((host, port), xmpp_port, SyncPageHandler) | |
| 2402 print 'Sync HTTP server started on port %d...' % server.server_port | |
| 2403 print 'Sync XMPP server started on port %d...' % server.xmpp_port | |
| 2404 server_data['port'] = server.server_port | |
| 2405 server_data['xmpp_port'] = server.xmpp_port | |
| 2406 elif self.options.server_type == SERVER_TCP_ECHO: | 1911 elif self.options.server_type == SERVER_TCP_ECHO: |
| 2407 # Used for generating the key (randomly) that encodes the "echo request" | 1912 # Used for generating the key (randomly) that encodes the "echo request" |
| 2408 # message. | 1913 # message. |
| 2409 random.seed() | 1914 random.seed() |
| 2410 server = TCPEchoServer((host, port), TCPEchoHandler) | 1915 server = TCPEchoServer((host, port), TCPEchoHandler) |
| 2411 print 'Echo TCP server started on port %d...' % server.server_port | 1916 print 'Echo TCP server started on port %d...' % server.server_port |
| 2412 server_data['port'] = server.server_port | 1917 server_data['port'] = server.server_port |
| 2413 elif self.options.server_type == SERVER_UDP_ECHO: | 1918 elif self.options.server_type == SERVER_UDP_ECHO: |
| 2414 # Used for generating the key (randomly) that encodes the "echo request" | 1919 # Used for generating the key (randomly) that encodes the "echo request" |
| 2415 # message. | 1920 # message. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2459 | 1964 |
| 2460 if self.__ocsp_server: | 1965 if self.__ocsp_server: |
| 2461 self.__ocsp_server.stop_serving() | 1966 self.__ocsp_server.stop_serving() |
| 2462 | 1967 |
| 2463 def add_options(self): | 1968 def add_options(self): |
| 2464 testserver_base.TestServerRunner.add_options(self) | 1969 testserver_base.TestServerRunner.add_options(self) |
| 2465 self.option_parser.add_option('-f', '--ftp', action='store_const', | 1970 self.option_parser.add_option('-f', '--ftp', action='store_const', |
| 2466 const=SERVER_FTP, default=SERVER_HTTP, | 1971 const=SERVER_FTP, default=SERVER_HTTP, |
| 2467 dest='server_type', | 1972 dest='server_type', |
| 2468 help='start up an FTP server.') | 1973 help='start up an FTP server.') |
| 2469 self.option_parser.add_option('--sync', action='store_const', | |
| 2470 const=SERVER_SYNC, default=SERVER_HTTP, | |
| 2471 dest='server_type', | |
| 2472 help='start up a sync server.') | |
| 2473 self.option_parser.add_option('--tcp-echo', action='store_const', | 1974 self.option_parser.add_option('--tcp-echo', action='store_const', |
| 2474 const=SERVER_TCP_ECHO, default=SERVER_HTTP, | 1975 const=SERVER_TCP_ECHO, default=SERVER_HTTP, |
| 2475 dest='server_type', | 1976 dest='server_type', |
| 2476 help='start up a tcp echo server.') | 1977 help='start up a tcp echo server.') |
| 2477 self.option_parser.add_option('--udp-echo', action='store_const', | 1978 self.option_parser.add_option('--udp-echo', action='store_const', |
| 2478 const=SERVER_UDP_ECHO, default=SERVER_HTTP, | 1979 const=SERVER_UDP_ECHO, default=SERVER_HTTP, |
| 2479 dest='server_type', | 1980 dest='server_type', |
| 2480 help='start up a udp echo server.') | 1981 help='start up a udp echo server.') |
| 2481 self.option_parser.add_option('--basic-auth-proxy', action='store_const', | 1982 self.option_parser.add_option('--basic-auth-proxy', action='store_const', |
| 2482 const=SERVER_BASIC_AUTH_PROXY, | 1983 const=SERVER_BASIC_AUTH_PROXY, |
| 2483 default=SERVER_HTTP, dest='server_type', | 1984 default=SERVER_HTTP, dest='server_type', |
| 2484 help='start up a proxy server which requires ' | 1985 help='start up a proxy server which requires ' |
| 2485 'basic authentication.') | 1986 'basic authentication.') |
| 2486 self.option_parser.add_option('--websocket', action='store_const', | 1987 self.option_parser.add_option('--websocket', action='store_const', |
| 2487 const=SERVER_WEBSOCKET, default=SERVER_HTTP, | 1988 const=SERVER_WEBSOCKET, default=SERVER_HTTP, |
| 2488 dest='server_type', | 1989 dest='server_type', |
| 2489 help='start up a WebSocket server.') | 1990 help='start up a WebSocket server.') |
| 2490 self.option_parser.add_option('--xmpp-port', default='0', type='int', | |
| 2491 help='Port used by the XMPP server. If ' | |
| 2492 'unspecified, the XMPP server will listen on ' | |
| 2493 'an ephemeral port.') | |
| 2494 self.option_parser.add_option('--data-dir', dest='data_dir', | |
| 2495 help='Directory from which to read the ' | |
| 2496 'files.') | |
| 2497 self.option_parser.add_option('--https', action='store_true', | 1991 self.option_parser.add_option('--https', action='store_true', |
| 2498 dest='https', help='Specify that https ' | 1992 dest='https', help='Specify that https ' |
| 2499 'should be used.') | 1993 'should be used.') |
| 2500 self.option_parser.add_option('--cert-and-key-file', | 1994 self.option_parser.add_option('--cert-and-key-file', |
| 2501 dest='cert_and_key_file', help='specify the ' | 1995 dest='cert_and_key_file', help='specify the ' |
| 2502 'path to the file containing the certificate ' | 1996 'path to the file containing the certificate ' |
| 2503 'and private key for the server in PEM ' | 1997 'and private key for the server in PEM ' |
| 2504 'format') | 1998 'format') |
| 2505 self.option_parser.add_option('--ocsp', dest='ocsp', default='ok', | 1999 self.option_parser.add_option('--ocsp', dest='ocsp', default='ok', |
| 2506 help='The type of OCSP response generated ' | 2000 help='The type of OCSP response generated ' |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2549 'load multipe keys into the server. If the ' | 2043 'load multipe keys into the server. If the ' |
| 2550 'server has multiple keys, it will rotate ' | 2044 'server has multiple keys, it will rotate ' |
| 2551 'through them in at each request a ' | 2045 'through them in at each request a ' |
| 2552 'round-robin fashion. The server will ' | 2046 'round-robin fashion. The server will ' |
| 2553 'generate a random key if none is specified ' | 2047 'generate a random key if none is specified ' |
| 2554 'on the command line.') | 2048 'on the command line.') |
| 2555 | 2049 |
| 2556 | 2050 |
| 2557 if __name__ == '__main__': | 2051 if __name__ == '__main__': |
| 2558 sys.exit(ServerRunner().main()) | 2052 sys.exit(ServerRunner().main()) |
| OLD | NEW |