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