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 |