Folks,

Here's an updated version of Daniels work. Changes w.r.t. to Daniels version:

* Remove all version except the one using SystemConfiguration

* Add "noproxy" function

* Add support for https, ftp and gopher

* More defensive programming

I'm going to do some testing with this version if everything works for me I'll add this to python2.6.

This doesn't support "proxy autoconfiguration", but I don't think that's possible to do within the structure of urllib and would require a JavaScript engine anyway.

Ronald

def _CStringFromCFString(sc, value):
    from ctypes import create_string_buffer
    length = sc.CFStringGetLength(value) + 1
    buff = create_string_buffer(length)
    sc.CFStringGetCString(value, buff, length, 0)
    return buff.value

def _CFNumberToInt32(sc, cfnum):
    from ctypes import byref, c_int
    val = c_int()
    sc.CFNumberGetValue(cfnum, kCFNumberSInt32Type, byref(val))
    return val.value


def proxybypass_macosx_sysconf(host):
    """
    Return True iff this host shouldn't be accessed using a proxy

    This function uses the MacOSX framework SystemConfiguration
    to fetch the proxy information.
    """
    from ctypes import cdll
    from ctypes.util import find_library
    import re
    import socket
    from fnmatch import fnmatch

    def ip2num(ipAddr):
        parts = ipAddr.split('.')
        parts = map(int, parts)
        if len(parts) != 4:
            parts = (parts + [0, 0, 0, 0])[:4]
        return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]

    sc = cdll.LoadLibrary(find_library("SystemConfiguration"))

    hostIP = None

    if not sc:
        return False

    kSCPropNetProxiesExceptionsList = sc.CFStringCreateWithCString(0, "ExceptionsList", 0)
    kSCPropNetProxiesExcludeSimpleHostnames = sc.CFStringCreateWithCString(0, "ExcludeSimpleHostnames", 0)

    
    proxyDict = sc.SCDynamicStoreCopyProxies(None)

    try:
        # Check for simple host names:
        if '.' not in host:
            exclude_simple = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesExcludeSimpleHostnames)
            if exclude_simple and sc.CFBooleanGetValue(exclude_simple):
                return True


        # Check the exceptions list:
        exceptions = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesExceptionsList)
        if exceptions:
            # Items in the list are strings like these: *.local, 169.254/16
            for index in xrange(sc.CFArrayGetCount(exceptions)):
                value = sc.CFArrayGetValueAtIndex(exceptions, index)
                if not value: continue
                value = _CStringFromCFString(sc, value)

                m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
                if m is not None:
                    if hostIP is None:
                        hostIP = socket.gethostbyname(host)
                        hostIP = ip2num(hostIP)

                    base = ip2num(m.group(1))
                    mask = int(m.group(2)[1:])
                    mask = 32 - mask

                    if (hostIP >> mask) == (base >> mask):
                        return True

                elif fnmatch(host, value):
                    return True
                
        return False

    finally:
        sc.CFRelease(kSCPropNetProxiesExceptionsList)
        sc.CFRelease(kSCPropNetProxiesExcludeSimpleHostnames)



