Home | History | Annotate | Download | only in base
      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:
     58   void Add(const char * name, const char * value) { map_[name] = value; }
     59   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   }
     67   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;
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    588 void LogGetProxyFault() {
    589   LOG_GLEM(LERROR, WINHTTP) << "WinHttpGetProxyForUrl faulted!!";
    590 }
    591 
    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 
    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 
    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.
    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.
    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 
    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 
    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.
   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"
   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 
   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 
   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 
   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 
   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