aboutsummaryrefslogtreecommitdiff
path: root/webrtc/base/proxydetect.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/base/proxydetect.cc')
-rw-r--r--webrtc/base/proxydetect.cc1303
1 files changed, 1303 insertions, 0 deletions
diff --git a/webrtc/base/proxydetect.cc b/webrtc/base/proxydetect.cc
new file mode 100644
index 0000000000..b144d20a97
--- /dev/null
+++ b/webrtc/base/proxydetect.cc
@@ -0,0 +1,1303 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/base/proxydetect.h"
+
+#if defined(WEBRTC_WIN)
+#include "webrtc/base/win32.h"
+#include <shlobj.h>
+#endif // WEBRTC_WIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <Security/Security.h>
+#include "macconversion.h"
+#endif
+
+#ifdef WEBRTC_IOS
+#include <CFNetwork/CFNetwork.h>
+#include "macconversion.h"
+#endif
+
+#include <map>
+
+#include "webrtc/base/fileutils.h"
+#include "webrtc/base/httpcommon.h"
+#include "webrtc/base/httpcommon-inl.h"
+#include "webrtc/base/pathutils.h"
+#include "webrtc/base/stringutils.h"
+
+#if defined(WEBRTC_WIN)
+#define _TRY_WINHTTP 1
+#define _TRY_JSPROXY 0
+#define _TRY_WM_FINDPROXY 0
+#define _TRY_IE_LAN_SETTINGS 1
+#endif // WEBRTC_WIN
+
+// For all platforms try Firefox.
+#define _TRY_FIREFOX 1
+
+// Use profiles.ini to find the correct profile for this user.
+// If not set, we'll just look for the default one.
+#define USE_FIREFOX_PROFILES_INI 1
+
+static const size_t kMaxLineLength = 1024;
+static const char kFirefoxPattern[] = "Firefox";
+static const char kInternetExplorerPattern[] = "MSIE";
+
+struct StringMap {
+ public:
+ void Add(const char * name, const char * value) { map_[name] = value; }
+ const std::string& Get(const char * name, const char * def = "") const {
+ std::map<std::string, std::string>::const_iterator it =
+ map_.find(name);
+ if (it != map_.end())
+ return it->second;
+ def_ = def;
+ return def_;
+ }
+ bool IsSet(const char * name) const {
+ return (map_.find(name) != map_.end());
+ }
+ private:
+ std::map<std::string, std::string> map_;
+ mutable std::string def_;
+};
+
+enum UserAgent {
+ UA_FIREFOX,
+ UA_INTERNETEXPLORER,
+ UA_OTHER,
+ UA_UNKNOWN
+};
+
+#if _TRY_WINHTTP
+//#include <winhttp.h>
+// Note: From winhttp.h
+
+const char WINHTTP[] = "winhttp";
+
+typedef LPVOID HINTERNET;
+
+typedef struct {
+ DWORD dwAccessType; // see WINHTTP_ACCESS_* types below
+ LPWSTR lpszProxy; // proxy server list
+ LPWSTR lpszProxyBypass; // proxy bypass list
+} WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO;
+
+typedef struct {
+ DWORD dwFlags;
+ DWORD dwAutoDetectFlags;
+ LPCWSTR lpszAutoConfigUrl;
+ LPVOID lpvReserved;
+ DWORD dwReserved;
+ BOOL fAutoLogonIfChallenged;
+} WINHTTP_AUTOPROXY_OPTIONS;
+
+typedef struct {
+ BOOL fAutoDetect;
+ LPWSTR lpszAutoConfigUrl;
+ LPWSTR lpszProxy;
+ LPWSTR lpszProxyBypass;
+} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
+
+extern "C" {
+ typedef HINTERNET (WINAPI * pfnWinHttpOpen)
+ (
+ IN LPCWSTR pwszUserAgent,
+ IN DWORD dwAccessType,
+ IN LPCWSTR pwszProxyName OPTIONAL,
+ IN LPCWSTR pwszProxyBypass OPTIONAL,
+ IN DWORD dwFlags
+ );
+ typedef BOOL (STDAPICALLTYPE * pfnWinHttpCloseHandle)
+ (
+ IN HINTERNET hInternet
+ );
+ typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetProxyForUrl)
+ (
+ IN HINTERNET hSession,
+ IN LPCWSTR lpcwszUrl,
+ IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
+ OUT WINHTTP_PROXY_INFO * pProxyInfo
+ );
+ typedef BOOL (STDAPICALLTYPE * pfnWinHttpGetIEProxyConfig)
+ (
+ IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig
+ );
+
+} // extern "C"
+
+#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
+#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
+#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
+#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
+#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
+#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
+#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
+#define WINHTTP_ACCESS_TYPE_NO_PROXY 1
+#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
+#define WINHTTP_NO_PROXY_NAME NULL
+#define WINHTTP_NO_PROXY_BYPASS NULL
+
+#endif // _TRY_WINHTTP
+
+#if _TRY_JSPROXY
+extern "C" {
+ typedef BOOL (STDAPICALLTYPE * pfnInternetGetProxyInfo)
+ (
+ LPCSTR lpszUrl,
+ DWORD dwUrlLength,
+ LPSTR lpszUrlHostName,
+ DWORD dwUrlHostNameLength,
+ LPSTR * lplpszProxyHostName,
+ LPDWORD lpdwProxyHostNameLength
+ );
+} // extern "C"
+#endif // _TRY_JSPROXY
+
+#if _TRY_WM_FINDPROXY
+#include <comutil.h>
+#include <wmnetsourcecreator.h>
+#include <wmsinternaladminnetsource.h>
+#endif // _TRY_WM_FINDPROXY
+
+#if _TRY_IE_LAN_SETTINGS
+#include <wininet.h>
+#include <string>
+#endif // _TRY_IE_LAN_SETTINGS
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+// Utility Functions
+//////////////////////////////////////////////////////////////////////
+
+#if defined(WEBRTC_WIN)
+#ifdef _UNICODE
+
+typedef std::wstring tstring;
+std::string Utf8String(const tstring& str) { return ToUtf8(str); }
+
+#else // !_UNICODE
+
+typedef std::string tstring;
+std::string Utf8String(const tstring& str) { return str; }
+
+#endif // !_UNICODE
+#endif // WEBRTC_WIN
+
+bool ProxyItemMatch(const Url<char>& url, char * item, size_t len) {
+ // hostname:443
+ if (char * port = ::strchr(item, ':')) {
+ *port++ = '\0';
+ if (url.port() != atol(port)) {
+ return false;
+ }
+ }
+
+ // A.B.C.D or A.B.C.D/24
+ int a, b, c, d, m;
+ int match = sscanf(item, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m);
+ if (match >= 4) {
+ uint32_t ip = ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) |
+ (d & 0xFF);
+ if ((match < 5) || (m > 32))
+ m = 32;
+ else if (m < 0)
+ m = 0;
+ uint32_t mask = (m == 0) ? 0 : (~0UL) << (32 - m);
+ SocketAddress addr(url.host(), 0);
+ // TODO: Support IPv6 proxyitems. This code block is IPv4 only anyway.
+ return !addr.IsUnresolved() &&
+ ((addr.ipaddr().v4AddressAsHostOrderInteger() & mask) == (ip & mask));
+ }
+
+ // .foo.com
+ if (*item == '.') {
+ size_t hostlen = url.host().length();
+ return (hostlen > len)
+ && (stricmp(url.host().c_str() + (hostlen - len), item) == 0);
+ }
+
+ // localhost or www.*.com
+ if (!string_match(url.host().c_str(), item))
+ return false;
+
+ return true;
+}
+
+bool ProxyListMatch(const Url<char>& url, const std::string& proxy_list,
+ char sep) {
+ const size_t BUFSIZE = 256;
+ char buffer[BUFSIZE];
+ const char* list = proxy_list.c_str();
+ while (*list) {
+ // Remove leading space
+ if (isspace(*list)) {
+ ++list;
+ continue;
+ }
+ // Break on separator
+ size_t len;
+ const char * start = list;
+ if (const char * end = ::strchr(list, sep)) {
+ len = (end - list);
+ list += len + 1;
+ } else {
+ len = strlen(list);
+ list += len;
+ }
+ // Remove trailing space
+ while ((len > 0) && isspace(start[len-1]))
+ --len;
+ // Check for oversized entry
+ if (len >= BUFSIZE)
+ continue;
+ memcpy(buffer, start, len);
+ buffer[len] = 0;
+ if (!ProxyItemMatch(url, buffer, len))
+ continue;
+ return true;
+ }
+ return false;
+}
+
+bool Better(ProxyType lhs, const ProxyType rhs) {
+ // PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
+ const int PROXY_VALUE[5] = { 0, 2, 3, 1 };
+ return (PROXY_VALUE[lhs] > PROXY_VALUE[rhs]);
+}
+
+bool ParseProxy(const std::string& saddress, ProxyInfo* proxy) {
+ const size_t kMaxAddressLength = 1024;
+ // Allow semicolon, space, or tab as an address separator
+ const char* const kAddressSeparator = " ;\t";
+
+ ProxyType ptype;
+ std::string host;
+ uint16_t port;
+
+ const char* address = saddress.c_str();
+ while (*address) {
+ size_t len;
+ const char * start = address;
+ if (const char * sep = strchr(address, kAddressSeparator)) {
+ len = (sep - address);
+ address += len + 1;
+ while (*address != '\0' && ::strchr(kAddressSeparator, *address)) {
+ address += 1;
+ }
+ } else {
+ len = strlen(address);
+ address += len;
+ }
+
+ if (len > kMaxAddressLength - 1) {
+ LOG(LS_WARNING) << "Proxy address too long [" << start << "]";
+ continue;
+ }
+
+ char buffer[kMaxAddressLength];
+ memcpy(buffer, start, len);
+ buffer[len] = 0;
+
+ char * colon = ::strchr(buffer, ':');
+ if (!colon) {
+ LOG(LS_WARNING) << "Proxy address without port [" << buffer << "]";
+ continue;
+ }
+
+ *colon = 0;
+ char * endptr;
+ port = static_cast<uint16_t>(strtol(colon + 1, &endptr, 0));
+ if (*endptr != 0) {
+ LOG(LS_WARNING) << "Proxy address with invalid port [" << buffer << "]";
+ continue;
+ }
+
+ if (char * equals = ::strchr(buffer, '=')) {
+ *equals = 0;
+ host = equals + 1;
+ if (_stricmp(buffer, "socks") == 0) {
+ ptype = PROXY_SOCKS5;
+ } else if (_stricmp(buffer, "https") == 0) {
+ ptype = PROXY_HTTPS;
+ } else {
+ LOG(LS_WARNING) << "Proxy address with unknown protocol ["
+ << buffer << "]";
+ ptype = PROXY_UNKNOWN;
+ }
+ } else {
+ host = buffer;
+ ptype = PROXY_UNKNOWN;
+ }
+
+ if (Better(ptype, proxy->type)) {
+ proxy->type = ptype;
+ proxy->address.SetIP(host);
+ proxy->address.SetPort(port);
+ }
+ }
+
+ return proxy->type != PROXY_NONE;
+}
+
+UserAgent GetAgent(const char* agent) {
+ if (agent) {
+ std::string agent_str(agent);
+ if (agent_str.find(kFirefoxPattern) != std::string::npos) {
+ return UA_FIREFOX;
+ } else if (agent_str.find(kInternetExplorerPattern) != std::string::npos) {
+ return UA_INTERNETEXPLORER;
+ } else if (agent_str.empty()) {
+ return UA_UNKNOWN;
+ }
+ }
+ return UA_OTHER;
+}
+
+bool EndsWith(const std::string& a, const std::string& b) {
+ if (b.size() > a.size()) {
+ return false;
+ }
+ int result = a.compare(a.size() - b.size(), b.size(), b);
+ return result == 0;
+}
+
+bool GetFirefoxProfilePath(Pathname* path) {
+#if defined(WEBRTC_WIN)
+ wchar_t w_path[MAX_PATH];
+ if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, w_path) !=
+ S_OK) {
+ LOG(LS_ERROR) << "SHGetFolderPath failed";
+ return false;
+ }
+ path->SetFolder(ToUtf8(w_path, wcslen(w_path)));
+ path->AppendFolder("Mozilla");
+ path->AppendFolder("Firefox");
+#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+ FSRef fr;
+ if (0 != FSFindFolder(kUserDomain, kApplicationSupportFolderType,
+ kCreateFolder, &fr)) {
+ LOG(LS_ERROR) << "FSFindFolder failed";
+ return false;
+ }
+ char buffer[NAME_MAX + 1];
+ if (0 != FSRefMakePath(&fr, reinterpret_cast<uint8_t*>(buffer),
+ ARRAY_SIZE(buffer))) {
+ LOG(LS_ERROR) << "FSRefMakePath failed";
+ return false;
+ }
+ path->SetFolder(std::string(buffer));
+ path->AppendFolder("Firefox");
+#else
+ char* user_home = getenv("HOME");
+ if (user_home == NULL) {
+ return false;
+ }
+ path->SetFolder(std::string(user_home));
+ path->AppendFolder(".mozilla");
+ path->AppendFolder("firefox");
+#endif // WEBRTC_WIN
+ return true;
+}
+
+bool GetDefaultFirefoxProfile(Pathname* profile_path) {
+ ASSERT(NULL != profile_path);
+ Pathname path;
+ if (!GetFirefoxProfilePath(&path)) {
+ return false;
+ }
+
+#if USE_FIREFOX_PROFILES_INI
+ // [Profile0]
+ // Name=default
+ // IsRelative=1
+ // Path=Profiles/2de53ejb.default
+ // Default=1
+
+ // Note: we are looking for the first entry with "Default=1", or the last
+ // entry in the file
+ path.SetFilename("profiles.ini");
+ scoped_ptr<FileStream> fs(Filesystem::OpenFile(path, "r"));
+ if (!fs) {
+ return false;
+ }
+ Pathname candidate;
+ bool relative = true;
+ std::string line;
+ while (fs->ReadLine(&line) == SR_SUCCESS) {
+ if (line.length() == 0) {
+ continue;
+ }
+ if (line.at(0) == '[') {
+ relative = true;
+ candidate.clear();
+ } else if (line.find("IsRelative=") == 0 &&
+ line.length() >= 12) {
+ // TODO: The initial Linux public launch revealed a fairly
+ // high number of machines where IsRelative= did not have anything after
+ // it. Perhaps that is legal profiles.ini syntax?
+ relative = (line.at(11) != '0');
+ } else if (line.find("Path=") == 0 &&
+ line.length() >= 6) {
+ if (relative) {
+ candidate = path;
+ } else {
+ candidate.clear();
+ }
+ candidate.AppendFolder(line.substr(5));
+ } else if (line.find("Default=") == 0 &&
+ line.length() >= 9) {
+ if ((line.at(8) != '0') && !candidate.empty()) {
+ break;
+ }
+ }
+ }
+ fs->Close();
+ if (candidate.empty()) {
+ return false;
+ }
+ profile_path->SetPathname(candidate.pathname());
+
+#else // !USE_FIREFOX_PROFILES_INI
+ path.AppendFolder("Profiles");
+ DirectoryIterator* it = Filesystem::IterateDirectory();
+ it->Iterate(path);
+ std::string extension(".default");
+ while (!EndsWith(it->Name(), extension)) {
+ if (!it->Next()) {
+ return false;
+ }
+ }
+
+ profile_path->SetPathname(path);
+ profile->AppendFolder("Profiles");
+ profile->AppendFolder(it->Name());
+ delete it;
+
+#endif // !USE_FIREFOX_PROFILES_INI
+
+ return true;
+}
+
+bool ReadFirefoxPrefs(const Pathname& filename,
+ const char * prefix,
+ StringMap* settings) {
+ scoped_ptr<FileStream> fs(Filesystem::OpenFile(filename, "r"));
+ if (!fs) {
+ LOG(LS_ERROR) << "Failed to open file: " << filename.pathname();
+ return false;
+ }
+
+ std::string line;
+ while (fs->ReadLine(&line) == SR_SUCCESS) {
+ size_t prefix_len = strlen(prefix);
+
+ // Skip blank lines and too long lines.
+ if ((line.length() == 0) || (line.length() > kMaxLineLength)
+ || (line.at(0) == '#') || line.compare(0, 2, "/*") == 0
+ || line.compare(0, 2, " *") == 0) {
+ continue;
+ }
+
+ char buffer[kMaxLineLength];
+ strcpyn(buffer, sizeof(buffer), line.c_str());
+ int nstart = 0, nend = 0, vstart = 0, vend = 0;
+ sscanf(buffer, "user_pref(\"%n%*[^\"]%n\", %n%*[^)]%n);",
+ &nstart, &nend, &vstart, &vend);
+ if (vend > 0) {
+ char* name = buffer + nstart;
+ name[nend - nstart] = 0;
+ if ((vend - vstart >= 2) && (buffer[vstart] == '"')) {
+ vstart += 1;
+ vend -= 1;
+ }
+ char* value = buffer + vstart;
+ value[vend - vstart] = 0;
+ if ((strncmp(name, prefix, prefix_len) == 0) && *value) {
+ settings->Add(name + prefix_len, value);
+ }
+ } else {
+ LOG_F(LS_WARNING) << "Unparsed pref [" << buffer << "]";
+ }
+ }
+ fs->Close();
+ return true;
+}
+
+bool GetFirefoxProxySettings(const char* url, ProxyInfo* proxy) {
+ Url<char> purl(url);
+ Pathname path;
+ bool success = false;
+ if (GetDefaultFirefoxProfile(&path)) {
+ StringMap settings;
+ path.SetFilename("prefs.js");
+ if (ReadFirefoxPrefs(path, "network.proxy.", &settings)) {
+ success = true;
+ proxy->bypass_list =
+ settings.Get("no_proxies_on", "localhost, 127.0.0.1");
+ if (settings.Get("type") == "1") {
+ // User has manually specified a proxy, try to figure out what
+ // type it is.
+ if (ProxyListMatch(purl, proxy->bypass_list.c_str(), ',')) {
+ // Our url is in the list of url's to bypass proxy.
+ } else if (settings.Get("share_proxy_settings") == "true") {
+ proxy->type = PROXY_UNKNOWN;
+ proxy->address.SetIP(settings.Get("http"));
+ proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
+ } else if (settings.IsSet("socks")) {
+ proxy->type = PROXY_SOCKS5;
+ proxy->address.SetIP(settings.Get("socks"));
+ proxy->address.SetPort(atoi(settings.Get("socks_port").c_str()));
+ } else if (settings.IsSet("ssl")) {
+ proxy->type = PROXY_HTTPS;
+ proxy->address.SetIP(settings.Get("ssl"));
+ proxy->address.SetPort(atoi(settings.Get("ssl_port").c_str()));
+ } else if (settings.IsSet("http")) {
+ proxy->type = PROXY_HTTPS;
+ proxy->address.SetIP(settings.Get("http"));
+ proxy->address.SetPort(atoi(settings.Get("http_port").c_str()));
+ }
+ } else if (settings.Get("type") == "2") {
+ // Browser is configured to get proxy settings from a given url.
+ proxy->autoconfig_url = settings.Get("autoconfig_url").c_str();
+ } else if (settings.Get("type") == "4") {
+ // Browser is configured to auto detect proxy config.
+ proxy->autodetect = true;
+ } else {
+ // No proxy set.
+ }
+ }
+ }
+ return success;
+}
+
+#if defined(WEBRTC_WIN) // Windows specific implementation for reading Internet
+ // Explorer proxy settings.
+
+void LogGetProxyFault() {
+ LOG_GLEM(LERROR, WINHTTP) << "WinHttpGetProxyForUrl faulted!!";
+}
+
+BOOL MyWinHttpGetProxyForUrl(pfnWinHttpGetProxyForUrl pWHGPFU,
+ HINTERNET hWinHttp, LPCWSTR url,
+ WINHTTP_AUTOPROXY_OPTIONS *options,
+ WINHTTP_PROXY_INFO *info) {
+ // WinHttpGetProxyForUrl() can call plugins which can crash.
+ // In the case of McAfee scriptproxy.dll, it does crash in
+ // older versions. Try to catch crashes here and treat as an
+ // error.
+ BOOL success = FALSE;
+
+#if (_HAS_EXCEPTIONS == 0)
+ __try {
+ success = pWHGPFU(hWinHttp, url, options, info);
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ // This is a separate function to avoid
+ // Visual C++ error 2712 when compiling with C++ EH
+ LogGetProxyFault();
+ }
+#else
+ success = pWHGPFU(hWinHttp, url, options, info);
+#endif // (_HAS_EXCEPTIONS == 0)
+
+ return success;
+}
+
+bool IsDefaultBrowserFirefox() {
+ HKEY key;
+ LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command",
+ 0, KEY_READ, &key);
+ if (ERROR_SUCCESS != result)
+ return false;
+
+ DWORD size, type;
+ bool success = false;
+ result = RegQueryValueEx(key, L"", 0, &type, NULL, &size);
+ if (result == ERROR_SUCCESS && type == REG_SZ) {
+ wchar_t* value = new wchar_t[size+1];
+ BYTE* buffer = reinterpret_cast<BYTE*>(value);
+ result = RegQueryValueEx(key, L"", 0, &type, buffer, &size);
+ if (result == ERROR_SUCCESS) {
+ // Size returned by RegQueryValueEx is in bytes, convert to number of
+ // wchar_t's.
+ size /= sizeof(value[0]);
+ value[size] = L'\0';
+ for (size_t i = 0; i < size; ++i) {
+ value[i] = tolowercase(value[i]);
+ }
+ success = (NULL != strstr(value, L"firefox.exe"));
+ }
+ delete[] value;
+ }
+
+ RegCloseKey(key);
+ return success;
+}
+
+bool GetWinHttpProxySettings(const char* url, ProxyInfo* proxy) {
+ HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
+ if (winhttp_handle == NULL) {
+ LOG(LS_ERROR) << "Failed to load winhttp.dll.";
+ return false;
+ }
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG iecfg;
+ memset(&iecfg, 0, sizeof(iecfg));
+ Url<char> purl(url);
+ pfnWinHttpGetIEProxyConfig pWHGIEPC =
+ reinterpret_cast<pfnWinHttpGetIEProxyConfig>(
+ GetProcAddress(winhttp_handle,
+ "WinHttpGetIEProxyConfigForCurrentUser"));
+ bool success = false;
+ if (pWHGIEPC && pWHGIEPC(&iecfg)) {
+ // We were read proxy config successfully.
+ success = true;
+ if (iecfg.fAutoDetect) {
+ proxy->autodetect = true;
+ }
+ if (iecfg.lpszAutoConfigUrl) {
+ proxy->autoconfig_url = ToUtf8(iecfg.lpszAutoConfigUrl);
+ GlobalFree(iecfg.lpszAutoConfigUrl);
+ }
+ if (iecfg.lpszProxyBypass) {
+ proxy->bypass_list = ToUtf8(iecfg.lpszProxyBypass);
+ GlobalFree(iecfg.lpszProxyBypass);
+ }
+ if (iecfg.lpszProxy) {
+ if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
+ ParseProxy(ToUtf8(iecfg.lpszProxy), proxy);
+ }
+ GlobalFree(iecfg.lpszProxy);
+ }
+ }
+ FreeLibrary(winhttp_handle);
+ return success;
+}
+
+// Uses the WinHTTP API to auto detect proxy for the given url. Firefox and IE
+// have slightly different option dialogs for proxy settings. In Firefox,
+// either a location of a proxy configuration file can be specified or auto
+// detection can be selected. In IE theese two options can be independently
+// selected. For the case where both options are selected (only IE) we try to
+// fetch the config file first, and if that fails we'll perform an auto
+// detection.
+//
+// Returns true if we successfully performed an auto detection not depending on
+// whether we found a proxy or not. Returns false on error.
+bool WinHttpAutoDetectProxyForUrl(const char* agent, const char* url,
+ ProxyInfo* proxy) {
+ Url<char> purl(url);
+ bool success = true;
+ HMODULE winhttp_handle = LoadLibrary(L"winhttp.dll");
+ if (winhttp_handle == NULL) {
+ LOG(LS_ERROR) << "Failed to load winhttp.dll.";
+ return false;
+ }
+ pfnWinHttpOpen pWHO =
+ reinterpret_cast<pfnWinHttpOpen>(GetProcAddress(winhttp_handle,
+ "WinHttpOpen"));
+ pfnWinHttpCloseHandle pWHCH =
+ reinterpret_cast<pfnWinHttpCloseHandle>(
+ GetProcAddress(winhttp_handle, "WinHttpCloseHandle"));
+ pfnWinHttpGetProxyForUrl pWHGPFU =
+ reinterpret_cast<pfnWinHttpGetProxyForUrl>(
+ GetProcAddress(winhttp_handle, "WinHttpGetProxyForUrl"));
+ if (pWHO && pWHCH && pWHGPFU) {
+ if (HINTERNET hWinHttp = pWHO(ToUtf16(agent).c_str(),
+ WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0)) {
+ BOOL result = FALSE;
+ WINHTTP_PROXY_INFO info;
+ memset(&info, 0, sizeof(info));
+ if (proxy->autodetect) {
+ // Use DHCP and DNS to try to find any proxy to use.
+ WINHTTP_AUTOPROXY_OPTIONS options;
+ memset(&options, 0, sizeof(options));
+ options.fAutoLogonIfChallenged = TRUE;
+
+ options.dwFlags |= WINHTTP_AUTOPROXY_AUTO_DETECT;
+ options.dwAutoDetectFlags |= WINHTTP_AUTO_DETECT_TYPE_DHCP
+ | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ result = MyWinHttpGetProxyForUrl(
+ pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
+ }
+ if (!result && !proxy->autoconfig_url.empty()) {
+ // We have the location of a proxy config file. Download it and
+ // execute it to find proxy settings for our url.
+ WINHTTP_AUTOPROXY_OPTIONS options;
+ memset(&options, 0, sizeof(options));
+ memset(&info, 0, sizeof(info));
+ options.fAutoLogonIfChallenged = TRUE;
+
+ std::wstring autoconfig_url16((ToUtf16)(proxy->autoconfig_url));
+ options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
+ options.lpszAutoConfigUrl = autoconfig_url16.c_str();
+
+ result = MyWinHttpGetProxyForUrl(
+ pWHGPFU, hWinHttp, ToUtf16(url).c_str(), &options, &info);
+ }
+ if (result) {
+ // Either the given auto config url was valid or auto
+ // detection found a proxy on this network.
+ if (info.lpszProxy) {
+ // TODO: Does this bypass list differ from the list
+ // retreived from GetWinHttpProxySettings earlier?
+ if (info.lpszProxyBypass) {
+ proxy->bypass_list = ToUtf8(info.lpszProxyBypass);
+ GlobalFree(info.lpszProxyBypass);
+ } else {
+ proxy->bypass_list.clear();
+ }
+ if (!ProxyListMatch(purl, proxy->bypass_list, ';')) {
+ // Found proxy for this URL. If parsing the address turns
+ // out ok then we are successful.
+ success = ParseProxy(ToUtf8(info.lpszProxy), proxy);
+ }
+ GlobalFree(info.lpszProxy);
+ }
+ } else {
+ // We could not find any proxy for this url.
+ LOG(LS_INFO) << "No proxy detected for " << url;
+ }
+ pWHCH(hWinHttp);
+ }
+ } else {
+ LOG(LS_ERROR) << "Failed loading WinHTTP functions.";
+ success = false;
+ }
+ FreeLibrary(winhttp_handle);
+ return success;
+}
+
+#if 0 // Below functions currently not used.
+
+bool GetJsProxySettings(const char* url, ProxyInfo* proxy) {
+ Url<char> purl(url);
+ bool success = false;
+
+ if (HMODULE hModJS = LoadLibrary(_T("jsproxy.dll"))) {
+ pfnInternetGetProxyInfo pIGPI =
+ reinterpret_cast<pfnInternetGetProxyInfo>(
+ GetProcAddress(hModJS, "InternetGetProxyInfo"));
+ if (pIGPI) {
+ char proxy[256], host[256];
+ memset(proxy, 0, sizeof(proxy));
+ char * ptr = proxy;
+ DWORD proxylen = sizeof(proxy);
+ std::string surl = Utf8String(url);
+ DWORD hostlen = _snprintf(host, sizeof(host), "http%s://%S",
+ purl.secure() ? "s" : "", purl.server());
+ if (pIGPI(surl.data(), surl.size(), host, hostlen, &ptr, &proxylen)) {
+ LOG(INFO) << "Proxy: " << proxy;
+ } else {
+ LOG_GLE(INFO) << "InternetGetProxyInfo";
+ }
+ }
+ FreeLibrary(hModJS);
+ }
+ return success;
+}
+
+bool GetWmProxySettings(const char* url, ProxyInfo* proxy) {
+ Url<char> purl(url);
+ bool success = false;
+
+ INSNetSourceCreator * nsc = 0;
+ HRESULT hr = CoCreateInstance(CLSID_ClientNetManager, 0, CLSCTX_ALL,
+ IID_INSNetSourceCreator, (LPVOID *) &nsc);
+ if (SUCCEEDED(hr)) {
+ if (SUCCEEDED(hr = nsc->Initialize())) {
+ VARIANT dispatch;
+ VariantInit(&dispatch);
+ if (SUCCEEDED(hr = nsc->GetNetSourceAdminInterface(L"http", &dispatch))) {
+ IWMSInternalAdminNetSource * ians = 0;
+ if (SUCCEEDED(hr = dispatch.pdispVal->QueryInterface(
+ IID_IWMSInternalAdminNetSource, (LPVOID *) &ians))) {
+ _bstr_t host(purl.server());
+ BSTR proxy = 0;
+ BOOL bProxyEnabled = FALSE;
+ DWORD port, context = 0;
+ if (SUCCEEDED(hr = ians->FindProxyForURL(
+ L"http", host, &bProxyEnabled, &proxy, &port, &context))) {
+ success = true;
+ if (bProxyEnabled) {
+ _bstr_t sproxy = proxy;
+ proxy->ptype = PT_HTTPS;
+ proxy->host = sproxy;
+ proxy->port = port;
+ }
+ }
+ SysFreeString(proxy);
+ if (FAILED(hr = ians->ShutdownProxyContext(context))) {
+ LOG(LS_INFO) << "IWMSInternalAdminNetSource::ShutdownProxyContext"
+ << "failed: " << hr;
+ }
+ ians->Release();
+ }
+ }
+ VariantClear(&dispatch);
+ if (FAILED(hr = nsc->Shutdown())) {
+ LOG(LS_INFO) << "INSNetSourceCreator::Shutdown failed: " << hr;
+ }
+ }
+ nsc->Release();
+ }
+ return success;
+}
+
+bool GetIePerConnectionProxySettings(const char* url, ProxyInfo* proxy) {
+ Url<char> purl(url);
+ bool success = false;
+
+ INTERNET_PER_CONN_OPTION_LIST list;
+ INTERNET_PER_CONN_OPTION options[3];
+ memset(&list, 0, sizeof(list));
+ memset(&options, 0, sizeof(options));
+
+ list.dwSize = sizeof(list);
+ list.dwOptionCount = 3;
+ list.pOptions = options;
+ options[0].dwOption = INTERNET_PER_CONN_FLAGS;
+ options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
+ options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
+ DWORD dwSize = sizeof(list);
+
+ if (!InternetQueryOption(0, INTERNET_OPTION_PER_CONNECTION_OPTION, &list,
+ &dwSize)) {
+ LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
+ } else if ((options[0].Value.dwValue & PROXY_TYPE_PROXY) != 0) {
+ success = true;
+ if (!ProxyListMatch(purl, nonnull(options[2].Value.pszValue), _T(';'))) {
+ ParseProxy(nonnull(options[1].Value.pszValue), proxy);
+ }
+ } else if ((options[0].Value.dwValue & PROXY_TYPE_DIRECT) != 0) {
+ success = true;
+ } else {
+ LOG(LS_INFO) << "unknown internet access type: "
+ << options[0].Value.dwValue;
+ }
+ if (options[1].Value.pszValue) {
+ GlobalFree(options[1].Value.pszValue);
+ }
+ if (options[2].Value.pszValue) {
+ GlobalFree(options[2].Value.pszValue);
+ }
+ return success;
+}
+
+#endif // 0
+
+// Uses the InternetQueryOption function to retrieve proxy settings
+// from the registry. This will only give us the 'static' settings,
+// ie, not any information about auto config etc.
+bool GetIeLanProxySettings(const char* url, ProxyInfo* proxy) {
+ Url<char> purl(url);
+ bool success = false;
+
+ wchar_t buffer[1024];
+ memset(buffer, 0, sizeof(buffer));
+ INTERNET_PROXY_INFO * info = reinterpret_cast<INTERNET_PROXY_INFO *>(buffer);
+ DWORD dwSize = sizeof(buffer);
+
+ if (!InternetQueryOption(0, INTERNET_OPTION_PROXY, info, &dwSize)) {
+ LOG(LS_INFO) << "InternetQueryOption failed: " << GetLastError();
+ } else if (info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
+ success = true;
+ } else if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
+ success = true;
+ if (!ProxyListMatch(purl, nonnull(reinterpret_cast<const char*>(
+ info->lpszProxyBypass)), ' ')) {
+ ParseProxy(nonnull(reinterpret_cast<const char*>(info->lpszProxy)),
+ proxy);
+ }
+ } else {
+ LOG(LS_INFO) << "unknown internet access type: " << info->dwAccessType;
+ }
+ return success;
+}
+
+bool GetIeProxySettings(const char* agent, const char* url, ProxyInfo* proxy) {
+ bool success = GetWinHttpProxySettings(url, proxy);
+ if (!success) {
+ // TODO: Should always call this if no proxy were detected by
+ // GetWinHttpProxySettings?
+ // WinHttp failed. Try using the InternetOptionQuery method instead.
+ return GetIeLanProxySettings(url, proxy);
+ }
+ return true;
+}
+
+#endif // WEBRTC_WIN
+
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) // WEBRTC_MAC && !defined(WEBRTC_IOS) specific implementation for reading system wide
+ // proxy settings.
+
+bool p_getProxyInfoForTypeFromDictWithKeys(ProxyInfo* proxy,
+ ProxyType type,
+ const CFDictionaryRef proxyDict,
+ const CFStringRef enabledKey,
+ const CFStringRef hostKey,
+ const CFStringRef portKey) {
+ // whether or not we set up the proxy info.
+ bool result = false;
+
+ // we use this as a scratch variable for determining if operations
+ // succeeded.
+ bool converted = false;
+
+ // the data we need to construct the SocketAddress for the proxy.
+ std::string hostname;
+ int port;
+
+ if ((proxyDict != NULL) &&
+ (CFGetTypeID(proxyDict) == CFDictionaryGetTypeID())) {
+ // CoreFoundation stuff that we'll have to get from
+ // the dictionaries and interpret or convert into more usable formats.
+ CFNumberRef enabledCFNum;
+ CFNumberRef portCFNum;
+ CFStringRef hostCFStr;
+
+ enabledCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, enabledKey);
+
+ if (p_isCFNumberTrue(enabledCFNum)) {
+ // let's see if we can get the address and port.
+ hostCFStr = (CFStringRef)CFDictionaryGetValue(proxyDict, hostKey);
+ converted = p_convertHostCFStringRefToCPPString(hostCFStr, hostname);
+ if (converted) {
+ portCFNum = (CFNumberRef)CFDictionaryGetValue(proxyDict, portKey);
+ converted = p_convertCFNumberToInt(portCFNum, &port);
+ if (converted) {
+ // we have something enabled, with a hostname and a port.
+ // That's sufficient to set up the proxy info.
+ proxy->type = type;
+ proxy->address.SetIP(hostname);
+ proxy->address.SetPort(port);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+// Looks for proxy information in the given dictionary,
+// return true if it found sufficient information to define one,
+// false otherwise. This is guaranteed to not change the values in proxy
+// unless a full-fledged proxy description was discovered in the dictionary.
+// However, at the present time this does not support username or password.
+// Checks first for a SOCKS proxy, then for HTTPS, then HTTP.
+bool GetMacProxySettingsFromDictionary(ProxyInfo* proxy,
+ const CFDictionaryRef proxyDict) {
+ // the function result.
+ bool gotProxy = false;
+
+
+ // first we see if there's a SOCKS proxy in place.
+ gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
+ PROXY_SOCKS5,
+ proxyDict,
+ kSCPropNetProxiesSOCKSEnable,
+ kSCPropNetProxiesSOCKSProxy,
+ kSCPropNetProxiesSOCKSPort);
+
+ if (!gotProxy) {
+ // okay, no SOCKS proxy, let's look for https.
+ gotProxy = p_getProxyInfoForTypeFromDictWithKeys(proxy,
+ PROXY_HTTPS,
+ proxyDict,
+ kSCPropNetProxiesHTTPSEnable,
+ kSCPropNetProxiesHTTPSProxy,
+ kSCPropNetProxiesHTTPSPort);
+ if (!gotProxy) {
+ // Finally, try HTTP proxy. Note that flute doesn't
+ // differentiate between HTTPS and HTTP, hence we are using the
+ // same flute type here, ie. PROXY_HTTPS.
+ gotProxy = p_getProxyInfoForTypeFromDictWithKeys(
+ proxy, PROXY_HTTPS, proxyDict, kSCPropNetProxiesHTTPEnable,
+ kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort);
+ }
+ }
+ return gotProxy;
+}
+
+// TODO(hughv) Update keychain functions. They work on 10.8, but are depricated.
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+bool p_putPasswordInProxyInfo(ProxyInfo* proxy) {
+ bool result = true; // by default we assume we're good.
+ // for all we know there isn't any password. We'll set to false
+ // if we find a problem.
+
+ // Ask the keychain for an internet password search for the given protocol.
+ OSStatus oss = 0;
+ SecKeychainAttributeList attrList;
+ attrList.count = 3;
+ SecKeychainAttribute attributes[3];
+ attrList.attr = attributes;
+
+ attributes[0].tag = kSecProtocolItemAttr;
+ attributes[0].length = sizeof(SecProtocolType);
+ SecProtocolType protocol;
+ switch (proxy->type) {
+ case PROXY_HTTPS :
+ protocol = kSecProtocolTypeHTTPS;
+ break;
+ case PROXY_SOCKS5 :
+ protocol = kSecProtocolTypeSOCKS;
+ break;
+ default :
+ LOG(LS_ERROR) << "asked for proxy password for unknown proxy type.";
+ result = false;
+ break;
+ }
+ attributes[0].data = &protocol;
+
+ UInt32 port = proxy->address.port();
+ attributes[1].tag = kSecPortItemAttr;
+ attributes[1].length = sizeof(UInt32);
+ attributes[1].data = &port;
+
+ std::string ip = proxy->address.ipaddr().ToString();
+ attributes[2].tag = kSecServerItemAttr;
+ attributes[2].length = ip.length();
+ attributes[2].data = const_cast<char*>(ip.c_str());
+
+ if (result) {
+ LOG(LS_INFO) << "trying to get proxy username/password";
+ SecKeychainSearchRef sref;
+ oss = SecKeychainSearchCreateFromAttributes(NULL,
+ kSecInternetPasswordItemClass,
+ &attrList, &sref);
+ if (0 == oss) {
+ LOG(LS_INFO) << "SecKeychainSearchCreateFromAttributes was good";
+ // Get the first item, if there is one.
+ SecKeychainItemRef iref;
+ oss = SecKeychainSearchCopyNext(sref, &iref);
+ if (0 == oss) {
+ LOG(LS_INFO) << "...looks like we have the username/password data";
+ // If there is, get the username and the password.
+
+ SecKeychainAttributeInfo attribsToGet;
+ attribsToGet.count = 1;
+ UInt32 tag = kSecAccountItemAttr;
+ UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
+ void *data;
+ UInt32 length;
+ SecKeychainAttributeList *localList;
+
+ attribsToGet.tag = &tag;
+ attribsToGet.format = &format;
+ OSStatus copyres = SecKeychainItemCopyAttributesAndData(iref,
+ &attribsToGet,
+ NULL,
+ &localList,
+ &length,
+ &data);
+ if (0 == copyres) {
+ LOG(LS_INFO) << "...and we can pull it out.";
+ // now, we know from experimentation (sadly not from docs)
+ // that the username is in the local attribute list,
+ // and the password in the data,
+ // both without null termination but with info on their length.
+ // grab the password from the data.
+ std::string password;
+ password.append(static_cast<const char*>(data), length);
+
+ // make the password into a CryptString
+ // huh, at the time of writing, you can't.
+ // so we'll skip that for now and come back to it later.
+
+ // now put the username in the proxy.
+ if (1 <= localList->attr->length) {
+ proxy->username.append(
+ static_cast<const char*>(localList->attr->data),
+ localList->attr->length);
+ LOG(LS_INFO) << "username is " << proxy->username;
+ } else {
+ LOG(LS_ERROR) << "got keychain entry with no username";
+ result = false;
+ }
+ } else {
+ LOG(LS_ERROR) << "couldn't copy info from keychain.";
+ result = false;
+ }
+ SecKeychainItemFreeAttributesAndData(localList, data);
+ } else if (errSecItemNotFound == oss) {
+ LOG(LS_INFO) << "...username/password info not found";
+ } else {
+ // oooh, neither 0 nor itemNotFound.
+ LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
+ result = false;
+ }
+ } else if (errSecItemNotFound == oss) { // noop
+ } else {
+ // oooh, neither 0 nor itemNotFound.
+ LOG(LS_ERROR) << "Couldn't get keychain information, error code" << oss;
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+bool GetMacProxySettings(ProxyInfo* proxy) {
+ // based on the Apple Technical Q&A QA1234
+ // http://developer.apple.com/qa/qa2001/qa1234.html
+ CFDictionaryRef proxyDict = SCDynamicStoreCopyProxies(NULL);
+ bool result = false;
+
+ if (proxyDict != NULL) {
+ // sending it off to another function makes it easier to unit test
+ // since we can make our own dictionary to hand to that function.
+ result = GetMacProxySettingsFromDictionary(proxy, proxyDict);
+
+ if (result) {
+ result = p_putPasswordInProxyInfo(proxy);
+ }
+
+ // We created the dictionary with something that had the
+ // word 'copy' in it, so we have to release it, according
+ // to the Carbon memory management standards.
+ CFRelease(proxyDict);
+ } else {
+ LOG(LS_ERROR) << "SCDynamicStoreCopyProxies failed";
+ }
+
+ return result;
+}
+#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
+
+#ifdef WEBRTC_IOS
+// iOS has only http proxy
+bool GetiOSProxySettings(ProxyInfo* proxy) {
+
+ bool result = false;
+
+ CFDictionaryRef proxy_dict = CFNetworkCopySystemProxySettings();
+ if (!proxy_dict) {
+ LOG(LS_ERROR) << "CFNetworkCopySystemProxySettings failed";
+ return false;
+ }
+
+ CFNumberRef proxiesHTTPEnable = (CFNumberRef)CFDictionaryGetValue(
+ proxy_dict, kCFNetworkProxiesHTTPEnable);
+ if (!p_isCFNumberTrue(proxiesHTTPEnable)) {
+ CFRelease(proxy_dict);
+ return false;
+ }
+
+ CFStringRef proxy_address = (CFStringRef)CFDictionaryGetValue(
+ proxy_dict, kCFNetworkProxiesHTTPProxy);
+ CFNumberRef proxy_port = (CFNumberRef)CFDictionaryGetValue(
+ proxy_dict, kCFNetworkProxiesHTTPPort);
+
+ // the data we need to construct the SocketAddress for the proxy.
+ std::string hostname;
+ int port;
+ if (p_convertHostCFStringRefToCPPString(proxy_address, hostname) &&
+ p_convertCFNumberToInt(proxy_port, &port)) {
+ // We have something enabled, with a hostname and a port.
+ // That's sufficient to set up the proxy info.
+ // Finally, try HTTP proxy. Note that flute doesn't
+ // differentiate between HTTPS and HTTP, hence we are using the
+ // same flute type here, ie. PROXY_HTTPS.
+ proxy->type = PROXY_HTTPS;
+
+ proxy->address.SetIP(hostname);
+ proxy->address.SetPort(port);
+ result = true;
+ }
+
+ // We created the dictionary with something that had the
+ // word 'copy' in it, so we have to release it, according
+ // to the Carbon memory management standards.
+ CFRelease(proxy_dict);
+
+ return result;
+}
+#endif // WEBRTC_IOS
+
+bool AutoDetectProxySettings(const char* agent, const char* url,
+ ProxyInfo* proxy) {
+#if defined(WEBRTC_WIN)
+ return WinHttpAutoDetectProxyForUrl(agent, url, proxy);
+#else
+ LOG(LS_WARNING) << "Proxy auto-detection not implemented for this platform";
+ return false;
+#endif
+}
+
+bool GetSystemDefaultProxySettings(const char* agent, const char* url,
+ ProxyInfo* proxy) {
+#if defined(WEBRTC_WIN)
+ return GetIeProxySettings(agent, url, proxy);
+#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+ return GetMacProxySettings(proxy);
+#elif defined(WEBRTC_IOS)
+ return GetiOSProxySettings(proxy);
+#else
+ // TODO: Get System settings if browser is not firefox.
+ return GetFirefoxProxySettings(url, proxy);
+#endif
+}
+
+bool GetProxySettingsForUrl(const char* agent, const char* url,
+ ProxyInfo* proxy, bool long_operation) {
+ UserAgent a = GetAgent(agent);
+ bool result;
+ switch (a) {
+ case UA_FIREFOX: {
+ result = GetFirefoxProxySettings(url, proxy);
+ break;
+ }
+#if defined(WEBRTC_WIN)
+ case UA_INTERNETEXPLORER:
+ result = GetIeProxySettings(agent, url, proxy);
+ break;
+ case UA_UNKNOWN:
+ // Agent not defined, check default browser.
+ if (IsDefaultBrowserFirefox()) {
+ result = GetFirefoxProxySettings(url, proxy);
+ } else {
+ result = GetIeProxySettings(agent, url, proxy);
+ }
+ break;
+#endif // WEBRTC_WIN
+ default:
+ result = GetSystemDefaultProxySettings(agent, url, proxy);
+ break;
+ }
+
+ // TODO: Consider using the 'long_operation' parameter to
+ // decide whether to do the auto detection.
+ if (result && (proxy->autodetect ||
+ !proxy->autoconfig_url.empty())) {
+ // Use WinHTTP to auto detect proxy for us.
+ result = AutoDetectProxySettings(agent, url, proxy);
+ if (!result) {
+ // Either auto detection is not supported or we simply didn't
+ // find any proxy, reset type.
+ proxy->type = rtc::PROXY_NONE;
+ }
+ }
+ return result;
+}
+
+} // namespace rtc