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