Skip to content

Commit 9dd6b1d

Browse files
MacOSX: remove dependency on Carbon package for urllib
This patch removes the dependency on the Carbon package from urllib. The mac-specific code for getting proxy configuration is now writting in Python using ctypes and uses the SystemConfiguration framework instead of InternetConfig. Also provides a mac-specific implementation of proxy_bypass.
1 parent 81af68e commit 9dd6b1d

File tree

1 file changed

+194
-24
lines changed

1 file changed

+194
-24
lines changed

Lib/urllib.py

Lines changed: 194 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,44 +1321,214 @@ def proxy_bypass_environment(host):
13211321

13221322

13231323
if sys.platform == 'darwin':
1324-
def getproxies_internetconfig():
1325-
"""Return a dictionary of scheme -> proxy server URL mappings.
1326-
1327-
By convention the mac uses Internet Config to store
1328-
proxies. An HTTP proxy, for instance, is stored under
1329-
the HttpProxy key.
1324+
def _CStringFromCFString(sc, value):
1325+
from ctypes import create_string_buffer
1326+
length = sc.CFStringGetLength(value) + 1
1327+
buff = create_string_buffer(length)
1328+
sc.CFStringGetCString(value, buff, length, 0)
1329+
return buff.value
1330+
1331+
def _CFNumberToInt32(sc, cfnum):
1332+
from ctypes import byref, c_int
1333+
val = c_int()
1334+
kCFNumberSInt32Type = 3
1335+
sc.CFNumberGetValue(cfnum, kCFNumberSInt32Type, byref(val))
1336+
return val.value
1337+
1338+
1339+
def proxy_bypass_macosx_sysconf(host):
1340+
"""
1341+
Return True iff this host shouldn't be accessed using a proxy
13301342
1343+
This function uses the MacOSX framework SystemConfiguration
1344+
to fetch the proxy information.
13311345
"""
1332-
try:
1333-
import ic
1334-
except ImportError:
1335-
return {}
1346+
from ctypes import cdll
1347+
from ctypes.util import find_library
1348+
import re
1349+
import socket
1350+
from fnmatch import fnmatch
1351+
1352+
def ip2num(ipAddr):
1353+
parts = ipAddr.split('.')
1354+
parts = map(int, parts)
1355+
if len(parts) != 4:
1356+
parts = (parts + [0, 0, 0, 0])[:4]
1357+
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
1358+
1359+
sc = cdll.LoadLibrary(find_library("SystemConfiguration"))
1360+
1361+
hostIP = None
1362+
1363+
if not sc:
1364+
return False
1365+
1366+
kSCPropNetProxiesExceptionsList = sc.CFStringCreateWithCString(0, "ExceptionsList", 0)
1367+
kSCPropNetProxiesExcludeSimpleHostnames = sc.CFStringCreateWithCString(0,
1368+
"ExcludeSimpleHostnames", 0)
1369+
1370+
1371+
proxyDict = sc.SCDynamicStoreCopyProxies(None)
13361372

13371373
try:
1338-
config = ic.IC()
1339-
except ic.error:
1374+
# Check for simple host names:
1375+
if '.' not in host:
1376+
exclude_simple = sc.CFDictionaryGetValue(proxyDict,
1377+
kSCPropNetProxiesExcludeSimpleHostnames)
1378+
if exclude_simple and _CFNumberToInt32(sc, exclude_simple):
1379+
return True
1380+
1381+
1382+
# Check the exceptions list:
1383+
exceptions = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesExceptionsList)
1384+
if exceptions:
1385+
# Items in the list are strings like these: *.local, 169.254/16
1386+
for index in xrange(sc.CFArrayGetCount(exceptions)):
1387+
value = sc.CFArrayGetValueAtIndex(exceptions, index)
1388+
if not value: continue
1389+
value = _CStringFromCFString(sc, value)
1390+
1391+
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
1392+
if m is not None:
1393+
if hostIP is None:
1394+
hostIP = socket.gethostbyname(host)
1395+
hostIP = ip2num(hostIP)
1396+
1397+
base = ip2num(m.group(1))
1398+
mask = int(m.group(2)[1:])
1399+
mask = 32 - mask
1400+
1401+
if (hostIP >> mask) == (base >> mask):
1402+
return True
1403+
1404+
elif fnmatch(host, value):
1405+
return True
1406+
1407+
return False
1408+
1409+
finally:
1410+
sc.CFRelease(kSCPropNetProxiesExceptionsList)
1411+
sc.CFRelease(kSCPropNetProxiesExcludeSimpleHostnames)
1412+
1413+
1414+
1415+
def getproxies_macosx_sysconf():
1416+
"""Return a dictionary of scheme -> proxy server URL mappings.
1417+
1418+
This function uses the MacOSX framework SystemConfiguration
1419+
to fetch the proxy information.
1420+
"""
1421+
from ctypes import cdll
1422+
from ctypes.util import find_library
1423+
1424+
sc = cdll.LoadLibrary(find_library("SystemConfiguration"))
1425+
1426+
if not sc:
13401427
return {}
1428+
1429+
1430+
kSCPropNetProxiesHTTPEnable = sc.CFStringCreateWithCString(0, "HTTPEnable", 0)
1431+
kSCPropNetProxiesHTTPProxy = sc.CFStringCreateWithCString(0, "HTTPProxy", 0)
1432+
kSCPropNetProxiesHTTPPort = sc.CFStringCreateWithCString(0, "HTTPPort", 0)
1433+
1434+
kSCPropNetProxiesHTTPSEnable = sc.CFStringCreateWithCString(0, "HTTPSEnable", 0)
1435+
kSCPropNetProxiesHTTPSProxy = sc.CFStringCreateWithCString(0, "HTTPSProxy", 0)
1436+
kSCPropNetProxiesHTTPSPort = sc.CFStringCreateWithCString(0, "HTTPSPort", 0)
1437+
1438+
kSCPropNetProxiesFTPEnable = sc.CFStringCreateWithCString(0, "FTPEnable", 0)
1439+
kSCPropNetProxiesFTPPassive = sc.CFStringCreateWithCString(0, "FTPPassive", 0)
1440+
kSCPropNetProxiesFTPPort = sc.CFStringCreateWithCString(0, "FTPPort", 0)
1441+
kSCPropNetProxiesFTPProxy = sc.CFStringCreateWithCString(0, "FTPProxy", 0)
1442+
1443+
kSCPropNetProxiesGopherEnable = sc.CFStringCreateWithCString(0, "GopherEnable", 0)
1444+
kSCPropNetProxiesGopherPort = sc.CFStringCreateWithCString(0, "GopherPort", 0)
1445+
kSCPropNetProxiesGopherProxy = sc.CFStringCreateWithCString(0, "GopherProxy", 0)
1446+
13411447
proxies = {}
1342-
# HTTP:
1343-
if 'UseHTTPProxy' in config and config['UseHTTPProxy']:
1344-
try:
1345-
value = config['HTTPProxyHost']
1346-
except ic.error:
1347-
pass
1348-
else:
1349-
proxies['http'] = 'http://%s' % value
1350-
# FTP: XXX To be done.
1351-
# Gopher: XXX To be done.
1448+
proxyDict = sc.SCDynamicStoreCopyProxies(None)
1449+
1450+
try:
1451+
# HTTP:
1452+
enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPEnable)
1453+
if enabled and _CFNumberToInt32(sc, enabled):
1454+
proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPProxy)
1455+
port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPPort)
1456+
1457+
if proxy:
1458+
proxy = _CStringFromCFString(sc, proxy)
1459+
if port:
1460+
port = _CFNumberToInt32(sc, port)
1461+
proxies["http"] = "http://%s:%i" % (proxy, port)
1462+
else:
1463+
proxies["http"] = "http://%s" % (proxy, )
1464+
1465+
# HTTPS:
1466+
enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSEnable)
1467+
if enabled and _CFNumberToInt32(sc, enabled):
1468+
proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSProxy)
1469+
port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesHTTPSPort)
1470+
1471+
if proxy:
1472+
proxy = _CStringFromCFString(sc, proxy)
1473+
if port:
1474+
port = _CFNumberToInt32(sc, port)
1475+
proxies["https"] = "http://%s:%i" % (proxy, port)
1476+
else:
1477+
proxies["https"] = "http://%s" % (proxy, )
1478+
1479+
# FTP:
1480+
enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPEnable)
1481+
if enabled and _CFNumberToInt32(sc, enabled):
1482+
proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPProxy)
1483+
port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPPort)
1484+
1485+
if proxy:
1486+
proxy = _CStringFromCFString(sc, proxy)
1487+
if port:
1488+
port = _CFNumberToInt32(sc, port)
1489+
proxies["ftp"] = "http://%s:%i" % (proxy, port)
1490+
else:
1491+
proxies["ftp"] = "http://%s" % (proxy, )
1492+
1493+
# Gopher:
1494+
enabled = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherEnable)
1495+
if enabled and _CFNumberToInt32(sc, enabled):
1496+
proxy = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherProxy)
1497+
port = sc.CFDictionaryGetValue(proxyDict, kSCPropNetProxiesGopherPort)
1498+
1499+
if proxy:
1500+
proxy = _CStringFromCFString(sc, proxy)
1501+
if port:
1502+
port = _CFNumberToInt32(sc, port)
1503+
proxies["gopher"] = "http://%s:%i" % (proxy, port)
1504+
else:
1505+
proxies["gopher"] = "http://%s" % (proxy, )
1506+
finally:
1507+
sc.CFRelease(proxyDict)
1508+
1509+
sc.CFRelease(kSCPropNetProxiesHTTPEnable)
1510+
sc.CFRelease(kSCPropNetProxiesHTTPProxy)
1511+
sc.CFRelease(kSCPropNetProxiesHTTPPort)
1512+
sc.CFRelease(kSCPropNetProxiesFTPEnable)
1513+
sc.CFRelease(kSCPropNetProxiesFTPPassive)
1514+
sc.CFRelease(kSCPropNetProxiesFTPPort)
1515+
sc.CFRelease(kSCPropNetProxiesFTPProxy)
1516+
sc.CFRelease(kSCPropNetProxiesGopherEnable)
1517+
sc.CFRelease(kSCPropNetProxiesGopherPort)
1518+
sc.CFRelease(kSCPropNetProxiesGopherProxy)
1519+
13521520
return proxies
13531521

1522+
1523+
13541524
def proxy_bypass(host):
13551525
if getproxies_environment():
13561526
return proxy_bypass_environment(host)
13571527
else:
1358-
return 0
1528+
return proxy_bypass_macosx_sysconf(host)
13591529

13601530
def getproxies():
1361-
return getproxies_environment() or getproxies_internetconfig()
1531+
return getproxies_environment() or getproxies_macosx_sysconf()
13621532

13631533
elif os.name == 'nt':
13641534
def getproxies_registry():

0 commit comments

Comments
 (0)