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
cfnum_to_int32(CFNumberRef num)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*
cfstring_to_pystring(CFStringRef ref)18 cfstring_to_pystring(CFStringRef ref)
19 {
20 const char* s;
21
22 s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
23 if (s) {
24 return PyString_FromString(s);
25
26 } else {
27 CFIndex len = CFStringGetLength(ref);
28 Boolean ok;
29 PyObject* result;
30 result = PyString_FromStringAndSize(NULL, len*4);
31
32 ok = CFStringGetCString(ref,
33 PyString_AS_STRING(result),
34 PyString_GET_SIZE(result),
35 kCFStringEncodingUTF8);
36 if (!ok) {
37 Py_DECREF(result);
38 return NULL;
39 } else {
40 _PyString_Resize(&result,
41 strlen(PyString_AS_STRING(result)));
42 }
43 return result;
44 }
45 }
46
47
48 static PyObject*
get_proxy_settings(PyObject * mod)49 get_proxy_settings(PyObject* mod __attribute__((__unused__)))
50 {
51 CFDictionaryRef proxyDict = NULL;
52 CFNumberRef aNum = NULL;
53 CFArrayRef anArray = NULL;
54 PyObject* result = NULL;
55 PyObject* v;
56 int r;
57
58 proxyDict = SCDynamicStoreCopyProxies(NULL);
59 if (!proxyDict) {
60 Py_INCREF(Py_None);
61 return Py_None;
62 }
63
64 result = PyDict_New();
65 if (result == NULL) goto error;
66
67 if (&kSCPropNetProxiesExcludeSimpleHostnames != NULL) {
68 aNum = CFDictionaryGetValue(proxyDict,
69 kSCPropNetProxiesExcludeSimpleHostnames);
70 if (aNum == NULL) {
71 v = PyBool_FromLong(0);
72 } else {
73 v = PyBool_FromLong(cfnum_to_int32(aNum));
74 }
75 } else {
76 v = PyBool_FromLong(0);
77 }
78
79 if (v == NULL) goto error;
80
81 r = PyDict_SetItemString(result, "exclude_simple", v);
82 Py_DECREF(v); v = NULL;
83 if (r == -1) goto error;
84
85 anArray = CFDictionaryGetValue(proxyDict,
86 kSCPropNetProxiesExceptionsList);
87 if (anArray != NULL) {
88 CFIndex len = CFArrayGetCount(anArray);
89 CFIndex i;
90 v = PyTuple_New(len);
91 if (v == NULL) goto error;
92
93 r = PyDict_SetItemString(result, "exceptions", v);
94 Py_DECREF(v);
95 if (r == -1) goto error;
96
97 for (i = 0; i < len; i++) {
98 CFStringRef aString = NULL;
99
100 aString = CFArrayGetValueAtIndex(anArray, i);
101 if (aString == NULL) {
102 PyTuple_SetItem(v, i, Py_None);
103 Py_INCREF(Py_None);
104 } else {
105 PyObject* t = cfstring_to_pystring(aString);
106 if (!t) {
107 PyTuple_SetItem(v, i, Py_None);
108 Py_INCREF(Py_None);
109 } else {
110 PyTuple_SetItem(v, i, t);
111 }
112 }
113 }
114 }
115
116 CFRelease(proxyDict);
117 return result;
118
119 error:
120 if (proxyDict) CFRelease(proxyDict);
121 Py_XDECREF(result);
122 return NULL;
123 }
124
125 static int
set_proxy(PyObject * proxies,char * proto,CFDictionaryRef proxyDict,CFStringRef enabledKey,CFStringRef hostKey,CFStringRef portKey)126 set_proxy(PyObject* proxies, char* proto, CFDictionaryRef proxyDict,
127 CFStringRef enabledKey,
128 CFStringRef hostKey, CFStringRef portKey)
129 {
130 CFNumberRef aNum;
131
132 aNum = CFDictionaryGetValue(proxyDict, enabledKey);
133 if (aNum && cfnum_to_int32(aNum)) {
134 CFStringRef hostString;
135
136 hostString = CFDictionaryGetValue(proxyDict, hostKey);
137 aNum = CFDictionaryGetValue(proxyDict, portKey);
138
139 if (hostString) {
140 int r;
141 PyObject* h = cfstring_to_pystring(hostString);
142 PyObject* v;
143 if (h) {
144 if (aNum) {
145 int32_t port = cfnum_to_int32(aNum);
146 v = PyString_FromFormat("http://%s:%ld",
147 PyString_AS_STRING(h),
148 (long)port);
149 } else {
150 v = PyString_FromFormat("http://%s",
151 PyString_AS_STRING(h));
152 }
153 Py_DECREF(h);
154 if (!v) return -1;
155 r = PyDict_SetItemString(proxies, proto,
156 v);
157 Py_DECREF(v);
158 return r;
159 }
160 }
161
162 }
163 return 0;
164 }
165
166
167
168 static PyObject*
get_proxies(PyObject * mod)169 get_proxies(PyObject* mod __attribute__((__unused__)))
170 {
171 PyObject* result = NULL;
172 int r;
173 CFDictionaryRef proxyDict = NULL;
174
175 proxyDict = SCDynamicStoreCopyProxies(NULL);
176 if (proxyDict == NULL) {
177 return PyDict_New();
178 }
179
180 result = PyDict_New();
181 if (result == NULL) goto error;
182
183 r = set_proxy(result, "http", proxyDict,
184 kSCPropNetProxiesHTTPEnable,
185 kSCPropNetProxiesHTTPProxy,
186 kSCPropNetProxiesHTTPPort);
187 if (r == -1) goto error;
188 r = set_proxy(result, "https", proxyDict,
189 kSCPropNetProxiesHTTPSEnable,
190 kSCPropNetProxiesHTTPSProxy,
191 kSCPropNetProxiesHTTPSPort);
192 if (r == -1) goto error;
193 r = set_proxy(result, "ftp", proxyDict,
194 kSCPropNetProxiesFTPEnable,
195 kSCPropNetProxiesFTPProxy,
196 kSCPropNetProxiesFTPPort);
197 if (r == -1) goto error;
198 r = set_proxy(result, "gopher", proxyDict,
199 kSCPropNetProxiesGopherEnable,
200 kSCPropNetProxiesGopherProxy,
201 kSCPropNetProxiesGopherPort);
202 if (r == -1) goto error;
203
204 CFRelease(proxyDict);
205 return result;
206 error:
207 if (proxyDict) CFRelease(proxyDict);
208 Py_XDECREF(result);
209 return NULL;
210 }
211
212 static PyMethodDef mod_methods[] = {
213 {
214 "_get_proxy_settings",
215 (PyCFunction)get_proxy_settings,
216 METH_NOARGS,
217 NULL,
218 },
219 {
220 "_get_proxies",
221 (PyCFunction)get_proxies,
222 METH_NOARGS,
223 NULL,
224 },
225 { 0, 0, 0, 0 }
226 };
227
init_scproxy(void)228 void init_scproxy(void)
229 {
230 (void)Py_InitModule4("_scproxy", mod_methods, NULL, NULL, PYTHON_API_VERSION);
231 }
232