diff options
author | Joe Gregorio <jcgregorio@google.com> | 2011-10-06 14:53:57 -0400 |
---|---|---|
committer | Joe Gregorio <jcgregorio@google.com> | 2011-10-06 14:53:57 -0400 |
commit | e428f07824d66a6aeaaa072a6fc896d32194cc75 (patch) | |
tree | c8d3b6bd08ced768342cf135ab65a35a8ce7141e | |
parent | b470dc487f16f441d5f5c88f4606dcd2b2605d37 (diff) | |
download | httplib2-e428f07824d66a6aeaaa072a6fc896d32194cc75.tar.gz |
Add socks.PROXY_TYPE_HTTP_NO_TUNNEL. Reviewed in http://codereview.appspot.com/4956072/. Fixes issue #38.
-rw-r--r-- | python2/httplib2/socks.py | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/python2/httplib2/socks.py b/python2/httplib2/socks.py index a458e1c..84cb93b 100644 --- a/python2/httplib2/socks.py +++ b/python2/httplib2/socks.py @@ -40,6 +40,7 @@ mainly to merge bug fixes found in Sourceforge """ +import base64 import socket import struct import sys @@ -50,6 +51,7 @@ if getattr(socket, 'socket', None) is None: PROXY_TYPE_SOCKS4 = 1 PROXY_TYPE_SOCKS5 = 2 PROXY_TYPE_HTTP = 3 +PROXY_TYPE_HTTP_NO_TUNNEL = 4 _defaultproxy = None _orgsocket = socket.socket @@ -126,6 +128,7 @@ class socksocket(socket.socket): self.__proxy = (None, None, None, None, None, None) self.__proxysockname = None self.__proxypeername = None + self.__httptunnel = True def __recvall(self, count): """__recvall(count) -> data @@ -139,6 +142,41 @@ class socksocket(socket.socket): data = data + d return data + def sendall(self, content, *args): + """ override socket.socket.sendall method to rewrite the header + for non-tunneling proxies if needed + """ + if not self.__httptunnel: + content = self.__rewriteproxy(content) + return super(socksocket, self).sendall(content, *args) + + def __rewriteproxy(self, header): + """ rewrite HTTP request headers to support non-tunneling proxies + (i.e. those which do not support the CONNECT method). + This only works for HTTP (not HTTPS) since HTTPS requires tunneling. + """ + host, endpt = None, None + hdrs = header.split("\r\n") + for hdr in hdrs: + if hdr.lower().startswith("host:"): + host = hdr + elif hdr.lower().startswith("get") or hdr.lower().startswith("post"): + endpt = hdr + if host and endpt: + hdrs.remove(host) + hdrs.remove(endpt) + host = host.split(" ")[1] + endpt = endpt.split(" ") + if (self.__proxy[4] != None and self.__proxy[5] != None): + hdrs.insert(0, self.__getauthheader()) + hdrs.insert(0, "Host: %s" % host) + hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2])) + return "\r\n".join(hdrs) + + def __getauthheader(self): + auth = self.__proxy[4] + ":" + self.__proxy[5] + return "Proxy-Authorization: Basic " + base64.b64encode(auth) + def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None): """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]]) Sets the proxy to be used. @@ -326,7 +364,12 @@ class socksocket(socket.socket): addr = socket.gethostbyname(destaddr) else: addr = destaddr - self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode()) + headers = ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"] + headers += ["Host: ", destaddr, "\r\n"] + if (self.__proxy[4] != None and self.__proxy[5] != None): + headers += [self.__getauthheader(), "\r\n"] + headers.append("\r\n") + self.sendall("".join(headers).encode()) # We read the response until we get the string "\r\n\r\n" resp = self.recv(1) while resp.find("\r\n\r\n".encode()) == -1: @@ -379,6 +422,16 @@ class socksocket(socket.socket): portnum = 8080 _orgsocket.connect(self,(self.__proxy[1], portnum)) self.__negotiatehttp(destpair[0], destpair[1]) + elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL: + if self.__proxy[2] != None: + portnum = self.__proxy[2] + else: + portnum = 8080 + _orgsocket.connect(self,(self.__proxy[1],portnum)) + if destpair[1] == 443: + self.__negotiatehttp(destpair[0],destpair[1]) + else: + self.__httptunnel = False elif self.__proxy[0] == None: _orgsocket.connect(self, (destpair[0], destpair[1])) else: |