|
1 # urllib2 opener to connection through a proxy using the CONNECT method, (useful for SSL) |
|
2 # tested with python 2.4 |
|
3 |
|
4 import urllib2 |
|
5 import urllib |
|
6 import httplib |
|
7 import socket |
|
8 |
|
9 |
|
10 class ProxyHTTPConnection(httplib.HTTPConnection): |
|
11 |
|
12 _ports = {'http' : 80, 'https' : 443} |
|
13 |
|
14 |
|
15 def request(self, method, url, body=None, headers={}): |
|
16 #request is called before connect, so can interpret url and get |
|
17 #real host/port to be used to make CONNECT request to proxy |
|
18 proto, rest = urllib.splittype(url) |
|
19 if proto is None: |
|
20 raise ValueError, "unknown URL type: %s" % url |
|
21 #get host |
|
22 host, rest = urllib.splithost(rest) |
|
23 #try to get port |
|
24 host, port = urllib.splitport(host) |
|
25 #if port is not defined try to get from proto |
|
26 if port is None: |
|
27 try: |
|
28 port = self._ports[proto] |
|
29 except KeyError: |
|
30 raise ValueError, "unknown protocol for: %s" % url |
|
31 self._real_host = host |
|
32 self._real_port = port |
|
33 httplib.HTTPConnection.request(self, method, url, body, headers) |
|
34 |
|
35 |
|
36 def connect(self): |
|
37 httplib.HTTPConnection.connect(self) |
|
38 #send proxy CONNECT request |
|
39 self.send("CONNECT %s:%d HTTP/1.0\r\n\r\n" % (self._real_host, self._real_port)) |
|
40 #expect a HTTP/1.0 200 Connection established |
|
41 response = self.response_class(self.sock, strict=self.strict, method=self._method) |
|
42 (version, code, message) = response._read_status() |
|
43 #probably here we can handle auth requests... |
|
44 if code != 200: |
|
45 #proxy returned and error, abort connection, and raise exception |
|
46 self.close() |
|
47 raise socket.error, "Proxy connection failed: %d %s" % (code, message.strip()) |
|
48 #eat up header block from proxy.... |
|
49 while True: |
|
50 #should not use directly fp probablu |
|
51 line = response.fp.readline() |
|
52 if line == '\r\n': break |
|
53 |
|
54 |
|
55 class ProxyHTTPSConnection(ProxyHTTPConnection): |
|
56 |
|
57 default_port = 443 |
|
58 |
|
59 def __init__(self, host, port = None, key_file = None, cert_file = None, strict = None): |
|
60 ProxyHTTPConnection.__init__(self, host, port) |
|
61 self.key_file = key_file |
|
62 self.cert_file = cert_file |
|
63 |
|
64 def connect(self): |
|
65 ProxyHTTPConnection.connect(self) |
|
66 #make the sock ssl-aware |
|
67 ssl = socket.ssl(self.sock, self.key_file, self.cert_file) |
|
68 self.sock = httplib.FakeSocket(self.sock, ssl) |
|
69 |
|
70 |
|
71 class ConnectHTTPHandler(urllib2.HTTPHandler): |
|
72 |
|
73 def do_open(self, http_class, req): |
|
74 return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req) |
|
75 |
|
76 |
|
77 class ConnectHTTPSHandler(urllib2.HTTPSHandler): |
|
78 |
|
79 def do_open(self, http_class, req): |
|
80 return urllib2.HTTPSHandler.do_open(self, ProxyHTTPSConnection, req) |
|
81 |
|
82 |
|
83 if __name__ == '__main__': |
|
84 |
|
85 import sys |
|
86 |
|
87 opener = urllib2.build_opener(ConnectHTTPHandler, ConnectHTTPSHandler) |
|
88 urllib2.install_opener(opener) |
|
89 req = urllib2.Request(url='http://google.com') |
|
90 req.set_proxy('10.101.1.1:80', 'http') |
|
91 f = urllib2.urlopen(req) |
|
92 print f.read() |
|
93 |