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