summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Molkentin <daniel@molkentin.de>2012-10-07 23:24:00 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-10-12 02:19:36 +0200
commit75492a109839d85b101efd45332ac83842741c75 (patch)
treeb167d6ee0e3f92a4921033f72acad5f1f99c3a87 /src
parent4d4cc4dc14993a533b032acae8862deeb9d695d2 (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 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.pri2
-rw-r--r--src/network/kernel/qnetworkproxy_mac.cpp116
2 files changed, 113 insertions, 5 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index 58fc5d6c3e..ceaecbd42d 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 7cbde8af4b..32618720ad 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));
+ }
}
}