Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8415120

Browse files
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
1 parent f88db8d commit 8415120

4 files changed

Lines changed: 335 additions & 27 deletions

File tree

Lib/urllib/request.py

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,44 +2140,82 @@ def proxy_bypass_environment(host):
21402140

21412141

21422142
if sys.platform == 'darwin':
2143-
def getproxies_internetconfig():
2144-
"""Return a dictionary of scheme -> proxy server URL mappings.
2143+
from _scproxy import _get_proxy_settings, _get_proxies
21452144

2146-
By convention the mac uses Internet Config to store
2147-
proxies. An HTTP proxy, for instance, is stored under
2148-
the HttpProxy key.
2145+
def proxy_bypass_macosx_sysconf(host):
2146+
"""
2147+
Return True iff this host shouldn't be accessed using a proxy
21492148
2149+
This function uses the MacOSX framework SystemConfiguration
2150+
to fetch the proxy information.
21502151
"""
2151-
try:
2152-
import ic
2153-
except ImportError:
2154-
return {}
2152+
import re
2153+
import socket
2154+
from fnmatch import fnmatch
2155+
2156+
hostonly, port = splitport(host)
2157+
2158+
def ip2num(ipAddr):
2159+
parts = ipAddr.split('.')
2160+
parts = map(int, parts)
2161+
if len(parts) != 4:
2162+
parts = (parts + [0, 0, 0, 0])[:4]
2163+
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
2164+
2165+
proxy_settings = _get_proxy_settings()
2166+
2167+
# Check for simple host names:
2168+
if '.' not in host:
2169+
if proxy_settings['exclude_simple']:
2170+
return True
2171+
2172+
hostIP = None
2173+
2174+
for value in proxy_settings.get('exceptions', ()):
2175+
# Items in the list are strings like these: *.local, 169.254/16
2176+
if not value: continue
2177+
2178+
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
2179+
if m is not None:
2180+
if hostIP is None:
2181+
try:
2182+
hostIP = socket.gethostbyname(hostonly)
2183+
hostIP = ip2num(hostIP)
2184+
except socket.error:
2185+
continue
2186+
2187+
base = ip2num(m.group(1))
2188+
mask = int(m.group(2)[1:])
2189+
mask = 32 - mask
2190+
2191+
if (hostIP >> mask) == (base >> mask):
2192+
return True
2193+
2194+
elif fnmatch(host, value):
2195+
return True
2196+
2197+
return False
2198+
2199+
2200+
def getproxies_macosx_sysconf():
2201+
"""Return a dictionary of scheme -> proxy server URL mappings.
2202+
2203+
This function uses the MacOSX framework SystemConfiguration
2204+
to fetch the proxy information.
2205+
"""
2206+
return _get_proxies()
2207+
21552208

2156-
try:
2157-
config = ic.IC()
2158-
except ic.error:
2159-
return {}
2160-
proxies = {}
2161-
# HTTP:
2162-
if 'UseHTTPProxy' in config and config['UseHTTPProxy']:
2163-
try:
2164-
value = config['HTTPProxyHost']
2165-
except ic.error:
2166-
pass
2167-
else:
2168-
proxies['http'] = 'http://%s' % value
2169-
# FTP: XXX To be done.
2170-
# Gopher: XXX To be done.
2171-
return proxies
21722209

21732210
def proxy_bypass(host):
21742211
if getproxies_environment():
21752212
return proxy_bypass_environment(host)
21762213
else:
2177-
return 0
2214+
return proxy_bypass_macosx_sysconf(host)
21782215

21792216
def getproxies():
2180-
return getproxies_environment() or getproxies_internetconfig()
2217+
return getproxies_environment() or getproxies_macosx_sysconf()
2218+
21812219

21822220
elif os.name == 'nt':
21832221
def getproxies_registry():

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ C-API
318318
Library
319319
-------
320320

321+
- Issue #7154: urllib.request can now detect the proxy settings on OSX 10.6
322+
(as long as the user didn't specify 'automatic proxy configuration').
323+
321324
- Issue #3817: ftplib.FTP.abort() method now considers 225 a valid response
322325
code as stated in RFC-959 at chapter 5.4.
323326

Modules/_scproxy.c

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Helper method for urllib to fetch the proxy configuration settings
3+
* using the SystemConfiguration framework.
4+
*/
5+
#include <Python.h>
6+
#include <SystemConfiguration/SystemConfiguration.h>
7+
8+
static int32_t
9+
cfnum_to_int32(CFNumberRef num)
10+
{
11+
int32_t result;
12+
13+
CFNumberGetValue(num, kCFNumberSInt32Type, &result);
14+
return result;
15+
}
16+
17+
static PyObject*
18+
cfstring_to_pystring(CFStringRef ref)
19+
{
20+
const char* s;
21+
22+
s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
23+
if (s) {
24+
return PyUnicode_DecodeUTF8(
25+
s, strlen(s), NULL);
26+
27+
} else {
28+
CFIndex len = CFStringGetLength(ref);
29+
Boolean ok;
30+
PyObject* result;
31+
char* buf;
32+
33+
buf = PyMem_Malloc(len*4);
34+
if (buf == NULL) {
35+
PyErr_NoMemory();
36+
return NULL;
37+
}
38+
39+
ok = CFStringGetCString(ref,
40+
buf, len * 4,
41+
kCFStringEncodingUTF8);
42+
if (!ok) {
43+
PyMem_Free(buf);
44+
return NULL;
45+
} else {
46+
result = PyUnicode_DecodeUTF8(
47+
buf, strlen(buf), NULL);
48+
PyMem_Free(buf);
49+
}
50+
return result;
51+
}
52+
}
53+
54+
55+
static PyObject*
56+
get_proxy_settings(PyObject* mod __attribute__((__unused__)))
57+
{
58+
CFDictionaryRef proxyDict = NULL;
59+
CFNumberRef aNum = NULL;
60+
CFArrayRef anArray = NULL;
61+
PyObject* result = NULL;
62+
PyObject* v;
63+
int r;
64+
65+
proxyDict = SCDynamicStoreCopyProxies(NULL);
66+
if (!proxyDict) {
67+
Py_INCREF(Py_None);
68+
return Py_None;
69+
}
70+
71+
result = PyDict_New();
72+
if (result == NULL) goto error;
73+
74+
if (&kSCPropNetProxiesExcludeSimpleHostnames != NULL) {
75+
aNum = CFDictionaryGetValue(proxyDict,
76+
kSCPropNetProxiesExcludeSimpleHostnames);
77+
if (aNum == NULL) {
78+
v = PyBool_FromLong(1);
79+
} else {
80+
v = PyBool_FromLong(cfnum_to_int32(aNum));
81+
}
82+
} else {
83+
v = PyBool_FromLong(1);
84+
}
85+
86+
if (v == NULL) goto error;
87+
88+
r = PyDict_SetItemString(result, "exclude_simple", v);
89+
Py_DECREF(v); v = NULL;
90+
if (r == -1) goto error;
91+
92+
anArray = CFDictionaryGetValue(proxyDict,
93+
kSCPropNetProxiesExceptionsList);
94+
if (anArray != NULL) {
95+
CFIndex len = CFArrayGetCount(anArray);
96+
CFIndex i;
97+
v = PyTuple_New(len);
98+
if (v == NULL) goto error;
99+
100+
r = PyDict_SetItemString(result, "exceptions", v);
101+
Py_DECREF(v);
102+
if (r == -1) goto error;
103+
104+
for (i = 0; i < len; i++) {
105+
CFStringRef aString = NULL;
106+
107+
aString = CFArrayGetValueAtIndex(anArray, i);
108+
if (aString == NULL) {
109+
PyTuple_SetItem(v, i, Py_None);
110+
Py_INCREF(Py_None);
111+
} else {
112+
PyObject* t = cfstring_to_pystring(aString);
113+
if (!t) {
114+
PyTuple_SetItem(v, i, Py_None);
115+
Py_INCREF(Py_None);
116+
} else {
117+
PyTuple_SetItem(v, i, t);
118+
}
119+
}
120+
}
121+
}
122+
123+
CFRelease(proxyDict);
124+
return result;
125+
126+
error:
127+
if (proxyDict) CFRelease(proxyDict);
128+
Py_XDECREF(result);
129+
return NULL;
130+
}
131+
132+
static int
133+
set_proxy(PyObject* proxies, char* proto, CFDictionaryRef proxyDict,
134+
CFStringRef enabledKey,
135+
CFStringRef hostKey, CFStringRef portKey)
136+
{
137+
CFNumberRef aNum;
138+
139+
aNum = CFDictionaryGetValue(proxyDict, enabledKey);
140+
if (aNum && cfnum_to_int32(aNum)) {
141+
CFStringRef hostString;
142+
143+
hostString = CFDictionaryGetValue(proxyDict, hostKey);
144+
aNum = CFDictionaryGetValue(proxyDict, portKey);
145+
146+
if (hostString) {
147+
int r;
148+
PyObject* h = cfstring_to_pystring(hostString);
149+
PyObject* v;
150+
if (h) {
151+
if (aNum) {
152+
int32_t port = cfnum_to_int32(aNum);
153+
v = PyUnicode_FromFormat("http://%U:%ld",
154+
h, (long)port);
155+
} else {
156+
v = PyUnicode_FromFormat("http://%U", h);
157+
}
158+
Py_DECREF(h);
159+
if (!v) return -1;
160+
r = PyDict_SetItemString(proxies, proto,
161+
v);
162+
Py_DECREF(v);
163+
return r;
164+
}
165+
}
166+
167+
}
168+
return 0;
169+
}
170+
171+
172+
173+
static PyObject*
174+
get_proxies(PyObject* mod __attribute__((__unused__)))
175+
{
176+
PyObject* result = NULL;
177+
int r;
178+
CFDictionaryRef proxyDict = NULL;
179+
180+
proxyDict = SCDynamicStoreCopyProxies(NULL);
181+
if (proxyDict == NULL) {
182+
return PyDict_New();
183+
}
184+
185+
result = PyDict_New();
186+
if (result == NULL) goto error;
187+
188+
r = set_proxy(result, "http", proxyDict,
189+
kSCPropNetProxiesHTTPEnable,
190+
kSCPropNetProxiesHTTPProxy,
191+
kSCPropNetProxiesHTTPPort);
192+
if (r == -1) goto error;
193+
r = set_proxy(result, "https", proxyDict,
194+
kSCPropNetProxiesHTTPSEnable,
195+
kSCPropNetProxiesHTTPSProxy,
196+
kSCPropNetProxiesHTTPSPort);
197+
if (r == -1) goto error;
198+
r = set_proxy(result, "ftp", proxyDict,
199+
kSCPropNetProxiesFTPEnable,
200+
kSCPropNetProxiesFTPProxy,
201+
kSCPropNetProxiesFTPPort);
202+
if (r == -1) goto error;
203+
r = set_proxy(result, "gopher", proxyDict,
204+
kSCPropNetProxiesGopherEnable,
205+
kSCPropNetProxiesGopherProxy,
206+
kSCPropNetProxiesGopherPort);
207+
if (r == -1) goto error;
208+
209+
CFRelease(proxyDict);
210+
return result;
211+
error:
212+
if (proxyDict) CFRelease(proxyDict);
213+
Py_XDECREF(result);
214+
return NULL;
215+
}
216+
217+
static PyMethodDef mod_methods[] = {
218+
{
219+
"_get_proxy_settings",
220+
(PyCFunction)get_proxy_settings,
221+
METH_NOARGS,
222+
NULL,
223+
},
224+
{
225+
"_get_proxies",
226+
(PyCFunction)get_proxies,
227+
METH_NOARGS,
228+
NULL,
229+
},
230+
{ 0, 0, 0, 0 }
231+
};
232+
233+
234+
235+
static struct PyModuleDef mod_module = {
236+
PyModuleDef_HEAD_INIT,
237+
"_scproxy",
238+
NULL,
239+
-1,
240+
mod_methods,
241+
NULL,
242+
NULL,
243+
NULL,
244+
NULL
245+
};
246+
247+
248+
#ifdef __cplusplus
249+
extern "C" {
250+
#endif
251+
252+
PyObject*
253+
PyInit__scproxy(void)
254+
{
255+
return PyModule_Create(&mod_module);
256+
}
257+
258+
#ifdef __cplusplus
259+
}
260+
#endif
261+

setup.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,12 @@ class db_found(Exception): pass
12381238
Extension('_gestalt', ['_gestalt.c'],
12391239
extra_link_args=['-framework', 'Carbon'])
12401240
)
1241+
exts.append(
1242+
Extension('_scproxy', ['_scproxy.c'],
1243+
extra_link_args=[
1244+
'-framework', 'SystemConfiguration',
1245+
'-framework', 'CoreFoundation',
1246+
]))
12411247

12421248
self.extensions.extend(exts)
12431249

0 commit comments

Comments
 (0)