_scproxy.c 6.3 KB

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