diff options
author | Aron Rosenberg <aronrosenberg@gmail.com> | 2012-04-04 16:34:33 -0700 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-04-11 01:42:12 +0200 |
commit | c524bbbb8aa4ba10bac68292a3078534f1b51df5 (patch) | |
tree | a6208ed0a2e93a2da6f463fd25903a60c1464b2f /src/network | |
parent | 97f9c6f8cdc0dd0f676c6ccfeb1cd6096e72fd48 (diff) |
Add Proxy Auto Config support (PAC) on Mac
Adds support for fetching and parsing Proxy Auto Config files if one
is specified in the Mac System Preferences
Task-Number: QTBUG-2069
Task-Number: QTIFW-28
Change-Id: I91feb999222187e7467f2c41383904cf0cff8633
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/kernel/kernel.pri | 2 | ||||
-rw-r--r-- | src/network/kernel/qnetworkproxy_mac.cpp | 116 |
2 files changed, 113 insertions, 5 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index a5508af31f..f9ea6065a3 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -33,7 +33,7 @@ win32: { } integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp -mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation +mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation -framework CoreServices mac:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp else:SOURCES += kernel/qnetworkproxy_generic.cpp diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp index d25917ee47..3e62c0f867 100644 --- a/src/network/kernel/qnetworkproxy_mac.cpp +++ b/src/network/kernel/qnetworkproxy_mac.cpp @@ -48,6 +48,7 @@ #include <QtCore/QRegExp> #include <QtCore/QStringList> +#include <QtCore/QUrl> #include <QtCore/qendian.h> #include <QtCore/qstringlist.h> #include "private/qcore_mac_p.h" @@ -146,6 +147,66 @@ static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict, QNetworkProxy::Pr return QNetworkProxy(); } + +static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict) +{ + QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy; + QString hostName; + quint16 port = 0; + QString user; + QString password; + + CFStringRef cfProxyType = (CFStringRef)CFDictionaryGetValue(dict, kCFProxyTypeKey); + if (CFStringCompare(cfProxyType, kCFProxyTypeNone, 0) == kCFCompareEqualTo) { + proxyType = QNetworkProxy::NoProxy; + } else if (CFStringCompare(cfProxyType, kCFProxyTypeFTP, 0) == kCFCompareEqualTo) { + proxyType = QNetworkProxy::FtpCachingProxy; + } else if (CFStringCompare(cfProxyType, kCFProxyTypeHTTP, 0) == kCFCompareEqualTo) { + proxyType = QNetworkProxy::HttpProxy; + } else if (CFStringCompare(cfProxyType, kCFProxyTypeHTTPS, 0) == kCFCompareEqualTo) { + proxyType = QNetworkProxy::HttpProxy; + } else if (CFStringCompare(cfProxyType, kCFProxyTypeSOCKS, 0) == kCFCompareEqualTo) { + proxyType = QNetworkProxy::Socks5Proxy; + } + + hostName = QCFString::toQString((CFStringRef)CFDictionaryGetValue(dict, kCFProxyHostNameKey)); + user = QCFString::toQString((CFStringRef)CFDictionaryGetValue(dict, kCFProxyUsernameKey)); + password = QCFString::toQString((CFStringRef)CFDictionaryGetValue(dict, kCFProxyPasswordKey)); + + CFNumberRef portNumber = (CFNumberRef)CFDictionaryGetValue(dict, kCFProxyPortNumberKey); + if (portNumber) { + CFNumberGetValue(portNumber, kCFNumberSInt16Type, &port); + } + + return QNetworkProxy(proxyType, hostName, port, user, password); +} + +const char * cfurlErrorDescription(SInt32 errorCode) +{ + switch (errorCode) { + case kCFURLUnknownError: + return "Unknown Error"; + case kCFURLUnknownSchemeError: + return "Unknown Scheme"; + case kCFURLResourceNotFoundError: + return "Resource Not Found"; + case kCFURLResourceAccessViolationError: + return "Resource Access Violation"; + case kCFURLRemoteHostUnavailableError: + return "Remote Host Unavailable"; + case kCFURLImproperArgumentsError: + return "Improper Arguments"; + case kCFURLUnknownPropertyKeyError: + return "Unknown Property Key"; + case kCFURLPropertyKeyUnavailableError: + return "Property Key Unavailable"; + case kCFURLTimeoutError: + return "Timeout"; + default: + return "Really Unknown Error"; + } +} + QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query) { QList<QNetworkProxy> result; @@ -168,11 +229,58 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query) int enabled; if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) { // PAC is enabled - CFStringRef pacUrl = - (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString); - QString url = QCFString::toQString(pacUrl); + CFStringRef cfPacLocation = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString); + +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) { + QCFType<CFDataRef> pacData; + QCFType<CFURLRef> pacUrl = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, NULL); + SInt32 errorCode; + if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacUrl, &pacData, NULL, NULL, &errorCode)) { + QString pacLocation = QCFString::toQString(cfPacLocation); + qWarning("Unable to get the PAC script at \"%s\" (%s)", qPrintable(pacLocation), cfurlErrorDescription(errorCode)); + return result; + } - // ### TODO: Use PAC somehow + QCFType<CFStringRef> pacScript = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1); + if (!pacScript) { + // This should never happen, but the documentation says it may return NULL if there was a problem creating the object. + QString pacLocation = QCFString::toQString(cfPacLocation); + qWarning("Unable to read the PAC script at \"%s\"", qPrintable(pacLocation)); + return result; + } + + QByteArray encodedURL = query.url().toEncoded(); // converted to UTF-8 + if (encodedURL.isEmpty()) { + return result; // Invalid URL, abort + } + + QCFType<CFURLRef> targetURL = CFURLCreateWithBytes(kCFAllocatorDefault, (UInt8*)encodedURL.data(), encodedURL.size(), kCFStringEncodingUTF8, NULL); + if (!targetURL) { + return result; // URL creation problem, abort + } + + QCFType<CFErrorRef> pacError; + QCFType<CFArrayRef> proxies = CFNetworkCopyProxiesForAutoConfigurationScript(pacScript, targetURL, &pacError); + if (!proxies) { + QString pacLocation = QCFString::toQString(cfPacLocation); + QCFType<CFStringRef> pacErrorDescription = CFErrorCopyDescription(pacError); + qWarning("Execution of PAC script at \"%s\" failed: %s", qPrintable(pacLocation), qPrintable(QCFString::toQString(pacErrorDescription))); + return result; + } + + CFIndex size = CFArrayGetCount(proxies); + for (CFIndex i = 0; i < size; ++i) { + CFDictionaryRef proxy = (CFDictionaryRef)CFArrayGetValueAtIndex(proxies, i); + result << proxyFromDictionary(proxy); + } + return result; + } else +#endif + { + QString pacLocation = QCFString::toQString(cfPacLocation); + qWarning("Mac system proxy: PAC script at \"%s\" not handled", qPrintable(pacLocation)); + } } } |