15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""HTTP proxy request handler with SSL support. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestHandler: Utility class for parsing HTTP requests. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyHandler: HTTP proxy handler. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import BaseHTTPServer 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cgi 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import OpenSSL 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import socket 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import SocketServer 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import traceback 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urlparse 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Class for reading HTTP requests and writing HTTP responses""" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protocol_version = "HTTP/1.1" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_version = protocol_version 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class HTTPRequestException(Exception): pass 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, rfile, wfile, server): 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.rfile = rfile 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.wfile = wfile 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.server = server 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ReadRequest(self): 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Reads and parses single HTTP request from self.rfile" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.raw_requestline = self.rfile.readline() 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.raw_requestline: 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.close_connection = 1 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise HTTPRequestException('failed to read request line') 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.parse_request(): 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise HTTPRequestException('failed to parse request') 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.headers = dict(self.headers) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.body = None 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'content-length' in self.headers: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.body = self.rfile.read(int(self.headers['content-length'])) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def log_message(self, format, *args): 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler): 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Request handler class for proxy server" 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_version = "PlaybackProxy/0.0.1" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protocol_version = "HTTP/1.1" 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_CONNECT(self): 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Handles CONNECT HTTP request" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server = self.path.split(':')[0] 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) certificate_file = os.path.join(self.certificate_directory, server) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isfile(certificate_file): 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stderr.write('request to connect %s is ignored\n' % server) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(501) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Proxy-agent', self.version_string()) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Send confirmation to browser. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_response(200, 'Connection established') 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.send_header('Proxy-agent', self.version_string()) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.end_headers() 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create SSL context. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context.use_privatekey_file(certificate_file) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context.use_certificate_file(certificate_file) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create and initialize SSL connection atop of tcp socket. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_connection = OpenSSL.SSL.Connection(context, self.connection) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_connection.set_accept_state() 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_connection.do_handshake() 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_rfile = socket._fileobject(ssl_connection, "rb", self.rbufsize) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ssl_wfile = socket._fileobject(ssl_connection, "wb", self.wbufsize) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Handle http requests coming from ssl_connection. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler = RequestHandler(ssl_rfile, ssl_wfile, self.path) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler.close_connection = 1 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while True: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler.ReadRequest() 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.driver.ProcessRequest(handler) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if handler.close_connection: break 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except (OpenSSL.SSL.SysCallError, OpenSSL.SSL.ZeroReturnError): 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.close_connection = 1 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_GET(self): 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.driver.ProcessRequest(self) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def do_POST(self): 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'content-length' in self.headers: 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.body = self.rfile.read(int(self.headers['content-length'])) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.driver.ProcessRequest(self) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def log_message(self, format, *args): 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stdout.write((format % args) + '\n') 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadingHTTPServer (SocketServer.ThreadingMixIn, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BaseHTTPServer.HTTPServer): 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateServer(driver, port, certificate_directory=None): 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not certificate_directory: 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) certificate_directory = os.path.join(os.getcwd(), 'certificates') 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyHandler.driver = driver 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyHandler.certificate_directory = certificate_directory 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ThreadingHTTPServer(('', port), ProxyHandler) 123