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 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* 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 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* 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 228 void init_scproxy(void) 229 { 230 (void)Py_InitModule4("_scproxy", mod_methods, NULL, NULL, PYTHON_API_VERSION); 231 } 232