Home | History | Annotate | Download | only in Modules
      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