diff options
Diffstat (limited to 'third_party/libjingle/files/talk/base/proxydetect.cc')
-rw-r--r-- | third_party/libjingle/files/talk/base/proxydetect.cc | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/third_party/libjingle/files/talk/base/proxydetect.cc b/third_party/libjingle/files/talk/base/proxydetect.cc new file mode 100644 index 0000000..2b52315 --- /dev/null +++ b/third_party/libjingle/files/talk/base/proxydetect.cc @@ -0,0 +1,827 @@ +// TODO: Abstract this better for cross-platformability + +#ifdef _WINDOWS +#include "talk/base/win32.h" +#include <shlobj.h> +#endif + +#include "talk/base/httpcommon.h" +#include "talk/base/httpcommon-inl.h" +#include "talk/base/proxydetect.h" +#include "talk/base/stringutils.h" +#include "talk/base/basicdefs.h" + +#if _WINDOWS +#define _TRY_FIREFOX 1 +#define _TRY_WINHTTP 1 +#define _TRY_JSPROXY 0 +#define _TRY_WM_FINDPROXY 0 +#define _TRY_IE_LAN_SETTINGS 1 +#endif // _WINDOWS + +#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 + +using namespace talk_base; + +////////////////////////////////////////////////////////////////////// +// Utility Functions +////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS +#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 // _WINDOWS + +////////////////////////////////////////////////////////////////////// +// GetProxySettingsForUrl +////////////////////////////////////////////////////////////////////// + +bool WildMatch(const char * target, const char * pattern) { + while (*pattern) { + if (*pattern == '*') { + if (!*++pattern) { + return true; + } + while (*target) { + if ((toupper(*pattern) == toupper(*target)) && WildMatch(target + 1, pattern + 1)) { + return true; + } + ++target; + } + return false; + } else { + if (toupper(*pattern) != toupper(*target)) { + return false; + } + ++target; + ++pattern; + } + } + return !*target; +} + +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 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 mask = (m == 0) ? 0 : (~0UL) << (32 - m); + SocketAddress addr(url.server()); + return !addr.IsUnresolved() && ((addr.ip() & mask) == (ip & mask)); + } + + // .foo.com + if (*item == '.') { + size_t hostlen = url.server().length(); + return (hostlen > len) + && (stricmp(url.server().c_str() + (hostlen - len), item) == 0); + } + + // localhost or www.*.com + if (!WildMatch(url.server().c_str(), item)) + return false; + + return true; +} + +bool ProxyListMatch(const Url<char>& url, const std::string& slist, char sep) { + const size_t BUFSIZE = 256; + char buffer[BUFSIZE]; + const char* clist = slist.c_str(); + while (*clist) { + // Remove leading space + if (isspace(*clist)) { + ++clist; + continue; + } + // Break on separator + size_t len; + const char * start = clist; + if (const char * end = strchr(clist, sep)) { + len = (end - clist); + clist += len + 1; + } else { + len = strlen(clist); + clist += 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[4] = { 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 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 (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>(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((int)port); + } + } + + return (proxy.type != PROXY_NONE); +} + +#if _WINDOWS +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; + + wchar_t* value = NULL; + DWORD size, type; + result = RegQueryValueEx(key, L"", 0, &type, NULL, &size); + if (REG_SZ != type) { + result = ERROR_ACCESS_DENIED; // Any error is fine + } else if (ERROR_SUCCESS == result) { + value = new wchar_t[size+1]; + BYTE* buffer = reinterpret_cast<BYTE*>(value); + result = RegQueryValueEx(key, L"", 0, &type, buffer, &size); + } + RegCloseKey(key); + + bool success = false; + if (ERROR_SUCCESS == result) { + 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; + return success; +} +#endif + +#if _TRY_FIREFOX + +#define USE_FIREFOX_PROFILES_INI 1 + +bool GetDefaultFirefoxProfile(std::wstring* profile) { + ASSERT(NULL != profile); + + wchar_t path[MAX_PATH]; + if (SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, path) != S_OK) + return false; + + std::wstring profile_root(path); + profile_root.append(L"\\Mozilla\\Firefox\\"); + +#if USE_FIREFOX_PROFILES_INI + std::wstring tmp(profile_root); + tmp.append(L"profiles.ini"); + + FILE * fp = _wfopen(tmp.c_str(), L"rb"); + if (!fp) + return false; + + // [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 + + std::wstring candidate; + bool relative = true; + + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp)) { + size_t len = strlen(buffer); + while ((len > 0) && isspace(buffer[len-1])) + buffer[--len] = 0; + if (buffer[0] == '[') { + relative = true; + candidate.clear(); + } else if (strnicmp(buffer, "IsRelative=", 11) == 0) { + relative = (buffer[11] != '0'); + } else if (strnicmp(buffer, "Path=", 5) == 0) { + if (relative) { + candidate = profile_root; + } else { + candidate.clear(); + } + candidate.append(ToUtf16(buffer + 5)); + candidate.append(L"\\"); + } else if (strnicmp(buffer, "Default=", 8) == 0) { + if ((buffer[8] != '0') && !candidate.empty()) { + break; + } + } + } + fclose(fp); + if (candidate.empty()) + return false; + *profile = candidate; + +#else // !USE_FIREFOX_PROFILES_INI + std::wstring tmp(profile_root); + tmp.append(L"Profiles\\*.default"); + WIN32_FIND_DATA fdata; + HANDLE hFind = FindFirstFile(tmp.c_str(), &fdata); + if (hFind == INVALID_HANDLE_VALUE) + return false; + + profile->assign(profile_root); + profile->append(L"Profiles\\"); + profile->append(fdata.cFileName); + profile->append(L"\\"); + FindClose(hFind); +#endif // !USE_FIREFOX_PROFILES_INI + + return true; +} + +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_; +}; + +bool ReadFirefoxPrefs(const std::wstring& filename, + const char * prefix, + StringMap& settings) { + FILE * fp = _wfopen(filename.c_str(), L"rb"); + if (!fp) + return false; + + size_t prefix_len = strlen(prefix); + bool overlong_line = false; + + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp)) { + size_t len = strlen(buffer); + bool missing_newline = (len > 0) && (buffer[len-1] != '\n'); + + if (missing_newline) { + overlong_line = true; + continue; + } else if (overlong_line) { + LOG_F(LS_INFO) << "Skipping long line"; + overlong_line = false; + continue; + } + + while ((len > 0) && isspace(buffer[len-1])) + buffer[--len] = 0; + + // Skip blank lines + if ((len == 0) || (buffer[0] == '#') + || (strncmp(buffer, "/*", 2) == 0) + || (strncmp(buffer, " *", 2) == 0)) + continue; + + 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 << "]"; + } + } + fclose(fp); + return true; +} +#endif // _TRY_FIREFOX + +#ifdef WIN32 +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) { + LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetProxyForUrl faulted!!"; + } +#else + success = pWHGPFU(hWinHttp, url, options, info); +#endif + + return success; +} +#endif + +bool GetProxySettingsForUrl(const char* agent, const char* url, + ProxyInfo& proxy, + bool long_operation) { + bool success = false; + Url<char> purl(url); + +#if 0 + assert( WildMatch(_T("A.B.C.D"), _T("a.b.c.d"))); + assert( WildMatch(_T("127.0.0.1"), _T("12*.0.*1"))); + assert(!WildMatch(_T("127.0.0.0"), _T("12*.0.*1"))); + assert(!WildMatch(_T("127.0.0.0"), _T("12*.0.*1"))); + assert( WildMatch(_T("127.1.0.21"), _T("12*.0.*1"))); + assert(!WildMatch(_T("127.1.1.21"), _T("12*.0.*1"))); + purl = PUrl(_T("http://a.b.c:500/")); + wchar_t item[256]; + _tcscpy(item, _T("a.b.c")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("a.x.c")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("a.b.*")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("a.x.*")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T(".b.c")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T(".x.c")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("a.b.c:500")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("a.b.c:501")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); + purl = PUrl(_T("http://1.2.3.4/")); + _tcscpy(item, _T("1.2.3.4")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("1.2.3.5")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("1.2.3.5/31")); + assert( ProxyItemMatch(purl, item, _tcslen(item))); + _tcscpy(item, _T("1.2.3.5/32")); + assert(!ProxyItemMatch(purl, item, _tcslen(item))); +#endif + + bool autoconfig = false; + bool use_firefox = false; + std::string autoconfig_url; + +#if _TRY_FIREFOX + use_firefox = IsDefaultBrowserFirefox(); + + if (use_firefox) { + std::wstring tmp; + if (GetDefaultFirefoxProfile(&tmp)) { + bool complete = true; + + StringMap settings; + tmp.append(L"prefs.js"); + if (ReadFirefoxPrefs(tmp, "network.proxy.", settings)) { + success = true; + if (settings.Get("type") == "1") { + if (ProxyListMatch(purl, settings.Get("no_proxies_on", "localhost, 127.0.0.1").c_str(), ',')) { + // 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") { + complete = success = false; + autoconfig_url = settings.Get("autoconfig_url").c_str(); + } else if (settings.Get("type") == "4") { + complete = success = false; + autoconfig = true; + } + } + if (complete) { // Otherwise fall through to IE autoproxy code + return success; + } + } + } +#endif // _TRY_FIREFOX + +#if _TRY_WINHTTP + if (!success) { + if (HMODULE hModWH = LoadLibrary(L"winhttp.dll")) { + pfnWinHttpOpen pWHO = reinterpret_cast<pfnWinHttpOpen>(GetProcAddress(hModWH, "WinHttpOpen")); + pfnWinHttpCloseHandle pWHCH = reinterpret_cast<pfnWinHttpCloseHandle>(GetProcAddress(hModWH, "WinHttpCloseHandle")); + pfnWinHttpGetProxyForUrl pWHGPFU = reinterpret_cast<pfnWinHttpGetProxyForUrl>(GetProcAddress(hModWH, "WinHttpGetProxyForUrl")); + pfnWinHttpGetIEProxyConfig pWHGIEPC = reinterpret_cast<pfnWinHttpGetIEProxyConfig>(GetProcAddress(hModWH, "WinHttpGetIEProxyConfigForCurrentUser")); + if (pWHO && pWHCH && pWHGPFU && pWHGIEPC) { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG iecfg; + memset(&iecfg, 0, sizeof(iecfg)); + if (!use_firefox && !pWHGIEPC(&iecfg)) { + LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetIEProxyConfigForCurrentUser"; + } else { + success = true; + if (!use_firefox) { + if (iecfg.fAutoDetect) { + autoconfig = true; + } + if (iecfg.lpszAutoConfigUrl) { + autoconfig_url = ToUtf8(iecfg.lpszAutoConfigUrl); + } + } + if (!long_operation) { + // Unless we perform this operation in the background, don't allow + // it to take a long time. + autoconfig = false; + } + if (autoconfig || !autoconfig_url.empty()) { + if (HINTERNET hWinHttp = pWHO(ToUtf16(agent).c_str(), + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0)) { + WINHTTP_AUTOPROXY_OPTIONS options; + memset(&options, 0, sizeof(options)); + if (autoconfig) { + options.dwFlags |= WINHTTP_AUTOPROXY_AUTO_DETECT; + options.dwAutoDetectFlags |= WINHTTP_AUTO_DETECT_TYPE_DHCP + | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + } + std::wstring autoconfig_url16((ToUtf16)(autoconfig_url)); + if (!autoconfig_url.empty()) { + options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL; + options.lpszAutoConfigUrl = autoconfig_url16.c_str(); + } + options.fAutoLogonIfChallenged = TRUE; + WINHTTP_PROXY_INFO info; + memset(&info, 0, sizeof(info)); + + BOOL success = MyWinHttpGetProxyForUrl(pWHGPFU, + hWinHttp, ToUtf16(url).c_str(), &options, &info); + + if (!success) { + LOG_GLEM(LERROR,WINHTTP) << "WinHttpGetProxyForUrl"; + } else { + if (iecfg.lpszProxy) + GlobalFree(iecfg.lpszProxy); + if (iecfg.lpszProxyBypass) + GlobalFree(iecfg.lpszProxyBypass); + iecfg.lpszProxy = info.lpszProxy; + iecfg.lpszProxyBypass = info.lpszProxyBypass; + } + pWHCH(hWinHttp); + } + } + if (!ProxyListMatch(purl, ToUtf8(nonnull(iecfg.lpszProxyBypass)), ' ')) { + ParseProxy(ToUtf8(nonnull(iecfg.lpszProxy)), proxy); + } + if (iecfg.lpszAutoConfigUrl) + GlobalFree(iecfg.lpszAutoConfigUrl); + if (iecfg.lpszProxy) + GlobalFree(iecfg.lpszProxy); + if (iecfg.lpszProxyBypass) + GlobalFree(iecfg.lpszProxyBypass); + } + } + FreeLibrary(hModWH); + } + } +#endif // _TRY_WINHTTP + +#if _TRY_JSPROXY + if (!success) { + 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); + } + } +#endif // _TRY_JSPROXY + +#if _TRY_WM_FINDPROXY + if (!success) { + 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(); + } + } +#endif // _TRY_WM_FINDPROXY + +#if _TRY_IE_LAN_SETTINGS + if (!success) { + 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; + } + } +#endif // _TRY_IE_LAN_SETTINGS + +#if 0 + if (!success) { + 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); + } + } +#endif // 0 + + return success; +} |