| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 """HTTP proxy request handler with SSL support. | |
| 5 | |
| 6 RequestHandler: Utility class for parsing HTTP requests. | |
| 7 ProxyHandler: HTTP proxy handler. | |
| 8 """ | |
| 9 | |
| 10 import BaseHTTPServer | |
| 11 import cgi | |
| 12 import OpenSSL | |
| 13 import os | |
| 14 import socket | |
| 15 import SocketServer | |
| 16 import sys | |
| 17 import traceback | |
| 18 import urlparse | |
| 19 | |
| 20 | |
| 21 class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |
| 22 """Class for reading HTTP requests and writing HTTP responses""" | |
| 23 | |
| 24 protocol_version = "HTTP/1.1" | |
| 25 request_version = protocol_version | |
| 26 | |
| 27 class HTTPRequestException(Exception): pass | |
| 28 | |
| 29 def __init__(self, rfile, wfile, server): | |
| 30 self.rfile = rfile | |
| 31 self.wfile = wfile | |
| 32 self.server = server | |
| 33 | |
| 34 def ReadRequest(self): | |
| 35 "Reads and parses single HTTP request from self.rfile" | |
| 36 | |
| 37 self.raw_requestline = self.rfile.readline() | |
| 38 if not self.raw_requestline: | |
| 39 self.close_connection = 1 | |
| 40 raise HTTPRequestException('failed to read request line') | |
| 41 if not self.parse_request(): | |
| 42 raise HTTPRequestException('failed to parse request') | |
| 43 self.headers = dict(self.headers) | |
| 44 self.body = None | |
| 45 if 'content-length' in self.headers: | |
| 46 self.body = self.rfile.read(int(self.headers['content-length'])) | |
| 47 | |
| 48 def log_message(self, format, *args): | |
| 49 pass | |
| 50 | |
| 51 | |
| 52 class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |
| 53 "Request handler class for proxy server" | |
| 54 | |
| 55 server_version = "PlaybackProxy/0.0.1" | |
| 56 protocol_version = "HTTP/1.1" | |
| 57 | |
| 58 def do_CONNECT(self): | |
| 59 "Handles CONNECT HTTP request" | |
| 60 | |
| 61 server = self.path.split(':')[0] | |
| 62 certificate_file = os.path.join(self.certificate_directory, server) | |
| 63 if not os.path.isfile(certificate_file): | |
| 64 sys.stderr.write('request to connect %s is ignored\n' % server) | |
| 65 self.send_response(501) | |
| 66 self.send_header('Proxy-agent', self.version_string()) | |
| 67 self.end_headers() | |
| 68 return | |
| 69 | |
| 70 # Send confirmation to browser. | |
| 71 self.send_response(200, 'Connection established') | |
| 72 self.send_header('Proxy-agent', self.version_string()) | |
| 73 self.end_headers() | |
| 74 | |
| 75 # Create SSL context. | |
| 76 context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) | |
| 77 context.use_privatekey_file(certificate_file) | |
| 78 context.use_certificate_file(certificate_file) | |
| 79 | |
| 80 # Create and initialize SSL connection atop of tcp socket. | |
| 81 ssl_connection = OpenSSL.SSL.Connection(context, self.connection) | |
| 82 ssl_connection.set_accept_state() | |
| 83 ssl_connection.do_handshake() | |
| 84 ssl_rfile = socket._fileobject(ssl_connection, "rb", self.rbufsize) | |
| 85 ssl_wfile = socket._fileobject(ssl_connection, "wb", self.wbufsize) | |
| 86 | |
| 87 # Handle http requests coming from ssl_connection. | |
| 88 handler = RequestHandler(ssl_rfile, ssl_wfile, self.path) | |
| 89 try: | |
| 90 handler.close_connection = 1 | |
| 91 while True: | |
| 92 handler.ReadRequest() | |
| 93 self.driver.ProcessRequest(handler) | |
| 94 if handler.close_connection: break | |
| 95 except (OpenSSL.SSL.SysCallError, OpenSSL.SSL.ZeroReturnError): | |
| 96 pass | |
| 97 finally: | |
| 98 self.close_connection = 1 | |
| 99 | |
| 100 def do_GET(self): | |
| 101 self.driver.ProcessRequest(self) | |
| 102 | |
| 103 def do_POST(self): | |
| 104 if 'content-length' in self.headers: | |
| 105 self.body = self.rfile.read(int(self.headers['content-length'])) | |
| 106 self.driver.ProcessRequest(self) | |
| 107 | |
| 108 def log_message(self, format, *args): | |
| 109 sys.stdout.write((format % args) + '\n') | |
| 110 | |
| 111 | |
| 112 class ThreadingHTTPServer (SocketServer.ThreadingMixIn, | |
| 113 BaseHTTPServer.HTTPServer): | |
| 114 pass | |
| 115 | |
| 116 | |
| 117 def CreateServer(driver, port, certificate_directory=None): | |
| 118 if not certificate_directory: | |
| 119 certificate_directory = os.path.join(os.getcwd(), 'certificates') | |
| 120 ProxyHandler.driver = driver | |
| 121 ProxyHandler.certificate_directory = certificate_directory | |
| 122 return ThreadingHTTPServer(('', port), ProxyHandler) | |
| OLD | NEW |