blob: 04a9c6160c5947cc6471da4b13df6cf2da1136d1 [file] [log] [blame]
// 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* list = slist.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[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;
}