You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 lines
6.0 KiB

  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* mod __attribute__((__unused__)))
  48. {
  49. CFDictionaryRef proxyDict = NULL;
  50. CFNumberRef aNum = NULL;
  51. CFArrayRef anArray = NULL;
  52. PyObject* result = NULL;
  53. PyObject* v;
  54. int r;
  55. proxyDict = SCDynamicStoreCopyProxies(NULL);
  56. if (!proxyDict) {
  57. Py_INCREF(Py_None);
  58. return Py_None;
  59. }
  60. result = PyDict_New();
  61. if (result == NULL) goto error;
  62. if (&kSCPropNetProxiesExcludeSimpleHostnames != NULL) {
  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. } else {
  71. v = PyBool_FromLong(0);
  72. }
  73. if (v == NULL) goto error;
  74. r = PyDict_SetItemString(result, "exclude_simple", v);
  75. Py_DECREF(v); v = NULL;
  76. if (r == -1) goto error;
  77. anArray = CFDictionaryGetValue(proxyDict,
  78. kSCPropNetProxiesExceptionsList);
  79. if (anArray != NULL) {
  80. CFIndex len = CFArrayGetCount(anArray);
  81. CFIndex i;
  82. v = PyTuple_New(len);
  83. if (v == NULL) goto error;
  84. r = PyDict_SetItemString(result, "exceptions", v);
  85. Py_DECREF(v);
  86. if (r == -1) goto error;
  87. for (i = 0; i < len; i++) {
  88. CFStringRef aString = NULL;
  89. aString = CFArrayGetValueAtIndex(anArray, i);
  90. if (aString == NULL) {
  91. PyTuple_SetItem(v, i, Py_None);
  92. Py_INCREF(Py_None);
  93. } else {
  94. PyObject* t = cfstring_to_pystring(aString);
  95. if (!t) {
  96. PyTuple_SetItem(v, i, Py_None);
  97. Py_INCREF(Py_None);
  98. } else {
  99. PyTuple_SetItem(v, i, t);
  100. }
  101. }
  102. }
  103. }
  104. CFRelease(proxyDict);
  105. return result;
  106. error:
  107. if (proxyDict) CFRelease(proxyDict);
  108. Py_XDECREF(result);
  109. return NULL;
  110. }
  111. static int
  112. set_proxy(PyObject* proxies, char* proto, CFDictionaryRef proxyDict,
  113. CFStringRef enabledKey,
  114. CFStringRef hostKey, CFStringRef portKey)
  115. {
  116. CFNumberRef aNum;
  117. aNum = CFDictionaryGetValue(proxyDict, enabledKey);
  118. if (aNum && cfnum_to_int32(aNum)) {
  119. CFStringRef hostString;
  120. hostString = CFDictionaryGetValue(proxyDict, hostKey);
  121. aNum = CFDictionaryGetValue(proxyDict, portKey);
  122. if (hostString) {
  123. int r;
  124. PyObject* h = cfstring_to_pystring(hostString);
  125. PyObject* v;
  126. if (h) {
  127. if (aNum) {
  128. int32_t port = cfnum_to_int32(aNum);
  129. v = PyUnicode_FromFormat("http://%U:%ld",
  130. h, (long)port);
  131. } else {
  132. v = PyUnicode_FromFormat("http://%U", h);
  133. }
  134. Py_DECREF(h);
  135. if (!v) return -1;
  136. r = PyDict_SetItemString(proxies, proto,
  137. v);
  138. Py_DECREF(v);
  139. return r;
  140. }
  141. }
  142. }
  143. return 0;
  144. }
  145. static PyObject*
  146. get_proxies(PyObject* mod __attribute__((__unused__)))
  147. {
  148. PyObject* result = NULL;
  149. int r;
  150. CFDictionaryRef proxyDict = NULL;
  151. proxyDict = SCDynamicStoreCopyProxies(NULL);
  152. if (proxyDict == NULL) {
  153. return PyDict_New();
  154. }
  155. result = PyDict_New();
  156. if (result == NULL) goto error;
  157. r = set_proxy(result, "http", proxyDict,
  158. kSCPropNetProxiesHTTPEnable,
  159. kSCPropNetProxiesHTTPProxy,
  160. kSCPropNetProxiesHTTPPort);
  161. if (r == -1) goto error;
  162. r = set_proxy(result, "https", proxyDict,
  163. kSCPropNetProxiesHTTPSEnable,
  164. kSCPropNetProxiesHTTPSProxy,
  165. kSCPropNetProxiesHTTPSPort);
  166. if (r == -1) goto error;
  167. r = set_proxy(result, "ftp", proxyDict,
  168. kSCPropNetProxiesFTPEnable,
  169. kSCPropNetProxiesFTPProxy,
  170. kSCPropNetProxiesFTPPort);
  171. if (r == -1) goto error;
  172. r = set_proxy(result, "gopher", proxyDict,
  173. kSCPropNetProxiesGopherEnable,
  174. kSCPropNetProxiesGopherProxy,
  175. kSCPropNetProxiesGopherPort);
  176. if (r == -1) goto error;
  177. CFRelease(proxyDict);
  178. return result;
  179. error:
  180. if (proxyDict) CFRelease(proxyDict);
  181. Py_XDECREF(result);
  182. return NULL;
  183. }
  184. static PyMethodDef mod_methods[] = {
  185. {
  186. "_get_proxy_settings",
  187. (PyCFunction)get_proxy_settings,
  188. METH_NOARGS,
  189. NULL,
  190. },
  191. {
  192. "_get_proxies",
  193. (PyCFunction)get_proxies,
  194. METH_NOARGS,
  195. NULL,
  196. },
  197. { 0, 0, 0, 0 }
  198. };
  199. static struct PyModuleDef mod_module = {
  200. PyModuleDef_HEAD_INIT,
  201. "_scproxy",
  202. NULL,
  203. -1,
  204. mod_methods,
  205. NULL,
  206. NULL,
  207. NULL,
  208. NULL
  209. };
  210. #ifdef __cplusplus
  211. extern "C" {
  212. #endif
  213. PyObject*
  214. PyInit__scproxy(void)
  215. {
  216. return PyModule_Create(&mod_module);
  217. }
  218. #ifdef __cplusplus
  219. }
  220. #endif