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