"""
SocksiPy + urllib2 handler

version: 0.2
author: e<e@tr0ll.in>

This module provides a Handler which you can use with urllib2 to allow it
to tunnel your connection through a socks.sockssocket socket,
with out monkey patching the original socket...
"""
import urllib2
import httplib
import socks
import ssl


class SocksiPyConnection(httplib.HTTPConnection):
    def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True,
                 username=None, password=None, *args, **kwargs):
        self.proxyargs = (proxytype, proxyaddr, proxyport, rdns,
                          username, password)
        httplib.HTTPConnection.__init__(self, *args, **kwargs)

    def connect(self):
        self.sock = socks.socksocket()
        self.sock.setproxy(*self.proxyargs)
        if type(self.timeout) in (int, float):
            self.sock.settimeout(self.timeout)
        self.sock.connect((self.host, self.port))


class SocksiPyConnectionS(httplib.HTTPSConnection):
    def __init__(self, proxytype, proxyaddr, proxyport=None, rdns=True,
                 username=None, password=None, *args, **kwargs):
        self.proxyargs = (proxytype, proxyaddr, proxyport, rdns,
                          username, password)
        httplib.HTTPSConnection.__init__(self, *args, **kwargs)

    def connect(self):
        sock = socks.socksocket()
        sock.setproxy(*self.proxyargs)
        if type(self.timeout) in (int, float):
            sock.settimeout(self.timeout)
        sock.connect((self.host, self.port))
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)


class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler):
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kw = kwargs
        urllib2.HTTPHandler.__init__(self)

    def http_open(self, req):
        def build(host, port=None, strict=None, timeout=0):
            conn = SocksiPyConnection(*self.args, host=host, port=port,
                                      strict=strict, timeout=timeout,
                                      **self.kw)
            return conn
        return self.do_open(build, req)

    def https_open(self, req):
        def build(host, port=None, strict=None, timeout=0):
            conn = SocksiPyConnectionS(*self.args, host=host, port=port,
                                       strict=strict, timeout=timeout,
                                       **self.kw)
            return conn
        return self.do_open(build, req)


if __name__ == "__main__":
    opener = urllib2.build_opener(
        SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, "localhost", 9050))
    print "HTTP:", opener.open("http://httpbin.org/ip").read()
    print "HTTPS:", opener.open("https://httpbin.org/ip").read()
