Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_scproxy.c
12 views
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* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
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
Py_BEGIN_ALLOW_THREADS
66
proxyDict = SCDynamicStoreCopyProxies(NULL);
67
Py_END_ALLOW_THREADS
68
69
if (!proxyDict) {
70
Py_RETURN_NONE;
71
}
72
73
result = PyDict_New();
74
if (result == NULL) goto error;
75
76
aNum = CFDictionaryGetValue(proxyDict,
77
kSCPropNetProxiesExcludeSimpleHostnames);
78
if (aNum == NULL) {
79
v = PyBool_FromLong(0);
80
} else {
81
v = PyBool_FromLong(cfnum_to_int32(aNum));
82
}
83
84
if (v == NULL) goto error;
85
86
r = PyDict_SetItemString(result, "exclude_simple", v);
87
Py_SETREF(v, NULL);
88
if (r == -1) goto error;
89
90
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;
97
98
r = PyDict_SetItemString(result, "exceptions", v);
99
Py_DECREF(v);
100
if (r == -1) goto error;
101
102
for (i = 0; i < len; i++) {
103
CFStringRef aString = NULL;
104
105
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
}
120
121
CFRelease(proxyDict);
122
return result;
123
124
error:
125
if (proxyDict) CFRelease(proxyDict);
126
Py_XDECREF(result);
127
return NULL;
128
}
129
130
static int
131
set_proxy(PyObject* proxies, const char* proto, CFDictionaryRef proxyDict,
132
CFStringRef enabledKey,
133
CFStringRef hostKey, CFStringRef portKey)
134
{
135
CFNumberRef aNum;
136
137
aNum = CFDictionaryGetValue(proxyDict, enabledKey);
138
if (aNum && cfnum_to_int32(aNum)) {
139
CFStringRef hostString;
140
141
hostString = CFDictionaryGetValue(proxyDict, hostKey);
142
aNum = CFDictionaryGetValue(proxyDict, portKey);
143
144
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
}
164
165
}
166
return 0;
167
}
168
169
170
171
static PyObject*
172
get_proxies(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
173
{
174
PyObject* result = NULL;
175
int r;
176
CFDictionaryRef proxyDict = NULL;
177
178
Py_BEGIN_ALLOW_THREADS
179
proxyDict = SCDynamicStoreCopyProxies(NULL);
180
Py_END_ALLOW_THREADS
181
182
if (proxyDict == NULL) {
183
return PyDict_New();
184
}
185
186
result = PyDict_New();
187
if (result == NULL) goto error;
188
189
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;
209
r = set_proxy(result, "socks", proxyDict,
210
kSCPropNetProxiesSOCKSEnable,
211
kSCPropNetProxiesSOCKSProxy,
212
kSCPropNetProxiesSOCKSPort);
213
if (r == -1) goto error;
214
215
CFRelease(proxyDict);
216
return result;
217
error:
218
if (proxyDict) CFRelease(proxyDict);
219
Py_XDECREF(result);
220
return NULL;
221
}
222
223
static PyMethodDef mod_methods[] = {
224
{
225
"_get_proxy_settings",
226
get_proxy_settings,
227
METH_NOARGS,
228
NULL,
229
},
230
{
231
"_get_proxies",
232
get_proxies,
233
METH_NOARGS,
234
NULL,
235
},
236
{ 0, 0, 0, 0 }
237
};
238
239
static PyModuleDef_Slot _scproxy_slots[] = {
240
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
241
{0, NULL}
242
};
243
244
static struct PyModuleDef _scproxy_module = {
245
PyModuleDef_HEAD_INIT,
246
.m_name = "_scproxy",
247
.m_size = 0,
248
.m_methods = mod_methods,
249
.m_slots = _scproxy_slots,
250
};
251
252
#ifdef __cplusplus
253
extern "C" {
254
#endif
255
256
PyMODINIT_FUNC
257
PyInit__scproxy(void)
258
{
259
return PyModuleDef_Init(&_scproxy_module);
260
}
261
262
#ifdef __cplusplus
263
}
264
#endif
265
266