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