blob: 4c1f1aa300c7172474a334af4150106b3d659bdc [file] [log] [blame]
Ronald Oussoren84151202010-04-18 20:46:11 +00001/*
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
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00008static int32_t
Ronald Oussoren84151202010-04-18 20:46:11 +00009cfnum_to_int32(CFNumberRef num)
10{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000011 int32_t result;
Ronald Oussoren84151202010-04-18 20:46:11 +000012
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000013 CFNumberGetValue(num, kCFNumberSInt32Type, &result);
14 return result;
Ronald Oussoren84151202010-04-18 20:46:11 +000015}
16
17static PyObject*
18cfstring_to_pystring(CFStringRef ref)
19{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000020 const char* s;
Ronald Oussoren84151202010-04-18 20:46:11 +000021
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000022 s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
23 if (s) {
24 return PyUnicode_DecodeUTF8(
25 s, strlen(s), NULL);
Ronald Oussoren84151202010-04-18 20:46:11 +000026
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000027 } else {
28 CFIndex len = CFStringGetLength(ref);
29 Boolean ok;
30 PyObject* result;
31 char* buf;
Ronald Oussoren84151202010-04-18 20:46:11 +000032
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000033 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 }
Ronald Oussoren84151202010-04-18 20:46:11 +000052}
53
54
55static PyObject*
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +053056get_proxy_settings(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
Ronald Oussoren84151202010-04-18 20:46:11 +000057{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 CFDictionaryRef proxyDict = NULL;
59 CFNumberRef aNum = NULL;
60 CFArrayRef anArray = NULL;
61 PyObject* result = NULL;
62 PyObject* v;
63 int r;
Ronald Oussoren84151202010-04-18 20:46:11 +000064
Max Bélanger4859ba02018-09-11 16:14:00 -070065 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 proxyDict = SCDynamicStoreCopyProxies(NULL);
Max Bélanger4859ba02018-09-11 16:14:00 -070067 Py_END_ALLOW_THREADS
68
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000069 if (!proxyDict) {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +020070 Py_RETURN_NONE;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 }
Ronald Oussoren84151202010-04-18 20:46:11 +000072
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 result = PyDict_New();
74 if (result == NULL) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +000075
Brett Cannon56be5f52016-09-07 14:07:16 -070076 aNum = CFDictionaryGetValue(proxyDict,
77 kSCPropNetProxiesExcludeSimpleHostnames);
78 if (aNum == NULL) {
Ronald Oussoren01c42892010-09-28 14:38:31 +000079 v = PyBool_FromLong(0);
Brett Cannon56be5f52016-09-07 14:07:16 -070080 } else {
81 v = PyBool_FromLong(cfnum_to_int32(aNum));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 }
Ronald Oussoren84151202010-04-18 20:46:11 +000083
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 if (v == NULL) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +000085
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 r = PyDict_SetItemString(result, "exclude_simple", v);
87 Py_DECREF(v); v = NULL;
88 if (r == -1) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +000089
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 anArray = CFDictionaryGetValue(proxyDict,
91 kSCPropNetProxiesExceptionsList);
92 if (anArray != NULL) {
93 CFIndex len = CFArrayGetCount(anArray);
94 CFIndex i;
95 v = PyTuple_New(len);
96 if (v == NULL) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +000097
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 r = PyDict_SetItemString(result, "exceptions", v);
99 Py_DECREF(v);
100 if (r == -1) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +0000101
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 for (i = 0; i < len; i++) {
103 CFStringRef aString = NULL;
Ronald Oussoren84151202010-04-18 20:46:11 +0000104
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000105 aString = CFArrayGetValueAtIndex(anArray, i);
106 if (aString == NULL) {
107 PyTuple_SetItem(v, i, Py_None);
108 Py_INCREF(Py_None);
109 } else {
110 PyObject* t = cfstring_to_pystring(aString);
111 if (!t) {
112 PyTuple_SetItem(v, i, Py_None);
113 Py_INCREF(Py_None);
114 } else {
115 PyTuple_SetItem(v, i, t);
116 }
117 }
118 }
119 }
Ronald Oussoren84151202010-04-18 20:46:11 +0000120
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 CFRelease(proxyDict);
122 return result;
Ronald Oussoren84151202010-04-18 20:46:11 +0000123
124error:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125 if (proxyDict) CFRelease(proxyDict);
126 Py_XDECREF(result);
127 return NULL;
Ronald Oussoren84151202010-04-18 20:46:11 +0000128}
129
130static int
Serhiy Storchakaef1585e2015-12-25 20:01:53 +0200131set_proxy(PyObject* proxies, const char* proto, CFDictionaryRef proxyDict,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 CFStringRef enabledKey,
133 CFStringRef hostKey, CFStringRef portKey)
Ronald Oussoren84151202010-04-18 20:46:11 +0000134{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 CFNumberRef aNum;
Ronald Oussoren84151202010-04-18 20:46:11 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 aNum = CFDictionaryGetValue(proxyDict, enabledKey);
138 if (aNum && cfnum_to_int32(aNum)) {
139 CFStringRef hostString;
Ronald Oussoren84151202010-04-18 20:46:11 +0000140
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 hostString = CFDictionaryGetValue(proxyDict, hostKey);
142 aNum = CFDictionaryGetValue(proxyDict, portKey);
Ronald Oussoren84151202010-04-18 20:46:11 +0000143
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 if (hostString) {
145 int r;
146 PyObject* h = cfstring_to_pystring(hostString);
147 PyObject* v;
148 if (h) {
149 if (aNum) {
150 int32_t port = cfnum_to_int32(aNum);
151 v = PyUnicode_FromFormat("http://%U:%ld",
152 h, (long)port);
153 } else {
154 v = PyUnicode_FromFormat("http://%U", h);
155 }
156 Py_DECREF(h);
157 if (!v) return -1;
158 r = PyDict_SetItemString(proxies, proto,
159 v);
160 Py_DECREF(v);
161 return r;
162 }
163 }
Ronald Oussoren84151202010-04-18 20:46:11 +0000164
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000165 }
166 return 0;
Ronald Oussoren84151202010-04-18 20:46:11 +0000167}
168
169
170
171static PyObject*
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530172get_proxies(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
Ronald Oussoren84151202010-04-18 20:46:11 +0000173{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000174 PyObject* result = NULL;
175 int r;
176 CFDictionaryRef proxyDict = NULL;
Ronald Oussoren84151202010-04-18 20:46:11 +0000177
Max Bélanger4859ba02018-09-11 16:14:00 -0700178 Py_BEGIN_ALLOW_THREADS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 proxyDict = SCDynamicStoreCopyProxies(NULL);
Max Bélanger4859ba02018-09-11 16:14:00 -0700180 Py_END_ALLOW_THREADS
181
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 if (proxyDict == NULL) {
183 return PyDict_New();
184 }
Ronald Oussoren84151202010-04-18 20:46:11 +0000185
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 result = PyDict_New();
187 if (result == NULL) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +0000188
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 r = set_proxy(result, "http", proxyDict,
190 kSCPropNetProxiesHTTPEnable,
191 kSCPropNetProxiesHTTPProxy,
192 kSCPropNetProxiesHTTPPort);
193 if (r == -1) goto error;
194 r = set_proxy(result, "https", proxyDict,
195 kSCPropNetProxiesHTTPSEnable,
196 kSCPropNetProxiesHTTPSProxy,
197 kSCPropNetProxiesHTTPSPort);
198 if (r == -1) goto error;
199 r = set_proxy(result, "ftp", proxyDict,
200 kSCPropNetProxiesFTPEnable,
201 kSCPropNetProxiesFTPProxy,
202 kSCPropNetProxiesFTPPort);
203 if (r == -1) goto error;
204 r = set_proxy(result, "gopher", proxyDict,
205 kSCPropNetProxiesGopherEnable,
206 kSCPropNetProxiesGopherProxy,
207 kSCPropNetProxiesGopherPort);
208 if (r == -1) goto error;
Ronald Oussoren84151202010-04-18 20:46:11 +0000209
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 CFRelease(proxyDict);
211 return result;
Ronald Oussoren84151202010-04-18 20:46:11 +0000212error:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 if (proxyDict) CFRelease(proxyDict);
214 Py_XDECREF(result);
215 return NULL;
Ronald Oussoren84151202010-04-18 20:46:11 +0000216}
217
218static PyMethodDef mod_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 {
220 "_get_proxy_settings",
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530221 get_proxy_settings,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 METH_NOARGS,
223 NULL,
224 },
225 {
226 "_get_proxies",
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530227 get_proxies,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 METH_NOARGS,
229 NULL,
230 },
231 { 0, 0, 0, 0 }
Ronald Oussoren84151202010-04-18 20:46:11 +0000232};
233
Mohamed Koubaa3ff69752020-09-08 22:28:48 -0500234static PyModuleDef_Slot _scproxy_slots[] = {
235 {0, NULL}
Ronald Oussoren84151202010-04-18 20:46:11 +0000236};
237
Mohamed Koubaa3ff69752020-09-08 22:28:48 -0500238static struct PyModuleDef _scproxy_module = {
239 PyModuleDef_HEAD_INIT,
240 .m_name = "_scproxy",
241 .m_size = 0,
242 .m_methods = mod_methods,
243 .m_slots = _scproxy_slots,
244};
Ronald Oussoren84151202010-04-18 20:46:11 +0000245
246#ifdef __cplusplus
247extern "C" {
248#endif
249
Victor Stinnerf024d262015-03-17 17:48:27 +0100250PyMODINIT_FUNC
Ronald Oussoren84151202010-04-18 20:46:11 +0000251PyInit__scproxy(void)
252{
Mohamed Koubaa3ff69752020-09-08 22:28:48 -0500253 return PyModuleDef_Init(&_scproxy_module);
Ronald Oussoren84151202010-04-18 20:46:11 +0000254}
255
256#ifdef __cplusplus
257}
258#endif