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 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport ssl 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import struct 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import threading 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urllib 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urlparse 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import zlib 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(BASE_DIR))) 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 42a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch# Temporary hack to deal with tlslite 0.3.8 -> 0.4.6 upgrade. 43a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch# 44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch# TODO(davidben): Remove this when it has cycled through all the bots and 45a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch# developer checkouts or when http://crbug.com/356276 is resolved. 46a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochtry: 47a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch os.remove(os.path.join(ROOT_DIR, 'third_party', 'tlslite', 48a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'tlslite', 'utils', 'hmac.pyc')) 49a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochexcept Exception: 50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch pass 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# Append at the end of sys.path, it's fine to use the system library. 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'pyftpdlib', 'src')) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch# Insert at the beginning of the path, we want to use our copies of the library 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# unconditionally. 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'pywebsocket', 'src')) 58a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochsys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'tlslite')) 59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport mod_pywebsocket.standalone 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from mod_pywebsocket.standalone import WebSocketServer 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch# import manually 63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochmod_pywebsocket.standalone.ssl = ssl 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport pyftpdlib.ftpserver 66a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 67a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport tlslite 68a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport tlslite.api 69a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 70a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport echo_message 71a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochimport testserver_base 72a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SERVER_HTTP = 0 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SERVER_FTP = 1 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_TCP_ECHO = 2 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_UDP_ECHO = 3 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_BASIC_AUTH_PROXY = 4 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SERVER_WEBSOCKET = 5 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Default request queue size for WebSocketServer. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_DEFAULT_REQUEST_QUEUE_SIZE = 128 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebSocketOptions: 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Holds options for WebSocketServer.""" 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, host, port, data_dir): 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request_queue_size = _DEFAULT_REQUEST_QUEUE_SIZE 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_host = host 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.port = port 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.websock_handlers = data_dir 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.scan_dir = None 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.allow_handlers_outside_root_dir = False 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.websock_handlers_map_file = None 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.cgi_directories = [] 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.is_executable_method = None 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.allow_draft75 = False 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.strict = True 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.use_tls = False 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.private_key = None 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.certificate = None 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.tls_client_auth = False 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.tls_client_ca = None 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch self.tls_module = 'ssl' 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.use_basic_auth = False 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.basic_auth_credential = 'Basic ' + base64.b64encode('test:test') 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RecordingSSLSessionCache(object): 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lookups and inserts in order to test session cache behaviours.""" 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log = [] 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getitem__(self, sessionID): 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log.append(('lookup', sessionID)) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise KeyError() 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __setitem__(self, sessionID, session): 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.log.append(('insert', sessionID)) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class HTTPServer(testserver_base.ClientRestrictingServerMixIn, 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer): 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of StoppableHTTPServer that adds client 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verification.""" 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OCSPServer(testserver_base.ClientRestrictingServerMixIn, 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BaseHTTPServer.HTTPServer): 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of HTTPServer that serves an 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OCSP response""" 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever_on_thread(self): 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread = threading.Thread(target = self.serve_forever, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = "OCSPServerThread") 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread.start() 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def stop_serving(self): 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.shutdown() 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.thread.join() 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HTTPSServer(tlslite.api.TLSSocketServerMixIn, 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.ClientRestrictingServerMixIn, 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BrokenPipeHandlerMixIn, 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer): 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of StoppableHTTPServer that add https support and 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client verification.""" 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, server_address, request_hander_class, pem_cert_and_key, 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ssl_client_auth, ssl_client_cas, ssl_client_cert_types, 1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ssl_bulk_ciphers, ssl_key_exchanges, enable_npn, 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch record_resume_info, tls_intolerant, 159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch tls_intolerance_type, signed_cert_timestamps, 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) fallback_scsv_enabled, ocsp_response, disable_session_cache): 161a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.cert_chain = tlslite.api.X509CertChain() 162a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.cert_chain.parsePemList(pem_cert_and_key) 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # Force using only python implementation - otherwise behavior is different 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # depending on whether m2crypto Python module is present (error is thrown 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # when it is). m2crypto uses a C (based on OpenSSL) implementation under 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch # the hood. 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private=True, 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch implementations=['python']) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_client_auth = ssl_client_auth 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_client_cas = [] 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) self.ssl_client_cert_types = [] 1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if enable_npn: 1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch self.next_protos = ['http/1.1'] 1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch else: 1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch self.next_protos = None 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) self.signed_cert_timestamps = signed_cert_timestamps 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.fallback_scsv_enabled = fallback_scsv_enabled 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.ocsp_response = ocsp_response 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if ssl_client_auth: 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for ca_file in ssl_client_cas: 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) s = open(ca_file).read() 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) x509 = tlslite.api.X509() 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) x509.parse(s) 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) self.ssl_client_cas.append(x509.subject) 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for cert_type in ssl_client_cert_types: 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) self.ssl_client_cert_types.append({ 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) "rsa_sign": tlslite.api.ClientCertificateType.rsa_sign, 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) "dss_sign": tlslite.api.ClientCertificateType.dss_sign, 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) "ecdsa_sign": tlslite.api.ClientCertificateType.ecdsa_sign, 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }[cert_type]) 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_handshake_settings = tlslite.api.HandshakeSettings() 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ssl_bulk_ciphers is not None: 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers 198a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if ssl_key_exchanges is not None: 199a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.ssl_handshake_settings.keyExchangeNames = ssl_key_exchanges 200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if tls_intolerant != 0: 201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.ssl_handshake_settings.tlsIntolerant = (3, tls_intolerant) 202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.ssl_handshake_settings.tlsIntoleranceType = tls_intolerance_type 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if disable_session_cache: 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.session_cache = None 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elif record_resume_info: 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If record_resume_info is true then we'll replace the session cache with 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # an object that records the lookups and inserts that it sees. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.session_cache = RecordingSSLSessionCache() 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.session_cache = tlslite.api.SessionCache() 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.StoppableHTTPServer.__init__(self, 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server_address, 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_hander_class) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handshake(self, tlsConnection): 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Creates the SSL connection.""" 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.tlsConnection = tlsConnection 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tlsConnection.handshakeServer(certChain=self.cert_chain, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) privateKey=self.private_key, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sessionCache=self.session_cache, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reqCert=self.ssl_client_auth, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) settings=self.ssl_handshake_settings, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reqCAs=self.ssl_client_cas, 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reqCertTypes=self.ssl_client_cert_types, 2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch nextProtos=self.next_protos, 230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) signedCertTimestamps= 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.signed_cert_timestamps, 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) fallbackSCSV=self.fallback_scsv_enabled, 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ocspResponse = self.ocsp_response) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tlsConnection.ignoreAbruptClose = True 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except tlslite.api.TLSAbruptCloseError: 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Ignore abrupt close. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except tlslite.api.TLSError, error: 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Handshake failure:", str(error) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FTPServer(testserver_base.ClientRestrictingServerMixIn, 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pyftpdlib.ftpserver.FTPServer): 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is a specialization of FTPServer that adds client verification.""" 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TCPEchoServer(testserver_base.ClientRestrictingServerMixIn, 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketServer.TCPServer): 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A TCP echo server that echoes back what it has received.""" 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def server_bind(self): 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Override server_bind to store the server name.""" 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SocketServer.TCPServer.server_bind(self) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host, port = self.socket.getsockname()[:2] 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_name = socket.getfqdn(host) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_port = port 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever(self): 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stop = False 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.nonce_time = None 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while not self.stop: 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle_request() 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.socket.close() 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class UDPEchoServer(testserver_base.ClientRestrictingServerMixIn, 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketServer.UDPServer): 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A UDP echo server that echoes back what it has received.""" 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def server_bind(self): 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Override server_bind to store the server name.""" 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SocketServer.UDPServer.server_bind(self) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host, port = self.socket.getsockname()[:2] 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_name = socket.getfqdn(host) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server_port = port 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def serve_forever(self): 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stop = False 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.nonce_time = None 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while not self.stop: 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle_request() 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.socket.close() 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestPageHandler(testserver_base.BasePageHandler): 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Class variables to allow for persistence state between page handler 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # invocations 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limits = {} 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = {} 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, request, client_address, socket_server): 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connect_handlers = [ 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.RedirectConnectHandler, 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ServerAuthConnectHandler, 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultConnectResponseHandler] 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_handlers = [ 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoCacheMaxAgeTimeHandler, 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoCacheTimeHandler, 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheTimeHandler, 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheExpiresHandler, 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheProxyRevalidateHandler, 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CachePrivateHandler, 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CachePublicHandler, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheSMaxAgeHandler, 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheMustRevalidateHandler, 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheMustRevalidateMaxAgeHandler, 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoStoreHandler, 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoStoreMaxAgeHandler, 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CacheNoTransformHandler, 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DownloadHandler, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DownloadFinishHandler, 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHeader, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHeaderCache, 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoAllHandler, 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ZipFileHandler, 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.FileHandler, 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetCookieHandler, 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetManyCookiesHandler, 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ExpectAndSetCookieHandler, 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SetHeaderHandler, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.AuthBasicHandler, 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.AuthDigestHandler, 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.SlowServerHandler, 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ChunkedServerHandler, 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ContentTypeHandler, 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.NoContentHandler, 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ServerRedirectHandler, 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ClientRedirectHandler, 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.GetSSLSessionCacheHandler, 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.SSLManySmallRecords, 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.GetChannelID, 3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.ClientCipherListHandler, 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.CloseSocketHandler, 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.RangeResetHandler, 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultResponseHandler] 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) post_handlers = [ 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoTitleHandler, 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHandler, 3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.PostOnlyFileHandler, 3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.EchoMultipartPostHandler] + get_handlers 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) put_handlers = [ 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoTitleHandler, 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.EchoHandler] + get_handlers 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) head_handlers = [ 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.FileHandler, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.DefaultResponseHandler] 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._mime_types = { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'crx' : 'application/x-chrome-extension', 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'exe' : 'application/octet-stream', 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'gif': 'image/gif', 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'jpeg' : 'image/jpeg', 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'jpg' : 'image/jpeg', 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'json': 'application/json', 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'pdf' : 'application/pdf', 362424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 'txt' : 'text/plain', 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'wav' : 'audio/wav', 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'xml' : 'text/xml' 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._default_mime_type = 'text/html' 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BasePageHandler.__init__(self, request, client_address, 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_server, connect_handlers, 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) get_handlers, head_handlers, 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) post_handlers, put_handlers) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetMIMETypeFromName(self, file_name): 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns the mime type for the specified file_name. So far it only looks 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) at the file extension.""" 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (_shortname, extension) = os.path.splitext(file_name.split("?")[0]) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(extension) == 0: 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # no extension. 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._default_mime_type 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # extension starts with a dot, so we need to remove it 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._mime_types.get(extension[1:], self._default_mime_type) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoCacheMaxAgeTimeHandler(self): 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and no caching requested.""" 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocachetime/maxage"): 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoCacheTimeHandler(self): 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and no caching requested.""" 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocachetime"): 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-cache') 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheTimeHandler(self): 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for one minute.""" 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cachetime"): 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60') 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheExpiresHandler(self): 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and set the page to expire on 1 Jan 2099.""" 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/expires"): 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Expires', 'Thu, 1 Jan 2099 00:00:00 GMT') 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheProxyRevalidateHandler(self): 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 60 seconds""" 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/proxy-revalidate"): 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, proxy-revalidate') 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CachePrivateHandler(self): 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 5 seconds.""" 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/private"): 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=3, private') 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CachePublicHandler(self): 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and allows caching for 5 seconds.""" 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/public"): 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=3, public') 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheSMaxAgeHandler(self): 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow for caching.""" 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/s-maxage"): 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'public, s-maxage = 60, max-age = 0') 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheMustRevalidateHandler(self): 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow caching.""" 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/must-revalidate"): 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'must-revalidate') 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheMustRevalidateMaxAgeHandler(self): 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow caching event though max-age of 60 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) seconds is specified.""" 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/must-revalidate/max-age"): 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, must-revalidate') 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoStoreHandler(self): 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the page to be stored.""" 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-store"): 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-store') 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoStoreMaxAgeHandler(self): 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the page to be stored even though max-age 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of 60 seconds is specified.""" 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-store/max-age"): 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=60, no-store') 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CacheNoTransformHandler(self): 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This request handler yields a page with the title set to the current 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system time, and does not allow the content to transformed during 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user-agent caching""" 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/cache/no-transform"): 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'no-transform') 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>%s</title></head></html>' % 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.time()) 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeader(self): 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler echoes back the value of a specific request header.""" 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.EchoHeaderHelper("/echoheader") 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeaderCache(self): 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function echoes back the value of a specific request header while 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowing caching for 16 hours.""" 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.EchoHeaderHelper("/echoheadercache") 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHeaderHelper(self, echo_header): 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function echoes back the value of the request header passed in.""" 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(echo_header): 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_name = self.path[query_char+1:] 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if echo_header == '/echoheadercache': 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'no-cache') 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # insert a vary header to properly indicate that the cachability of this 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # request is subject to value of the request header being echoed. 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_name) > 0: 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Vary', header_name) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_name) > 0: 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.headers.getheader(header_name)) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ReadRequestBody(self): 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This function reads the body of the current HTTP request, handling 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) both plain and chunked transfer encoded requests.""" 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.headers.getheader('transfer-encoding') != 'chunked': 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = int(self.headers.getheader('content-length')) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.rfile.read(length) 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Read the request body as chunks. 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body = "" 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while True: 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = self.rfile.readline() 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = int(line, 16) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if length == 0: 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rfile.readline() 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body += self.rfile.read(length) 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rfile.read(2) 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return body 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoHandler(self): 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just echoes back the payload of the request, for testing 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) form submission.""" 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echo"): 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.ReadRequestBody()) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoTitleHandler(self): 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler is like Echo, but sets the page title to the request.""" 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echotitle"): 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request = self.ReadRequestBody() 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><title>') 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(request) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</title></head></html>') 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def EchoAllHandler(self): 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler yields a (more) human-readable page listing information 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) about the request header & contents.""" 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/echoall"): 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head><style>' 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'pre { border: 1px solid black; margin: 5px; padding: 5px }' 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '</style></head><body>' 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<div style="float: right">' 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<a href="/echo">back to referring page</a></div>' 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '<h1>Request Body:</h1><pre>') 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT': 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qs = self.ReadRequestBody() 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params = cgi.parse_qs(qs, keep_blank_values=1) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for param in params: 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s=%s\n' % (param, params[param][0])) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</pre>') 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<h1>Request Headers:</h1><pre>%s</pre>' % self.headers) 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) def EchoMultipartPostHandler(self): 7283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) """This handler echoes received multipart post data as json format.""" 7293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if not (self._ShouldHandleRequest("/echomultipartpost") or 7313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self._ShouldHandleRequest("/searchbyimage")): 7323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return False 7333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) content_type, parameters = cgi.parse_header( 7353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.headers.getheader('content-type')) 7363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if content_type == 'multipart/form-data': 7373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart = cgi.parse_multipart(self.rfile, parameters) 7383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) elif content_type == 'application/x-www-form-urlencoded': 7393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) raise Exception('POST by application/x-www-form-urlencoded is ' 7403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 'not implemented.') 7413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) else: 7423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart = {} 7433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) # Since the data can be binary, we encode them by base64. 7453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart_base64_encoded = {} 7463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for field, values in post_multipart.items(): 7473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) post_multipart_base64_encoded[field] = [base64.b64encode(value) 7483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for value in values] 7493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) result = {'POST_multipart' : post_multipart_base64_encoded} 7513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.send_response(200) 7533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.send_header("Content-type", "text/plain") 7543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.end_headers() 7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.wfile.write(json.dumps(result, indent=2, sort_keys=False)) 7563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return True 7573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DownloadHandler(self): 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends a downloadable file with or without reporting 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the size (6K).""" 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.path.startswith("/download-unknown-size"): 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_length = False 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.path.startswith("/download-known-size"): 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_length = True 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The test which uses this functionality is attempting to send 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # small chunks of data to the client. Use a fairly large buffer 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # so that we'll fill chrome's IO buffer enough to force it to 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # actually write the data. 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # See also the comments in the client-side of this test in 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # download_uitest.cc 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_chunk1 = 35*1024 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_chunk2 = 10*1024 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/octet-stream') 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if send_length: 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', size_chunk1 + size_chunk2) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # First chunk of data: 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("*" * size_chunk1) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.flush() 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # handle requests until one of them clears this flag. 7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.handle_request() 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Second chunk of data: 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("*" * size_chunk2) 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DownloadFinishHandler(self): 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just tells the server to finish the current download.""" 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/download-finish"): 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = False 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-Control', 'max-age=0') 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _ReplaceFileData(self, data, query_parameters): 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Replaces matching substrings in a file. 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the 'replace_text' URL query parameter is present, it is expected to be 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of the form old_text:new_text, which indicates that any old_text strings in 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the file are replaced with new_text. Multiple 'replace_text' parameters may 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) be specified. 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the parameters are not present, |data| is returned. 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query_parameters) 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_values = query_dict.get('replace_text', []) 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for replace_text_value in replace_text_values: 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_args = replace_text_value.split(':') 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(replace_text_args) != 2: 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise ValueError( 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'replace_text must be of form old_text:new_text. Actual value: %s' % 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replace_text_value) 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_text_b64, new_text_b64 = replace_text_args 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_text = base64.urlsafe_b64decode(old_text_b64) 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_text = base64.urlsafe_b64decode(new_text_b64) 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data.replace(old_text, new_text) 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ZipFileHandler(self): 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file in compressed form. 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Can pass in a parameter that specifies that the content length be 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) C - the compressed size (OK), 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) U - the uncompressed size (Non-standard, but handled), 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) S - less than compressed (OK because we keep going), 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) M - larger than compressed but less than uncompressed (an error), 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L - larger than uncompressed (an error) 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: compressedfiles/Picture_1.doc?C 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = "/compressedfiles/" 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Consume a request body if present. 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT' : 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ReadRequestBody() 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not query in ('C', 'U', 'S', 'M', 'L'): 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_path = url_path[len(prefix):] 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entries = sub_path.split('/') 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(self.server.data_dir, *entries) 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isdir(file_path): 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(file_path, 'index.html') 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(file_path): 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "File not found " + sub_path + " full path:" + file_path 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(file_path, "rb") 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uncompressed_len = len(data) 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Compress the data. 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = zlib.compress(data) 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compressed_len = len(data) 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query == 'U': 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = uncompressed_len 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'S': 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len / 2 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'M': 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = (compressed_len + uncompressed_len) / 2 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif query == 'L': 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length = compressed_len + uncompressed_len 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/msword') 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-encoding', 'deflate') 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', content_length) 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('ETag', '\'' + file_path + '\'') 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def FileHandler(self): 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file. Wow, it's like 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a real webserver!""" 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = self.server.file_root_url 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._FileHandlerHelper(prefix) 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def PostOnlyFileHandler(self): 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sends the contents of the requested file on a POST.""" 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix = urlparse.urljoin(self.server.file_root_url, 'post/') 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.path.startswith(prefix): 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._FileHandlerHelper(prefix) 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _FileHandlerHelper(self, prefix): 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_body = '' 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.command == 'POST' or self.command == 'PUT': 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Consume a request body if present. 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_body = self.ReadRequestBody() 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query) 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_body = query_dict.get('expected_body', []) 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_body and request_body not in expected_body: 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(404) 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('') 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_headers = query_dict.get('expected_headers', []) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for expected_header in expected_headers: 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_name, expected_value = expected_header.split(':') 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.headers.getheader(header_name) != expected_value: 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(404) 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('') 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_path = url_path[len(prefix):] 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entries = sub_path.split('/') 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(self.server.data_dir, *entries) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isdir(file_path): 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path = os.path.join(file_path, 'index.html') 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(file_path): 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "File not found " + sub_path + " full path:" + file_path 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(file_path, "rb") 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self._ReplaceFileData(data, query) 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_protocol_version = self.protocol_version 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If file.mock-http-headers exists, it contains the headers we 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # should send. Read them in and parse them. 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_path = file_path + '.mock-http-headers' 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isfile(headers_path): 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(headers_path, "r") 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "HTTP/1.1 200 OK" 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = f.readline() 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http_major, http_minor, status_code = re.findall( 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'HTTP/(\d+).(\d+) (\d+)', response)[0] 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = "HTTP/%s.%s" % (http_major, http_minor) 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(int(status_code)) 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in f: 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_values = re.findall('(\S+):\s*(.*)', line) 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(header_values) > 0: 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "name: value" 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name, value = header_values[0] 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header(name, value) 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Could be more generic once we support mime-type sniffing, but for 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # now we need to set it explicitly. 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range_header = self.headers.get('Range') 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if range_header and range_header.startswith('bytes='): 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Note this doesn't handle all valid byte range_header values (i.e. 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # left open ended ones), just enough for what we needed so far. 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range_header = range_header[6:].split('-') 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start = int(range_header[0]) 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if range_header[1]: 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end = int(range_header[1]) 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end = len(data) - 1 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(206) 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_range = ('bytes ' + str(start) + '-' + str(end) + '/' + 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) str(len(data))) 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Range', content_range) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[start: end + 1] 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', self.GetMIMETypeFromName(file_path)) 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Accept-Ranges', 'bytes') 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(data)) 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('ETag', '\'' + file_path + '\'') 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.command != 'HEAD'): 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetCookieHandler(self): 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just sets a cookie, for testing cookie handling.""" 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-cookie"): 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_values = self.path[query_char + 1:].split('&') 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_values = ("",) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in cookie_values: 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', '%s' % cookie_value) 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in cookie_values: 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s' % cookie_value) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetManyCookiesHandler(self): 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler just sets a given number of cookies, for testing handling 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of large numbers of cookies.""" 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-many-cookies"): 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_cookies = int(self.path[query_char + 1:]) 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_cookies = 0 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('', 'text/html') 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for _i in range(0, num_cookies): 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', 'a=') 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%d cookies were sent' % num_cookies) 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ExpectAndSetCookieHandler(self): 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Expects some cookies to be sent, and if they are, sets more cookies. 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The expect parameter specifies a required cookie. May be specified multiple 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) times. 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The set parameter specifies a cookie to set if all required cookies are 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preset. May be specified multiple times. 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The data parameter specifies the response body data to be returned.""" 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/expect-and-set-cookie"): 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, _, _, query, _ = urlparse.urlparse(self.path) 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_dict = cgi.parse_qs(query) 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookies = set() 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'Cookie' in self.headers: 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookie_header = self.headers.getheader('Cookie') 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cookies.update([s.strip() for s in cookie_header.split(';')]) 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_all_expected_cookies = True 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for expected_cookie in query_dict.get('expect', []): 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_cookie not in cookies: 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_all_expected_cookies = False 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if got_all_expected_cookies: 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for cookie_value in query_dict.get('set', []): 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', '%s' % cookie_value) 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for data_value in query_dict.get('data', []): 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data_value) 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetHeaderHandler(self): 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler sets a response header. Parameters are in the 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key%3A%20value&key2%3A%20value2 format.""" 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/set-header"): 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char != -1: 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_values = self.path[query_char + 1:].split('&') 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_values = ("",) 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header_value in headers_values: 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_value = urllib.unquote(header_value) 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (key, value) = header_value.split(': ', 1) 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header(key, value) 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header_value in headers_values: 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%s' % header_value) 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AuthBasicHandler(self): 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler tests 'Basic' authentication. It just sends a page with 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title 'user/pass' if you succeed.""" 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/auth-basic"): 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username = userpass = password = b64str = "" 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_password = 'secret' 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = 'testrealm' 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cookie_if_challenged = False 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_params = cgi.parse_qs(query, True) 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'set-cookie-if-challenged' in query_params: 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cookie_if_challenged = True 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'password' in query_params: 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_password = query_params['password'][0] 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'realm' in query_params: 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = query_params['realm'][0] 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('authorization') 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth: 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('no auth') 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b64str = re.findall(r'Basic (\S+)', auth)[0] 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) userpass = base64.b64decode(b64str) 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username, password = re.findall(r'([^:]+):(\S+)', userpass)[0] 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if password != expected_password: 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong password') 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication failed. 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', 'Basic realm="%s"' % realm) 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if set_cookie_if_challenged: 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Set-Cookie', 'got_challenged=true') 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>Denied: %s</title>' % e) 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('b64str=%s<p>' % b64str) 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('username: %s<p>' % username) 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('userpass: %s<p>' % userpass) 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('password: %s<p>' % password) 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication successful. (Return a cachable response to allow for 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # testing cached pages that require authentication.) 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_protocol_version = self.protocol_version 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = "HTTP/1.1" 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if_none_match = self.headers.getheader('if-none-match') 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if if_none_match == "abc": 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(304) 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif url_path.endswith(".gif"): 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Using chrome/test/data/google/logo.gif as the test image 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_image_path = ['google', 'logo.gif'] 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gif_path = os.path.join(self.server.data_dir, *test_image_path) 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(gif_path): 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_error(404) 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = open(gif_path, "rb") 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = f.read() 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'image/gif') 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Etag', 'abc') 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(data) 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Cache-control', 'max-age=60000') 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Etag', 'abc') 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>%s/%s</title>' % (username, password)) 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = old_protocol_version 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetNonce(self, force_reset=False): 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a nonce that's stable per request path for the server's lifetime. 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is a fake implementation. A real implementation would only use a given 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nonce a single time (hence the name n-once). However, for the purposes of 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unittesting, we don't care about the security of the nonce. 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) force_reset: Iff set, the nonce will be changed. Useful for testing the 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "stale" response. 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if force_reset or not self.server.nonce_time: 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server.nonce_time = time.time() 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return hashlib.md5('privatekey%s%d' % 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (self.path, self.server.nonce_time)).hexdigest() 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AuthDigestHandler(self): 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This handler tests 'Digest' authentication. 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It just sends a page with title 'user/pass' if you succeed. 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A stale response is sent iff "stale" is present in the request path. 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/auth-digest"): 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stale = 'stale' in self.path 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nonce = self.GetNonce(force_reset=stale) 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opaque = hashlib.md5('opaque').hexdigest() 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) password = 'secret' 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) realm = 'testrealm' 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('authorization') 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs = {} 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth: 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('no auth') 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not auth.startswith('Digest'): 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('not digest') 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Pull out all the name="value" pairs as a dictionary. 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Make sure it's all valid. 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['nonce'] != nonce: 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong nonce') 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['opaque'] != opaque: 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong opaque') 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check the 'response' value and make sure it matches our magic hash. 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # See http://www.ietf.org/rfc/rfc2617.txt 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hash_a1 = hashlib.md5( 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ':'.join([pairs['username'], realm, password])).hexdigest() 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hash_a2 = hashlib.md5(':'.join([self.command, pairs['uri']])).hexdigest() 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = hashlib.md5(':'.join([hash_a1, nonce, pairs['nc'], 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = hashlib.md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if pairs['response'] != response: 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise Exception('wrong password') 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication failed. 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr = ('Digest ' 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'realm="%s", ' 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'domain="/", ' 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'qop="auth", ' 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithm=MD5, ' 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'nonce="%s", ' 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'opaque="%s"') % (realm, nonce, opaque) 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if stale: 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr += ', stale="TRUE"' 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', hdr) 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>Denied: %s</title>' % e) 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('pairs=%s<p>' % pairs) 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('You sent:<br>%s<p>' % self.headers) 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('We are replying:<br>%s<p>' % hdr) 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Authentication successful. 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<title>%s/%s</title>' % (pairs['username'], password)) 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>') 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('auth=%s<p>' % auth) 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('pairs=%s<p>' % pairs) 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SlowServerHandler(self): 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Wait for the user suggested time before responding. The syntax is 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /slow?0.5 to wait for half a second.""" 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/slow"): 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_sec = 1.0 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char >= 0: 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_sec = int(self.path[query_char + 1:]) 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(wait_sec) 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("waited %d seconds" % wait_sec) 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ChunkedServerHandler(self): 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send chunked response. Allows to specify chunks parameters: 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - waitBeforeHeaders - ms to wait before sending headers 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - waitBetweenChunks - ms to wait between chunks 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - chunkSize - size of each chunk in bytes 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) - chunksNumber - number of chunks 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: /chunked?waitBeforeHeaders=1000&chunkSize=5&chunksNumber=5 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waits one second, then sends headers and five chunks five bytes each.""" 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/chunked"): 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunkedSettings = {'waitBeforeHeaders' : 0, 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'waitBetweenChunks' : 0, 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'chunkSize' : 5, 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'chunksNumber' : 5} 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char >= 0: 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params = self.path[query_char + 1:].split('&') 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for param in params: 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyValue = param.split('=') 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(keyValue) == 2: 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunkedSettings[keyValue[0]] = int(keyValue[1]) 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(0.001 * chunkedSettings['waitBeforeHeaders']) 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.protocol_version = 'HTTP/1.1' # Needed for chunked encoding 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Transfer-Encoding', 'chunked') 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Chunked encoding: sending all chunks, then final zero-length chunk and 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # then final CRLF. 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for i in range(0, chunkedSettings['chunksNumber']): 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if i > 0: 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(0.001 * chunkedSettings['waitBetweenChunks']) 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendChunkHelp('*' * chunkedSettings['chunkSize']) 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.flush() # Keep in mind that we start flushing only after 1kb. 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendChunkHelp('') 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ContentTypeHandler(self): 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a string of html with the given content type. E.g., 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /contenttype?text/css returns an html file with the Content-Type 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header set to text/css.""" 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/contenttype"): 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type = self.path[query_char + 1:].strip() 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not content_type: 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type = 'text/html' 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', content_type) 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write("<html>\n<body>\n<p>HTML text</p>\n</body>\n</html>\n") 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def NoContentHandler(self): 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a 204 No Content response.""" 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest("/nocontent"): 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(204) 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ServerRedirectHandler(self): 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a server redirect to the given URL. The syntax is 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '/server-redirect?http://foo.bar/asdf' to redirect to 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'http://foo.bar/asdf'""" 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_name = "/server-redirect" 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(test_name): 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char < 0 or len(self.path) <= query_char + 1: 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendRedirectHelp(test_name) 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1410d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) dest = urllib.unquote(self.path[query_char + 1:]) 14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(301) # moved permanently 14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Location', dest) 14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>Redirecting to %s</body></html>' % dest) 14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ClientRedirectHandler(self): 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a client redirect to the given URL. The syntax is 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '/client-redirect?http://foo.bar/asdf' to redirect to 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'http://foo.bar/asdf'""" 14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_name = "/client-redirect" 14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest(test_name): 14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_char = self.path.find('?') 14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if query_char < 0 or len(self.path) <= query_char + 1: 14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendRedirectHelp(test_name) 14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 1434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) dest = urllib.unquote(self.path[query_char + 1:]) 14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><head>') 14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<meta http-equiv="refresh" content="0;url=%s">' % dest) 14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</head><body>Redirecting to %s</body></html>' % dest) 14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetSSLSessionCacheHandler(self): 14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Send a reply containing a log of the session cache operations.""" 14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest('/ssl-session-cache'): 14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 1455a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch log = self.server.session_cache.log 14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except AttributeError: 14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('Pass --https-record-resume in order to use' + 14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' this request') 1459a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return True 1460a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 1461a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch for (action, sessionID) in log: 1462a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.wfile.write('%s\t%s\n' % (action, bytes(sessionID).encode('hex'))) 14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def SSLManySmallRecords(self): 14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Sends a reply consisting of a variety of small writes. These will be 14672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) translated into a series of small SSL records when used over an HTTPS 14682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server.""" 14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/ssl-many-small-records'): 14712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 14742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Write ~26K of data, in 1350 byte chunks 14782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for i in xrange(20): 14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write('*' * 1350) 14802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 14812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 14822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def GetChannelID(self): 14842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Send a reply containing the hashed ChannelID that the client provided.""" 14852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/channel-id'): 14872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 14882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 14902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'text/plain') 14912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 1492a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch channel_id = bytes(self.server.tlsConnection.channel_id) 14932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(hashlib.sha256(channel_id).digest().encode('base64')) 14942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 14952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def ClientCipherListHandler(self): 14971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """Send a reply containing the cipher suite list that the client 14981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci provided. Each cipher suite value is serialized in decimal, followed by a 14991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci newline.""" 15001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 15011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if not self._ShouldHandleRequest('/client-cipher-list'): 15021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 15031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 15041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.send_response(200) 15051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.send_header('Content-Type', 'text/plain') 15061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.end_headers() 15071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 15081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for cipher_suite in self.server.tlsConnection.clientHello.cipher_suites: 15091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.wfile.write(str(cipher_suite)) 15101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.wfile.write('\n') 15111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return True 15121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CloseSocketHandler(self): 15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Closes the socket without sending anything.""" 15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._ShouldHandleRequest('/close-socket'): 15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.close() 15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def RangeResetHandler(self): 15232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Send data broken up by connection resets every N (default 4K) bytes. 15242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Support range requests. If the data requested doesn't straddle a reset 15252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boundary, it will all be sent. Used for testing resuming downloads.""" 15262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def DataForRange(start, end): 15282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Data to be provided for a particular range of bytes.""" 15292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Offset and scale to avoid too obvious (and hence potentially 15302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # collidable) data. 15312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ''.join([chr(y % 256) 15322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for y in range(start * 2 + 15, end * 2 + 15, 2)]) 15332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._ShouldHandleRequest('/rangereset'): 15352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 15362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) # HTTP/1.1 is required for ETag and range support. 1538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.protocol_version = 'HTTP/1.1' 15392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) _, _, url_path, _, query, _ = urlparse.urlparse(self.path) 15402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Defaults 15422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size = 8000 15432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Note that the rst is sent just before sending the rst_boundary byte. 15442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_boundary = 4000 15452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) respond_to_range = True 15462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hold_for_signal = False 15472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = -1 15482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token = 'DEFAULT' 15492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = 0 15502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) send_verifiers = True 15512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Parse the query 15532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) qdict = urlparse.parse_qs(query, True) 15542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'size' in qdict: 15552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size = int(qdict['size'][0]) 15562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'rst_boundary' in qdict: 15572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_boundary = int(qdict['rst_boundary'][0]) 15582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'token' in qdict: 15592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Identifying token for stateful tests. 15602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token = qdict['token'][0] 15612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'rst_limit' in qdict: 15622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Max number of rsts for a given token. 15632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = int(qdict['rst_limit'][0]) 15642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'bounce_range' in qdict: 15652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) respond_to_range = False 15662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'hold' in qdict: 15672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Note that hold_for_signal will not work with null range requests; 15682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # see TODO below. 15692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hold_for_signal = True 15702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'no_verifiers' in qdict: 15712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) send_verifiers = False 15722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if 'fail_precondition' in qdict: 15732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = int(qdict['fail_precondition'][0]) 15742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Record already set information, or set it. 15762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rst_limit = TestPageHandler.rst_limits.setdefault(token, rst_limit) 15772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if rst_limit != 0: 15782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestPageHandler.rst_limits[token] -= 1 15792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fail_precondition = TestPageHandler.fail_precondition.setdefault( 15802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) token, fail_precondition) 15812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if fail_precondition != 0: 15822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestPageHandler.fail_precondition[token] -= 1 15832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = 0 15852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = size - 1 15862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Does that define what we want to return, or do we need to apply 15882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # a range? 15892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_response = False 15902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_header = self.headers.getheader('range') 15912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if range_header and respond_to_range: 15922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mo = re.match("bytes=(\d*)-(\d*)", range_header) 15932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if mo.group(1): 15942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = int(mo.group(1)) 15952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if mo.group(2): 15962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = int(mo.group(2)) 15972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if last_byte > size - 1: 15982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_byte = size - 1 15992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range_response = True 16002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if last_byte < first_byte: 16012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return False 16022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (fail_precondition and 16042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (self.headers.getheader('If-Modified-Since') or 16052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.headers.getheader('If-Match'))): 16062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(412) 16072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 16082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 16092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if range_response: 16112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(206) 16122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Range', 16132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'bytes %d-%d/%d' % (first_byte, last_byte, size)) 16142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 16152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_response(200) 16162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Type', 'application/octet-stream') 16172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Content-Length', last_byte - first_byte + 1) 16182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if send_verifiers: 16195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # If fail_precondition is non-zero, then the ETag for each request will be 16205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # different. 16215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) etag = "%s%d" % (token, fail_precondition) 16225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.send_header('ETag', etag) 16232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.send_header('Last-Modified', 'Tue, 19 Feb 2013 14:32 EST') 16242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.end_headers() 16252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if hold_for_signal: 16272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # TODO(rdsmith/phajdan.jr): http://crbug.com/169519: Without writing 16282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # a single byte, the self.server.handle_request() below hangs 16292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # without processing new incoming requests. 16302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(DataForRange(first_byte, first_byte + 1)) 16312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_byte = first_byte + 1 16322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # handle requests until one of them clears this flag. 16332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 16342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 16352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.handle_request() 16362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary 16382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if possible_rst >= last_byte or rst_limit == 0: 16392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # No RST has been requested in this range, so we don't need to 16402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # do anything fancy; just write the data and let the python 16412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # infrastructure close the connection. 16422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(DataForRange(first_byte, last_byte + 1)) 16432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 16442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 16452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # We're resetting the connection part way in; go to the RST 16472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # boundary and then send an RST. 16482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Because socket semantics do not guarantee that all the data will be 16492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # sent when using the linger semantics to hard close a socket, 16502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # we send the data and then wait for our peer to release us 16512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # before sending the reset. 16522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data = DataForRange(first_byte, possible_rst) 16532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.write(data) 16542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.flush() 16552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.wait_for_download = True 16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while self.server.wait_for_download: 16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.server.handle_request() 16582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) l_onoff = 1 # Linger is active. 16592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) l_linger = 0 # Seconds to linger for. 16602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct.pack('ii', l_onoff, l_linger)) 16622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Close all duplicates of the underlying socket to force the RST. 16642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.wfile.close() 16652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.rfile.close() 16662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.connection.close() 16672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 16692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DefaultResponseHandler(self): 16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is the catch-all response handler for requests that aren't handled 16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) by one of the special handlers above. 16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Note that we specify the content-length as without it the https connection 16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is not closed properly (and the browser keeps expecting data).""" 16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = "Default response given for path: " + self.path 16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(contents)) 16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.command != 'HEAD'): 16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(contents) 16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def RedirectConnectHandler(self): 16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a redirect to the CONNECT request for www.redirect.com. This 16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response is not specified by the RFC, so the browser should not follow 16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the redirect.""" 16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.path.find("www.redirect.com") < 0): 16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest = "http://www.destination.com/foo.js" 16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(302) # moved temporarily 16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Location', dest) 16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ServerAuthConnectHandler(self): 17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Sends a 401 to the CONNECT request for www.server-auth.com. This 17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response doesn't make sense because the proxy server cannot request 17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server authentication.""" 17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.path.find("www.server-auth.com") < 0): 17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) challenge = 'Basic realm="WallyWorld"' 17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(401) # unauthorized 17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('WWW-Authenticate', challenge) 17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Connection', 'close') 17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def DefaultConnectResponseHandler(self): 17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This is the catch-all response handler for CONNECT requests that aren't 17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled by one of the special handlers above. Real Web servers respond 17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) with 400 to CONNECT requests.""" 17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = "Your client has issued a malformed or illegal request." 17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) # bad request 17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', len(contents)) 17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(contents) 17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called by the redirect handling function when there is no parameter 17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def sendRedirectHelp(self, redirect_name): 17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'text/html') 17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('<html><body><h1>Error: no redirect destination</h1>') 17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('Use <pre>%s?http://dest...</pre>' % redirect_name) 17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('</body></html>') 17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called by chunked handling function 17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def sendChunkHelp(self, chunk): 17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Each chunk consists of: chunk size (hex), CRLF, chunk body, CRLF 17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('%X\r\n' % len(chunk)) 17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(chunk) 17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write('\r\n') 17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OCSPHandler(testserver_base.BasePageHandler): 17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, request, client_address, socket_server): 17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handlers = [self.OCSPResponse] 17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.ocsp_response = socket_server.ocsp_response 17512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) testserver_base.BasePageHandler.__init__(self, request, client_address, 17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_server, [], handlers, [], 17532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handlers, []) 17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def OCSPResponse(self): 17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200) 17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Type', 'application/ocsp-response') 17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Content-Length', str(len(self.ocsp_response))) 17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile.write(self.ocsp_response) 17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TCPEchoHandler(SocketServer.BaseRequestHandler): 17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """The RequestHandler class for TCP echo server. 17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It is instantiated once per connection to the server, and overrides the 17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle() method to implement communication to the client. 17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handle(self): 17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Handles the request from the client and constructs a response.""" 17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self.request.recv(65536).strip() 17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the "echo request" message received from the client. Send back 17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "echo response" message if "echo request" message is valid. 17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_data = echo_message.GetEchoResponseData(data) 17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not return_data: 17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request.send(return_data) 17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UDPEchoHandler(SocketServer.BaseRequestHandler): 17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """The RequestHandler class for UDP echo server. 17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) It is instantiated once per connection to the server, and overrides the 17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle() method to implement communication to the client. 17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def handle(self): 17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Handles the request from the client and constructs a response.""" 17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = self.request[0].strip() 17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_socket = self.request[1] 17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the "echo request" message received from the client. Send back 18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # "echo response" message if "echo request" message is valid. 18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_data = echo_message.GetEchoResponseData(data) 18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not return_data: 18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_socket.sendto(return_data, self.client_address) 18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A request handler that behaves as a proxy server which requires 18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) basic authentication. Only CONNECT, GET and HEAD is supported for now. 18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar 18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def parse_request(self): 18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Overrides parse_request to check credential.""" 18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self): 18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auth = self.headers.getheader('Proxy-Authorization') 18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if auth != self._AUTH_CREDENTIAL: 18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(407) 18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Proxy-Authenticate', 'Basic realm="MyRealm1"') 18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _start_read_write(self, sock): 18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.setblocking(0) 18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request.setblocking(0) 18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rlist = [self.request, sock] 18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while True: 18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ready_sockets, _unused, errors = select.select(rlist, [], []) 18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if errors: 18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for s in ready_sockets: 18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) received = s.recv(1024) 18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(received) == 0: 18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if s == self.request: 18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other = sock 18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other = self.request 18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other.send(received) 18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _do_common_method(self): 18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = urlparse.urlparse(self.path) 18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = url.port 18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not port: 18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if url.scheme == 'http': 18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = 80 18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif url.scheme == 'https': 18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = 443 18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not url.hostname or not port: 18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) 18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(url.path) == 0: 18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = '/' 18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = url.path 18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(url.query) > 0: 18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = '%s?%s' % (url.path, url.query) 18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = None 18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = socket.create_connection((url.hostname, port)) 18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('%s %s %s\r\n' % ( 18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.command, path, self.protocol_version)) 18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for header in self.headers.headers: 18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header = header.strip() 18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header.lower().startswith('connection') or 18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header.lower().startswith('proxy')): 18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('%s\r\n' % header) 18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.send('\r\n') 18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._start_read_write(sock) 18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if sock is not None: 18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.close() 18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_CONNECT(self): 18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos = self.path.rfind(':') 18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host = self.path[:pos] 18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = int(self.path[pos+1:]) 18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(400) 18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock = socket.create_connection((host, port)) 19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200, 'Connection established') 19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._start_read_write(sock) 19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(500) 19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sock.close() 19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_GET(self): 19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._do_common_method() 19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_HEAD(self): 19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._do_common_method() 19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServerRunner(testserver_base.TestServerRunner): 19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """TestServerRunner for the net test servers.""" 19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super(ServerRunner, self).__init__() 19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server = None 19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __make_data_dir(self): 19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.data_dir: 19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isdir(self.options.data_dir): 19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('specified data dir not found: ' + 19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.data_dir + ' exiting...') 19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = self.options.data_dir 19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create the default path to our data dir, relative to the exe dir. 19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = os.path.join(BASE_DIR, "..", "..", "..", "..", 19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "test", "data") 19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #TODO(ibrar): Must use Find* funtion defined in google\tools 19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #i.e my_data_dir = FindUpward(my_data_dir, "test", "data") 19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return my_data_dir 19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def create_server(self, server_data): 19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = self.options.port 19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host = self.options.host 19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.server_type == SERVER_HTTP: 19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.https: 19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pem_cert_and_key = None 19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.cert_and_key_file: 19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(self.options.cert_and_key_file): 19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified server cert file not found: ' + 19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.cert_and_key_file + ' exiting...') 19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pem_cert_and_key = file(self.options.cert_and_key_file, 'r').read() 19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # generate a new certificate and run an OCSP server for it. 19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server = OCSPServer((host, 0), OCSPHandler) 19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print ('OCSP server started on %s:%d...' % 19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (host, self.__ocsp_server.server_port)) 19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_der = None 19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = None 19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.ocsp == 'ok': 19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_GOOD 19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'revoked': 19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_REVOKED 19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'invalid': 19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_INVALID 19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'unauthorized': 19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_UNAUTHORIZED 19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.ocsp == 'unknown': 19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_state = minica.OCSP_STATE_UNKNOWN 19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('unknown OCSP status: ' + 19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ocsp_status) 19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (pem_cert_and_key, ocsp_der) = minica.GenerateCertKeyAndOCSP( 19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subject = "127.0.0.1", 19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ocsp_url = ("http://%s:%d/ocsp" % 19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (host, self.__ocsp_server.server_port)), 1982a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ocsp_state = ocsp_state, 1983a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) serial = self.options.cert_serial) 19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.ocsp_response = ocsp_der 19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ca_cert in self.options.ssl_client_ca: 19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(ca_cert): 19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified trusted client CA file not found: ' + ca_cert + 19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' exiting...') 19925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 19935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stapled_ocsp_response = None 19945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if self.__ocsp_server and self.options.staple_ocsp_response: 19955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stapled_ocsp_response = self.__ocsp_server.ocsp_response 19965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key, 19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_auth, 19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_ca, 2000cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) self.options.ssl_client_cert_type, 20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_bulk_cipher, 2002a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.options.ssl_key_exchange, 20030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch self.options.enable_npn, 20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.record_resume, 2005a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) self.options.tls_intolerant, 2006116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.options.tls_intolerance_type, 20075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.options.signed_cert_timestamps_tls_ext.decode( 20085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "base64"), 20095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.options.fallback_scsv, 20105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) stapled_ocsp_response, 20115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.options.disable_session_cache) 201246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) print 'HTTPS server started on https://%s:%d...' % \ 201346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) (host, server.server_port) 20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPServer((host, port), TestPageHandler) 201646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) print 'HTTP server started on http://%s:%d...' % \ 201746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) (host, server.server_port) 20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server.data_dir = self.__make_data_dir() 20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server.file_root_url = self.options.file_root_url 20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_WEBSOCKET: 20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Launch pywebsocket via WebSocketServer. 20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logger = logging.getLogger() 20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logger.addHandler(logging.StreamHandler()) 20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO(toyoshim): Remove following os.chdir. Currently this operation 20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is required to work correctly. It should be fixed from pywebsocket side. 20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.chdir(self.__make_data_dir()) 20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options = WebSocketOptions(host, port, '.') 203046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scheme = "ws" 20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.cert_and_key_file: 203246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scheme = "wss" 20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.use_tls = True 20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.private_key = self.options.cert_and_key_file 20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.certificate = self.options.cert_and_key_file 20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.options.ssl_client_auth: 20375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) websocket_options.tls_client_cert_optional = False 20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.tls_client_auth = True 20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(self.options.ssl_client_ca) != 1: 20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'one trusted client CA file should be specified') 20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(self.options.ssl_client_ca[0]): 20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError( 20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'specified trusted client CA file not found: ' + 20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.ssl_client_ca[0] + ' exiting...') 20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) websocket_options.tls_client_ca = self.options.ssl_client_ca[0] 20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = WebSocketServer(websocket_options) 204846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) print 'WebSocket server started on %s://%s:%d...' % \ 204946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) (scheme, host, server.server_port) 20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 20515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) websocket_options.use_basic_auth = self.options.ws_basic_auth 20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_TCP_ECHO: 20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Used for generating the key (randomly) that encodes the "echo request" 20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # message. 20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) random.seed() 20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = TCPEchoServer((host, port), TCPEchoHandler) 20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Echo TCP server started on port %d...' % server.server_port 20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_UDP_ECHO: 20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Used for generating the key (randomly) that encodes the "echo request" 20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # message. 20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) random.seed() 20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = UDPEchoServer((host, port), UDPEchoHandler) 20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Echo UDP server started on port %d...' % server.server_port 20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_BASIC_AUTH_PROXY: 20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = HTTPServer((host, port), BasicAuthProxyRequestHandler) 20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'BasicAuthProxy server started on port %d...' % server.server_port 20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.server_port 20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif self.options.server_type == SERVER_FTP: 20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_data_dir = self.__make_data_dir() 20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate a dummy authorizer for managing 'virtual' users 20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer = pyftpdlib.ftpserver.DummyAuthorizer() 20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Define a new user having full r/w permissions and a read-only 20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # anonymous user 20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') 20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorizer.add_anonymous(my_data_dir) 20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate FTP handler class 20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler = pyftpdlib.ftpserver.FTPHandler 20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler.authorizer = authorizer 20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Define a customized banner (string returned when client connects) 20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % 20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pyftpdlib.ftpserver.__ver__) 20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Instantiate FTP server class and listen to address:port 20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = pyftpdlib.ftpserver.FTPServer((host, port), ftp_handler) 20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_data['port'] = server.socket.getsockname()[1] 20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'FTP server started on port %d...' % server_data['port'] 20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise testserver_base.OptionError('unknown server type' + 20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.options.server_type) 20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return server 20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def run_server(self): 21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__ocsp_server: 21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.serve_forever_on_thread() 21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) testserver_base.TestServerRunner.run_server(self) 21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.__ocsp_server: 21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.__ocsp_server.stop_serving() 21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def add_options(self): 21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) testserver_base.TestServerRunner.add_options(self) 21115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.option_parser.add_option('--disable-session-cache', 21125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) action='store_true', 21135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dest='disable_session_cache', 21145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) help='tells the server to disable the' 21155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 'TLS session cache.') 21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('-f', '--ftp', action='store_const', 21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_FTP, default=SERVER_HTTP, 21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up an FTP server.') 21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--tcp-echo', action='store_const', 21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_TCP_ECHO, default=SERVER_HTTP, 21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a tcp echo server.') 21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--udp-echo', action='store_const', 21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_UDP_ECHO, default=SERVER_HTTP, 21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a udp echo server.') 21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--basic-auth-proxy', action='store_const', 21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_BASIC_AUTH_PROXY, 21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=SERVER_HTTP, dest='server_type', 21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a proxy server which requires ' 21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'basic authentication.') 21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--websocket', action='store_const', 21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const=SERVER_WEBSOCKET, default=SERVER_HTTP, 21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='server_type', 21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='start up a WebSocket server.') 21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--https', action='store_true', 21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='https', help='Specify that https ' 21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'should be used.') 21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--cert-and-key-file', 21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='cert_and_key_file', help='specify the ' 21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'path to the file containing the certificate ' 21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'and private key for the server in PEM ' 21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'format') 21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ocsp', dest='ocsp', default='ok', 21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='The type of OCSP response generated ' 21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'for the automatically generated ' 21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate. One of [ok,revoked,invalid]') 2149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self.option_parser.add_option('--cert-serial', dest='cert_serial', 2150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default=0, type=int, 2151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) help='If non-zero then the generated ' 2152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 'certificate will have this serial number') 21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--tls-intolerant', dest='tls_intolerant', 21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default='0', type='int', 21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='If nonzero, certain TLS connections ' 21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'will be aborted in order to test version ' 21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'fallback. 1 means all TLS versions will be ' 21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted. 2 means TLS 1.1 or higher will be ' 21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted. 3 means TLS 1.2 or higher will be ' 21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted.') 2161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.option_parser.add_option('--tls-intolerance-type', 2162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch dest='tls_intolerance_type', 2163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch default="alert", 2164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch help='Controls how the server reacts to a ' 2165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'TLS version it is intolerant to. Valid ' 2166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'values are "alert", "close", and "reset".') 21675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.option_parser.add_option('--signed-cert-timestamps-tls-ext', 21685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dest='signed_cert_timestamps_tls_ext', 2169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) default='', 2170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) help='Base64 encoded SCT list. If set, ' 2171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'server will respond with a ' 2172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'signed_certificate_timestamp TLS extension ' 2173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'whenever the client supports it.') 21745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.option_parser.add_option('--fallback-scsv', dest='fallback_scsv', 21755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default=False, const=True, 21765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) action='store_const', 21775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) help='If given, TLS_FALLBACK_SCSV support ' 21785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'will be enabled. This causes the server to ' 21795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'reject fallback connections from compatible ' 21805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'clients (e.g. Chrome).') 21815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.option_parser.add_option('--staple-ocsp-response', 21825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dest='staple_ocsp_response', 21835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default=False, action='store_true', 21845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) help='If set, server will staple the OCSP ' 21855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'response whenever OCSP is on and the client ' 21865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'supports OCSP stapling.') 21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--https-record-resume', 21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='record_resume', const=True, 21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=False, action='store_const', 21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Record resumption cache events rather ' 21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'than resuming as normal. Allows the use of ' 21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'the /ssl-session-cache request') 21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-client-auth', action='store_true', 21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Require SSL client auth on every ' 21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'connection.') 21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-client-ca', action='append', 21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default=[], help='Specify that the client ' 21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate request should include the CA ' 21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'named in the subject of the DER-encoded ' 22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'certificate contained in the specified ' 22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'file. This option may appear multiple ' 22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'times, indicating multiple CA names should ' 22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'be sent in the request.') 2204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) self.option_parser.add_option('--ssl-client-cert-type', action='append', 2205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default=[], help='Specify that the client ' 2206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'certificate request should include the ' 2207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'specified certificate_type value. This ' 2208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'option may appear multiple times, ' 2209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'indicating multiple values should be send ' 2210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'in the request. Valid values are ' 2211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) '"rsa_sign", "dss_sign", and "ecdsa_sign". ' 2212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 'If omitted, "rsa_sign" will be used.') 22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--ssl-bulk-cipher', action='append', 22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Specify the bulk encryption ' 22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithm(s) that will be accepted by the ' 22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SSL server. Valid values are "aes256", ' 22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '"aes128", "3des", "rc4". If omitted, all ' 22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'algorithms will be used. This option may ' 22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'appear multiple times, indicating ' 22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'multiple algorithms should be enabled.'); 2221a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self.option_parser.add_option('--ssl-key-exchange', action='append', 2222a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch help='Specify the key exchange algorithm(s)' 2223a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'that will be accepted by the SSL server. ' 2224a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'Valid values are "rsa", "dhe_rsa". If ' 2225a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'omitted, all algorithms will be used. This ' 2226a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'option may appear multiple times, ' 2227a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'indicating multiple algorithms should be ' 2228a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'enabled.'); 22290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch # TODO(davidben): Add ALPN support to tlslite. 22300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch self.option_parser.add_option('--enable-npn', dest='enable_npn', 22310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch default=False, const=True, 22320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch action='store_const', 22330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch help='Enable server support for the NPN ' 22340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 'extension. The server will advertise ' 22350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 'support for exactly one protocol, http/1.1') 22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.option_parser.add_option('--file-root-url', default='/files/', 22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Specify a root URL for files served.') 22385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # TODO(ricea): Generalize this to support basic auth for HTTP too. 22395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.option_parser.add_option('--ws-basic-auth', action='store_true', 22405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dest='ws_basic_auth', 22415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) help='Enable basic-auth for WebSocket') 22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(ServerRunner().main()) 2246