/** * Get proxy information from a proxy script. * @param dict : Dictionary to search through. * @param targetURLString : Target remote URL * @param logger : Log object * @return Collection of proxy information. */ ProxyInfoVec proxyInformationFromPac(CFDictionaryRef dict, const std::string &targetURLString, Logger &logger) { ProxyInfoVec proxyInfoVec; // is there a PAC enabled? If so, use it first. CFNumberRef pacEnabled; if ((pacEnabled = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue( dict, kSCPropNetProxiesProxyAutoConfigEnable)))) { int enabled; if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) { // PAC is enabled CFStringRef cfPacLocation = reinterpret_cast<CFStringRef>(CFDictionaryGetValue( dict, kSCPropNetProxiesProxyAutoConfigURLString)); CFDataRef pacData; CFURLRef pacURL = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, nullptr); SInt32 errorCode; if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacURL, &pacData, nullptr, nullptr, &errorCode)) { logger.debug() << "Unable to get the PAC script at " << toString(cfPacLocation) << "Error code: " << errorCode << std::endl; return proxyInfoVec; } CFStringRef pacScript = CFStringCreateFromExternalRepresentation( kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1); CFURLRef targetURL = CFURLCreateWithBytes( kCFAllocatorDefault, (UInt8 *)targetURLString.c_str(), targetURLString.size(), kCFStringEncodingUTF8, nullptr); if (!targetURL) { logger.debug("Problem with Target URI for proxy script"); return proxyInfoVec; } CFErrorRef pacError; CFArrayRef proxies = CFNetworkCopyProxiesForAutoConfigurationScript( pacScript, targetURL, &pacError); if (!proxies) { std::string pacLocation = toString(cfPacLocation); CFStringRef pacErrorDescription = CFErrorCopyDescription(pacError); logger.debug() << "Execution of PAC script at \"%s\" failed: %s" << pacLocation << toString(pacErrorDescription) << std::endl; } CFIndex size = CFArrayGetCount(proxies); for (CFIndex i = 0; i < size; ++i) { CFDictionaryRef proxy = reinterpret_cast<CFDictionaryRef>( CFArrayGetValueAtIndex(proxies, i)); proxyInfoVec.push_back(proxyFromDictionary(proxy)); } } } return proxyInfoVec; }
QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query) { QList<QNetworkProxy> result; // obtain a dictionary to the proxy settings: CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); if (!dict) { qWarning("QNetworkProxyFactory::systemProxyForQuery: SCDynamicStoreCopyProxies returned NULL"); return result; // failed } if (isHostExcluded(dict, query.peerHostName())) { CFRelease(dict); return result; // no proxy for this host } // is there a PAC enabled? If so, use it first. CFNumberRef pacEnabled; if ((pacEnabled = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable))) { int enabled; if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) { // PAC is enabled 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; } 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)); } } } // no PAC, decide which proxy we're looking for based on the query bool isHttps = false; QString protocol = query.protocolTag().toLower(); // try the protocol-specific proxy QNetworkProxy protocolSpecificProxy; if (protocol == QLatin1String("ftp")) { protocolSpecificProxy = proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy, kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort); } else if (protocol == QLatin1String("http")) { protocolSpecificProxy = proxyFromDictionary(dict, QNetworkProxy::HttpProxy, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); } else if (protocol == QLatin1String("https")) { isHttps = true; protocolSpecificProxy = proxyFromDictionary(dict, QNetworkProxy::HttpProxy, kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort); } if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy) result << protocolSpecificProxy; // let's add SOCKSv5 if present too QNetworkProxy socks5 = proxyFromDictionary(dict, QNetworkProxy::Socks5Proxy, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); if (socks5.type() != QNetworkProxy::DefaultProxy) result << socks5; // let's add the HTTPS proxy if present (and if we haven't added // yet) if (!isHttps) { QNetworkProxy https = proxyFromDictionary(dict, QNetworkProxy::HttpProxy, kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort); if (https.type() != QNetworkProxy::DefaultProxy && https != protocolSpecificProxy) result << https; } CFRelease(dict); return result; }