(root)/
Python-3.12.0/
Modules/
_scproxy.c
       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