testserver.py revision f2477e01787aa58f445919b809d89e252beef54f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)"""This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)testing Chrome. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)It supports several test URLs, as specified by the handlers in TestPageHandler. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)By default, it listens on an ephemeral port and sends the port number back to 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the originating process over a pipe. The originating process can specify an 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)explicit port if necessary. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)It can use https if you specify the flag --https=CERT where CERT is the path 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to a pem file containing the certificate and private key that should be used. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import base64 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import BaseHTTPServer 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cgi 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import hashlib 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import minica 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import json 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import random 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import select 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import socket 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import SocketServer 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import struct 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import threading 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urllib 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urlparse 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import zlib 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import echo_message 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyftpdlib.ftpserver 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import testserver_base 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tlslite 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tlslite.api 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)sys.path.insert( 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0, os.path.join(BASE_DIR, '..', '..', '..', 'third_party/pywebsocket/src')) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from mod_pywebsocket.standalone import WebSocketServer 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SERVER_HTTP = 0 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SERVER_FTP = 1 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_TCP_ECHO = 2 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_UDP_ECHO = 3 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_BASIC_AUTH_PROXY = 4 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_WEBSOCKET = 5 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Default request queue size for WebSocketServer. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_DEFAULT_REQUEST_QUEUE_SIZE = 128 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebSocketOptions: 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Holds options for WebSocketServer.""" 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, host, port, data_dir): 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_host = host 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.port = port 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.websock_handlers = data_dir 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.scan_dir = None 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.allow_handlers_outside_root_dir = False 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.websock_handlers_map_file = None 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.cgi_directories = [] 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.is_executable_method = None 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.allow_draft75 = False 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.strict = True 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.use_tls = False 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.private_key = None 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.certificate = None 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.tls_client_auth = False 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.tls_client_ca = None 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.use_basic_auth = False 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RecordingSSLSessionCache(object): 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lookups and inserts in order to test session cache behaviours.""" 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log = [] 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getitem__(self, sessionID): 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log.append(('lookup', sessionID)) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise KeyError() 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __setitem__(self, sessionID, session): 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log.append(('insert', sessionID)) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class HTTPServer(testserver_base.ClientRestrictingServerMixIn, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer): 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of StoppableHTTPServer that adds client 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verification.""" 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OCSPServer(testserver_base.ClientRestrictingServerMixIn, 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BaseHTTPServer.HTTPServer): 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of HTTPServer that serves an 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OCSP response""" 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever_on_thread(self): 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread = threading.Thread(target = self.serve_forever, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = "OCSPServerThread") 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread.start() 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def stop_serving(self): 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.shutdown() 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread.join() 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HTTPSServer(tlslite.api.TLSSocketServerMixIn, 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.ClientRestrictingServerMixIn, 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer): 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of StoppableHTTPServer that add https support and 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client verification.""" 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, server_address, request_hander_class, pem_cert_and_key, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) record_resume_info, tls_intolerant): 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # Force using only python implementation - otherwise behavior is different 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # depending on whether m2crypto Python module is present (error is thrown 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # when it is). m2crypto uses a C (based on OpenSSL) implementation under 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # the hood. 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private=True, 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch implementations=['python']) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_client_auth = ssl_client_auth 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_client_cas = [] 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.tls_intolerant = tls_intolerant 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ca_file in ssl_client_cas: 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = open(ca_file).read() 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x509 = tlslite.api.X509() 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x509.parse(s) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_client_cas.append(x509.subject) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_handshake_settings = tlslite.api.HandshakeSettings() 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ssl_bulk_ciphers is not None: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if record_resume_info: 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If record_resume_info is true then we'll replace the session cache with 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # an object that records the lookups and inserts that it sees. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.session_cache = RecordingSSLSessionCache() 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.session_cache = tlslite.api.SessionCache() 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer.__init__(self, 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server_address, 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_hander_class) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handshake(self, tlsConnection): 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Creates the SSL connection.""" 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.tlsConnection = tlsConnection 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tlsConnection.handshakeServer(certChain=self.cert_chain, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) privateKey=self.private_key, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sessionCache=self.session_cache, 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reqCert=self.ssl_client_auth, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) settings=self.ssl_handshake_settings, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reqCAs=self.ssl_client_cas, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tlsIntolerant=self.tls_intolerant) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tlsConnection.ignoreAbruptClose = True 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except tlslite.api.TLSAbruptCloseError: 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Ignore abrupt close. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except tlslite.api.TLSError, error: 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Handshake failure:", str(error) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FTPServer(testserver_base.ClientRestrictingServerMixIn, 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pyftpdlib.ftpserver.FTPServer): 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of FTPServer that adds client verification.""" 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TCPEchoServer(testserver_base.ClientRestrictingServerMixIn, 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketServer.TCPServer): 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A TCP echo server that echoes back what it has received.""" 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def server_bind(self): 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Override server_bind to store the server name.""" 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SocketServer.TCPServer.server_bind(self) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host, port = self.socket.getsockname()[:2] 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_name = socket.getfqdn(host) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_port = port 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever(self): 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stop = False 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.nonce_time = None 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while not self.stop: 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle_request() 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.socket.close() 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class UDPEchoServer(testserver_base.ClientRestrictingServerMixIn, 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketServer.UDPServer): 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A UDP echo server that echoes back what it has received.""" 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def server_bind(self): 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Override server_bind to store the server name.""" 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SocketServer.UDPServer.server_bind(self) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host, port = self.socket.getsockname()[:2] 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_name = socket.getfqdn(host) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_port = port 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever(self): 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stop = False 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.nonce_time = None 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while not self.stop: 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle_request() 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.socket.close() 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestPageHandler(testserver_base.BasePageHandler): 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Class variables to allow for persistence state between page handler 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # invocations 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limits = {} 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = {} 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, request, client_address, socket_server): 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connect_handlers = [ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.RedirectConnectHandler, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ServerAuthConnectHandler, 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultConnectResponseHandler] 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_handlers = [ 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoCacheMaxAgeTimeHandler, 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoCacheTimeHandler, 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheTimeHandler, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheExpiresHandler, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheProxyRevalidateHandler, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CachePrivateHandler, 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CachePublicHandler, 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheSMaxAgeHandler, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheMustRevalidateHandler, 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheMustRevalidateMaxAgeHandler, 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoStoreHandler, 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoStoreMaxAgeHandler, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoTransformHandler, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DownloadHandler, 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DownloadFinishHandler, 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHeader, 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHeaderCache, 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoAllHandler, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ZipFileHandler, 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.FileHandler, 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetCookieHandler, 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetManyCookiesHandler, 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ExpectAndSetCookieHandler, 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetHeaderHandler, 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.AuthBasicHandler, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.AuthDigestHandler, 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SlowServerHandler, 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ChunkedServerHandler, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ContentTypeHandler, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoContentHandler, 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ServerRedirectHandler, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ClientRedirectHandler, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.MultipartHandler, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.GetSSLSessionCacheHandler, 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.SSLManySmallRecords, 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.GetChannelID, 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CloseSocketHandler, 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.RangeResetHandler, 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultResponseHandler] 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) post_handlers = [ 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoTitleHandler, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHandler, 2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.PostOnlyFileHandler, 2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.EchoMultipartPostHandler] + get_handlers 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) put_handlers = [ 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoTitleHandler, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHandler] + get_handlers 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) head_handlers = [ 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.FileHandler, 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultResponseHandler] 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._mime_types = { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'crx' : 'application/x-chrome-extension', 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'exe' : 'application/octet-stream', 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'gif': 'image/gif', 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'jpeg' : 'image/jpeg', 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'jpg' : 'image/jpeg', 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'json': 'application/json', 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'pdf' : 'application/pdf', 303424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 'txt' : 'text/plain', 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'wav' : 'audio/wav', 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'xml' : 'text/xml' 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._default_mime_type = 'text/html' 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BasePageHandler.__init__(self, request, client_address, 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_server, connect_handlers, 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) get_handlers, head_handlers, 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) post_handlers, put_handlers) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetMIMETypeFromName(self, file_name): 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns the mime type for the specified file_name. So far it only looks 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) at the file extension.""" 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (_shortname, extension) = os.path.splitext(file_name.split("?")[0]) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(extension) == 0: 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # no extension. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._default_mime_type 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # extension starts with a dot, so we need to remove it 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._mime_types.get(extension[1:], self._default_mime_type) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoCacheMaxAgeTimeHandler(self): 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and no caching requested.""" 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocachetime/maxage"): 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoCacheTimeHandler(self): 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and no caching requested.""" 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocachetime"): 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-cache') 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheTimeHandler(self): 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for one minute.""" 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cachetime"): 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60') 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheExpiresHandler(self): 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and set the page to expire on 1 Jan 2099.""" 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/expires"): 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Expires', 'Thu, 1 Jan 2099 00:00:00 GMT') 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheProxyRevalidateHandler(self): 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 60 seconds""" 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/proxy-revalidate"): 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, proxy-revalidate') 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CachePrivateHandler(self): 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 5 seconds.""" 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/private"): 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=3, private') 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CachePublicHandler(self): 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 5 seconds.""" 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/public"): 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=3, public') 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheSMaxAgeHandler(self): 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow for caching.""" 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/s-maxage"): 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'public, s-maxage = 60, max-age = 0') 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheMustRevalidateHandler(self): 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow caching.""" 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/must-revalidate"): 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'must-revalidate') 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheMustRevalidateMaxAgeHandler(self): 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow caching event though max-age of 60 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) seconds is specified.""" 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/must-revalidate/max-age"): 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, must-revalidate') 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoStoreHandler(self): 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the page to be stored.""" 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-store"): 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-store') 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoStoreMaxAgeHandler(self): 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the page to be stored even though max-age 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of 60 seconds is specified.""" 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-store/max-age"): 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, no-store') 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoTransformHandler(self): 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the content to transformed during 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user-agent caching""" 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-transform"): 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-transform') 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeader(self): 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler echoes back the value of a specific request header.""" 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.EchoHeaderHelper("/echoheader") 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeaderCache(self): 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function echoes back the value of a specific request header while 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowing caching for 16 hours.""" 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.EchoHeaderHelper("/echoheadercache") 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeaderHelper(self, echo_header): 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function echoes back the value of the request header passed in.""" 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(echo_header): 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_name = self.path[query_char+1:] 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if echo_header == '/echoheadercache': 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'no-cache') 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # insert a vary header to properly indicate that the cachability of this 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # request is subject to value of the request header being echoed. 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_name) > 0: 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Vary', header_name) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_name) > 0: 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.headers.getheader(header_name)) 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ReadRequestBody(self): 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function reads the body of the current HTTP request, handling 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) both plain and chunked transfer encoded requests.""" 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.headers.getheader('transfer-encoding') != 'chunked': 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = int(self.headers.getheader('content-length')) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.rfile.read(length) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Read the request body as chunks. 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body = "" 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while True: 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = self.rfile.readline() 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = int(line, 16) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if length == 0: 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rfile.readline() 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body += self.rfile.read(length) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rfile.read(2) 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return body 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHandler(self): 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just echoes back the payload of the request, for testing 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) form submission.""" 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echo"): 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.ReadRequestBody()) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoTitleHandler(self): 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler is like Echo, but sets the page title to the request.""" 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echotitle"): 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request = self.ReadRequestBody() 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>') 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(request) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</title></head></html>') 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoAllHandler(self): 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler yields a (more) human-readable page listing information 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) about the request header & contents.""" 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echoall"): 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><style>' 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'pre { border: 1px solid black; margin: 5px; padding: 5px }' 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '</style></head><body>' 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<div style="float: right">' 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<a href="/echo">back to referring page</a></div>' 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<h1>Request Body:</h1><pre>') 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT': 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qs = self.ReadRequestBody() 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params = cgi.parse_qs(qs, keep_blank_values=1) 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for param in params: 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s=%s\n' % (param, params[param][0])) 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</pre>') 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<h1>Request Headers:</h1><pre>%s</pre>' % self.headers) 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) def EchoMultipartPostHandler(self): 6693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) """This handler echoes received multipart post data as json format.""" 6703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if not (self._ShouldHandleRequest("/echomultipartpost") or 6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self._ShouldHandleRequest("/searchbyimage")): 6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return False 6743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) content_type, parameters = cgi.parse_header( 6763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.headers.getheader('content-type')) 6773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if content_type == 'multipart/form-data': 6783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart = cgi.parse_multipart(self.rfile, parameters) 6793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) elif content_type == 'application/x-www-form-urlencoded': 6803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) raise Exception('POST by application/x-www-form-urlencoded is ' 6813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 'not implemented.') 6823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) else: 6833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart = {} 6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) # Since the data can be binary, we encode them by base64. 6863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart_base64_encoded = {} 6873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for field, values in post_multipart.items(): 6883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart_base64_encoded[field] = [base64.b64encode(value) 6893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for value in values] 6903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) result = {'POST_multipart' : post_multipart_base64_encoded} 6923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.send_response(200) 6943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.send_header("Content-type", "text/plain") 6953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.end_headers() 6963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.wfile.write(json.dumps(result, indent=2, sort_keys=False)) 6973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return True 6983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DownloadHandler(self): 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends a downloadable file with or without reporting 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the size (6K).""" 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.path.startswith("/download-unknown-size"): 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_length = False 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.path.startswith("/download-known-size"): 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_length = True 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The test which uses this functionality is attempting to send 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # small chunks of data to the client. Use a fairly large buffer 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # so that we'll fill chrome's IO buffer enough to force it to 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # actually write the data. 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # See also the comments in the client-side of this test in 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # download_uitest.cc 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_chunk1 = 35*1024 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_chunk2 = 10*1024 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/octet-stream') 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if send_length: 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', size_chunk1 + size_chunk2) 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # First chunk of data: 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("*" * size_chunk1) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.flush() 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # handle requests until one of them clears this flag. 7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.handle_request() 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Second chunk of data: 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("*" * size_chunk2) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DownloadFinishHandler(self): 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just tells the server to finish the current download.""" 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/download-finish"): 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = False 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _ReplaceFileData(self, data, query_parameters): 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Replaces matching substrings in a file. 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the 'replace_text' URL query parameter is present, it is expected to be 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of the form old_text:new_text, which indicates that any old_text strings in 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the file are replaced with new_text. Multiple 'replace_text' parameters may 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) be specified. 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the parameters are not present, |data| is returned. 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query_parameters) 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_values = query_dict.get('replace_text', []) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for replace_text_value in replace_text_values: 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_args = replace_text_value.split(':') 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(replace_text_args) != 2: 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise ValueError( 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'replace_text must be of form old_text:new_text. Actual value: %s' % 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_value) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_text_b64, new_text_b64 = replace_text_args 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_text = base64.urlsafe_b64decode(old_text_b64) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_text = base64.urlsafe_b64decode(new_text_b64) 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data.replace(old_text, new_text) 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ZipFileHandler(self): 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file in compressed form. 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Can pass in a parameter that specifies that the content length be 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) C - the compressed size (OK), 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) U - the uncompressed size (Non-standard, but handled), 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) S - less than compressed (OK because we keep going), 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) M - larger than compressed but less than uncompressed (an error), 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L - larger than uncompressed (an error) 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: compressedfiles/Picture_1.doc?C 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = "/compressedfiles/" 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Consume a request body if present. 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT' : 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ReadRequestBody() 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not query in ('C', 'U', 'S', 'M', 'L'): 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_path = url_path[len(prefix):] 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entries = sub_path.split('/') 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(self.server.data_dir, *entries) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isdir(file_path): 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(file_path, 'index.html') 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(file_path): 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "File not found " + sub_path + " full path:" + file_path 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(file_path, "rb") 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uncompressed_len = len(data) 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Compress the data. 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = zlib.compress(data) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compressed_len = len(data) 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query == 'U': 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = uncompressed_len 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'S': 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len / 2 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'M': 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = (compressed_len + uncompressed_len) / 2 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'L': 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len + uncompressed_len 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/msword') 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-encoding', 'deflate') 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', content_length) 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('ETag', '\'' + file_path + '\'') 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def FileHandler(self): 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file. Wow, it's like 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a real webserver!""" 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = self.server.file_root_url 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._FileHandlerHelper(prefix) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PostOnlyFileHandler(self): 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file on a POST.""" 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = urlparse.urljoin(self.server.file_root_url, 'post/') 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._FileHandlerHelper(prefix) 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _FileHandlerHelper(self, prefix): 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_body = '' 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT': 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Consume a request body if present. 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_body = self.ReadRequestBody() 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query) 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_body = query_dict.get('expected_body', []) 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_body and request_body not in expected_body: 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(404) 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('') 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_headers = query_dict.get('expected_headers', []) 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for expected_header in expected_headers: 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_name, expected_value = expected_header.split(':') 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.headers.getheader(header_name) != expected_value: 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(404) 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('') 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_path = url_path[len(prefix):] 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entries = sub_path.split('/') 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(self.server.data_dir, *entries) 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isdir(file_path): 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(file_path, 'index.html') 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(file_path): 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "File not found " + sub_path + " full path:" + file_path 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(file_path, "rb") 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self._ReplaceFileData(data, query) 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_protocol_version = self.protocol_version 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If file.mock-http-headers exists, it contains the headers we 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # should send. Read them in and parse them. 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_path = file_path + '.mock-http-headers' 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isfile(headers_path): 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(headers_path, "r") 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "HTTP/1.1 200 OK" 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = f.readline() 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_major, http_minor, status_code = re.findall( 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'HTTP/(\d+).(\d+) (\d+)', response)[0] 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = "HTTP/%s.%s" % (http_major, http_minor) 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(int(status_code)) 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in f: 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_values = re.findall('(\S+):\s*(.*)', line) 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_values) > 0: 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "name: value" 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name, value = header_values[0] 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header(name, value) 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Could be more generic once we support mime-type sniffing, but for 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # now we need to set it explicitly. 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range_header = self.headers.get('Range') 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if range_header and range_header.startswith('bytes='): 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Note this doesn't handle all valid byte range_header values (i.e. 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # left open ended ones), just enough for what we needed so far. 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range_header = range_header[6:].split('-') 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start = int(range_header[0]) 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if range_header[1]: 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end = int(range_header[1]) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end = len(data) - 1 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(206) 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_range = ('bytes ' + str(start) + '-' + str(end) + '/' + 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) str(len(data))) 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Range', content_range) 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[start: end + 1] 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', self.GetMIMETypeFromName(file_path)) 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Accept-Ranges', 'bytes') 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(data)) 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('ETag', '\'' + file_path + '\'') 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.command != 'HEAD'): 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetCookieHandler(self): 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just sets a cookie, for testing cookie handling.""" 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-cookie"): 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_values = self.path[query_char + 1:].split('&') 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_values = ("",) 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in cookie_values: 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', '%s' % cookie_value) 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in cookie_values: 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s' % cookie_value) 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetManyCookiesHandler(self): 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just sets a given number of cookies, for testing handling 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of large numbers of cookies.""" 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-many-cookies"): 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_cookies = int(self.path[query_char + 1:]) 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_cookies = 0 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('', 'text/html') 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for _i in range(0, num_cookies): 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', 'a=') 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%d cookies were sent' % num_cookies) 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ExpectAndSetCookieHandler(self): 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Expects some cookies to be sent, and if they are, sets more cookies. 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The expect parameter specifies a required cookie. May be specified multiple 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) times. 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The set parameter specifies a cookie to set if all required cookies are 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preset. May be specified multiple times. 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The data parameter specifies the response body data to be returned.""" 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/expect-and-set-cookie"): 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, _, _, query, _ = urlparse.urlparse(self.path) 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query) 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookies = set() 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'Cookie' in self.headers: 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_header = self.headers.getheader('Cookie') 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookies.update([s.strip() for s in cookie_header.split(';')]) 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_all_expected_cookies = True 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for expected_cookie in query_dict.get('expect', []): 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_cookie not in cookies: 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_all_expected_cookies = False 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if got_all_expected_cookies: 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in query_dict.get('set', []): 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', '%s' % cookie_value) 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for data_value in query_dict.get('data', []): 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data_value) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetHeaderHandler(self): 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sets a response header. Parameters are in the 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key%3A%20value&key2%3A%20value2 format.""" 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-header"): 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_values = self.path[query_char + 1:].split('&') 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_values = ("",) 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header_value in headers_values: 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_value = urllib.unquote(header_value) 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (key, value) = header_value.split(': ', 1) 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header(key, value) 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header_value in headers_values: 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s' % header_value) 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AuthBasicHandler(self): 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler tests 'Basic' authentication. It just sends a page with 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title 'user/pass' if you succeed.""" 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/auth-basic"): 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username = userpass = password = b64str = "" 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_password = 'secret' 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = 'testrealm' 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cookie_if_challenged = False 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_params = cgi.parse_qs(query, True) 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'set-cookie-if-challenged' in query_params: 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cookie_if_challenged = True 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'password' in query_params: 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_password = query_params['password'][0] 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'realm' in query_params: 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = query_params['realm'][0] 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('authorization') 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth: 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('no auth') 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b64str = re.findall(r'Basic (\S+)', auth)[0] 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) userpass = base64.b64decode(b64str) 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username, password = re.findall(r'([^:]+):(\S+)', userpass)[0] 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if password != expected_password: 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong password') 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication failed. 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', 'Basic realm="%s"' % realm) 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if set_cookie_if_challenged: 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', 'got_challenged=true') 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>Denied: %s</title>' % e) 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('b64str=%s<p>' % b64str) 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('username: %s<p>' % username) 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('userpass: %s<p>' % userpass) 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('password: %s<p>' % password) 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication successful. (Return a cachable response to allow for 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # testing cached pages that require authentication.) 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_protocol_version = self.protocol_version 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = "HTTP/1.1" 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if_none_match = self.headers.getheader('if-none-match') 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if if_none_match == "abc": 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(304) 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif url_path.endswith(".gif"): 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Using chrome/test/data/google/logo.gif as the test image 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_image_path = ['google', 'logo.gif'] 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gif_path = os.path.join(self.server.data_dir, *test_image_path) 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(gif_path): 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(gif_path, "rb") 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'image/gif') 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Etag', 'abc') 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Etag', 'abc') 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>%s/%s</title>' % (username, password)) 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetNonce(self, force_reset=False): 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a nonce that's stable per request path for the server's lifetime. 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is a fake implementation. A real implementation would only use a given 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nonce a single time (hence the name n-once). However, for the purposes of 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unittesting, we don't care about the security of the nonce. 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) force_reset: Iff set, the nonce will be changed. Useful for testing the 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "stale" response. 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if force_reset or not self.server.nonce_time: 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.nonce_time = time.time() 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return hashlib.md5('privatekey%s%d' % 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (self.path, self.server.nonce_time)).hexdigest() 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AuthDigestHandler(self): 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler tests 'Digest' authentication. 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It just sends a page with title 'user/pass' if you succeed. 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A stale response is sent iff "stale" is present in the request path. 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/auth-digest"): 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stale = 'stale' in self.path 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nonce = self.GetNonce(force_reset=stale) 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opaque = hashlib.md5('opaque').hexdigest() 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) password = 'secret' 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = 'testrealm' 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('authorization') 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs = {} 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth: 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('no auth') 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth.startswith('Digest'): 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('not digest') 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Pull out all the name="value" pairs as a dictionary. 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Make sure it's all valid. 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['nonce'] != nonce: 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong nonce') 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['opaque'] != opaque: 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong opaque') 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check the 'response' value and make sure it matches our magic hash. 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # See http://www.ietf.org/rfc/rfc2617.txt 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hash_a1 = hashlib.md5( 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ':'.join([pairs['username'], realm, password])).hexdigest() 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hash_a2 = hashlib.md5(':'.join([self.command, pairs['uri']])).hexdigest() 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = hashlib.md5(':'.join([hash_a1, nonce, pairs['nc'], 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = hashlib.md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['response'] != response: 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong password') 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication failed. 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr = ('Digest ' 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'realm="%s", ' 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'domain="/", ' 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'qop="auth", ' 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithm=MD5, ' 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'nonce="%s", ' 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'opaque="%s"') % (realm, nonce, opaque) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if stale: 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr += ', stale="TRUE"' 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', hdr) 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>Denied: %s</title>' % e) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('pairs=%s<p>' % pairs) 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('We are replying:<br>%s<p>' % hdr) 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication successful. 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>%s/%s</title>' % (pairs['username'], password)) 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('pairs=%s<p>' % pairs) 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SlowServerHandler(self): 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Wait for the user suggested time before responding. The syntax is 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /slow?0.5 to wait for half a second.""" 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/slow"): 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_sec = 1.0 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char >= 0: 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_sec = int(self.path[query_char + 1:]) 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(wait_sec) 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("waited %d seconds" % wait_sec) 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ChunkedServerHandler(self): 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send chunked response. Allows to specify chunks parameters: 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - waitBeforeHeaders - ms to wait before sending headers 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - waitBetweenChunks - ms to wait between chunks 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - chunkSize - size of each chunk in bytes 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - chunksNumber - number of chunks 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: /chunked?waitBeforeHeaders=1000&chunkSize=5&chunksNumber=5 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waits one second, then sends headers and five chunks five bytes each.""" 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/chunked"): 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunkedSettings = {'waitBeforeHeaders' : 0, 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'waitBetweenChunks' : 0, 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'chunkSize' : 5, 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'chunksNumber' : 5} 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char >= 0: 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params = self.path[query_char + 1:].split('&') 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for param in params: 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyValue = param.split('=') 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(keyValue) == 2: 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunkedSettings[keyValue[0]] = int(keyValue[1]) 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(0.001 * chunkedSettings['waitBeforeHeaders']) 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = 'HTTP/1.1' # Needed for chunked encoding 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Transfer-Encoding', 'chunked') 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Chunked encoding: sending all chunks, then final zero-length chunk and 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # then final CRLF. 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for i in range(0, chunkedSettings['chunksNumber']): 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if i > 0: 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(0.001 * chunkedSettings['waitBetweenChunks']) 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendChunkHelp('*' * chunkedSettings['chunkSize']) 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.flush() # Keep in mind that we start flushing only after 1kb. 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendChunkHelp('') 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ContentTypeHandler(self): 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a string of html with the given content type. E.g., 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /contenttype?text/css returns an html file with the Content-Type 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header set to text/css.""" 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/contenttype"): 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type = self.path[query_char + 1:].strip() 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not content_type: 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type = 'text/html' 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', content_type) 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("<html>\n<body>\n<p>HTML text</p>\n</body>\n</html>\n") 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoContentHandler(self): 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a 204 No Content response.""" 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocontent"): 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(204) 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ServerRedirectHandler(self): 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a server redirect to the given URL. The syntax is 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '/server-redirect?http://foo.bar/asdf' to redirect to 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'http://foo.bar/asdf'""" 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_name = "/server-redirect" 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(test_name): 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char < 0 or len(self.path) <= query_char + 1: 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendRedirectHelp(test_name) 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1351d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) dest = urllib.unquote(self.path[query_char + 1:]) 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(301) # moved permanently 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Location', dest) 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>Redirecting to %s</body></html>' % dest) 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ClientRedirectHandler(self): 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a client redirect to the given URL. The syntax is 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '/client-redirect?http://foo.bar/asdf' to redirect to 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'http://foo.bar/asdf'""" 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_name = "/client-redirect" 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(test_name): 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char < 0 or len(self.path) <= query_char + 1: 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendRedirectHelp(test_name) 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1375d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) dest = urllib.unquote(self.path[query_char + 1:]) 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<meta http-equiv="refresh" content="0;url=%s">' % dest) 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>Redirecting to %s</body></html>' % dest) 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def MultipartHandler(self): 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send a multipart response (10 text/html pages).""" 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_name = '/multipart' 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(test_name): 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_frames = 10 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bound = '12345' 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'multipart/x-mixed-replace;boundary=' + bound) 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for i in xrange(num_frames): 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('--' + bound + '\r\n') 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('Content-Type: text/html\r\n\r\n') 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>page ' + str(i) + '</title>') 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('page ' + str(i)) 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('--' + bound + '--') 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetSSLSessionCacheHandler(self): 14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send a reply containing a log of the session cache operations.""" 14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest('/ssl-session-cache'): 14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (action, sessionID) in self.server.session_cache.log: 14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s\t%s\n' % (action, sessionID.encode('hex'))) 14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except AttributeError: 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('Pass --https-record-resume in order to use' + 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' this request') 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def SSLManySmallRecords(self): 14272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Sends a reply consisting of a variety of small writes. These will be 14282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) translated into a series of small SSL records when used over an HTTPS 14292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server.""" 14302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/ssl-many-small-records'): 14322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 14332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 14352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 14372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Write ~26K of data, in 1350 byte chunks 14392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for i in xrange(20): 14402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write('*' * 1350) 14412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 14422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 14432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def GetChannelID(self): 14452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Send a reply containing the hashed ChannelID that the client provided.""" 14462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/channel-id'): 14482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 14492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 14512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 14532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) channel_id = self.server.tlsConnection.channel_id.tostring() 14542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) 14552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 14562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CloseSocketHandler(self): 14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Closes the socket without sending anything.""" 14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest('/close-socket'): 14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.close() 14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def RangeResetHandler(self): 14672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Send data broken up by connection resets every N (default 4K) bytes. 14682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Support range requests. If the data requested doesn't straddle a reset 14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boundary, it will all be sent. Used for testing resuming downloads.""" 14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def DataForRange(start, end): 14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Data to be provided for a particular range of bytes.""" 14732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Offset and scale to avoid too obvious (and hence potentially 14742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # collidable) data. 14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ''.join([chr(y % 256) 14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for y in range(start * 2 + 15, end * 2 + 15, 2)]) 14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/rangereset'): 14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 14802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) # HTTP/1.1 is required for ETag and range support. 1482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.protocol_version = 'HTTP/1.1' 14832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 14842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Defaults 14862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size = 8000 14872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Note that the rst is sent just before sending the rst_boundary byte. 14882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_boundary = 4000 14892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) respond_to_range = True 14902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hold_for_signal = False 14912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = -1 14922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token = 'DEFAULT' 14932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = 0 14942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) send_verifiers = True 14952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Parse the query 14972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) qdict = urlparse.parse_qs(query, True) 14982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'size' in qdict: 14992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size = int(qdict['size'][0]) 15002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'rst_boundary' in qdict: 15012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_boundary = int(qdict['rst_boundary'][0]) 15022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'token' in qdict: 15032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Identifying token for stateful tests. 15042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token = qdict['token'][0] 15052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'rst_limit' in qdict: 15062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Max number of rsts for a given token. 15072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = int(qdict['rst_limit'][0]) 15082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'bounce_range' in qdict: 15092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) respond_to_range = False 15102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'hold' in qdict: 15112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Note that hold_for_signal will not work with null range requests; 15122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # see TODO below. 15132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hold_for_signal = True 15142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'no_verifiers' in qdict: 15152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) send_verifiers = False 15162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'fail_precondition' in qdict: 15172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = int(qdict['fail_precondition'][0]) 15182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Record already set information, or set it. 15202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = TestPageHandler.rst_limits.setdefault(token, rst_limit) 15212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if rst_limit != 0: 15222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestPageHandler.rst_limits[token] -= 1 15232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = TestPageHandler.fail_precondition.setdefault( 15242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token, fail_precondition) 15252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if fail_precondition != 0: 15262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestPageHandler.fail_precondition[token] -= 1 15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = 0 15292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = size - 1 15302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Does that define what we want to return, or do we need to apply 15322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # a range? 15332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_response = False 15342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_header = self.headers.getheader('range') 15352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if range_header and respond_to_range: 15362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mo = re.match("bytes=(\d*)-(\d*)", range_header) 15372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if mo.group(1): 15382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = int(mo.group(1)) 15392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if mo.group(2): 15402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = int(mo.group(2)) 15412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if last_byte > size - 1: 15422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = size - 1 15432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_response = True 15442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if last_byte < first_byte: 15452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 15462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (fail_precondition and 15482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (self.headers.getheader('If-Modified-Since') or 15492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.headers.getheader('If-Match'))): 15502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(412) 15512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 15522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 15532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if range_response: 15552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(206) 15562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Range', 15572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'bytes %d-%d/%d' % (first_byte, last_byte, size)) 15582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 15592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 15602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'application/octet-stream') 15612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Length', last_byte - first_byte + 1) 15622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if send_verifiers: 15632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Etag', '"XYZZY"') 15642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Last-Modified', 'Tue, 19 Feb 2013 14:32 EST') 15652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 15662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if hold_for_signal: 15682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # TODO(rdsmith/phajdan.jr): http://crbug.com/169519: Without writing 15692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # a single byte, the self.server.handle_request() below hangs 15702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # without processing new incoming requests. 15712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(DataForRange(first_byte, first_byte + 1)) 15722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = first_byte + 1 15732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # handle requests until one of them clears this flag. 15742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 15752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 15762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.handle_request() 15772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary 15792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if possible_rst >= last_byte or rst_limit == 0: 15802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # No RST has been requested in this range, so we don't need to 15812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # do anything fancy; just write the data and let the python 15822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # infrastructure close the connection. 15832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(DataForRange(first_byte, last_byte + 1)) 15842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 15852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 15862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # We're resetting the connection part way in; go to the RST 15882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # boundary and then send an RST. 15892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Because socket semantics do not guarantee that all the data will be 15902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # sent when using the linger semantics to hard close a socket, 15912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # we send the data and then wait for our peer to release us 15922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # before sending the reset. 15932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data = DataForRange(first_byte, possible_rst) 15942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(data) 15952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 15962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 15972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 15982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.handle_request() 15992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) l_onoff = 1 # Linger is active. 16002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) l_linger = 0 # Seconds to linger for. 16012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct.pack('ii', l_onoff, l_linger)) 16032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Close all duplicates of the underlying socket to force the RST. 16052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.close() 16062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.rfile.close() 16072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.connection.close() 16082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 16102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DefaultResponseHandler(self): 16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is the catch-all response handler for requests that aren't handled 16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) by one of the special handlers above. 16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Note that we specify the content-length as without it the https connection 16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is not closed properly (and the browser keeps expecting data).""" 16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = "Default response given for path: " + self.path 16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(contents)) 16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.command != 'HEAD'): 16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(contents) 16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def RedirectConnectHandler(self): 16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a redirect to the CONNECT request for www.redirect.com. This 16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response is not specified by the RFC, so the browser should not follow 16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the redirect.""" 16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.path.find("www.redirect.com") < 0): 16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest = "http://www.destination.com/foo.js" 16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(302) # moved temporarily 16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Location', dest) 16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ServerAuthConnectHandler(self): 16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a 401 to the CONNECT request for www.server-auth.com. This 16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response doesn't make sense because the proxy server cannot request 16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server authentication.""" 16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.path.find("www.server-auth.com") < 0): 16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) challenge = 'Basic realm="WallyWorld"' 16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) # unauthorized 16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', challenge) 16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DefaultConnectResponseHandler(self): 16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is the catch-all response handler for CONNECT requests that aren't 16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled by one of the special handlers above. Real Web servers respond 16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) with 400 to CONNECT requests.""" 16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = "Your client has issued a malformed or illegal request." 16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) # bad request 16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(contents)) 16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(contents) 16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called by the redirect handling function when there is no parameter 16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def sendRedirectHelp(self, redirect_name): 16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><body><h1>Error: no redirect destination</h1>') 16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('Use <pre>%s?http://dest...</pre>' % redirect_name) 16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called by chunked handling function 16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def sendChunkHelp(self, chunk): 16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF 16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%X\r\n' % len(chunk)) 16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(chunk) 16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('\r\n') 16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OCSPHandler(testserver_base.BasePageHandler): 16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, request, client_address, socket_server): 16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handlers = [self.OCSPResponse] 16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ocsp_response = socket_server.ocsp_response 16922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BasePageHandler.__init__(self, request, client_address, 16932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_server, [], handlers, [], 16942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handlers, []) 16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def OCSPResponse(self): 16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/ocsp-response') 16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', str(len(self.ocsp_response))) 17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.ocsp_response) 17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TCPEchoHandler(SocketServer.BaseRequestHandler): 17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """The RequestHandler class for TCP echo server. 17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It is instantiated once per connection to the server, and overrides the 17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle() method to implement communication to the client. 17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handle(self): 17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Handles the request from the client and constructs a response.""" 17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self.request.recv(65536).strip() 17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the "echo request" message received from the client. Send back 17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "echo response" message if "echo request" message is valid. 17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_data = echo_message.GetEchoResponseData(data) 17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not return_data: 17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request.send(return_data) 17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UDPEchoHandler(SocketServer.BaseRequestHandler): 17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """The RequestHandler class for UDP echo server. 17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It is instantiated once per connection to the server, and overrides the 17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle() method to implement communication to the client. 17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handle(self): 17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Handles the request from the client and constructs a response.""" 17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self.request[0].strip() 17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_socket = self.request[1] 17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the "echo request" message received from the client. Send back 17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "echo response" message if "echo request" message is valid. 17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_data = echo_message.GetEchoResponseData(data) 17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not return_data: 17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_socket.sendto(return_data, self.client_address) 17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A request handler that behaves as a proxy server which requires 17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) basic authentication. Only CONNECT, GET and HEAD is supported for now. 17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar 17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def parse_request(self): 17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Overrides parse_request to check credential.""" 17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self): 17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('Proxy-Authorization') 17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if auth != self._AUTH_CREDENTIAL: 17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(407) 17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Proxy-Authenticate', 'Basic realm="MyRealm1"') 17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _start_read_write(self, sock): 17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.setblocking(0) 17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request.setblocking(0) 17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rlist = [self.request, sock] 17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while True: 17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ready_sockets, _unused, errors = select.select(rlist, [], []) 17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if errors: 17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for s in ready_sockets: 17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) received = s.recv(1024) 17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(received) == 0: 17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if s == self.request: 17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other = sock 17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other = self.request 17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other.send(received) 17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _do_common_method(self): 17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = urlparse.urlparse(self.path) 17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = url.port 17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not port: 17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if url.scheme == 'http': 17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = 80 17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif url.scheme == 'https': 18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = 443 18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not url.hostname or not port: 18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) 18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(url.path) == 0: 18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = '/' 18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = url.path 18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(url.query) > 0: 18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = '%s?%s' % (url.path, url.query) 18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = None 18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = socket.create_connection((url.hostname, port)) 18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('%s %s %s\r\n' % ( 18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.command, path, self.protocol_version)) 18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header in self.headers.headers: 18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header = header.strip() 18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header.lower().startswith('connection') or 18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header.lower().startswith('proxy')): 18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('%s\r\n' % header) 18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('\r\n') 18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._start_read_write(sock) 18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if sock is not None: 18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.close() 18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_CONNECT(self): 18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos = self.path.rfind(':') 18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host = self.path[:pos] 18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = int(self.path[pos+1:]) 18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) 18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = socket.create_connection((host, port)) 18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200, 'Connection established') 18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._start_read_write(sock) 18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.close() 18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_GET(self): 18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._do_common_method() 18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_HEAD(self): 18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._do_common_method() 18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServerRunner(testserver_base.TestServerRunner): 18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """TestServerRunner for the net test servers.""" 18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super(ServerRunner, self).__init__() 18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server = None 18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __make_data_dir(self): 18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.data_dir: 18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isdir(self.options.data_dir): 18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('specified data dir not found: ' + 18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.data_dir + ' exiting...') 18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = self.options.data_dir 18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create the default path to our data dir, relative to the exe dir. 18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = os.path.join(BASE_DIR, "..", "..", "..", "..", 18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "test", "data") 18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #TODO(ibrar): Must use Find* funtion defined in google\tools 18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #i.e my_data_dir = FindUpward(my_data_dir, "test", "data") 18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return my_data_dir 18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def create_server(self, server_data): 18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = self.options.port 18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host = self.options.host 18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.server_type == SERVER_HTTP: 18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.https: 18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pem_cert_and_key = None 18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.cert_and_key_file: 18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(self.options.cert_and_key_file): 18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified server cert file not found: ' + 18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.cert_and_key_file + ' exiting...') 18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pem_cert_and_key = file(self.options.cert_and_key_file, 'r').read() 18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # generate a new certificate and run an OCSP server for it. 18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server = OCSPServer((host, 0), OCSPHandler) 18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print ('OCSP server started on %s:%d...' % 19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (host, self.__ocsp_server.server_port)) 19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_der = None 19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = None 19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.ocsp == 'ok': 19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_GOOD 19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'revoked': 19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_REVOKED 19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'invalid': 19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_INVALID 19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'unauthorized': 19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_UNAUTHORIZED 19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'unknown': 19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_UNKNOWN 19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('unknown OCSP status: ' + 19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ocsp_status) 19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (pem_cert_and_key, ocsp_der) = minica.GenerateCertKeyAndOCSP( 19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subject = "127.0.0.1", 19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_url = ("http://%s:%d/ocsp" % 19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (host, self.__ocsp_server.server_port)), 1923a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ocsp_state = ocsp_state, 1924a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) serial = self.options.cert_serial) 19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.ocsp_response = ocsp_der 19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ca_cert in self.options.ssl_client_ca: 19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(ca_cert): 19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified trusted client CA file not found: ' + ca_cert + 19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' exiting...') 19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key, 19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_auth, 19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_ca, 19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_bulk_cipher, 19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.record_resume, 19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.tls_intolerant) 19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'HTTPS server started on %s:%d...' % (host, server.server_port) 19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPServer((host, port), TestPageHandler) 19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'HTTP server started on %s:%d...' % (host, server.server_port) 19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server.data_dir = self.__make_data_dir() 19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server.file_root_url = self.options.file_root_url 19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_WEBSOCKET: 19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Launch pywebsocket via WebSocketServer. 19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logger = logging.getLogger() 19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logger.addHandler(logging.StreamHandler()) 19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO(toyoshim): Remove following os.chdir. Currently this operation 19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is required to work correctly. It should be fixed from pywebsocket side. 19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.chdir(self.__make_data_dir()) 19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options = WebSocketOptions(host, port, '.') 19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.cert_and_key_file: 19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.use_tls = True 19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.private_key = self.options.cert_and_key_file 19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.certificate = self.options.cert_and_key_file 19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.ssl_client_auth: 19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.tls_client_auth = True 19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(self.options.ssl_client_ca) != 1: 19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'one trusted client CA file should be specified') 19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(self.options.ssl_client_ca[0]): 19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified trusted client CA file not found: ' + 19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_ca[0] + ' exiting...') 19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.tls_client_ca = self.options.ssl_client_ca[0] 19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = WebSocketServer(websocket_options) 19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'WebSocket server started on %s:%d...' % (host, server.server_port) 19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_TCP_ECHO: 19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Used for generating the key (randomly) that encodes the "echo request" 19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # message. 19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) random.seed() 19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = TCPEchoServer((host, port), TCPEchoHandler) 19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Echo TCP server started on port %d...' % server.server_port 19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_UDP_ECHO: 19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Used for generating the key (randomly) that encodes the "echo request" 19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # message. 19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) random.seed() 19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = UDPEchoServer((host, port), UDPEchoHandler) 19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Echo UDP server started on port %d...' % server.server_port 19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_BASIC_AUTH_PROXY: 19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPServer((host, port), BasicAuthProxyRequestHandler) 19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'BasicAuthProxy server started on port %d...' % server.server_port 19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_FTP: 19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = self.__make_data_dir() 19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate a dummy authorizer for managing 'virtual' users 19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer = pyftpdlib.ftpserver.DummyAuthorizer() 19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Define a new user having full r/w permissions and a read-only 19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # anonymous user 19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') 19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer.add_anonymous(my_data_dir) 20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate FTP handler class 20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler = pyftpdlib.ftpserver.FTPHandler 20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler.authorizer = authorizer 20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Define a customized banner (string returned when client connects) 20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % 20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pyftpdlib.ftpserver.__ver__) 20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate FTP server class and listen to address:port 20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = pyftpdlib.ftpserver.FTPServer((host, port), ftp_handler) 20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.socket.getsockname()[1] 20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'FTP server started on port %d...' % server_data['port'] 20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('unknown server type' + 20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.server_type) 20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return server 20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def run_server(self): 20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__ocsp_server: 20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.serve_forever_on_thread() 20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) testserver_base.TestServerRunner.run_server(self) 20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__ocsp_server: 20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.stop_serving() 20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def add_options(self): 20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) testserver_base.TestServerRunner.add_options(self) 20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('-f', '--ftp', action='store_const', 20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_FTP, default=SERVER_HTTP, 20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up an FTP server.') 20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--tcp-echo', action='store_const', 20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_TCP_ECHO, default=SERVER_HTTP, 20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a tcp echo server.') 20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--udp-echo', action='store_const', 20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_UDP_ECHO, default=SERVER_HTTP, 20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a udp echo server.') 20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--basic-auth-proxy', action='store_const', 20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_BASIC_AUTH_PROXY, 20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=SERVER_HTTP, dest='server_type', 20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a proxy server which requires ' 20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'basic authentication.') 20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--websocket', action='store_const', 20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_WEBSOCKET, default=SERVER_HTTP, 20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a WebSocket server.') 20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--https', action='store_true', 20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='https', help='Specify that https ' 20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'should be used.') 20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--cert-and-key-file', 20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='cert_and_key_file', help='specify the ' 20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'path to the file containing the certificate ' 20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'and private key for the server in PEM ' 20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'format') 20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ocsp', dest='ocsp', default='ok', 20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='The type of OCSP response generated ' 20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'for the automatically generated ' 20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate. One of [ok,revoked,invalid]') 2064a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self.option_parser.add_option('--cert-serial', dest='cert_serial', 2065a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default=0, type=int, 2066a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) help='If non-zero then the generated ' 2067a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 'certificate will have this serial number') 20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--tls-intolerant', dest='tls_intolerant', 20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default='0', type='int', 20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='If nonzero, certain TLS connections ' 20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'will be aborted in order to test version ' 20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'fallback. 1 means all TLS versions will be ' 20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted. 2 means TLS 1.1 or higher will be ' 20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted. 3 means TLS 1.2 or higher will be ' 20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted.') 20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--https-record-resume', 20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='record_resume', const=True, 20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=False, action='store_const', 20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Record resumption cache events rather ' 20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'than resuming as normal. Allows the use of ' 20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'the /ssl-session-cache request') 20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-client-auth', action='store_true', 20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Require SSL client auth on every ' 20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'connection.') 20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-client-ca', action='append', 20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=[], help='Specify that the client ' 20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate request should include the CA ' 20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'named in the subject of the DER-encoded ' 20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate contained in the specified ' 20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'file. This option may appear multiple ' 20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'times, indicating multiple CA names should ' 20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'be sent in the request.') 20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-bulk-cipher', action='append', 20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Specify the bulk encryption ' 20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithm(s) that will be accepted by the ' 20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SSL server. Valid values are "aes256", ' 20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '"aes128", "3des", "rc4". If omitted, all ' 20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithms will be used. This option may ' 20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'appear multiple times, indicating ' 21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'multiple algorithms should be enabled.'); 21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--file-root-url', default='/files/', 21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Specify a root URL for files served.') 21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(ServerRunner().main()) 2107