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