11#include <CFNetwork/CFProxySupport.h>
12#include <CoreFoundation/CoreFoundation.h>
13#include <SystemConfiguration/SystemConfiguration.h>
26std::string
toString(CFStringRef str) {
29 CFIndex length = CFStringGetLength(str);
30 const UniChar *chars = CFStringGetCharactersPtr(str);
32 return std::string(
reinterpret_cast<const char *
>(chars), length);
34 std::vector<UniChar> buffer(length);
35 CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data());
36 return std::string(
reinterpret_cast<const char *
>(buffer.data()), length);
42enum ProxyType { DefaultProxy, Socks5Proxy, NoProxy, HttpProxy, HttpCachingProxy, FtpCachingProxy };
45using ProxyInfoVec = std::vector<ProxyInfo>;
52ProxyInfo proxyFromDictionary(CFDictionaryRef dict) {
54 ProxyType proxyType = NoProxy;
56 CFStringRef cfProxyType =
reinterpret_cast<CFStringRef
>(CFDictionaryGetValue(dict, kCFProxyTypeKey));
58 if (CFStringCompare(cfProxyType, kCFProxyTypeFTP, 0) == kCFCompareEqualTo) {
59 proxyType = FtpCachingProxy;
60 }
else if (CFStringCompare(cfProxyType, kCFProxyTypeHTTP, 0) == kCFCompareEqualTo) {
61 proxyType = HttpProxy;
62 }
else if (CFStringCompare(cfProxyType, kCFProxyTypeHTTPS, 0) == kCFCompareEqualTo) {
63 proxyType = HttpProxy;
64 }
else if (CFStringCompare(cfProxyType, kCFProxyTypeSOCKS, 0) == kCFCompareEqualTo) {
65 proxyType = Socks5Proxy;
69 std::string hostName =
toString(
reinterpret_cast<CFStringRef
>(CFDictionaryGetValue(dict, kCFProxyHostNameKey)));
70 CFNumberRef portNumber =
reinterpret_cast<CFNumberRef
>(CFDictionaryGetValue(dict, kCFProxyPortNumberKey));
72 CFNumberGetValue(portNumber, kCFNumberSInt16Type, &port);
74 if (proxyType != NoProxy) {
75 proxyInfo = ProxyInfo(hostName, port, proxyType == HttpProxy);
88ProxyInfoVec proxyInformationFromPac(CFDictionaryRef dict,
const std::string &targetURLString, Logger &logger) {
89 ProxyInfoVec proxyInfoVec;
92 CFNumberRef pacEnabled;
94 reinterpret_cast<CFNumberRef
>(CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable)))) {
96 if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
98 CFStringRef cfPacLocation =
99 reinterpret_cast<CFStringRef
>(CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString));
101 CFURLRef pacURL = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation,
nullptr);
103 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacURL, &pacData,
nullptr,
nullptr,
105 logger.debug() <<
"Unable to get the PAC script at " <<
toString(cfPacLocation) <<
"Error code: " << errorCode
110 CFStringRef pacScript =
111 CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1);
113 CFURLRef targetURL = CFURLCreateWithBytes(kCFAllocatorDefault,
114 reinterpret_cast<UInt8 *
>(
const_cast<char *
>(targetURLString.c_str())),
115 targetURLString.size(), kCFStringEncodingUTF8,
nullptr);
117 logger.debug(
"Problem with Target URI for proxy script");
122 CFArrayRef proxies = CFNetworkCopyProxiesForAutoConfigurationScript(pacScript, targetURL, &pacError);
125 std::string pacLocation =
toString(cfPacLocation);
126 CFStringRef pacErrorDescription = CFErrorCopyDescription(pacError);
127 logger.debug() <<
"Execution of PAC script at \"%s\" failed: %s" << pacLocation <<
toString(pacErrorDescription)
131 CFIndex size = CFArrayGetCount(proxies);
132 for (CFIndex i = 0; i < size; ++i) {
133 CFDictionaryRef proxy =
reinterpret_cast<CFDictionaryRef
>(CFArrayGetValueAtIndex(proxies, i));
134 proxyInfoVec.push_back(proxyFromDictionary(proxy));
149ProxyInfo proxyFromDictionary(CFDictionaryRef dict, CFStringRef enableKey, CFStringRef hostKey, CFStringRef portKey) {
151 CFNumberRef protoEnabled;
152 CFNumberRef protoPort;
153 CFStringRef protoHost;
154 if (enableKey && (protoEnabled =
reinterpret_cast<CFNumberRef
>(CFDictionaryGetValue(dict, enableKey))) &&
155 (protoHost =
reinterpret_cast<CFStringRef
>(CFDictionaryGetValue(dict, hostKey))) &&
156 (protoPort =
reinterpret_cast<CFNumberRef
>(CFDictionaryGetValue(dict, portKey)))) {
158 if (CFNumberGetValue(protoEnabled, kCFNumberIntType, &enabled) && enabled) {
159 std::string host =
toString(protoHost);
162 CFNumberGetValue(protoPort, kCFNumberIntType, &port);
163 proxyInfo = ProxyInfo(host, port, HttpProxy);
176ProxyInfo httpProxyFromSystem(CFDictionaryRef dict) {
177 ProxyInfo tempProxy =
178 proxyFromDictionary(dict, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort);
192 CFDictionaryRef dict = SCDynamicStoreCopyProxies(
nullptr);
194 logger.
debug(
"NetworkProxyOSX SCDynamicStoreCopyProxies returned NULL. No "
195 "proxy information retrieved");
200 ProxyInfoVec info = proxyInformationFromPac(dict, targetURLString, logger);
202 bool foundHttpProxy =
false;
203 auto proxyIt = std::find_if(info.cbegin(), info.cend(), [](
const auto &proxy) { return proxy.isHttpProxy(); });
204 if (proxyIt != info.cend()) {
205 foundHttpProxy =
true;
206 httpProxy = *proxyIt;
210 if (!foundHttpProxy) {
211 ProxyInfo tempProxy = httpProxyFromSystem(dict);
212 if (tempProxy.isHttpProxy()) {
213 httpProxy = tempProxy;
214 foundHttpProxy =
true;
218 if (!foundHttpProxy) {
219 logger.
debug(
"NetworkProxyOSX. No system HTTP Proxy set!");
230ProxyInfo NetworkProxy::getHttpProxy(
const std::string &targetURLString) {
231 return findHttpProxy(targetURLString, m_logger);
The Logger class is in charge of the publishing messages from the framework through various channels.
void debug(const std::string &msg)
Logs at debug level.
NetworkProxy()
Constructor.
std::string toString(const T &value)
Convert a number to a string.
Helper class which provides the Collimation Length for SANS instruments.