1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/base/proxydetect.h"
12
13 #if defined(WEBRTC_WIN)
14 #include "webrtc/base/win32.h"
15 #include <shlobj.h>
16 #endif // WEBRTC_WIN
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
23 #include <SystemConfiguration/SystemConfiguration.h>
24 #include <CoreFoundation/CoreFoundation.h>
25 #include <CoreServices/CoreServices.h>
26 #include <Security/Security.h>
27 #include "macconversion.h"
28 #endif
29
30 #ifdef WEBRTC_IOS
31 #include <CFNetwork/CFNetwork.h>
32 #include "macconversion.h"
33 #endif
34
35 #include <map>
36
37 #include "webrtc/base/arraysize.h"
38 #include "webrtc/base/fileutils.h"
39 #include "webrtc/base/httpcommon.h"
40 #include "webrtc/base/httpcommon-inl.h"
41 #include "webrtc/base/pathutils.h"
42 #include "webrtc/base/stringutils.h"
43
44 #if defined(WEBRTC_WIN)
45 #define _TRY_WINHTTP 1
46 #define _TRY_JSPROXY 0
47 #define _TRY_WM_FINDPROXY 0
48 #define _TRY_IE_LAN_SETTINGS 1
49 #endif // WEBRTC_WIN
50
51 // For all platforms try Firefox.
52 #define _TRY_FIREFOX 1
53
54 // Use profiles.ini to find the correct profile for this user.
55 // If not set, we'll just look for the default one.
56 #define USE_FIREFOX_PROFILES_INI 1
57
58 static const size_t kMaxLineLength = 1024;
59 static const char kFirefoxPattern[] = "Firefox";
60 static const char kInternetExplorerPattern[] = "MSIE";
61
62 struct StringMap {
63 public:
AddStringMap64 void Add(const char * name, const char * value) { map_[name] = value; }
GetStringMap65 const std::string& Get(const char * name, const char * def = "") const {
66 std::map<std::string, std::string>::const_iterator it =
67 map_.find(name);
68 if (it != map_.end())
69 return it->second;
70 def_ = def;
71 return def_;
72 }
IsSetStringMap73 bool IsSet(const char * name) const {
74 return (map_.find(name) != map_.end());
75 }
76 private:
77 std::map<std::string, std::string> map_;
78 mutable std::string def_;
79 };
80
81 enum UserAgent {
82 UA_FIREFOX,
83 UA_INTERNETEXPLORER,
84 UA_OTHER,
85 UA_UNKNOWN
86 };
87
88 #if _TRY_WINHTTP
89 //#include <winhttp.h>
90 // Note: From winhttp.h
91
92 const char WINHTTP[] = "winhttp";
93
94 typedef LPVOID HINTERNET;
95
96 typedef struct {
97 DWORD dwAccessType; // see WINHTTP_ACCESS_* types below
98 LPWSTR lpszProxy; // proxy server list
99 LPWSTR lpszProxyBypass; // proxy bypass list
100 } WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO;
101
102 typedef struct {
103 DWORD dwFlags;
104 DWORD dwAutoDetectFlags;
105 LPCWSTR lpszAutoConfigUrl;
106 LPVOID lpvReserved;
107 DWORD dwReserved;
108 BOOL fAutoLogonIfChallenged;
109 } WINHTTP_AUTOPROXY_OPTIONS;
110
111 typedef struct {
112 BOOL fAutoDetect;
113 LPWSTR lpszAutoConfigUrl;
114 LPWSTR lpszProxy;
115 LPWSTR lpszProxyBypass;
116 } WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
117
118 extern "C" {
119 typedef HINTERNET (WINAPI * pfnWinHttpOpen)
120 (
121 IN LPCWSTR pwszUserAgent,
122 IN DWORD dwAccessType,
123 IN LPCWSTR pwszProxyName OPTIONAL,
124 IN LPCWSTR pwszProxyBypass OPTIONAL,
125 IN DWORD dwFlags
126 );
127 typedef BOOL (STDAPICALLTYPE * pfnWinHttpCloseHandle)
128 (
129 IN HINTERNET hInternet
130 );
131 typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetProxyForUrl)
132 (
133 IN HINTERNET hSession,
134 IN LPCWSTR lpcwszUrl,
135 IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
136 OUT WINHTTP_PROXY_INFO * pProxyInfo
137 );
138 typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetIEProxyConfig)
139 (
140 IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig
141 );
142
143 } // extern "C"
144
145 #define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
146 #define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
147 #define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
148 #define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
149 #define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
150 #define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
151 #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
152 #define WINHTTP_ACCESS_TYPE_NO_PROXY 1
153 #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
154 #define WINHTTP_NO_PROXY_NAME NULL
155 #define WINHTTP_NO_PROXY_BYPASS NULL
156
157 #endif // _TRY_WINHTTP
158
159 #if _TRY_JSPROXY
160 extern "C" {
161 typedef BOOL (STDAPICALLTYPE * pfnInternetGetProxyInfo)
162 (
163 LPCSTR lpszUrl,
164 DWORD dwUrlLength,
165 LPSTR lpszUrlHostName,
166 DWORD dwUrlHostNameLength,
167 LPSTR * lplpszProxyHostName,
168 LPDWORD lpdwProxyHostNameLength
169 );
170 } // extern "C"
171 #endif // _TRY_JSPROXY
172
173 #if _TRY_WM_FINDPROXY
174 #include <comutil.h>
175 #include <wmnetsourcecreator.h>
176 #include <wmsinternaladminnetsource.h>
177 #endif // _TRY_WM_FINDPROXY
178
179 #if _TRY_IE_LAN_SETTINGS
180 #include <wininet.h>
181 #include <string>
182 #endif // _TRY_IE_LAN_SETTINGS
183
184 namespace rtc {
185
186 //////////////////////////////////////////////////////////////////////
187 // Utility Functions
188 //////////////////////////////////////////////////////////////////////
189
190 #if defined(WEBRTC_WIN)
191 #ifdef _UNICODE
192
193 typedef std::wstring tstring;
Utf8String(const tstring & str)194 std::string Utf8String(const tstring& str) { return ToUtf8(str); }
195
196 #else // !_UNICODE
197
198 typedef std::string tstring;
199 std::string Utf8String(const tstring& str) { return str; }
200
201 #endif // !_UNICODE
202 #endif // WEBRTC_WIN
203
ProxyItemMatch(const Url<char> & url,char * item,size_t len)204 bool ProxyItemMatch(const Url<char>& url, char * item, size_t len) {
205 // hostname:443
206 if (char * port = ::strchr(item, ':')) {
207 *port++ = '\0';
208 if (url.port() != atol(port)) {
209 return false;
210 }
211 }
212
213 // A.B.C.D or A.B.C.D/24
214 int a, b, c, d, m;
215 int match = sscanf(item, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m);
216 if (match >= 4) {
217 uint32_t ip = ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) |
218 (d & 0xFF);
219 if ((match < 5) || (m > 32))
220 m = 32;
221 else if (m < 0)
222 m = 0;
223 uint32_t mask = (m == 0) ? 0 : (~0UL) << (32 - m);
224 SocketAddress addr(url.host(), 0);
225 // TODO: Support IPv6 proxyitems. This code block is IPv4 only anyway.
226 return !addr.IsUnresolvedIP() &&
227 ((addr.ipaddr().v4AddressAsHostOrderInteger() & mask) == (ip & mask));
228 }
229
230 // .foo.com
231 if (*item == '.') {
232 size_t hostlen = url.host().length();
233 return (hostlen > len)
234 && (stricmp(url.host().c_str() + (hostlen - len), item) == 0);
235 }
236
237 // localhost or www.*.com
238 if (!string_match(url.host().c_str(), item))
239 return false;
240
241 return true;
242 }
243
ProxyListMatch(const Url<char> & url,const std::string & proxy_list,char sep)244 bool ProxyListMatch(const Url<char>& url, const std::string& proxy_list,
245 char sep) {
246 const size_t BUFSIZE = 256;
247 char buffer[BUFSIZE];
248 const char* list = proxy_list.c_str();
249 while (*list) {
250 // Remove leading space
251 if (isspace(*list)) {
252 ++list;
253 continue;
254 }
255 // Break on separator
256 size_t len;
257 const char * start = list;
258 if (const char * end = ::strchr(list, sep)) {
259 len = (end - list);
260 list += len + 1;
261 } else {
262 len = strlen(list);
263 list += len;
264 }
265 // Remove trailing space
266 while ((len > 0) && isspace(start[len-1]))
267 --len;
268 // Check for oversized entry
269 if (len >= BUFSIZE)
270 continue;
271 memcpy(buffer, start, len);
272 buffer[len] = 0;
273 if (!ProxyItemMatch(url, buffer, len))
274 continue;
275 return true;
276 }
277 return false;
278 }
279
Better(ProxyType lhs,const ProxyType rhs)280 bool Better(ProxyType lhs, const ProxyType rhs) {
281 // PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
282 const int PROXY_VALUE[5] = { 0, 2, 3, 1 };
283 return (PROXY_VALUE[lhs] > PROXY_VALUE[rhs]);
284 }
285
ParseProxy(const std::string & saddress,ProxyInfo * proxy)286 bool ParseProxy(const std::string& saddress, ProxyInfo* proxy) {
287 const size_t kMaxAddressLength = 1024;
288 // Allow semicolon, space, or tab as an address separator
289 const char* const kAddressSeparator = " ;\t";
290
291 ProxyType ptype;
292 std::string host;
293 uint16_t port;
294
295 const char* address = saddress.c_str();
296 while (*address) {
297 size_t len;
298 const char * start = address;
299 if (const char * sep = strchr(address, kAddressSeparator)) {
300 len = (sep - address);
301 address += len + 1;
302 while (*address != '\0' && ::strchr(kAddressSeparator, *address)) {
303 address += 1;
304 }
305 } else {
306 len = strlen(address);
307 address += len;
308 }
309
310 if (len > kMaxAddressLength - 1) {
311 LOG(LS_WARNING) << "Proxy address too long [" << start << "]";
312 continue;
313 }
314
315 char buffer[kMaxAddressLength];
316 memcpy(buffer, start, len);
317 buffer[len] = 0;
318
319 char * colon = ::strchr(buffer, ':');
320 if (!colon) {
321 LOG(LS_WARNING) << "Proxy address without port [" << buffer << "]";
322 continue;
323 }
324
325 *colon = 0;
326 char * endptr;
327 port = static_cast<uint16_t>(strtol(colon + 1, &endptr, 0));
328 if (*endptr != 0) {
329 LOG(LS_WARNING) << "Proxy address with invalid port [" << buffer << "]";
330 continue;
331 }
332
333 if (char * equals = ::strchr(buffer, '=')) {
334 *equals = 0;
335 host = equals + 1;
336 if (_stricmp(buffer, "socks") == 0) {
337 ptype = PROXY_SOCKS5;
338 } else if (_stricmp(buffer, "https") == 0) {
339 ptype = PROXY_HTTPS;
340 } else {
341 LOG(LS_WARNING) << "Proxy address with unknown protocol ["
342 << buffer << "]";
343 ptype = PROXY_UNKNOWN;
344 }
345 } else {
346 host = buffer;
347 ptype = PROXY_UNKNOWN;
348 }
349
350 if (Better(ptype, proxy->type)) {
351 proxy->type = ptype;
352 proxy->address.SetIP(host);
353 proxy->address.SetPort(port);
354 }
355 }
356
357 return proxy->type != PROXY_NONE;
358 }
359
GetAgent(const char * agent)360 UserAgent GetAgent(const char* agent) {
361 if (agent) {
362 std::string agent_str(agent);
363 if (agent_str.find(kFirefoxPattern) != std::string::npos) {
364 return UA_FIREFOX;
365 } else if (agent_str.find(kInternetExplorerPattern) != std::string::npos) {
366 return UA_INTERNETEXPLORER;
367 } else if (agent_str.empty()) {
368 return UA_UNKNOWN;
369 }
370 }
371 return UA_OTHER;
372 }
373
EndsWith(const std::string & a,const std::string & b)374 bool EndsWith(const std::string& a, const std::string& b) {
375 if (b.size() > a.size()) {
376 return false;
377 }
378 int result = a.compare(a.size() - b.size(), b.size(), b);
379 return result == 0;
380 }
381
GetFirefoxProfilePath(Pathname * path)382 bool GetFirefoxProfilePath(Pathname* path) {
383 #if defined(WEBRTC_WIN)
384 wchar_t w_path[MAX_PATH];
385 if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, w_path) !=
386 S_OK) {
387 LOG(LS_ERROR) << "SHGetFolderPath failed";
388 return false;
389 }
390 path->SetFolder(ToUtf8(w_path, wcslen(w_path)));
391 path->AppendFolder("Mozilla");
392 path->AppendFolder("Firefox");
393 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
394 FSRef fr;
395 if (0 != FSFindFolder(kUserDomain, kApplicationSupportFolderType,
396 kCreateFolder, &fr)) {
397 LOG(LS_ERROR) << "FSFindFolder failed";
398 return false;
399 }
400 char buffer[NAME_MAX + 1];
401 if (0 != FSRefMakePath(&fr, reinterpret_cast<uint8_t*>(buffer),
402 arraysize(buffer))) {
403 LOG(LS_ERROR) << "FSRefMakePath failed";
404 return false;
405 }
406 path->SetFolder(std::string(buffer));
407 path->AppendFolder("Firefox");
408 #else
409 char* user_home = getenv("HOME");
410 if (user_home == NULL) {
411 return false;
412 }
413 path->SetFolder(std::string(user_home));
414 path->AppendFolder(".mozilla");
415 path->AppendFolder("firefox");
416 #endif // WEBRTC_WIN
417 return true;
418 }
419
GetDefaultFirefoxProfile(Pathname * profile_path)420 bool GetDefaultFirefoxProfile(Pathname* profile_path) {
421 ASSERT(NULL != profile_path);
422 Pathname path;
423 if (!GetFirefoxProfilePath(&path)) {
424 return false;
425 }
426
427 #if USE_FIREFOX_PROFILES_INI
428 // [Profile0]
429 // Name=default
430 // IsRelative=1
431 // Path=Profiles/2de53ejb.default
432 // Default=1
433
434 // Note: we are looking for the first entry with "Default=1", or the last
435 // entry in the file
436 path.SetFilename("profiles.ini");
437 scoped_ptr<FileStream> fs(Filesystem::OpenFile(path, "r"));
438 if (!fs) {
439 return false;
440 }
441 Pathname candidate;
442 bool relative = true;
443 std::string line;
444 while (fs->ReadLine(&line) == SR_SUCCESS) {
445 if (line.length() == 0) {
446 continue;
447 }
448 if (line.at(0) == '[') {
449 relative = true;
450 candidate.clear();
451 } else if (line.find("IsRelative=") == 0 &&
452 line.length() >= 12) {
453 // TODO: The initial Linux public launch revealed a fairly
454 // high number of machines where IsRelative= did not have anything after
455 // it. Perhaps that is legal profiles.ini syntax?
456 relative = (line.at(11) != '0');
457 } else if (line.find("Path=") == 0 &&
458 line.length() >= 6) {
459 if (relative) {
460 candidate = path;
461 } else {
462 candidate.clear();
463 }
464 candidate.AppendFolder(line.substr(5));
465 } else if (line.find("Default=") == 0 &&
466 line.length() >= 9) {
467 if ((line.at(8) != '0') && !candidate.empty()) {
468 break;
469 }
470 }
471 }
472 fs->Close();
473 if (candidate.empty()) {
474 return false;
475 }
476 profile_path->SetPathname(candidate.pathname());
477
478 #else // !USE_FIREFOX_PROFILES_INI
479 path.AppendFolder("Profiles");
480 DirectoryIterator* it = Filesystem::IterateDirectory();
481 it->Iterate(path);
482 std::string extension(".default");
483 while (!EndsWith(it->Name(), extension)) {
484 if (!it->Next()) {
485 return false;
486 }
487 }
488
489 profile_path->SetPathname(path);
490 profile->AppendFolder("Profiles");
491 profile->AppendFolder(it->Name());
492 delete it;
493
494 #endif // !USE_FIREFOX_PROFILES_INI
495
496 return true;
497 }
498
ReadFirefoxPrefs(const Pathname & filename,const char * prefix,StringMap * settings)499 bool ReadFirefoxPrefs(const Pathname& filename,
500 const char * prefix,
501 StringMap* settings) {
502 scoped_ptr<FileStream> fs(Filesystem::OpenFile(filename, "r"));
503 if (!fs) {
504 LOG(LS_ERROR) << "Failed to open file: " << filename.pathname();
505 return false;
506 }
507
508 std::string line;
509 while (fs->ReadLine(&line) == SR_SUCCESS) {
510 size_t prefix_len = strlen(prefix);
511
512 // Skip blank lines and too long lines.
513 if ((line.length() == 0) || (line.length() > kMaxLineLength)
514 || (line.at(0) == '#') || line.compare(0, 2, "/*") == 0
515 || line.compare(0, 2, " *") == 0) {
516 continue;
517 }
518
519 char buffer[kMaxLineLength];
520 strcpyn(buffer, sizeof(buffer), line.c_str());
521 int nstart = 0, nend = 0, vstart = 0, vend = 0;
522 sscanf(buffer, "user_pref(\"%n%*[^\"]%n\", %n%*[^)]%n);",
523 &nstart, &nend, &vstart, &vend);
524 if (vend > 0) {
525 char* name = buffer + nstart;
526 name[nend - nstart] = 0;
527 if ((vend - vstart >= 2) && (buffer[vstart] == '"')) {
528 vstart += 1;
529 vend -= 1;
530 }
531 char* value = buffer + vstart;
532 value[vend - vstart] = 0;
533 if ((strncmp(name, prefix, prefix_len) == 0) && *value) {
534 settings->Add(name + prefix_len, value);
535 }
536 } else {
537 LOG_F(LS_WARNING) << "Unparsed pref [" << buffer << "]";
538 }
539 }
540 fs->Close();
541 return true;
542 }
543
GetFirefoxProxySettings(const char * url,ProxyInfo * proxy)544 bool GetFirefoxProxySettings(const char* url, ProxyInfo* proxy) {
545 Url<char> purl(url);
546 Pathname path;
547 bool success = false;
548 if (GetDefaultFirefoxProfile(&path)) {
549 StringMap settings;
550 path.SetFilename("prefs.js");
551 if (ReadFirefoxPrefs(path, "network.proxy.", &settings)) {
552 success = true;
553 proxy->bypass_list =
554 settings.Get("no_proxies_on", "localhost, 127.0.0.1");
555 if (settings.Get("type") == "1") {
556 // User has manually specified a proxy, try to figure out what
557 // type it is.
558 if (ProxyListMatch(purl, proxy->bypass_list.c_str(), ',')) {
559 // Our url is in the list of url's to bypass proxy.
560 } else if (settings.Get("share_proxy_settings") == "true") {
561 proxy->type = PROXY_UNKNOWN;
562 proxy->address.SetIP(settings.Get("http"));
563 proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
564 } else if (settings.IsSet("socks")) {
565 proxy->type = PROXY_SOCKS5;
566 proxy->address.SetIP(settings.Get("socks"));
567 proxy->address.SetPort(atoi(settings.Get("socks_port").c_str()));
568 } else if (settings.IsSet("ssl")) {
569 proxy->type = PROXY_HTTPS;
570 proxy->address.SetIP(settings.Get("ssl"));
571 proxy->address.SetPort(atoi(settings.Get("ssl_port").c_str()));
572 } else if (settings.IsSet("http")) {
573 proxy->type = PROXY_HTTPS;
574 proxy->address.SetIP(settings.Get("http"));
575 proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
576 }
577 } else if (settings.Get("type") == "2") {
578 // Browser is configured to get proxy settings from a given url.
579 proxy->autoconfig_url = settings.Get("autoconfig_url").c_str();
580 } else if (settings.Get("type") == "4") {
581 // Browser is configured to auto detect proxy config.
582 proxy->autodetect = true;
583 } else {
584 // No proxy set.
585 }
586 }
587 }
588 return success;
589 }
590
591 #if defined(WEBRTC_WIN) // Windows specific implementation for reading Internet
592 // Explorer proxy settings.
593
LogGetProxyFault()594 void LogGetProxyFault() {
595 LOG_GLEM(LERROR, WINHTTP) << "WinHttpGetProxyForUrl faulted!!";
596 }
597
MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,HINTERNET hWinHttp,LPCWSTR url,WINHTTP_AUTOPROXY_OPTIONS * options,WINHTTP_PROXY_INFO * info)598 BOOL MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,
599 HINTERNET hWinHttp, LPCWSTR url,
600 WINHTTP_AUTOPROXY_OPTIONS *options,
601 WINHTTP_PROXY_INFO *info) {
602 // WinHttpGetProxyForUrl() can call plugins which can crash.
603 // In the case of McAfee scriptproxy.dll, it does crash in
604 // older versions. Try to catch crashes here and treat as an
605 // error.
606 BOOL success = FALSE;
607
608 #if (_HAS_EXCEPTIONS == 0)
609 __try {
610 success = pWHGPFU(hWinHttp, url, options, info);
611 } __except(EXCEPTION_EXECUTE_HANDLER) {
612 // This is a separate function to avoid
613 // Visual C++ error 2712 when compiling with C++ EH
614 LogGetProxyFault();
615 }
616 #else
617 success = pWHGPFU(hWinHttp, url, options, info);
618 #endif // (_HAS_EXCEPTIONS == 0)
619
620 return success;
621 }
622
IsDefaultBrowserFirefox()623 bool IsDefaultBrowserFirefox() {
624 HKEY key;
625 LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command",
626 0, KEY_READ, &key);
627 if (ERROR_SUCCESS != result)
628 return false;
629
630 DWORD size, type;
631 bool success = false;
632 result = RegQueryValueEx(key, L"", 0, &type, NULL, &size);
633 if (result == ERROR_SUCCESS && type == REG_SZ) {
634 wchar_t* value = new wchar_t[size+1];
635 BYTE* buffer = reinterpret_cast<BYTE*>(value);
636 result = RegQueryValueEx(key, L"", 0, &type, buffer, &size);
637 if (result == ERROR_SUCCESS) {
638 // Size returned by RegQueryValueEx is in bytes, convert to number of
639 // wchar_t's.
640 size /= sizeof(value[0]);
641 value[size] = L'\0';
642 for (size_t i = 0; i < size; ++i) {
643 value[i] = tolowercase(value[i]);
644 }
645 success = (NULL != strstr(value, L"firefox.exe"));
646 }
647 delete[] value;
648 }
649
650 RegCloseKey(key);
651 return success;
652 }
653
GetWinHttpProxySettings(const char * url,ProxyInfo * proxy)654 bool GetWinHttpProxySettings(const char* url, ProxyInfo* proxy) {
655 HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
656 if (winhttp_handle == NULL) {
657 LOG(LS_ERROR) << "Failed to load winhttp.dll.";
658 return false;
659 }
660 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG iecfg;
661 memset(&iecfg, 0, sizeof(iecfg));
662 Url<char> purl(url);
663 pfnWinHttpGetIEProxyConfig pWHGIEPC =
664 reinterpret_cast<pfnWinHttpGetIEProxyConfig>(
665 GetProcAddress(winhttp_handle,
666 "WinHttpGetIEProxyConfigForCurrentUser"));
667 bool success = false;
668 if (pWHGIEPC && pWHGIEPC(&iecfg)) {
669 // We were read proxy config successfully.
670 success = true;
671 if (iecfg.fAutoDetect) {
672 proxy->autodetect = true;
673 }
674 if (iecfg.lpszAutoConfigUrl) {
675 proxy->autoconfig_url = ToUtf8(iecfg.lpszAutoConfigUrl);
676 GlobalFree(iecfg.lpszAutoConfigUrl);
677 }
678 if (iecfg.lpszProxyBypass) {
679 proxy->bypass_list = ToUtf8(iecfg.lpszProxyBypass);
680 GlobalFree(iecfg.lpszProxyBypass);
681 }
682 if (iecfg.lpszProxy) {
683 if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
684 ParseProxy(ToUtf8(iecfg.lpszProxy), proxy);
685 }
686 GlobalFree(iecfg.lpszProxy);
687 }
688 }
689 FreeLibrary(winhttp_handle);
690 return success;
691 }
692
693 // Uses the WinHTTP API to auto detect proxy for the given url. Firefox and IE
694 // have slightly different option dialogs for proxy settings. In Firefox,
695 // either a location of a proxy configuration file can be specified or auto
696 // detection can be selected. In IE theese two options can be independently
697 // selected. For the case where both options are selected (only IE) we try to
698 // fetch the config file first, and if that fails we'll perform an auto
699 // detection.
700 //
701 // Returns true if we successfully performed an auto detection not depending on
702 // whether we found a proxy or not. Returns false on error.
WinHttpAutoDetectProxyForUrl(const char * agent,const char * url,ProxyInfo * proxy)703 bool WinHttpAutoDetectProxyForUrl(const char* agent, const char* url,
704 ProxyInfo* proxy) {
705 Url<char> purl(url);
706 bool success = true;
707 HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
708 if (winhttp_handle == NULL) {
709 LOG(LS_ERROR) << "Failed to load winhttp.dll.";
710 return false;
711 }
712 pfnWinHttpOpen pWHO =
713 reinterpret_cast<pfnWinHttpOpen>(GetProcAddress(winhttp_handle,
714 "WinHttpOpen"));
715 pfnWinHttpCloseHandle pWHCH =
716 reinterpret_cast<pfnWinHttpCloseHandle>(
717 GetProcAddress(winhttp_handle, "WinHttpCloseHandle"));
718 pfnWinHttpGetProxyForUrl pWHGPFU =
719 reinterpret_cast<pfnWinHttpGetProxyForUrl>(
720 GetProcAddress(winhttp_handle, "WinHttpGetProxyForUrl"));
721 if (pWHO && pWHCH && pWHGPFU) {
722 if (HINTERNET hWinHttp = pWHO(ToUtf16(agent).c_str(),
723 WINHTTP_ACCESS_TYPE_NO_PROXY,
724 WINHTTP_NO_PROXY_NAME,
725 WINHTTP_NO_PROXY_BYPASS,
726 0)) {
727 BOOL result = FALSE;
728 WINHTTP_PROXY_INFO info;
729 memset(&info, 0, sizeof(info));
730 if (proxy->autodetect) {
731 // Use DHCP and DNS to try to find any proxy to use.
732 WINHTTP_AUTOPROXY_OPTIONS options;
733 memset(&options, 0, sizeof(options));
734 options.fAutoLogonIfChallenged = TRUE;
735
736 options.dwFlags |= WINHTTP_AUTOPROXY_AUTO_DETECT;
737 options.dwAutoDetectFlags |= WINHTTP_AUTO_DETECT_TYPE_DHCP
738 | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
739 result = MyWinHttpGetProxyForUrl(
740 pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
741 }
742 if (!result && !proxy->autoconfig_url.empty()) {
743 // We have the location of a proxy config file. Download it and
744 // execute it to find proxy settings for our url.
745 WINHTTP_AUTOPROXY_OPTIONS options;
746 memset(&options, 0, sizeof(options));
747 memset(&info, 0, sizeof(info));
748 options.fAutoLogonIfChallenged = TRUE;
749
750 std::wstring autoconfig_url16((ToUtf16)(proxy->autoconfig_url));
751 options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
752 options.lpszAutoConfigUrl = autoconfig_url16.c_str();
753
754 result = MyWinHttpGetProxyForUrl(
755 pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
756 }
757 if (result) {
758 // Either the given auto config url was valid or auto
759 // detection found a proxy on this network.
760 if (info.lpszProxy) {
761 // TODO: Does this bypass list differ from the list
762 // retreived from GetWinHttpProxySettings earlier?
763 if (info.lpszProxyBypass) {
764 proxy->bypass_list = ToUtf8(info.lpszProxyBypass);
765 GlobalFree(info.lpszProxyBypass);
766 } else {
767 proxy->bypass_list.clear();
768 }
769 if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
770 // Found proxy for this URL. If parsing the address turns
771 // out ok then we are successful.
772 success = ParseProxy(ToUtf8(info.lpszProxy), proxy);
773 }
774 GlobalFree(info.lpszProxy);
775 }
776 } else {
777 // We could not find any proxy for this url.
778 LOG(LS_INFO) << "No proxy detected for " << url;
779 }
780 pWHCH(hWinHttp);
781 }
782 } else {
783 LOG(LS_ERROR) << "Failed loading WinHTTP functions.";
784 success = false;
785 }
786 FreeLibrary(winhttp_handle);
787 return success;
788 }
789
790 #if 0 // Below functions currently not used.
791
792 bool GetJsProxySettings(const char* url, ProxyInfo* proxy) {
793 Url<char> purl(url);
794 bool success = false;
795
796 if (HMODULE hModJS = LoadLibrary(_T("jsproxy.dll"))) {
797 pfnInternetGetProxyInfo pIGPI =
798 reinterpret_cast<pfnInternetGetProxyInfo>(
799 GetProcAddress(hModJS, "InternetGetProxyInfo"));
800 if (pIGPI) {
801 char proxy[256], host[256];
802 memset(proxy, 0, sizeof(proxy));
803 char * ptr = proxy;
804 DWORD proxylen = sizeof(proxy);
805 std::string surl = Utf8String(url);
806 DWORD hostlen = _snprintf(host, sizeof(host), "http%s://%S",
807 purl.secure() ? "s" : "", purl.server());
808 if (pIGPI(surl.data(), surl.size(), host, hostlen, &ptr, &proxylen)) {
809 LOG(INFO) << "Proxy: " << proxy;
810 } else {
811 LOG_GLE(INFO) << "InternetGetProxyInfo";
812 }
813 }
814 FreeLibrary(hModJS);
815 }
816 return success;
817 }
818
819 bool GetWmProxySettings(const char* url, ProxyInfo* proxy) {
820 Url<char> purl(url);
821 bool success = false;
822
823 INSNetSourceCreator * nsc = 0;
824 HRESULT hr = CoCreateInstance(CLSID_ClientNetManager, 0, CLSCTX_ALL,
825 IID_INSNetSourceCreator, (LPVOID *) &nsc);
826 if (SUCCEEDED(hr)) {
827 if (SUCCEEDED(hr = nsc->Initialize())) {
828 VARIANT dispatch;
829 VariantInit(&dispatch);
830 if (SUCCEEDED(hr = nsc->GetNetSourceAdminInterface(L"http", &dispatch))) {
831 IWMSInternalAdminNetSource * ians = 0;
832 if (SUCCEEDED(hr = dispatch.pdispVal->QueryInterface(
833 IID_IWMSInternalAdminNetSource, (LPVOID *) &ians))) {
834 _bstr_t host(purl.server());
835 BSTR proxy = 0;
836 BOOL bProxyEnabled = FALSE;
837 DWORD port, context = 0;
838 if (SUCCEEDED(hr = ians->FindProxyForURL(
839 L"http", host, &bProxyEnabled, &proxy, &port, &context))) {
840 success = true;
841 if (bProxyEnabled) {
842 _bstr_t sproxy = proxy;
843 proxy->ptype = PT_HTTPS;
844 proxy->host = sproxy;
845 proxy->port = port;
846 }
847 }
848 SysFreeString(proxy);
849 if (FAILED(hr = ians->ShutdownProxyContext(context))) {
850 LOG(LS_INFO) << "IWMSInternalAdminNetSource::ShutdownProxyContext"
851 << "failed: " << hr;
852 }
853 ians->Release();
854 }
855 }
856 VariantClear(&dispatch);
857 if (FAILED(hr = nsc->Shutdown())) {
858 LOG(LS_INFO) << "INSNetSourceCreator::Shutdown failed: " << hr;
859 }
860 }
861 nsc->Release();
862 }
863 return success;
864 }
865
866 bool GetIePerConnectionProxySettings(const char* url, ProxyInfo* proxy) {
867 Url<char> purl(url);
868 bool success = false;
869
870 INTERNET_PER_CONN_OPTION_LIST list;
871 INTERNET_PER_CONN_OPTION options[3];
872 memset(&list, 0, sizeof(list));
873 memset(&options, 0, sizeof(options));
874
875 list.dwSize = sizeof(list);
876 list.dwOptionCount = 3;
877 list.pOptions = options;
878 options[0].dwOption = INTERNET_PER_CONN_FLAGS;
879 options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
880 options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
881 DWORD dwSize = sizeof(list);
882
883 if (!InternetQueryOption(0, INTERNET_OPTION_PER_CONNECTION_OPTION, &list,
884 &dwSize)) {
885 LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
886 } else if ((options[0].Value.dwValue & PROXY_TYPE_PROXY) != 0) {
887 success = true;
888 if (!ProxyListMatch(purl, nonnull(options[2].Value.pszValue), _T(';'))) {
889 ParseProxy(nonnull(options[1].Value.pszValue), proxy);
890 }
891 } else if ((options[0].Value.dwValue & PROXY_TYPE_DIRECT) != 0) {
892 success = true;
893 } else {
894 LOG(LS_INFO) << "unknown internet access type: "
895 << options[0].Value.dwValue;
896 }
897 if (options[1].Value.pszValue) {
898 GlobalFree(options[1].Value.pszValue);
899 }
900 if (options[2].Value.pszValue) {
901 GlobalFree(options[2].Value.pszValue);
902 }
903 return success;
904 }
905
906 #endif // 0
907
908 // Uses the InternetQueryOption function to retrieve proxy settings
909 // from the registry. This will only give us the 'static' settings,
910 // ie, not any information about auto config etc.
GetIeLanProxySettings(const char * url,ProxyInfo * proxy)911 bool GetIeLanProxySettings(const char* url, ProxyInfo* proxy) {
912 Url<char> purl(url);
913 bool success = false;
914
915 wchar_t buffer[1024];
916 memset(buffer, 0, sizeof(buffer));
917 INTERNET_PROXY_INFO * info = reinterpret_cast<INTERNET_PROXY_INFO *>(buffer);
918 DWORD dwSize = sizeof(buffer);
919
920 if (!InternetQueryOption(0, INTERNET_OPTION_PROXY, info, &dwSize)) {
921 LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
922 } else if (info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
923 success = true;
924 } else if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
925 success = true;
926 if (!ProxyListMatch(purl, nonnull(reinterpret_cast<const char*>(
927 info->lpszProxyBypass)), ' ')) {
928 ParseProxy(nonnull(reinterpret_cast<const char*>(info->lpszProxy)),
929 proxy);
930 }
931 } else {
932 LOG(LS_INFO) << "unknown internet access type: " << info->dwAccessType;
933 }
934 return success;
935 }
936
GetIeProxySettings(const char * agent,const char * url,ProxyInfo * proxy)937 bool GetIeProxySettings(const char* agent, const char* url, ProxyInfo* proxy) {
938 bool success = GetWinHttpProxySettings(url, proxy);
939 if (!success) {
940 // TODO: Should always call this if no proxy were detected by
941 // GetWinHttpProxySettings?
942 // WinHttp failed. Try using the InternetOptionQuery method instead.
943 return GetIeLanProxySettings(url, proxy);
944 }
945 return true;
946 }
947
948 #endif // WEBRTC_WIN
949
950 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) // WEBRTC_MAC && !defined(WEBRTC_IOS) specific implementation for reading system wide
951 // proxy settings.
952
p_getProxyInfoForTypeFromDictWithKeys(ProxyInfo * proxy,ProxyType type,const CFDictionaryRef proxyDict,const CFStringRef enabledKey,const CFStringRef hostKey,const CFStringRef portKey)953 bool p_getProxyInfoForTypeFromDictWithKeys(ProxyInfo* proxy,
954 ProxyType type,
955 const CFDictionaryRef proxyDict,
956 const CFStringRef enabledKey,
957 const CFStringRef hostKey,
958 const CFStringRef portKey) {
959 // whether or not we set up the proxy info.
960 bool result = false;
961
962 // we use this as a scratch variable for determining if operations
963 // succeeded.
964 bool converted = false;
965
966 // the data we need to construct the SocketAddress for the proxy.
967 std::string hostname;
968 int port;
969
970 if ((proxyDict != NULL) &&
971 (CFGetTypeID(proxyDict) == CFDictionaryGetTypeID())) {
972 // CoreFoundation stuff that we'll have to get from
973 // the dictionaries and interpret or convert into more usable formats.
974 CFNumberRef enabledCFNum;
975 CFNumberRef portCFNum;
976 CFStringRef hostCFStr;
977
978 enabledCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, enabledKey);
979
980 if (p_isCFNumberTrue(enabledCFNum)) {
981 // let's see if we can get the address and port.
982 hostCFStr = (CFStringRef)CFDictionaryGetValue(proxyDict, hostKey);
983 converted = p_convertHostCFStringRefToCPPString(hostCFStr, hostname);
984 if (converted) {
985 portCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, portKey);
986 converted = p_convertCFNumberToInt(portCFNum, &port);
987 if (converted) {
988 // we have something enabled, with a hostname and a port.
989 // That's sufficient to set up the proxy info.
990 proxy->type = type;
991 proxy->address.SetIP(hostname);
992 proxy->address.SetPort(port);
993 result = true;
994 }
995 }
996 }
997 }
998
999 return result;
1000 }
1001
1002 // Looks for proxy information in the given dictionary,
1003 // return true if it found sufficient information to define one,
1004 // false otherwise. This is guaranteed to not change the values in proxy
1005 // unless a full-fledged proxy description was discovered in the dictionary.
1006 // However, at the present time this does not support username or password.
1007 // Checks first for a SOCKS proxy, then for HTTPS, then HTTP.
GetMacProxySettingsFromDictionary(ProxyInfo * proxy,const CFDictionaryRef proxyDict)1008 bool GetMacProxySettingsFromDictionary(ProxyInfo* proxy,
1009 const CFDictionaryRef proxyDict) {
1010 // the function result.
1011 bool gotProxy = false;
1012
1013
1014 // first we see if there's a SOCKS proxy in place.
1015 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
1016 PROXY_SOCKS5,
1017 proxyDict,
1018 kSCPropNetProxiesSOCKSEnable,
1019 kSCPropNetProxiesSOCKSProxy,
1020 kSCPropNetProxiesSOCKSPort);
1021
1022 if (!gotProxy) {
1023 // okay, no SOCKS proxy, let's look for https.
1024 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
1025 PROXY_HTTPS,
1026 proxyDict,
1027 kSCPropNetProxiesHTTPSEnable,
1028 kSCPropNetProxiesHTTPSProxy,
1029 kSCPropNetProxiesHTTPSPort);
1030 if (!gotProxy) {
1031 // Finally, try HTTP proxy. Note that flute doesn't
1032 // differentiate between HTTPS and HTTP, hence we are using the
1033 // same flute type here, ie. PROXY_HTTPS.
1034 gotProxy = p_getProxyInfoForTypeFromDictWithKeys(
1035 proxy, PROXY_HTTPS, proxyDict, kSCPropNetProxiesHTTPEnable,
1036 kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort);
1037 }
1038 }
1039 return gotProxy;
1040 }
1041
1042 // TODO(hughv) Update keychain functions. They work on 10.8, but are depricated.
1043 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
p_putPasswordInProxyInfo(ProxyInfo * proxy)1044 bool p_putPasswordInProxyInfo(ProxyInfo* proxy) {
1045 bool result = true; // by default we assume we're good.
1046 // for all we know there isn't any password. We'll set to false
1047 // if we find a problem.
1048
1049 // Ask the keychain for an internet password search for the given protocol.
1050 OSStatus oss = 0;
1051 SecKeychainAttributeList attrList;
1052 attrList.count = 3;
1053 SecKeychainAttribute attributes[3];
1054 attrList.attr = attributes;
1055
1056 attributes[0].tag = kSecProtocolItemAttr;
1057 attributes[0].length = sizeof(SecProtocolType);
1058 SecProtocolType protocol;
1059 switch (proxy->type) {
1060 case PROXY_HTTPS :
1061 protocol = kSecProtocolTypeHTTPS;
1062 break;
1063 case PROXY_SOCKS5 :
1064 protocol = kSecProtocolTypeSOCKS;
1065 break;
1066 default :
1067 LOG(LS_ERROR) << "asked for proxy password for unknown proxy type.";
1068 result = false;
1069 break;
1070 }
1071 attributes[0].data = &protocol;
1072
1073 UInt32 port = proxy->address.port();
1074 attributes[1].tag = kSecPortItemAttr;
1075 attributes[1].length = sizeof(UInt32);
1076 attributes[1].data = &port;
1077
1078 std::string ip = proxy->address.ipaddr().ToString();
1079 attributes[2].tag = kSecServerItemAttr;
1080 attributes[2].length = ip.length();
1081 attributes[2].data = const_cast<char*>(ip.c_str());
1082
1083 if (result) {
1084 LOG(LS_INFO) << "trying to get proxy username/password";
1085 SecKeychainSearchRef sref;
1086 oss = SecKeychainSearchCreateFromAttributes(NULL,
1087 kSecInternetPasswordItemClass,
1088 &attrList, &sref);
1089 if (0 == oss) {
1090 LOG(LS_INFO) << "SecKeychainSearchCreateFromAttributes was good";
1091 // Get the first item, if there is one.
1092 SecKeychainItemRef iref;
1093 oss = SecKeychainSearchCopyNext(sref, &iref);
1094 if (0 == oss) {
1095 LOG(LS_INFO) << "...looks like we have the username/password data";
1096 // If there is, get the username and the password.
1097
1098 SecKeychainAttributeInfo attribsToGet;
1099 attribsToGet.count = 1;
1100 UInt32 tag = kSecAccountItemAttr;
1101 UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
1102 void *data;
1103 UInt32 length;
1104 SecKeychainAttributeList *localList;
1105
1106 attribsToGet.tag = &tag;
1107 attribsToGet.format = &format;
1108 OSStatus copyres = SecKeychainItemCopyAttributesAndData(iref,
1109 &attribsToGet,
1110 NULL,
1111 &localList,
1112 &length,
1113 &data);
1114 if (0 == copyres) {
1115 LOG(LS_INFO) << "...and we can pull it out.";
1116 // now, we know from experimentation (sadly not from docs)
1117 // that the username is in the local attribute list,
1118 // and the password in the data,
1119 // both without null termination but with info on their length.
1120 // grab the password from the data.
1121 std::string password;
1122 password.append(static_cast<const char*>(data), length);
1123
1124 // make the password into a CryptString
1125 // huh, at the time of writing, you can't.
1126 // so we'll skip that for now and come back to it later.
1127
1128 // now put the username in the proxy.
1129 if (1 <= localList->attr->length) {
1130 proxy->username.append(
1131 static_cast<const char*>(localList->attr->data),
1132 localList->attr->length);
1133 LOG(LS_INFO) << "username is " << proxy->username;
1134 } else {
1135 LOG(LS_ERROR) << "got keychain entry with no username";
1136 result = false;
1137 }
1138 } else {
1139 LOG(LS_ERROR) << "couldn't copy info from keychain.";
1140 result = false;
1141 }
1142 SecKeychainItemFreeAttributesAndData(localList, data);
1143 } else if (errSecItemNotFound == oss) {
1144 LOG(LS_INFO) << "...username/password info not found";
1145 } else {
1146 // oooh, neither 0 nor itemNotFound.
1147 LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
1148 result = false;
1149 }
1150 } else if (errSecItemNotFound == oss) { // noop
1151 } else {
1152 // oooh, neither 0 nor itemNotFound.
1153 LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
1154 result = false;
1155 }
1156 }
1157
1158 return result;
1159 }
1160
GetMacProxySettings(ProxyInfo * proxy)1161 bool GetMacProxySettings(ProxyInfo* proxy) {
1162 // based on the Apple Technical Q&A QA1234
1163 // http://developer.apple.com/qa/qa2001/qa1234.html
1164 CFDictionaryRef proxyDict = SCDynamicStoreCopyProxies(NULL);
1165 bool result = false;
1166
1167 if (proxyDict != NULL) {
1168 // sending it off to another function makes it easier to unit test
1169 // since we can make our own dictionary to hand to that function.
1170 result = GetMacProxySettingsFromDictionary(proxy, proxyDict);
1171
1172 if (result) {
1173 result = p_putPasswordInProxyInfo(proxy);
1174 }
1175
1176 // We created the dictionary with something that had the
1177 // word 'copy' in it, so we have to release it, according
1178 // to the Carbon memory management standards.
1179 CFRelease(proxyDict);
1180 } else {
1181 LOG(LS_ERROR) << "SCDynamicStoreCopyProxies failed";
1182 }
1183
1184 return result;
1185 }
1186 #endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
1187
1188 #ifdef WEBRTC_IOS
1189 // iOS has only http proxy
GetiOSProxySettings(ProxyInfo * proxy)1190 bool GetiOSProxySettings(ProxyInfo* proxy) {
1191
1192 bool result = false;
1193
1194 CFDictionaryRef proxy_dict = CFNetworkCopySystemProxySettings();
1195 if (!proxy_dict) {
1196 LOG(LS_ERROR) << "CFNetworkCopySystemProxySettings failed";
1197 return false;
1198 }
1199
1200 CFNumberRef proxiesHTTPEnable = (CFNumberRef)CFDictionaryGetValue(
1201 proxy_dict, kCFNetworkProxiesHTTPEnable);
1202 if (!p_isCFNumberTrue(proxiesHTTPEnable)) {
1203 CFRelease(proxy_dict);
1204 return false;
1205 }
1206
1207 CFStringRef proxy_address = (CFStringRef)CFDictionaryGetValue(
1208 proxy_dict, kCFNetworkProxiesHTTPProxy);
1209 CFNumberRef proxy_port = (CFNumberRef)CFDictionaryGetValue(
1210 proxy_dict, kCFNetworkProxiesHTTPPort);
1211
1212 // the data we need to construct the SocketAddress for the proxy.
1213 std::string hostname;
1214 int port;
1215 if (p_convertHostCFStringRefToCPPString(proxy_address, hostname) &&
1216 p_convertCFNumberToInt(proxy_port, &port)) {
1217 // We have something enabled, with a hostname and a port.
1218 // That's sufficient to set up the proxy info.
1219 // Finally, try HTTP proxy. Note that flute doesn't
1220 // differentiate between HTTPS and HTTP, hence we are using the
1221 // same flute type here, ie. PROXY_HTTPS.
1222 proxy->type = PROXY_HTTPS;
1223
1224 proxy->address.SetIP(hostname);
1225 proxy->address.SetPort(port);
1226 result = true;
1227 }
1228
1229 // We created the dictionary with something that had the
1230 // word 'copy' in it, so we have to release it, according
1231 // to the Carbon memory management standards.
1232 CFRelease(proxy_dict);
1233
1234 return result;
1235 }
1236 #endif // WEBRTC_IOS
1237
AutoDetectProxySettings(const char * agent,const char * url,ProxyInfo * proxy)1238 bool AutoDetectProxySettings(const char* agent, const char* url,
1239 ProxyInfo* proxy) {
1240 #if defined(WEBRTC_WIN)
1241 return WinHttpAutoDetectProxyForUrl(agent, url, proxy);
1242 #else
1243 LOG(LS_WARNING) << "Proxy auto-detection not implemented for this platform";
1244 return false;
1245 #endif
1246 }
1247
GetSystemDefaultProxySettings(const char * agent,const char * url,ProxyInfo * proxy)1248 bool GetSystemDefaultProxySettings(const char* agent, const char* url,
1249 ProxyInfo* proxy) {
1250 #if defined(WEBRTC_WIN)
1251 return GetIeProxySettings(agent, url, proxy);
1252 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
1253 return GetMacProxySettings(proxy);
1254 #elif defined(WEBRTC_IOS)
1255 return GetiOSProxySettings(proxy);
1256 #else
1257 // TODO: Get System settings if browser is not firefox.
1258 return GetFirefoxProxySettings(url, proxy);
1259 #endif
1260 }
1261
GetProxySettingsForUrl(const char * agent,const char * url,ProxyInfo * proxy,bool long_operation)1262 bool GetProxySettingsForUrl(const char* agent, const char* url,
1263 ProxyInfo* proxy, bool long_operation) {
1264 UserAgent a = GetAgent(agent);
1265 bool result;
1266 switch (a) {
1267 case UA_FIREFOX: {
1268 result = GetFirefoxProxySettings(url, proxy);
1269 break;
1270 }
1271 #if defined(WEBRTC_WIN)
1272 case UA_INTERNETEXPLORER:
1273 result = GetIeProxySettings(agent, url, proxy);
1274 break;
1275 case UA_UNKNOWN:
1276 // Agent not defined, check default browser.
1277 if (IsDefaultBrowserFirefox()) {
1278 result = GetFirefoxProxySettings(url, proxy);
1279 } else {
1280 result = GetIeProxySettings(agent, url, proxy);
1281 }
1282 break;
1283 #endif // WEBRTC_WIN
1284 default:
1285 result = GetSystemDefaultProxySettings(agent, url, proxy);
1286 break;
1287 }
1288
1289 // TODO: Consider using the 'long_operation' parameter to
1290 // decide whether to do the auto detection.
1291 if (result && (proxy->autodetect ||
1292 !proxy->autoconfig_url.empty())) {
1293 // Use WinHTTP to auto detect proxy for us.
1294 result = AutoDetectProxySettings(agent, url, proxy);
1295 if (!result) {
1296 // Either auto detection is not supported or we simply didn't
1297 // find any proxy, reset type.
1298 proxy->type = rtc::PROXY_NONE;
1299 }
1300 }
1301 return result;
1302 }
1303
1304 } // namespace rtc
1305