summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Gregorio <jcgregorio@google.com>2011-10-06 14:53:57 -0400
committerJoe Gregorio <jcgregorio@google.com>2011-10-06 14:53:57 -0400
commite428f07824d66a6aeaaa072a6fc896d32194cc75 (patch)
treec8d3b6bd08ced768342cf135ab65a35a8ce7141e
parentb470dc487f16f441d5f5c88f4606dcd2b2605d37 (diff)
downloadhttplib2-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.py55
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: