Merged revisions 80198 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r80198 | ronald.oussoren | 2010-04-18 22:46:11 +0200 (Sun, 18 Apr 2010) | 4 lines

  For for issue #7154: Port the code that uses
  the SystemConfiguration framework to detect the
  proxy settings on OSX from the trunk to python 3.2
........
This commit is contained in:
Ronald Oussoren 2010-04-18 20:49:34 +00:00
parent b136a9c9d7
commit 218cc58d08
4 changed files with 335 additions and 27 deletions

View File

@ -2142,44 +2142,82 @@ def proxy_bypass_environment(host):
if sys.platform == 'darwin': if sys.platform == 'darwin':
def getproxies_internetconfig(): from _scproxy import _get_proxy_settings, _get_proxies
def proxy_bypass_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.
"""
import re
import socket
from fnmatch import fnmatch
hostonly, port = splitport(host)
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]
proxy_settings = _get_proxy_settings()
# Check for simple host names:
if '.' not in host:
if proxy_settings['exclude_simple']:
return True
hostIP = None
for value in proxy_settings.get('exceptions', ()):
# Items in the list are strings like these: *.local, 169.254/16
if not value: continue
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
if m is not None:
if hostIP is None:
try:
hostIP = socket.gethostbyname(hostonly)
hostIP = ip2num(hostIP)
except socket.error:
continue
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
def getproxies_macosx_sysconf():
"""Return a dictionary of scheme -> proxy server URL mappings. """Return a dictionary of scheme -> proxy server URL mappings.
By convention the mac uses Internet Config to store This function uses the MacOSX framework SystemConfiguration
proxies. An HTTP proxy, for instance, is stored under to fetch the proxy information.
the HttpProxy key.
""" """
try: return _get_proxies()
import ic
except ImportError:
return {}
try:
config = ic.IC()
except ic.error:
return {}
proxies = {}
# HTTP:
if 'UseHTTPProxy' in config and config['UseHTTPProxy']:
try:
value = config['HTTPProxyHost']
except ic.error:
pass
else:
proxies['http'] = 'http://%s' % value
# FTP: XXX To be done.
# Gopher: XXX To be done.
return proxies
def proxy_bypass(host): def proxy_bypass(host):
if getproxies_environment(): if getproxies_environment():
return proxy_bypass_environment(host) return proxy_bypass_environment(host)
else: else:
return 0 return proxy_bypass_macosx_sysconf(host)
def getproxies(): def getproxies():
return getproxies_environment() or getproxies_internetconfig() return getproxies_environment() or getproxies_macosx_sysconf()
elif os.name == 'nt': elif os.name == 'nt':
def getproxies_registry(): def getproxies_registry():

View File

@ -198,6 +198,9 @@ Core and Builtins
Library Library
------- -------
- Issue #7154: urllib.request can now detect the proxy settings on OSX 10.6
(as long as the user didn't specify 'automatic proxy configuration').
- Issue #8412: os.system() now accepts bytes, bytearray and str with - Issue #8412: os.system() now accepts bytes, bytearray and str with
surrogates. surrogates.

261
Modules/_scproxy.c Normal file
View File

@ -0,0 +1,261 @@
/*
* Helper method for urllib to fetch the proxy configuration settings
* using the SystemConfiguration framework.
*/
#include <Python.h>
#include <SystemConfiguration/SystemConfiguration.h>
static int32_t
cfnum_to_int32(CFNumberRef num)
{
int32_t result;
CFNumberGetValue(num, kCFNumberSInt32Type, &result);
return result;
}
static PyObject*
cfstring_to_pystring(CFStringRef ref)
{
const char* s;
s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
if (s) {
return PyUnicode_DecodeUTF8(
s, strlen(s), NULL);
} else {
CFIndex len = CFStringGetLength(ref);
Boolean ok;
PyObject* result;
char* buf;
buf = PyMem_Malloc(len*4);
if (buf == NULL) {
PyErr_NoMemory();
return NULL;
}
ok = CFStringGetCString(ref,
buf, len * 4,
kCFStringEncodingUTF8);
if (!ok) {
PyMem_Free(buf);
return NULL;
} else {
result = PyUnicode_DecodeUTF8(
buf, strlen(buf), NULL);
PyMem_Free(buf);
}
return result;
}
}
static PyObject*
get_proxy_settings(PyObject* mod __attribute__((__unused__)))
{
CFDictionaryRef proxyDict = NULL;
CFNumberRef aNum = NULL;
CFArrayRef anArray = NULL;
PyObject* result = NULL;
PyObject* v;
int r;
proxyDict = SCDynamicStoreCopyProxies(NULL);
if (!proxyDict) {
Py_INCREF(Py_None);
return Py_None;
}
result = PyDict_New();
if (result == NULL) goto error;
if (&kSCPropNetProxiesExcludeSimpleHostnames != NULL) {
aNum = CFDictionaryGetValue(proxyDict,
kSCPropNetProxiesExcludeSimpleHostnames);
if (aNum == NULL) {
v = PyBool_FromLong(1);
} else {
v = PyBool_FromLong(cfnum_to_int32(aNum));
}
} else {
v = PyBool_FromLong(1);
}
if (v == NULL) goto error;
r = PyDict_SetItemString(result, "exclude_simple", v);
Py_DECREF(v); v = NULL;
if (r == -1) goto error;
anArray = CFDictionaryGetValue(proxyDict,
kSCPropNetProxiesExceptionsList);
if (anArray != NULL) {
CFIndex len = CFArrayGetCount(anArray);
CFIndex i;
v = PyTuple_New(len);
if (v == NULL) goto error;
r = PyDict_SetItemString(result, "exceptions", v);
Py_DECREF(v);
if (r == -1) goto error;
for (i = 0; i < len; i++) {
CFStringRef aString = NULL;
aString = CFArrayGetValueAtIndex(anArray, i);
if (aString == NULL) {
PyTuple_SetItem(v, i, Py_None);
Py_INCREF(Py_None);
} else {
PyObject* t = cfstring_to_pystring(aString);
if (!t) {
PyTuple_SetItem(v, i, Py_None);
Py_INCREF(Py_None);
} else {
PyTuple_SetItem(v, i, t);
}
}
}
}
CFRelease(proxyDict);
return result;
error:
if (proxyDict) CFRelease(proxyDict);
Py_XDECREF(result);
return NULL;
}
static int
set_proxy(PyObject* proxies, char* proto, CFDictionaryRef proxyDict,
CFStringRef enabledKey,
CFStringRef hostKey, CFStringRef portKey)
{
CFNumberRef aNum;
aNum = CFDictionaryGetValue(proxyDict, enabledKey);
if (aNum && cfnum_to_int32(aNum)) {
CFStringRef hostString;
hostString = CFDictionaryGetValue(proxyDict, hostKey);
aNum = CFDictionaryGetValue(proxyDict, portKey);
if (hostString) {
int r;
PyObject* h = cfstring_to_pystring(hostString);
PyObject* v;
if (h) {
if (aNum) {
int32_t port = cfnum_to_int32(aNum);
v = PyUnicode_FromFormat("http://%U:%ld",
h, (long)port);
} else {
v = PyUnicode_FromFormat("http://%U", h);
}
Py_DECREF(h);
if (!v) return -1;
r = PyDict_SetItemString(proxies, proto,
v);
Py_DECREF(v);
return r;
}
}
}
return 0;
}
static PyObject*
get_proxies(PyObject* mod __attribute__((__unused__)))
{
PyObject* result = NULL;
int r;
CFDictionaryRef proxyDict = NULL;
proxyDict = SCDynamicStoreCopyProxies(NULL);
if (proxyDict == NULL) {
return PyDict_New();
}
result = PyDict_New();
if (result == NULL) goto error;
r = set_proxy(result, "http", proxyDict,
kSCPropNetProxiesHTTPEnable,
kSCPropNetProxiesHTTPProxy,
kSCPropNetProxiesHTTPPort);
if (r == -1) goto error;
r = set_proxy(result, "https", proxyDict,
kSCPropNetProxiesHTTPSEnable,
kSCPropNetProxiesHTTPSProxy,
kSCPropNetProxiesHTTPSPort);
if (r == -1) goto error;
r = set_proxy(result, "ftp", proxyDict,
kSCPropNetProxiesFTPEnable,
kSCPropNetProxiesFTPProxy,
kSCPropNetProxiesFTPPort);
if (r == -1) goto error;
r = set_proxy(result, "gopher", proxyDict,
kSCPropNetProxiesGopherEnable,
kSCPropNetProxiesGopherProxy,
kSCPropNetProxiesGopherPort);
if (r == -1) goto error;
CFRelease(proxyDict);
return result;
error:
if (proxyDict) CFRelease(proxyDict);
Py_XDECREF(result);
return NULL;
}
static PyMethodDef mod_methods[] = {
{
"_get_proxy_settings",
(PyCFunction)get_proxy_settings,
METH_NOARGS,
NULL,
},
{
"_get_proxies",
(PyCFunction)get_proxies,
METH_NOARGS,
NULL,
},
{ 0, 0, 0, 0 }
};
static struct PyModuleDef mod_module = {
PyModuleDef_HEAD_INIT,
"_scproxy",
NULL,
-1,
mod_methods,
NULL,
NULL,
NULL,
NULL
};
#ifdef __cplusplus
extern "C" {
#endif
PyObject*
PyInit__scproxy(void)
{
return PyModule_Create(&mod_module);
}
#ifdef __cplusplus
}
#endif

View File

@ -1218,6 +1218,12 @@ class PyBuildExt(build_ext):
Extension('_gestalt', ['_gestalt.c'], Extension('_gestalt', ['_gestalt.c'],
extra_link_args=['-framework', 'Carbon']) extra_link_args=['-framework', 'Carbon'])
) )
exts.append(
Extension('_scproxy', ['_scproxy.c'],
extra_link_args=[
'-framework', 'SystemConfiguration',
'-framework', 'CoreFoundation',
]))
self.extensions.extend(exts) self.extensions.extend(exts)