def getproxies_macosx_sysconf():
    """Return a dictionary of scheme -> proxy server URL mappings.
   
    This function uses the MacOSX framework SystemConfiguration
    to fetch the proxy information.
    """
    from ctypes import cdll
    from ctypes.util import find_library

    sc = cdll.LoadLibrary(find_library("SystemConfiguration"))

    if not sc:
        return {}


    kCFNumberSInt32Type = 3
    kSCPropNetProxiesHTTPEnable = sc.CFStringCreateWithCString(0, "HTTPEnable", 0)
    kSCPropNetProxiesHTTPProxy = sc.CFStringCreateWithCString(0, "HTTPProxy", 0)
    kSCPropNetProxiesHTTPPort = sc.CFStringCreateWithCString(0, "HTTPPort", 0)

    kSCPropNetProxiesHTTPSEnable = sc.CFStringCreateWithCString(0, "HTTPSEnable", 0)
    kSCPropNetProxiesHTTPSProxy = sc.CFStringCreateWithCString(0, "HTTPSProxy", 0)
    kSCPropNetProxiesHTTPSPort = sc.CFStringCreateWithCString(0, "HTTPSPort", 0)

    kSCPropNetProxiesFTPEnable = sc.CFStringCreateWithCString(0, "FTPEnable", 0)
    kSCPropNetProxiesFTPPassive = sc.CFStringCreateWithCString(0, "FTPPassive", 0)
    kSCPropNetProxiesFTPPort = sc.CFStringCreateWithCString(0, "FTPPort", 0)
    kSCPropNetProxiesFTPProxy = sc.CFStringCreateWithCString(0, "FTPProxy", 0)

    kSCPropNetProxiesGopherEnable = sc.CFStringCreateWithCString(0, "GopherEnable", 0)
    kSCPropNetProxiesGopherPort = sc.CFStringCreateWithCString(0, "GopherPort", 0)
    kSCPropNetProxiesGopherProxy = sc.CFStringCreateWithCString(0, "GopherProxy", 0)

    proxies = {}
    proxyDict = sc.SCDynamicStoreCopyProxies(None)
    try:
        # HTTP:
        enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPEnable)
        if enabled and sc.CFBooleanGetValue(enabled):
            proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPProxy)
            port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPPort)

            if proxy:
                proxy = _CStringFromCFString(sc, proxy)
                if port:
                    port = _CFNumberToInt32(sc, port)
                    proxies["http"] = "http://%s:%i"; % (proxy, port)
                else:
                    proxies["http"] = "http://%s"; % (proxy, )

        # HTTPS:
        enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSEnable)
        if enabled and sc.CFBooleanGetValue(enabled):
            proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSProxy)
            port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSPort)

            if proxy:
                proxy = _CStringFromCFString(sc, proxy)
                if port:
                    port = _CFNumberToInt32(sc, port)
                    proxies["https"] = "http://%s:%i"; % (proxy, port)
                else:
                    proxies["https"] = "http://%s"; % (proxy, )

        # FTP:
        enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPEnable)
        if enabled and sc.CFBooleanGetValue(enabled):
            proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPProxy)
            port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPPort)

            if proxy:
                proxy = _CStringFromCFString(sc, proxy)
                if port:
                    port = _CFNumberToInt32(sc, port)
                    proxies["ftp"] = "http://%s:%i"; % (proxy, port)
                else:
                    proxies["ftp"] = "http://%s"; % (proxy, )

        # Gopher: 
        enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherEnable)
        if enabled and sc.CFBooleanGetValue(enabled):
            proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherProxy)
            port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherPort)

            if proxy:
                proxy = _CStringFromCFString(sc, proxy)
                if port:
                    port = _CFNumberToInt32(sc, port)
                    proxies["gopher"] = "http://%s:%i"; % (proxy, port)
                else:
                    proxies["gopher"] = "http://%s"; % (proxy, )
    finally:
        sc.CFRelease(proxyDict)

    sc.CFRelease(kSCPropNetProxiesHTTPEnable)
    sc.CFRelease(kSCPropNetProxiesHTTPProxy)
    sc.CFRelease(kSCPropNetProxiesHTTPPort)
    sc.CFRelease(kSCPropNetProxiesFTPEnable)
    sc.CFRelease(kSCPropNetProxiesFTPPassive)
    sc.CFRelease(kSCPropNetProxiesFTPPort)
    sc.CFRelease(kSCPropNetProxiesFTPProxy)
    sc.CFRelease(kSCPropNetProxiesGopherEnable)
    sc.CFRelease(kSCPropNetProxiesGopherPort)
    sc.CFRelease(kSCPropNetProxiesGopherProxy)

    return proxies



print getproxies_macosx_sysconf()
print proxybypass_macosx_sysconf("169.254.10.10")


On 14 Apr, 2008, at 14:24, Daniel Miller wrote:

Thanks Nicholas,

The general CF rule is that if you use a function named *Get*, then you don't need to CFRelease; if you use a function named *Copy* or *Create*, you do. So, what you've written looks fine.

With that in mind one further modification seems to be necessary. Take three attached.

~ Daniel

< urllib_contribution.py>_______________________________________________
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig

_______________________________________________
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig

Reply via email to