diff options
author | Daniel Molkentin <daniel@molkentin.de> | 2012-10-07 21:24:00 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-10-12 00:19:36 (GMT) |
commit | 75492a109839d85b101efd45332ac83842741c75 (patch) | |
tree | b167d6ee0e3f92a4921033f72acad5f1f99c3a87 /src | |
parent | 4d4cc4dc14993a533b032acae8862deeb9d695d2 (diff) | |
download | Qt-75492a109839d85b101efd45332ac83842741c75.zip Qt-75492a109839d85b101efd45332ac83842741c75.tar.gz Qt-75492a109839d85b101efd45332ac83842741c75.tar.bz2 |
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
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
(cherry picked from commit c524bbbb8aa4ba10bac68292a3078534f1b51df5)
Change-Id: Iad8fa2a7517f9254e9c9a3c573bec0f7f4df0dfb
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
Diffstat (limited to 'src')
-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 58fc5d6..ceaecbd 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -25,7 +25,7 @@ unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp -mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation +mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation -framework CoreServices qpa:mac:!ios:SOURCES += kernel/qnetworkproxy_mac.cpp else:!qpa:mac:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp index 7cbde8a..3261872 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)); + } } } |