blob: 4aa6665d1350cb59647237d629d7695d53c9242c [file] [log] [blame]
/*
* Helper method for urllib to fetch the proxy configuration settings
* using the SystemConfiguration framework.
*/
#include <Python.h>
#include <SystemConfiguration/SystemConfiguration.h>
static int32_t
cfnum_to_int32(CFNumberRef num)
{
int32_t result;
CFNumberGetValue(num, kCFNumberSInt32Type, &result);
return result;
}
static PyObject*
cfstring_to_pystring(CFStringRef ref)
{
const char* s;
s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
if (s) {
return PyString_FromString(s);
} else {
CFIndex len = CFStringGetLength(ref);
Boolean ok;
PyObject* result;
result = PyString_FromStringAndSize(NULL, len*4);
ok = CFStringGetCString(ref,
PyString_AS_STRING(result),
PyString_GET_SIZE(result),
kCFStringEncodingUTF8);
if (!ok) {
Py_DECREF(result);
return NULL;
} else {
_PyString_Resize(&result,
strlen(PyString_AS_STRING(result)));
}
return result;
}
}
static PyObject*
get_proxy_settings(PyObject* mod __attribute__((__unused__)))
{
CFDictionaryRef proxyDict = NULL;
CFNumberRef aNum = NULL;
CFArrayRef anArray = NULL;
PyObject* result = NULL;
PyObject* v;
int r;
proxyDict = SCDynamicStoreCopyProxies(NULL);
if (!proxyDict) {
Py_INCREF(Py_None);
return Py_None;
}
result = PyDict_New();
if (result == NULL) goto error;
if (&kSCPropNetProxiesExcludeSimpleHostnames != NULL) {
aNum = CFDictionaryGetValue(proxyDict,
kSCPropNetProxiesExcludeSimpleHostnames);
if (aNum == NULL) {
v = PyBool_FromLong(0);
} else {
v = PyBool_FromLong(cfnum_to_int32(aNum));
}
} else {
v = PyBool_FromLong(0);
}
if (v == NULL) goto error;
r = PyDict_SetItemString(result, "exclude_simple", v);
Py_DECREF(v); v = NULL;
if (r == -1) goto error;
anArray = CFDictionaryGetValue(proxyDict,
kSCPropNetProxiesExceptionsList);
if (anArray != NULL) {
CFIndex len = CFArrayGetCount(anArray);
CFIndex i;
v = PyTuple_New(len);
if (v == NULL) goto error;
r = PyDict_SetItemString(result, "exceptions", v);
Py_DECREF(v);
if (r == -1) goto error;
for (i = 0; i < len; i++) {
CFStringRef aString = NULL;
aString = CFArrayGetValueAtIndex(anArray, i);
if (aString == NULL) {
PyTuple_SetItem(v, i, Py_None);
Py_INCREF(Py_None);
} else {
PyObject* t = cfstring_to_pystring(aString);
if (!t) {
PyTuple_SetItem(v, i, Py_None);
Py_INCREF(Py_None);
} else {
PyTuple_SetItem(v, i, t);
}
}
}
}
CFRelease(proxyDict);
return result;
error:
if (proxyDict) CFRelease(proxyDict);
Py_XDECREF(result);
return NULL;
}
static int
set_proxy(PyObject* proxies, char* proto, CFDictionaryRef proxyDict,
CFStringRef enabledKey,
CFStringRef hostKey, CFStringRef portKey)
{
CFNumberRef aNum;
aNum = CFDictionaryGetValue(proxyDict, enabledKey);
if (aNum && cfnum_to_int32(aNum)) {
CFStringRef hostString;
hostString = CFDictionaryGetValue(proxyDict, hostKey);
aNum = CFDictionaryGetValue(proxyDict, portKey);
if (hostString) {
int r;
PyObject* h = cfstring_to_pystring(hostString);
PyObject* v;
if (h) {
if (aNum) {
int32_t port = cfnum_to_int32(aNum);
v = PyString_FromFormat("http://%s:%ld",
PyString_AS_STRING(h),
(long)port);
} else {
v = PyString_FromFormat("http://%s",
PyString_AS_STRING(h));
}
Py_DECREF(h);
if (!v) return -1;
r = PyDict_SetItemString(proxies, proto,
v);
Py_DECREF(v);
return r;
}
}
}
return 0;
}
static PyObject*
get_proxies(PyObject* mod __attribute__((__unused__)))
{
PyObject* result = NULL;
int r;
CFDictionaryRef proxyDict = NULL;
proxyDict = SCDynamicStoreCopyProxies(NULL);
if (proxyDict == NULL) {
return PyDict_New();
}
result = PyDict_New();
if (result == NULL) goto error;
r = set_proxy(result, "http", proxyDict,
kSCPropNetProxiesHTTPEnable,
kSCPropNetProxiesHTTPProxy,
kSCPropNetProxiesHTTPPort);
if (r == -1) goto error;
r = set_proxy(result, "https", proxyDict,
kSCPropNetProxiesHTTPSEnable,
kSCPropNetProxiesHTTPSProxy,
kSCPropNetProxiesHTTPSPort);
if (r == -1) goto error;
r = set_proxy(result, "ftp", proxyDict,
kSCPropNetProxiesFTPEnable,
kSCPropNetProxiesFTPProxy,
kSCPropNetProxiesFTPPort);
if (r == -1) goto error;
r = set_proxy(result, "gopher", proxyDict,
kSCPropNetProxiesGopherEnable,
kSCPropNetProxiesGopherProxy,
kSCPropNetProxiesGopherPort);
if (r == -1) goto error;
CFRelease(proxyDict);
return result;
error:
if (proxyDict) CFRelease(proxyDict);
Py_XDECREF(result);
return NULL;
}
static PyMethodDef mod_methods[] = {
{
"_get_proxy_settings",
(PyCFunction)get_proxy_settings,
METH_NOARGS,
NULL,
},
{
"_get_proxies",
(PyCFunction)get_proxies,
METH_NOARGS,
NULL,
},
{ 0, 0, 0, 0 }
};
void init_scproxy(void)
{
(void)Py_InitModule4("_scproxy", mod_methods, NULL, NULL, PYTHON_API_VERSION);
}