Mantid
Loading...
Searching...
No Matches
NetworkProxyOSX.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7// Compile on OSX only.
8#if defined(__APPLE__)
9
11#include <CFNetwork/CFProxySupport.h>
12#include <CoreFoundation/CoreFoundation.h>
13#include <SystemConfiguration/SystemConfiguration.h>
14#include <sstream>
15#include <string>
16#include <vector>
17
18namespace Mantid {
19namespace Kernel {
20
26std::string toString(CFStringRef str) {
27 if (!str)
28 return std::string();
29 CFIndex length = CFStringGetLength(str);
30 const UniChar *chars = CFStringGetCharactersPtr(str);
31 if (chars)
32 return std::string(reinterpret_cast<const char *>(chars), length);
33
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);
37}
38
42enum ProxyType { DefaultProxy, Socks5Proxy, NoProxy, HttpProxy, HttpCachingProxy, FtpCachingProxy };
43
45using ProxyInfoVec = std::vector<ProxyInfo>;
46
52ProxyInfo proxyFromDictionary(CFDictionaryRef dict) {
53 ProxyInfo proxyInfo;
54 ProxyType proxyType = NoProxy;
55
56 CFStringRef cfProxyType = reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, kCFProxyTypeKey));
57
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;
66 }
67
68 int port = 0;
69 std::string hostName = toString(reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, kCFProxyHostNameKey)));
70 CFNumberRef portNumber = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCFProxyPortNumberKey));
71 if (portNumber) {
72 CFNumberGetValue(portNumber, kCFNumberSInt16Type, &port);
73 }
74 if (proxyType != NoProxy) {
75 proxyInfo = ProxyInfo(hostName, port, proxyType == HttpProxy);
76 }
77
78 return proxyInfo;
79}
80
88ProxyInfoVec proxyInformationFromPac(CFDictionaryRef dict, const std::string &targetURLString, Logger &logger) {
89 ProxyInfoVec proxyInfoVec;
90
91 // is there a PAC enabled? If so, use it first.
92 CFNumberRef pacEnabled;
93 if ((pacEnabled =
94 reinterpret_cast<CFNumberRef>(CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable)))) {
95 int enabled;
96 if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
97 // PAC is enabled
98 CFStringRef cfPacLocation =
99 reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString));
100 CFDataRef pacData;
101 CFURLRef pacURL = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, nullptr);
102 SInt32 errorCode;
103 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacURL, &pacData, nullptr, nullptr,
104 &errorCode)) {
105 logger.debug() << "Unable to get the PAC script at " << toString(cfPacLocation) << "Error code: " << errorCode
106 << '\n';
107 return proxyInfoVec;
108 }
109
110 CFStringRef pacScript =
111 CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1);
112
113 CFURLRef targetURL = CFURLCreateWithBytes(kCFAllocatorDefault,
114 reinterpret_cast<UInt8 *>(const_cast<char *>(targetURLString.c_str())),
115 targetURLString.size(), kCFStringEncodingUTF8, nullptr);
116 if (!targetURL) {
117 logger.debug("Problem with Target URI for proxy script");
118 return proxyInfoVec;
119 }
120
121 CFErrorRef pacError;
122 CFArrayRef proxies = CFNetworkCopyProxiesForAutoConfigurationScript(pacScript, targetURL, &pacError);
123
124 if (!proxies) {
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)
128 << '\n';
129 }
130
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));
135 }
136 }
137 }
138 return proxyInfoVec;
139}
140
149ProxyInfo proxyFromDictionary(CFDictionaryRef dict, CFStringRef enableKey, CFStringRef hostKey, CFStringRef portKey) {
150 ProxyInfo proxyInfo;
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)))) {
157 int enabled;
158 if (CFNumberGetValue(protoEnabled, kCFNumberIntType, &enabled) && enabled) {
159 std::string host = toString(protoHost);
160
161 int port;
162 CFNumberGetValue(protoPort, kCFNumberIntType, &port);
163 proxyInfo = ProxyInfo(host, port, HttpProxy);
164 }
165 }
166
167 // proxy not enabled
168 return proxyInfo;
169}
170
176ProxyInfo httpProxyFromSystem(CFDictionaryRef dict) {
177 ProxyInfo tempProxy =
178 proxyFromDictionary(dict, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort);
179
180 return tempProxy;
181}
182
190ProxyInfo findHttpProxy(const std::string &targetURLString, Mantid::Kernel::Logger &logger) {
191 ProxyInfo httpProxy;
192 CFDictionaryRef dict = SCDynamicStoreCopyProxies(nullptr);
193 if (!dict) {
194 logger.debug("NetworkProxyOSX SCDynamicStoreCopyProxies returned NULL. No "
195 "proxy information retrieved");
196 return httpProxy;
197 }
198
199 // Query the proxy pac first.
200 ProxyInfoVec info = proxyInformationFromPac(dict, targetURLString, logger);
201
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;
207 }
208
209 // Query the http proxy settings second.
210 if (!foundHttpProxy) {
211 ProxyInfo tempProxy = httpProxyFromSystem(dict);
212 if (tempProxy.isHttpProxy()) {
213 httpProxy = tempProxy;
214 foundHttpProxy = true;
215 }
216 }
217
218 if (!foundHttpProxy) {
219 logger.debug("NetworkProxyOSX. No system HTTP Proxy set!");
220 }
221
222 return httpProxy;
223}
224
225//----------------------------------------------------------------------------------------------
228NetworkProxy::NetworkProxy() : m_logger("network_proxy_logger_osx") {}
229
230ProxyInfo NetworkProxy::getHttpProxy(const std::string &targetURLString) {
231 return findHttpProxy(targetURLString, m_logger);
232}
233
234} // namespace Kernel
235} // namespace Mantid
236
237#endif
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
std::string toString(const T &value)
Convert a number to a string.
Definition: Strings.cpp:703
Helper class which provides the Collimation Length for SANS instruments.