| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome_frame/utils.h" | |
| 6 | |
| 7 #include <atlsafe.h> | |
| 8 #include <atlsecurity.h> | |
| 9 #include <htiframe.h> | |
| 10 #include <mshtml.h> | |
| 11 #include <shlobj.h> | |
| 12 #include <limits> | |
| 13 | |
| 14 #include "base/file_version_info.h" | |
| 15 #include "base/lazy_instance.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/path_service.h" | |
| 18 #include "base/strings/string_number_conversions.h" | |
| 19 #include "base/strings/string_piece.h" | |
| 20 #include "base/strings/string_tokenizer.h" | |
| 21 #include "base/strings/string_util.h" | |
| 22 #include "base/strings/stringprintf.h" | |
| 23 #include "base/strings/utf_string_conversions.h" | |
| 24 #include "base/threading/thread_local.h" | |
| 25 #include "base/win/registry.h" | |
| 26 #include "base/win/scoped_bstr.h" | |
| 27 #include "base/win/scoped_comptr.h" | |
| 28 #include "base/win/scoped_variant.h" | |
| 29 #include "chrome/common/automation_messages.h" | |
| 30 #include "chrome/common/chrome_paths_internal.h" | |
| 31 #include "chrome/common/url_constants.h" | |
| 32 #include "chrome/installer/util/chrome_frame_distribution.h" | |
| 33 #include "chrome_frame/chrome_tab.h" | |
| 34 #include "chrome_frame/extra_system_apis.h" | |
| 35 #include "chrome_frame/html_utils.h" | |
| 36 #include "chrome_frame/navigation_constraints.h" | |
| 37 #include "chrome_frame/policy_settings.h" | |
| 38 #include "chrome_frame/registry_list_preferences_holder.h" | |
| 39 #include "chrome_frame/simple_resource_loader.h" | |
| 40 #include "extensions/common/constants.h" | |
| 41 #include "grit/chromium_strings.h" | |
| 42 #include "net/base/escape.h" | |
| 43 #include "net/http/http_util.h" | |
| 44 #include "ui/base/models/menu_model.h" | |
| 45 #include "url/gurl.h" | |
| 46 #include "url/url_canon.h" | |
| 47 | |
| 48 using base::win::RegKey; | |
| 49 | |
| 50 // Note that these values are all lower case and are compared to | |
| 51 // lower-case-transformed values. | |
| 52 const char kGCFProtocol[] = "gcf"; | |
| 53 const wchar_t kBodyTag[] = L"body"; | |
| 54 const wchar_t kContentAttribName[] = L"content"; | |
| 55 const wchar_t kChromeContentPrefix[] = L"chrome="; | |
| 56 const wchar_t kChromeMimeType[] = L"application/chromepage"; | |
| 57 const wchar_t kChromeProtocolPrefix[] = L"gcf:"; | |
| 58 const wchar_t kHttpEquivAttribName[] = L"http-equiv"; | |
| 59 const wchar_t kIexploreProfileName[] = L"iexplore"; | |
| 60 const wchar_t kMetaTag[] = L"meta"; | |
| 61 const wchar_t kRundllProfileName[] = L"rundll32"; | |
| 62 const wchar_t kXUACompatValue[] = L"x-ua-compatible"; | |
| 63 | |
| 64 // Registry key and value names related to Chrome Frame configuration options. | |
| 65 const wchar_t kAllowUnsafeURLs[] = L"AllowUnsafeURLs"; | |
| 66 const wchar_t kChromeFrameConfigKey[] = L"Software\\Google\\ChromeFrame"; | |
| 67 const wchar_t kEnableBuggyBhoIntercept[] = L"EnableBuggyBhoIntercept"; | |
| 68 const wchar_t kEnableGCFRendererByDefault[] = L"IsDefaultRenderer"; | |
| 69 const wchar_t kSkipGCFMetadataCheck[] = L"SkipGCFMetadataCheck"; | |
| 70 const wchar_t kExcludeUAFromDomainList[] = L"ExcludeUAFromDomain"; | |
| 71 const wchar_t kPatchProtocols[] = L"PatchProtocols"; | |
| 72 const wchar_t kRenderInGCFUrlList[] = L"RenderInGcfUrls"; | |
| 73 const wchar_t kRenderInHostUrlList[] = L"RenderInHostUrls"; | |
| 74 | |
| 75 static const wchar_t kChromeFramePersistNPAPIReg[] = L"PersistNPAPIReg"; | |
| 76 | |
| 77 const char kAttachExternalTabPrefix[] = "attach_external_tab"; | |
| 78 | |
| 79 // Indicates that we are running in a test environment, where execptions, etc | |
| 80 // are handled by the chrome test crash server. | |
| 81 const wchar_t kChromeFrameHeadlessMode[] = L"ChromeFrameHeadlessMode"; | |
| 82 | |
| 83 // Indicates that we are running in an environment that expects chrome renderer | |
| 84 // accessibility to be enabled for use in automation tests. | |
| 85 const wchar_t kChromeFrameAccessibleMode[] = L"ChromeFrameAccessibleMode"; | |
| 86 | |
| 87 // Indicates that we are running in an environment that wishes to avoid | |
| 88 // DLL pinning, such as the perf tests. | |
| 89 const wchar_t kChromeFrameUnpinnedMode[] = L"kChromeFrameUnpinnedMode"; | |
| 90 | |
| 91 // Controls whether we download subresources, etc on the chrome frame page in | |
| 92 // the background worker thread. Defaults to true. | |
| 93 const wchar_t kUseBackgroundThreadForSubResources[] | |
| 94 = L"BackgroundHTTPWorkerThread"; | |
| 95 | |
| 96 // {1AF32B6C-A3BA-48B9-B24E-8AA9C41F6ECD} | |
| 97 static const IID IID_IWebBrowserPriv2IE7 = { 0x1AF32B6C, 0xA3BA, 0x48B9, | |
| 98 { 0xB2, 0x4E, 0x8A, 0xA9, 0xC4, 0x1F, 0x6E, 0xCD } }; | |
| 99 | |
| 100 // {3ED72303-6FFC-4214-BA90-FAF1862DEC8A} | |
| 101 static const IID IID_IWebBrowserPriv2IE8 = { 0x3ED72303, 0x6FFC, 0x4214, | |
| 102 { 0xBA, 0x90, 0xFA, 0xF1, 0x86, 0x2D, 0xEC, 0x8A } }; | |
| 103 | |
| 104 // {486F6159-9F3F-4827-82D4-283CEF397733} | |
| 105 static const IID IID_IWebBrowserPriv2IE8XP = { 0x486F6159, 0x9F3F, 0x4827, | |
| 106 { 0x82, 0xD4, 0x28, 0x3C, 0xEF, 0x39, 0x77, 0x33 } }; | |
| 107 | |
| 108 // {38339692-0BC9-46CB-8E5C-4677A5C83DD5} | |
| 109 static const IID IID_IWebBrowserPriv2IE8XPBeta = { 0x38339692, 0x0BC9, 0x46CB, | |
| 110 { 0x8E, 0x5C, 0x46, 0x77, 0xA5, 0xC8, 0x3D, 0xD5 } }; | |
| 111 | |
| 112 namespace { | |
| 113 | |
| 114 // A flag used to signal when an active browser instance on the current thread | |
| 115 // is loading a Chrome Frame document. There's no reference stored with the | |
| 116 // pointer so it should not be dereferenced and used for comparison against a | |
| 117 // living instance only. | |
| 118 base::LazyInstance<base::ThreadLocalPointer<IBrowserService> > | |
| 119 g_tls_browser_for_cf_navigation = LAZY_INSTANCE_INITIALIZER; | |
| 120 | |
| 121 // Holds the cached preferences for the per-url render type settings. | |
| 122 base::LazyInstance<RegistryListPreferencesHolder>::Leaky | |
| 123 g_render_type_for_url_holder; | |
| 124 | |
| 125 // Holds the cached preferences for the per-url user agent filter. | |
| 126 base::LazyInstance<RegistryListPreferencesHolder>::Leaky | |
| 127 g_user_agent_filter_holder; | |
| 128 | |
| 129 } // end anonymous namespace | |
| 130 | |
| 131 HRESULT UtilRegisterTypeLib(HINSTANCE tlb_instance, | |
| 132 LPCOLESTR index, | |
| 133 bool for_current_user_only) { | |
| 134 CComBSTR path; | |
| 135 CComPtr<ITypeLib> type_lib; | |
| 136 HRESULT hr = AtlLoadTypeLib(tlb_instance, index, &path, &type_lib); | |
| 137 if (SUCCEEDED(hr)) { | |
| 138 hr = UtilRegisterTypeLib(type_lib, path, NULL, for_current_user_only); | |
| 139 } | |
| 140 return hr; | |
| 141 } | |
| 142 | |
| 143 HRESULT UtilUnRegisterTypeLib(HINSTANCE tlb_instance, | |
| 144 LPCOLESTR index, | |
| 145 bool for_current_user_only) { | |
| 146 CComBSTR path; | |
| 147 CComPtr<ITypeLib> type_lib; | |
| 148 HRESULT hr = AtlLoadTypeLib(tlb_instance, index, &path, &type_lib); | |
| 149 if (SUCCEEDED(hr)) { | |
| 150 hr = UtilUnRegisterTypeLib(type_lib, for_current_user_only); | |
| 151 } | |
| 152 return hr; | |
| 153 } | |
| 154 | |
| 155 HRESULT UtilRegisterTypeLib(LPCWSTR typelib_path, | |
| 156 bool for_current_user_only) { | |
| 157 if (NULL == typelib_path) { | |
| 158 return E_INVALIDARG; | |
| 159 } | |
| 160 CComBSTR path; | |
| 161 CComPtr<ITypeLib> type_lib; | |
| 162 HRESULT hr = ::LoadTypeLib(typelib_path, &type_lib); | |
| 163 if (SUCCEEDED(hr)) { | |
| 164 hr = UtilRegisterTypeLib(type_lib, | |
| 165 typelib_path, | |
| 166 NULL, | |
| 167 for_current_user_only); | |
| 168 } | |
| 169 return hr; | |
| 170 } | |
| 171 | |
| 172 HRESULT UtilUnRegisterTypeLib(LPCWSTR typelib_path, | |
| 173 bool for_current_user_only) { | |
| 174 CComPtr<ITypeLib> type_lib; | |
| 175 HRESULT hr = ::LoadTypeLib(typelib_path, &type_lib); | |
| 176 if (SUCCEEDED(hr)) { | |
| 177 hr = UtilUnRegisterTypeLib(type_lib, for_current_user_only); | |
| 178 } | |
| 179 return hr; | |
| 180 } | |
| 181 | |
| 182 HRESULT UtilRegisterTypeLib(ITypeLib* typelib, | |
| 183 LPCWSTR typelib_path, | |
| 184 LPCWSTR help_dir, | |
| 185 bool for_current_user_only) { | |
| 186 typedef HRESULT(WINAPI *RegisterTypeLibPrototype)(ITypeLib FAR* type_lib, | |
| 187 OLECHAR FAR* full_path, | |
| 188 OLECHAR FAR* help_dir); | |
| 189 LPCSTR function_name = | |
| 190 for_current_user_only ? "RegisterTypeLibForUser" : "RegisterTypeLib"; | |
| 191 RegisterTypeLibPrototype reg_tlb = | |
| 192 reinterpret_cast<RegisterTypeLibPrototype>( | |
| 193 GetProcAddress(GetModuleHandle(_T("oleaut32.dll")), | |
| 194 function_name)); | |
| 195 if (NULL == reg_tlb) { | |
| 196 return E_FAIL; | |
| 197 } | |
| 198 return reg_tlb(typelib, | |
| 199 const_cast<OLECHAR*>(typelib_path), | |
| 200 const_cast<OLECHAR*>(help_dir)); | |
| 201 } | |
| 202 | |
| 203 HRESULT UtilUnRegisterTypeLib(ITypeLib* typelib, | |
| 204 bool for_current_user_only) { | |
| 205 if (NULL == typelib) { | |
| 206 return E_INVALIDARG; | |
| 207 } | |
| 208 typedef HRESULT(WINAPI *UnRegisterTypeLibPrototype)( | |
| 209 REFGUID libID, | |
| 210 unsigned short wVerMajor, // NOLINT | |
| 211 unsigned short wVerMinor, // NOLINT | |
| 212 LCID lcid, | |
| 213 SYSKIND syskind); | |
| 214 LPCSTR function_name = | |
| 215 for_current_user_only ? "UnRegisterTypeLibForUser" : "UnRegisterTypeLib"; | |
| 216 | |
| 217 UnRegisterTypeLibPrototype unreg_tlb = | |
| 218 reinterpret_cast<UnRegisterTypeLibPrototype>( | |
| 219 GetProcAddress(GetModuleHandle(_T("oleaut32.dll")), | |
| 220 function_name)); | |
| 221 if (NULL == unreg_tlb) { | |
| 222 return E_FAIL; | |
| 223 } | |
| 224 TLIBATTR* tla = NULL; | |
| 225 HRESULT hr = typelib->GetLibAttr(&tla); | |
| 226 if (SUCCEEDED(hr)) { | |
| 227 hr = unreg_tlb(tla->guid, | |
| 228 tla->wMajorVerNum, | |
| 229 tla->wMinorVerNum, | |
| 230 tla->lcid, | |
| 231 tla->syskind); | |
| 232 typelib->ReleaseTLibAttr(tla); | |
| 233 } | |
| 234 return hr; | |
| 235 } | |
| 236 | |
| 237 bool UtilRemovePersistentNPAPIMarker() { | |
| 238 BrowserDistribution* cf_dist = BrowserDistribution::GetDistribution(); | |
| 239 std::wstring cf_state_key_path(cf_dist->GetStateKey()); | |
| 240 RegKey cf_state_key; | |
| 241 | |
| 242 LONG result = cf_state_key.Open(HKEY_LOCAL_MACHINE, cf_state_key_path.c_str(), | |
| 243 KEY_SET_VALUE); | |
| 244 if (result == ERROR_SUCCESS) | |
| 245 result = cf_state_key.DeleteValue(kChromeFramePersistNPAPIReg); | |
| 246 return (result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); | |
| 247 } | |
| 248 | |
| 249 HRESULT UtilGetXUACompatContentValue(const std::wstring& html_string, | |
| 250 std::wstring* content_value) { | |
| 251 if (!content_value) { | |
| 252 return E_POINTER; | |
| 253 } | |
| 254 | |
| 255 // Fail fast if the string X-UA-Compatible isn't in html_string | |
| 256 if (StringToLowerASCII(html_string).find(kXUACompatValue) == | |
| 257 std::wstring::npos) { | |
| 258 return E_FAIL; | |
| 259 } | |
| 260 | |
| 261 HTMLScanner scanner(html_string.c_str()); | |
| 262 | |
| 263 // Build the list of meta tags that occur before the body tag is hit. | |
| 264 HTMLScanner::StringRangeList tag_list; | |
| 265 scanner.GetTagsByName(kMetaTag, &tag_list, kBodyTag); | |
| 266 | |
| 267 // Search the list of meta tags for one with an http-equiv="X-UA-Compatible" | |
| 268 // attribute. | |
| 269 HTMLScanner::StringRange attribute; | |
| 270 std::string search_attribute_ascii(WideToASCII(kXUACompatValue)); | |
| 271 HTMLScanner::StringRangeList::const_iterator tag_list_iter(tag_list.begin()); | |
| 272 for (; tag_list_iter != tag_list.end(); tag_list_iter++) { | |
| 273 if (!tag_list_iter->GetTagAttribute(kHttpEquivAttribName, &attribute)) { | |
| 274 continue; | |
| 275 } | |
| 276 | |
| 277 // We found an http-equiv meta tag, check its value using the ascii | |
| 278 // case-insensitive comparison method. | |
| 279 if (!attribute.LowerCaseEqualsASCII(search_attribute_ascii.c_str())) { | |
| 280 continue; | |
| 281 } | |
| 282 | |
| 283 // We found our X-UA-Compatible meta tag so look for and extract | |
| 284 // the value of the content attribute. | |
| 285 if (!tag_list_iter->GetTagAttribute(kContentAttribName, &attribute)) { | |
| 286 continue; | |
| 287 } | |
| 288 | |
| 289 // Found the content string, copy and return. | |
| 290 content_value->assign(attribute.Copy()); | |
| 291 return S_OK; | |
| 292 } | |
| 293 | |
| 294 return E_FAIL; | |
| 295 } | |
| 296 | |
| 297 void DisplayVersionMismatchWarning(HWND parent, | |
| 298 const std::string& server_version) { | |
| 299 // Obtain the current module version. | |
| 300 scoped_ptr<FileVersionInfo> module_version_info( | |
| 301 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | |
| 302 base::string16 version_string(module_version_info->file_version()); | |
| 303 std::wstring wide_server_version; | |
| 304 if (server_version.empty()) { | |
| 305 wide_server_version = SimpleResourceLoader::Get(IDS_VERSIONUNKNOWN); | |
| 306 } else { | |
| 307 wide_server_version = base::ASCIIToWide(server_version); | |
| 308 } | |
| 309 std::wstring title = SimpleResourceLoader::Get(IDS_VERSIONMISMATCH_HEADER); | |
| 310 std::wstring message; | |
| 311 base::SStringPrintf(&message, | |
| 312 SimpleResourceLoader::Get(IDS_VERSIONMISMATCH).c_str(), | |
| 313 wide_server_version.c_str(), | |
| 314 version_string.c_str()); | |
| 315 | |
| 316 ::MessageBox(parent, message.c_str(), title.c_str(), MB_OK); | |
| 317 } | |
| 318 | |
| 319 std::string CreateJavascript(const std::string& function_name, | |
| 320 const std::string args) { | |
| 321 std::string script_string = "javascript:"; | |
| 322 script_string += function_name + "("; | |
| 323 if (!args.empty()) { | |
| 324 script_string += "'"; | |
| 325 script_string += args; | |
| 326 script_string += "'"; | |
| 327 } | |
| 328 script_string += ")"; | |
| 329 return script_string; | |
| 330 } | |
| 331 | |
| 332 AddRefModule::AddRefModule() { | |
| 333 // TODO(tommi): Override the module's Lock/Unlock methods to call | |
| 334 // npapi::SetValue(NPPVpluginKeepLibraryInMemory) and keep the dll loaded | |
| 335 // while the module's refcount is > 0. Only do this when we're being | |
| 336 // used as an NPAPI module. | |
| 337 _pAtlModule->Lock(); | |
| 338 } | |
| 339 | |
| 340 | |
| 341 AddRefModule::~AddRefModule() { | |
| 342 _pAtlModule->Unlock(); | |
| 343 } | |
| 344 | |
| 345 bool IsChrome(RendererType renderer_type) { | |
| 346 DCHECK_GE(renderer_type, RENDERER_TYPE_UNDETERMINED); | |
| 347 DCHECK_LE(renderer_type, RENDERER_TYPE_OTHER); | |
| 348 return renderer_type >= RENDERER_TYPE_CHROME_MIN && | |
| 349 renderer_type <= RENDERER_TYPE_CHROME_MAX; | |
| 350 } | |
| 351 | |
| 352 namespace { | |
| 353 const char kIEImageName[] = "iexplore.exe"; | |
| 354 } // namespace | |
| 355 | |
| 356 std::wstring GetHostProcessName(bool include_extension) { | |
| 357 base::FilePath exe; | |
| 358 if (PathService::Get(base::FILE_EXE, &exe)) | |
| 359 exe = exe.BaseName(); | |
| 360 if (!include_extension) { | |
| 361 exe = exe.RemoveExtension(); | |
| 362 } | |
| 363 return exe.value(); | |
| 364 } | |
| 365 | |
| 366 BrowserType GetBrowserType() { | |
| 367 static BrowserType browser_type = BROWSER_INVALID; | |
| 368 | |
| 369 if (browser_type == BROWSER_INVALID) { | |
| 370 std::wstring exe(GetHostProcessName(true)); | |
| 371 if (!exe.empty()) { | |
| 372 std::wstring::const_iterator begin = exe.begin(); | |
| 373 std::wstring::const_iterator end = exe.end(); | |
| 374 if (LowerCaseEqualsASCII(begin, end, kIEImageName)) { | |
| 375 browser_type = BROWSER_IE; | |
| 376 } else { | |
| 377 browser_type = BROWSER_UNKNOWN; | |
| 378 } | |
| 379 } else { | |
| 380 NOTREACHED(); | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 return browser_type; | |
| 385 } | |
| 386 | |
| 387 uint32 GetIEMajorVersion() { | |
| 388 static uint32 ie_major_version = UINT_MAX; | |
| 389 | |
| 390 if (ie_major_version == UINT_MAX) { | |
| 391 wchar_t exe_path[MAX_PATH]; | |
| 392 HMODULE mod = GetModuleHandle(NULL); | |
| 393 GetModuleFileName(mod, exe_path, arraysize(exe_path) - 1); | |
| 394 std::wstring exe_name = base::FilePath(exe_path).BaseName().value(); | |
| 395 if (!LowerCaseEqualsASCII(exe_name, kIEImageName)) { | |
| 396 ie_major_version = 0; | |
| 397 } else { | |
| 398 uint32 high = 0; | |
| 399 uint32 low = 0; | |
| 400 if (GetModuleVersion(mod, &high, &low)) { | |
| 401 ie_major_version = HIWORD(high); | |
| 402 } else { | |
| 403 ie_major_version = 0; | |
| 404 } | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 return ie_major_version; | |
| 409 } | |
| 410 | |
| 411 IEVersion GetIEVersion() { | |
| 412 static IEVersion ie_version = IE_INVALID; | |
| 413 | |
| 414 if (ie_version == IE_INVALID) { | |
| 415 uint32 major_version = GetIEMajorVersion(); | |
| 416 switch (major_version) { | |
| 417 case 0: | |
| 418 ie_version = NON_IE; | |
| 419 break; | |
| 420 case 6: | |
| 421 ie_version = IE_6; | |
| 422 break; | |
| 423 case 7: | |
| 424 ie_version = IE_7; | |
| 425 break; | |
| 426 case 8: | |
| 427 ie_version = IE_8; | |
| 428 break; | |
| 429 case 9: | |
| 430 ie_version = IE_9; | |
| 431 break; | |
| 432 case 10: | |
| 433 ie_version = IE_10; | |
| 434 break; | |
| 435 default: | |
| 436 ie_version = (major_version >= 11) ? IE_11 : IE_UNSUPPORTED; | |
| 437 break; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 return ie_version; | |
| 442 } | |
| 443 | |
| 444 base::FilePath GetIETemporaryFilesFolder() { | |
| 445 LPITEMIDLIST tif_pidl = NULL; | |
| 446 HRESULT hr = SHGetFolderLocation(NULL, CSIDL_INTERNET_CACHE, NULL, | |
| 447 SHGFP_TYPE_CURRENT, &tif_pidl); | |
| 448 if (SUCCEEDED(hr) && tif_pidl) { | |
| 449 base::win::ScopedComPtr<IShellFolder> parent_folder; | |
| 450 LPITEMIDLIST relative_pidl = NULL; | |
| 451 hr = SHBindToParent(tif_pidl, IID_IShellFolder, | |
| 452 reinterpret_cast<void**>(parent_folder.Receive()), | |
| 453 const_cast<LPCITEMIDLIST*>(&relative_pidl)); | |
| 454 if (SUCCEEDED(hr) && relative_pidl) { | |
| 455 STRRET path = {0}; | |
| 456 hr = parent_folder->GetDisplayNameOf(relative_pidl, | |
| 457 SHGDN_NORMAL | SHGDN_FORPARSING, | |
| 458 &path); | |
| 459 DCHECK(SUCCEEDED(hr)); | |
| 460 base::win::ScopedBstr temp_internet_files_bstr; | |
| 461 StrRetToBSTR(&path, relative_pidl, temp_internet_files_bstr.Receive()); | |
| 462 base::FilePath temp_internet_files( | |
| 463 static_cast<BSTR>(temp_internet_files_bstr)); | |
| 464 ILFree(tif_pidl); | |
| 465 return temp_internet_files; | |
| 466 } else { | |
| 467 NOTREACHED() << "SHBindToParent failed with Error:" << hr; | |
| 468 ILFree(tif_pidl); | |
| 469 } | |
| 470 } else { | |
| 471 NOTREACHED() << "SHGetFolderLocation for internet cache failed. Error:" | |
| 472 << hr; | |
| 473 } | |
| 474 // As a last ditch effort we use the SHGetFolderPath function to retrieve the | |
| 475 // path. This function has a limitation of MAX_PATH. | |
| 476 wchar_t path[MAX_PATH + 1] = {0}; | |
| 477 hr = SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, | |
| 478 path); | |
| 479 if (SUCCEEDED(hr)) { | |
| 480 return base::FilePath(path); | |
| 481 } else { | |
| 482 NOTREACHED() << "SHGetFolderPath for internet cache failed. Error:" | |
| 483 << hr; | |
| 484 } | |
| 485 return base::FilePath(); | |
| 486 } | |
| 487 | |
| 488 bool IsIEInPrivate() { | |
| 489 typedef BOOL (WINAPI* IEIsInPrivateBrowsingPtr)(); | |
| 490 bool incognito_mode = false; | |
| 491 HMODULE h = GetModuleHandle(L"ieframe.dll"); | |
| 492 if (h) { | |
| 493 IEIsInPrivateBrowsingPtr IsInPrivate = | |
| 494 reinterpret_cast<IEIsInPrivateBrowsingPtr>(GetProcAddress(h, | |
| 495 "IEIsInPrivateBrowsing")); | |
| 496 if (IsInPrivate) { | |
| 497 incognito_mode = !!IsInPrivate(); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 return incognito_mode; | |
| 502 } | |
| 503 | |
| 504 HRESULT DoFileDownloadInIE(const wchar_t* url) { | |
| 505 DCHECK(url); | |
| 506 | |
| 507 HMODULE mod = ::GetModuleHandleA("ieframe.dll"); | |
| 508 if (!mod) | |
| 509 mod = ::GetModuleHandleA("shdocvw.dll"); | |
| 510 | |
| 511 if (!mod) { | |
| 512 NOTREACHED(); | |
| 513 return E_UNEXPECTED; | |
| 514 } | |
| 515 | |
| 516 typedef HRESULT (WINAPI* DoFileDownloadFn)(const wchar_t*); | |
| 517 DoFileDownloadFn fn = reinterpret_cast<DoFileDownloadFn>( | |
| 518 ::GetProcAddress(mod, "DoFileDownload")); | |
| 519 DCHECK(fn); | |
| 520 return fn ? fn(url) : E_UNEXPECTED; | |
| 521 } | |
| 522 | |
| 523 bool GetModuleVersion(HMODULE module, uint32* high, uint32* low) { | |
| 524 DCHECK(module != NULL) | |
| 525 << "Please use GetModuleHandle(NULL) to get the process name"; | |
| 526 DCHECK(high); | |
| 527 | |
| 528 bool ok = false; | |
| 529 | |
| 530 HRSRC res = FindResource(module, | |
| 531 reinterpret_cast<const wchar_t*>(VS_VERSION_INFO), RT_VERSION); | |
| 532 if (res) { | |
| 533 HGLOBAL res_data = LoadResource(module, res); | |
| 534 DWORD version_resource_size = SizeofResource(module, res); | |
| 535 const void* readonly_resource_data = LockResource(res_data); | |
| 536 if (readonly_resource_data && version_resource_size) { | |
| 537 // Copy data as VerQueryValue tries to modify the data. This causes | |
| 538 // exceptions and heap corruption errors if debugger is attached. | |
| 539 scoped_ptr<char[]> data(new char[version_resource_size]); | |
| 540 if (data.get()) { | |
| 541 memcpy(data.get(), readonly_resource_data, version_resource_size); | |
| 542 VS_FIXEDFILEINFO* ver_info = NULL; | |
| 543 UINT info_size = 0; | |
| 544 if (VerQueryValue(data.get(), L"\\", | |
| 545 reinterpret_cast<void**>(&ver_info), &info_size)) { | |
| 546 *high = ver_info->dwFileVersionMS; | |
| 547 if (low != NULL) | |
| 548 *low = ver_info->dwFileVersionLS; | |
| 549 ok = true; | |
| 550 } | |
| 551 | |
| 552 UnlockResource(res_data); | |
| 553 } | |
| 554 FreeResource(res_data); | |
| 555 } | |
| 556 } | |
| 557 | |
| 558 return ok; | |
| 559 } | |
| 560 | |
| 561 std::string ResolveURL(const std::string& document, | |
| 562 const std::string& relative) { | |
| 563 if (document.empty()) { | |
| 564 return GURL(relative).spec(); | |
| 565 } else { | |
| 566 return GURL(document).Resolve(relative).spec(); | |
| 567 } | |
| 568 } | |
| 569 | |
| 570 bool HaveSameOrigin(const std::string& url1, const std::string& url2) { | |
| 571 GURL a(url1), b(url2); | |
| 572 bool ret; | |
| 573 if (a.is_valid() != b.is_valid()) { | |
| 574 // Either (but not both) url is invalid, so they can't match. | |
| 575 ret = false; | |
| 576 } else if (!a.is_valid()) { | |
| 577 // Both URLs are invalid (see first check). Just check if the opaque | |
| 578 // strings match exactly. | |
| 579 ret = url1.compare(url2) == 0; | |
| 580 } else if (a.GetOrigin() != b.GetOrigin()) { | |
| 581 // The origins don't match. | |
| 582 ret = false; | |
| 583 } else { | |
| 584 // we have a match. | |
| 585 ret = true; | |
| 586 } | |
| 587 | |
| 588 return ret; | |
| 589 } | |
| 590 | |
| 591 int GetConfigInt(int default_value, const wchar_t* value_name) { | |
| 592 int ret = default_value; | |
| 593 RegKey config_key; | |
| 594 if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 595 KEY_QUERY_VALUE) == ERROR_SUCCESS) { | |
| 596 config_key.ReadValueDW(value_name, reinterpret_cast<DWORD*>(&ret)); | |
| 597 } | |
| 598 | |
| 599 return ret; | |
| 600 } | |
| 601 | |
| 602 int64 GetConfigInt64(int64 default_value, const wchar_t* value_name) { | |
| 603 int64 ret = default_value; | |
| 604 RegKey config_key; | |
| 605 if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 606 KEY_QUERY_VALUE) == ERROR_SUCCESS) { | |
| 607 config_key.ReadInt64(value_name, &ret); | |
| 608 } | |
| 609 | |
| 610 return ret; | |
| 611 } | |
| 612 | |
| 613 bool GetConfigBool(bool default_value, const wchar_t* value_name) { | |
| 614 DWORD value = GetConfigInt(default_value, value_name); | |
| 615 return (value != FALSE); | |
| 616 } | |
| 617 | |
| 618 bool SetConfigInt(const wchar_t* value_name, int value) { | |
| 619 RegKey config_key; | |
| 620 if (config_key.Create(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 621 KEY_SET_VALUE) == ERROR_SUCCESS) { | |
| 622 if (config_key.WriteValue(value_name, value) == ERROR_SUCCESS) { | |
| 623 return true; | |
| 624 } | |
| 625 } | |
| 626 | |
| 627 return false; | |
| 628 } | |
| 629 | |
| 630 bool SetConfigBool(const wchar_t* value_name, bool value) { | |
| 631 return SetConfigInt(value_name, value); | |
| 632 } | |
| 633 | |
| 634 bool SetConfigInt64(const wchar_t* value_name, int64 value) { | |
| 635 RegKey config_key; | |
| 636 if (config_key.Create(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 637 KEY_SET_VALUE) == ERROR_SUCCESS) { | |
| 638 if (config_key.WriteValue(value_name, &value, sizeof(value), | |
| 639 REG_QWORD) == ERROR_SUCCESS) { | |
| 640 return true; | |
| 641 } | |
| 642 } | |
| 643 | |
| 644 return false; | |
| 645 } | |
| 646 | |
| 647 bool DeleteConfigValue(const wchar_t* value_name) { | |
| 648 RegKey config_key; | |
| 649 if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 650 KEY_WRITE) == ERROR_SUCCESS) { | |
| 651 if (config_key.DeleteValue(value_name) == ERROR_SUCCESS) { | |
| 652 return true; | |
| 653 } | |
| 654 } | |
| 655 return false; | |
| 656 } | |
| 657 | |
| 658 bool IsGcfDefaultRenderer() { | |
| 659 DWORD is_default = 0; // NOLINT | |
| 660 | |
| 661 // First check policy settings | |
| 662 PolicySettings::RendererForUrl renderer = | |
| 663 PolicySettings::GetInstance()->default_renderer(); | |
| 664 if (renderer != PolicySettings::RENDERER_NOT_SPECIFIED) { | |
| 665 is_default = (renderer == PolicySettings::RENDER_IN_CHROME_FRAME); | |
| 666 } else { | |
| 667 // TODO(tommi): Implement caching for this config value as it gets | |
| 668 // checked frequently. | |
| 669 RegKey config_key; | |
| 670 if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 671 KEY_READ) == ERROR_SUCCESS) { | |
| 672 config_key.ReadValueDW(kEnableGCFRendererByDefault, &is_default); | |
| 673 } | |
| 674 } | |
| 675 | |
| 676 return is_default != 0; | |
| 677 } | |
| 678 | |
| 679 // Check for the registry key 'SkipGCFMetadataCheck' and if true, then | |
| 680 // ignore presence of <meta http-equiv="X-UA-Compatible" content="chrome=1"> | |
| 681 bool SkipMetadataCheck() { | |
| 682 // Check policy settings | |
| 683 PolicySettings::SkipMetadataCheck metadataCheck = | |
| 684 PolicySettings::GetInstance()->skip_metadata_check(); | |
| 685 if (metadataCheck != PolicySettings::SKIP_METADATA_CHECK_NOT_SPECIFIED) | |
| 686 return (metadataCheck == PolicySettings::SKIP_METADATA_CHECK_YES); | |
| 687 | |
| 688 DWORD skip = 0; | |
| 689 RegKey config_key; | |
| 690 if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey, | |
| 691 KEY_READ) == ERROR_SUCCESS) { | |
| 692 config_key.ReadValueDW(kSkipGCFMetadataCheck, &skip); | |
| 693 } | |
| 694 return skip != 0; | |
| 695 } | |
| 696 | |
| 697 RendererType RendererTypeForUrl(const std::wstring& url) { | |
| 698 // First check if the default renderer settings are specified by policy. | |
| 699 // If so, then that overrides the user settings. | |
| 700 PolicySettings::RendererForUrl renderer = | |
| 701 PolicySettings::GetInstance()->GetRendererForUrl(url.c_str()); | |
| 702 if (renderer != PolicySettings::RENDERER_NOT_SPECIFIED) { | |
| 703 // We may know at this point that policy says do NOT render in Chrome Frame. | |
| 704 // To maintain consistency, we return RENDERER_TYPE_UNDETERMINED so that | |
| 705 // content sniffing, etc. still take place. | |
| 706 // TODO(tommi): Clarify the intent here. | |
| 707 return (renderer == PolicySettings::RENDER_IN_CHROME_FRAME) ? | |
| 708 RENDERER_TYPE_CHROME_OPT_IN_URL : RENDERER_TYPE_UNDETERMINED; | |
| 709 } | |
| 710 | |
| 711 // TODO(robertshield): Move this into a holder-type class that listens | |
| 712 // for reg change events as well. | |
| 713 static int render_in_cf_by_default = FALSE; | |
| 714 | |
| 715 RegistryListPreferencesHolder& render_type_for_url_holder = | |
| 716 g_render_type_for_url_holder.Get(); | |
| 717 if (!render_type_for_url_holder.Valid()) { | |
| 718 const wchar_t* url_list_name = kRenderInGCFUrlList; | |
| 719 if (IsGcfDefaultRenderer()) { | |
| 720 url_list_name = kRenderInHostUrlList; | |
| 721 render_in_cf_by_default = TRUE; | |
| 722 } else { | |
| 723 render_in_cf_by_default = FALSE; | |
| 724 } | |
| 725 | |
| 726 render_type_for_url_holder.Init(HKEY_CURRENT_USER, | |
| 727 kChromeFrameConfigKey, | |
| 728 url_list_name); | |
| 729 } | |
| 730 DCHECK(render_type_for_url_holder.Valid()); | |
| 731 | |
| 732 RendererType renderer_type = | |
| 733 render_in_cf_by_default ? RENDERER_TYPE_CHROME_DEFAULT_RENDERER : | |
| 734 RENDERER_TYPE_UNDETERMINED; | |
| 735 | |
| 736 if (render_type_for_url_holder.ListMatches(url)) { | |
| 737 renderer_type = render_in_cf_by_default ? | |
| 738 RENDERER_TYPE_UNDETERMINED : | |
| 739 RENDERER_TYPE_CHROME_OPT_IN_URL; | |
| 740 } | |
| 741 | |
| 742 return renderer_type; | |
| 743 } | |
| 744 | |
| 745 bool ShouldRemoveUAForUrl(const base::string16& url) { | |
| 746 // TODO(robertshield): Wire up the stuff in PolicySettings here so the value | |
| 747 // can be specified via group policy. | |
| 748 // TODO(robertshield): Add a default list of exclusions here for site with | |
| 749 // known bad UA parsing. | |
| 750 RegistryListPreferencesHolder& user_agent_filter_holder = | |
| 751 g_user_agent_filter_holder.Get(); | |
| 752 if (!user_agent_filter_holder.Valid()) { | |
| 753 user_agent_filter_holder.Init(HKEY_CURRENT_USER, | |
| 754 kChromeFrameConfigKey, | |
| 755 kExcludeUAFromDomainList); | |
| 756 } | |
| 757 DCHECK(user_agent_filter_holder.Valid()); | |
| 758 | |
| 759 return user_agent_filter_holder.ListMatches(url); | |
| 760 } | |
| 761 | |
| 762 RegistryListPreferencesHolder& GetRendererTypePreferencesHolderForTesting() { | |
| 763 return g_render_type_for_url_holder.Get(); | |
| 764 } | |
| 765 | |
| 766 RegistryListPreferencesHolder& GetUserAgentPreferencesHolderForTesting() { | |
| 767 return g_user_agent_filter_holder.Get(); | |
| 768 } | |
| 769 | |
| 770 HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker, | |
| 771 const wchar_t* headers, IBindCtx* bind_ctx, | |
| 772 const wchar_t* fragment, IStream* post_data, | |
| 773 VARIANT* flags) { | |
| 774 DCHECK(browser); | |
| 775 DCHECK(moniker); | |
| 776 DCHECK(bind_ctx); | |
| 777 | |
| 778 base::win::ScopedComPtr<IWebBrowser2> web_browser2; | |
| 779 HRESULT hr = DoQueryService(SID_SWebBrowserApp, browser, | |
| 780 web_browser2.Receive()); | |
| 781 DCHECK(web_browser2); | |
| 782 DLOG_IF(WARNING, FAILED(hr)) << base::StringPrintf(L"SWebBrowserApp 0x%08X", | |
| 783 hr); | |
| 784 if (FAILED(hr)) | |
| 785 return hr; | |
| 786 | |
| 787 // If the data to be downloaded was received in response to a post request | |
| 788 // then we need to reissue the post request. | |
| 789 base::win::ScopedVariant post_data_variant; | |
| 790 if (post_data) { | |
| 791 RewindStream(post_data); | |
| 792 | |
| 793 CComSafeArray<uint8> safe_array_post; | |
| 794 | |
| 795 STATSTG stat; | |
| 796 post_data->Stat(&stat, STATFLAG_NONAME); | |
| 797 | |
| 798 if (stat.cbSize.LowPart > 0) { | |
| 799 std::string data; | |
| 800 | |
| 801 HRESULT hr = E_FAIL; | |
| 802 while ((hr = ReadStream(post_data, 0xffff, &data)) == S_OK) { | |
| 803 safe_array_post.Add( | |
| 804 data.size(), | |
| 805 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data()))); | |
| 806 data.clear(); | |
| 807 } | |
| 808 } else { | |
| 809 // If we get here it means that the navigation is being reissued for a | |
| 810 // POST request with no data. To ensure that the new window used as a | |
| 811 // target to handle the new navigation issues a POST request | |
| 812 // we need valid POST data. In this case we create a dummy 1 byte array. | |
| 813 // May not work as expected with some web sites. | |
| 814 DLOG(WARNING) << "Reissuing navigation with empty POST data. May not" | |
| 815 << " work as expected"; | |
| 816 safe_array_post.Create(1); | |
| 817 } | |
| 818 post_data_variant.Set(safe_array_post.Detach()); | |
| 819 } | |
| 820 // Create a new bind context that's not associated with our callback. | |
| 821 // Calling RevokeBindStatusCallback doesn't disassociate the callback with | |
| 822 // the bind context in IE7. The returned bind context has the same | |
| 823 // implementation of GetRunningObjectTable as the bind context we held which | |
| 824 // basically delegates to ole32's GetRunningObjectTable. The object table | |
| 825 // is then used to determine if the moniker is already running and via | |
| 826 // that mechanism is associated with the same internet request as has already | |
| 827 // been issued. | |
| 828 | |
| 829 // TODO(tommi): See if we can get HlinkSimpleNavigateToMoniker to work | |
| 830 // instead. Looks like we'll need to support IHTMLDocument2 (get_URL in | |
| 831 // particular), access to IWebBrowser2 etc. | |
| 832 // HlinkSimpleNavigateToMoniker(moniker, url, NULL, host, bind_context, | |
| 833 // NULL, 0, 0); | |
| 834 | |
| 835 base::win::ScopedComPtr<IUriContainer> uri_container; | |
| 836 hr = uri_container.QueryFrom(moniker); | |
| 837 | |
| 838 base::win::ScopedVariant headers_var; | |
| 839 if (headers && headers[0]) | |
| 840 headers_var.Set(headers); | |
| 841 | |
| 842 if (uri_container) { | |
| 843 // IE7 and IE8. | |
| 844 const IID* interface_ids[] = { | |
| 845 &IID_IWebBrowserPriv2IE7, | |
| 846 &IID_IWebBrowserPriv2IE8, | |
| 847 &IID_IWebBrowserPriv2IE8XP, | |
| 848 &IID_IWebBrowserPriv2IE8XPBeta, | |
| 849 }; | |
| 850 | |
| 851 base::win::ScopedComPtr<IWebBrowserPriv2Common, NULL> browser_priv2; | |
| 852 for (int i = 0; i < arraysize(interface_ids) && browser_priv2 == NULL; | |
| 853 ++i) { | |
| 854 hr = web_browser2.QueryInterface(*interface_ids[i], | |
| 855 reinterpret_cast<void**>(browser_priv2.Receive())); | |
| 856 } | |
| 857 | |
| 858 DCHECK(browser_priv2); | |
| 859 | |
| 860 if (browser_priv2) { | |
| 861 base::win::ScopedComPtr<IUri> uri_obj; | |
| 862 uri_container->GetIUri(uri_obj.Receive()); | |
| 863 DCHECK(uri_obj); | |
| 864 | |
| 865 if (GetIEVersion() < IE_9) { | |
| 866 hr = browser_priv2->NavigateWithBindCtx2( | |
| 867 uri_obj, flags, NULL, post_data_variant.AsInput(), | |
| 868 headers_var.AsInput(), bind_ctx, | |
| 869 const_cast<wchar_t*>(fragment)); | |
| 870 } else { | |
| 871 IWebBrowserPriv2CommonIE9* browser_priv2_ie9 = | |
| 872 reinterpret_cast<IWebBrowserPriv2CommonIE9*>(browser_priv2.get()); | |
| 873 hr = browser_priv2_ie9->NavigateWithBindCtx2( | |
| 874 uri_obj, flags, NULL, post_data_variant.AsInput(), | |
| 875 headers_var.AsInput(), bind_ctx, | |
| 876 const_cast<wchar_t*>(fragment), 0); | |
| 877 } | |
| 878 DLOG_IF(WARNING, FAILED(hr)) | |
| 879 << base::StringPrintf(L"NavigateWithBindCtx2 0x%08X", hr); | |
| 880 } | |
| 881 } else { | |
| 882 // IE6 | |
| 883 LPOLESTR url = NULL; | |
| 884 if (SUCCEEDED(hr = moniker->GetDisplayName(bind_ctx, NULL, &url))) { | |
| 885 DVLOG(1) << __FUNCTION__ << " " << url; | |
| 886 base::win::ScopedComPtr<IWebBrowserPriv> browser_priv; | |
| 887 if (SUCCEEDED(hr = browser_priv.QueryFrom(web_browser2))) { | |
| 888 GURL target_url(url); | |
| 889 // On IE6 if the original URL has a fragment then the navigation | |
| 890 // attempt is ignored. To workaround this we strip the fragment from | |
| 891 // the url and initiate the navigation. When the active document loads | |
| 892 // we retrieve the original url with the fragment from the Navigation | |
| 893 // manager and use it. | |
| 894 if (target_url.has_ref()) { | |
| 895 url_parse::Component comp; | |
| 896 GURL::Replacements replacements; | |
| 897 replacements.SetRef("", comp); | |
| 898 | |
| 899 target_url = target_url.ReplaceComponents(replacements); | |
| 900 fragment = NULL; | |
| 901 } | |
| 902 | |
| 903 base::win::ScopedVariant var_url( | |
| 904 base::UTF8ToWide(target_url.spec()).c_str()); | |
| 905 hr = browser_priv->NavigateWithBindCtx(var_url.AsInput(), flags, NULL, | |
| 906 post_data_variant.AsInput(), | |
| 907 headers_var.AsInput(), bind_ctx, | |
| 908 const_cast<wchar_t*>(fragment)); | |
| 909 DLOG_IF(WARNING, FAILED(hr)) | |
| 910 << base::StringPrintf(L"NavigateWithBindCtx 0x%08X", hr); | |
| 911 } else { | |
| 912 NOTREACHED(); | |
| 913 } | |
| 914 ::CoTaskMemFree(url); | |
| 915 } else { | |
| 916 DLOG(ERROR) << base::StringPrintf("GetDisplayName: 0x%08X", hr); | |
| 917 } | |
| 918 } | |
| 919 | |
| 920 return hr; | |
| 921 } | |
| 922 | |
| 923 void MarkBrowserOnThreadForCFNavigation(IBrowserService* browser) { | |
| 924 DCHECK(browser != NULL); | |
| 925 DCHECK(g_tls_browser_for_cf_navigation.Pointer()->Get() == NULL || | |
| 926 g_tls_browser_for_cf_navigation.Pointer()->Get() == browser); | |
| 927 g_tls_browser_for_cf_navigation.Pointer()->Set(browser); | |
| 928 } | |
| 929 | |
| 930 bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag) { | |
| 931 DCHECK(browser); | |
| 932 bool ret = (g_tls_browser_for_cf_navigation.Pointer()->Get() == browser); | |
| 933 if (ret && clear_flag) | |
| 934 g_tls_browser_for_cf_navigation.Pointer()->Set(NULL); | |
| 935 return ret; | |
| 936 } | |
| 937 | |
| 938 bool IsValidUrlScheme(const GURL& url, bool is_privileged) { | |
| 939 if (url.is_empty()) | |
| 940 return false; | |
| 941 | |
| 942 if (url.SchemeIs(content::kHttpScheme) || | |
| 943 url.SchemeIs(content::kHttpsScheme) || | |
| 944 url.SchemeIs(chrome::kAboutScheme)) | |
| 945 return true; | |
| 946 | |
| 947 // Additional checking for view-source. Allow only http and https | |
| 948 // URLs in view source. | |
| 949 if (url.SchemeIs(content::kViewSourceScheme)) { | |
| 950 GURL sub_url(url.GetContent()); | |
| 951 if (sub_url.SchemeIs(content::kHttpScheme) || | |
| 952 sub_url.SchemeIs(content::kHttpsScheme)) | |
| 953 return true; | |
| 954 else | |
| 955 return false; | |
| 956 } | |
| 957 | |
| 958 if (is_privileged && | |
| 959 (url.SchemeIs(chrome::kDataScheme) || | |
| 960 url.SchemeIs(extensions::kExtensionScheme))) | |
| 961 return true; | |
| 962 | |
| 963 return false; | |
| 964 } | |
| 965 | |
| 966 std::string GetRawHttpHeaders(IWinInetHttpInfo* info) { | |
| 967 DCHECK(info); | |
| 968 | |
| 969 std::string buffer; | |
| 970 | |
| 971 DWORD size = 0; | |
| 972 DWORD flags = 0; | |
| 973 DWORD reserved = 0; | |
| 974 HRESULT hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &size, | |
| 975 &flags, &reserved); | |
| 976 if (!size) { | |
| 977 DLOG(WARNING) << "Failed to query HTTP headers size. Error: " << hr; | |
| 978 } else { | |
| 979 buffer.resize(size + 1); | |
| 980 hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, &buffer[0], | |
| 981 &size, &flags, &reserved); | |
| 982 if (FAILED(hr)) { | |
| 983 DLOG(WARNING) << "Failed to query HTTP headers. Error: " << hr; | |
| 984 } | |
| 985 } | |
| 986 | |
| 987 return buffer; | |
| 988 } | |
| 989 | |
| 990 bool IsSubFrameRequest(IUnknown* service_provider) { | |
| 991 DCHECK(service_provider); | |
| 992 | |
| 993 // We need to be able to get at an IWebBrowser2 if we are to decide whether | |
| 994 // this request originates from a non-top-level frame. | |
| 995 base::win::ScopedComPtr<IWebBrowser2> web_browser; | |
| 996 HRESULT hr = DoQueryService(IID_ITargetFrame2, service_provider, | |
| 997 web_browser.Receive()); | |
| 998 | |
| 999 bool is_sub_frame_request = false; | |
| 1000 if (web_browser) { | |
| 1001 // Now check to see if we are in a sub-frame. | |
| 1002 base::win::ScopedComPtr<IHTMLWindow2> current_frame, parent_frame; | |
| 1003 hr = DoQueryService(IID_IHTMLWindow2, service_provider, | |
| 1004 current_frame.Receive()); | |
| 1005 if (current_frame) { | |
| 1006 // Only the top level window will return self when get_parent is called. | |
| 1007 current_frame->get_parent(parent_frame.Receive()); | |
| 1008 if (parent_frame != current_frame) { | |
| 1009 DVLOG(1) << "Sub frame detected"; | |
| 1010 is_sub_frame_request = true; | |
| 1011 } | |
| 1012 } | |
| 1013 } else { | |
| 1014 DVLOG(1) << "IsSubFrameRequest - no IWebBrowser2"; | |
| 1015 is_sub_frame_request = true; | |
| 1016 } | |
| 1017 | |
| 1018 return is_sub_frame_request; | |
| 1019 } | |
| 1020 | |
| 1021 bool IsHeadlessMode() { | |
| 1022 bool headless = GetConfigBool(false, kChromeFrameHeadlessMode); | |
| 1023 return headless; | |
| 1024 } | |
| 1025 | |
| 1026 bool IsAccessibleMode() { | |
| 1027 bool accessible = GetConfigBool(false, kChromeFrameAccessibleMode); | |
| 1028 return accessible; | |
| 1029 } | |
| 1030 | |
| 1031 bool IsUnpinnedMode() { | |
| 1032 // We only check this value once and then cache it since changing the registry | |
| 1033 // once we've pinned the DLL won't have any effect. | |
| 1034 static bool unpinned = GetConfigBool(false, kChromeFrameUnpinnedMode); | |
| 1035 return unpinned; | |
| 1036 } | |
| 1037 | |
| 1038 std::wstring GetActualUrlFromMoniker(IMoniker* moniker, | |
| 1039 IBindCtx* bind_context, | |
| 1040 const std::wstring& bho_url) { | |
| 1041 CComHeapPtr<WCHAR> display_name; | |
| 1042 moniker->GetDisplayName(bind_context, NULL, &display_name); | |
| 1043 std::wstring moniker_url = display_name; | |
| 1044 | |
| 1045 GURL parsed_url(base::WideToUTF8(bho_url)); | |
| 1046 if (!parsed_url.has_ref()) | |
| 1047 return moniker_url; | |
| 1048 | |
| 1049 if (StartsWith(bho_url, moniker_url, false) && | |
| 1050 bho_url[moniker_url.length()] == L'#') | |
| 1051 return bho_url; | |
| 1052 | |
| 1053 return moniker_url; | |
| 1054 } | |
| 1055 | |
| 1056 bool IsTopLevelWindow(HWND window) { | |
| 1057 long style = GetWindowLong(window, GWL_STYLE); // NOLINT | |
| 1058 if (!(style & WS_CHILD)) | |
| 1059 return true; | |
| 1060 | |
| 1061 HWND parent = GetParent(window); | |
| 1062 return !parent || (parent == GetDesktopWindow()); | |
| 1063 } | |
| 1064 | |
| 1065 HRESULT RewindStream(IStream* stream) { | |
| 1066 HRESULT hr = E_POINTER; | |
| 1067 if (stream) { | |
| 1068 LARGE_INTEGER zero = {0}; | |
| 1069 ULARGE_INTEGER new_pos = {0}; | |
| 1070 hr = stream->Seek(zero, STREAM_SEEK_SET, &new_pos); | |
| 1071 } | |
| 1072 | |
| 1073 return hr; | |
| 1074 } | |
| 1075 | |
| 1076 std::wstring GuidToString(const GUID& guid) { | |
| 1077 std::wstring ret; | |
| 1078 ::StringFromGUID2(guid, WriteInto(&ret, 39), 39); | |
| 1079 return ret; | |
| 1080 } | |
| 1081 | |
| 1082 int32 MapCookieStateToCookieAction(InternetCookieState cookie_state) { | |
| 1083 int32 cookie_action = COOKIEACTION_NONE; | |
| 1084 | |
| 1085 switch (cookie_state) { | |
| 1086 case COOKIE_STATE_UNKNOWN: | |
| 1087 cookie_action = COOKIEACTION_NONE; | |
| 1088 break; | |
| 1089 case COOKIE_STATE_ACCEPT: | |
| 1090 cookie_action = COOKIEACTION_ACCEPT; | |
| 1091 break; | |
| 1092 case COOKIE_STATE_LEASH: | |
| 1093 cookie_action = COOKIEACTION_LEASH; | |
| 1094 break; | |
| 1095 case COOKIE_STATE_DOWNGRADE: | |
| 1096 cookie_action = COOKIEACTION_DOWNGRADE; | |
| 1097 break; | |
| 1098 case COOKIE_STATE_REJECT: | |
| 1099 cookie_action = COOKIEACTION_REJECT; | |
| 1100 break; | |
| 1101 default: | |
| 1102 cookie_action = COOKIEACTION_REJECT; | |
| 1103 break; | |
| 1104 } | |
| 1105 return cookie_action; | |
| 1106 } | |
| 1107 | |
| 1108 GURL GetUrlWithoutFragment(const wchar_t* url) { | |
| 1109 GURL parsed_url(url); | |
| 1110 | |
| 1111 if (parsed_url.has_ref()) { | |
| 1112 url_parse::Component comp; | |
| 1113 GURL::Replacements replacements; | |
| 1114 replacements.SetRef("", comp); | |
| 1115 | |
| 1116 parsed_url = parsed_url.ReplaceComponents(replacements); | |
| 1117 } | |
| 1118 return parsed_url; | |
| 1119 } | |
| 1120 | |
| 1121 bool CompareUrlsWithoutFragment(const wchar_t* url1, const wchar_t* url2) { | |
| 1122 GURL parsed_url1 = GetUrlWithoutFragment(url1); | |
| 1123 GURL parsed_url2 = GetUrlWithoutFragment(url2); | |
| 1124 return parsed_url1 == parsed_url2; | |
| 1125 } | |
| 1126 | |
| 1127 std::string FindReferrerFromHeaders(const wchar_t* headers, | |
| 1128 const wchar_t* additional_headers) { | |
| 1129 std::string referrer; | |
| 1130 | |
| 1131 const wchar_t* both_headers[] = { headers, additional_headers }; | |
| 1132 for (int i = 0; referrer.empty() && i < arraysize(both_headers); ++i) { | |
| 1133 if (!both_headers[i]) | |
| 1134 continue; | |
| 1135 std::string raw_headers_utf8 = base::WideToUTF8(both_headers[i]); | |
| 1136 net::HttpUtil::HeadersIterator it(raw_headers_utf8.begin(), | |
| 1137 raw_headers_utf8.end(), "\r\n"); | |
| 1138 while (it.GetNext()) { | |
| 1139 if (LowerCaseEqualsASCII(it.name(), "referer")) { | |
| 1140 referrer = it.values(); | |
| 1141 break; | |
| 1142 } | |
| 1143 } | |
| 1144 } | |
| 1145 | |
| 1146 return referrer; | |
| 1147 } | |
| 1148 | |
| 1149 std::string GetHttpHeadersFromBinding(IBinding* binding) { | |
| 1150 if (binding == NULL) { | |
| 1151 DLOG(WARNING) << "GetHttpResponseStatus - no binding_"; | |
| 1152 return std::string(); | |
| 1153 } | |
| 1154 | |
| 1155 base::win::ScopedComPtr<IWinInetHttpInfo> info; | |
| 1156 if (FAILED(info.QueryFrom(binding))) { | |
| 1157 DLOG(WARNING) << "Failed to QI for IWinInetHttpInfo"; | |
| 1158 return std::string(); | |
| 1159 } | |
| 1160 | |
| 1161 return GetRawHttpHeaders(info); | |
| 1162 } | |
| 1163 | |
| 1164 int GetHttpResponseStatusFromBinding(IBinding* binding) { | |
| 1165 DVLOG(1) << __FUNCTION__; | |
| 1166 if (binding == NULL) { | |
| 1167 DLOG(WARNING) << "GetHttpResponseStatus - no binding_"; | |
| 1168 return 0; | |
| 1169 } | |
| 1170 | |
| 1171 int http_status = 0; | |
| 1172 | |
| 1173 base::win::ScopedComPtr<IWinInetHttpInfo> info; | |
| 1174 if (SUCCEEDED(info.QueryFrom(binding))) { | |
| 1175 char status[10] = {0}; | |
| 1176 DWORD buf_size = sizeof(status); | |
| 1177 DWORD flags = 0; | |
| 1178 DWORD reserved = 0; | |
| 1179 if (SUCCEEDED(info->QueryInfo(HTTP_QUERY_STATUS_CODE, status, &buf_size, | |
| 1180 &flags, &reserved))) { | |
| 1181 base::StringToInt(status, &http_status); | |
| 1182 } else { | |
| 1183 NOTREACHED() << "Failed to get HTTP status"; | |
| 1184 } | |
| 1185 } else { | |
| 1186 NOTREACHED() << "failed to get IWinInetHttpInfo from binding_"; | |
| 1187 } | |
| 1188 | |
| 1189 return http_status; | |
| 1190 } | |
| 1191 | |
| 1192 CLIPFORMAT GetTextHtmlClipboardFormat() { | |
| 1193 static const CLIPFORMAT text_html = RegisterClipboardFormat(CFSTR_MIME_HTML); | |
| 1194 return text_html; | |
| 1195 } | |
| 1196 | |
| 1197 bool IsTextHtmlMimeType(const wchar_t* mime_type) { | |
| 1198 return IsTextHtmlClipFormat(RegisterClipboardFormatW(mime_type)); | |
| 1199 } | |
| 1200 | |
| 1201 bool IsTextHtmlClipFormat(CLIPFORMAT cf) { | |
| 1202 return cf == GetTextHtmlClipboardFormat(); | |
| 1203 } | |
| 1204 | |
| 1205 bool IsSystemProcess() { | |
| 1206 bool is_system = false; | |
| 1207 CAccessToken process_token; | |
| 1208 if (process_token.GetProcessToken(TOKEN_QUERY, GetCurrentProcess())) { | |
| 1209 CSid logon_sid; | |
| 1210 if (process_token.GetUser(&logon_sid)) { | |
| 1211 is_system = logon_sid == Sids::System(); | |
| 1212 } | |
| 1213 } | |
| 1214 return is_system; | |
| 1215 } | |
| 1216 | |
| 1217 | |
| 1218 std::string BindStatus2Str(ULONG bind_status) { | |
| 1219 std::string s; | |
| 1220 static const char* const bindstatus_txt[] = { | |
| 1221 "BINDSTATUS_FINDINGRESOURCE", | |
| 1222 "BINDSTATUS_CONNECTING", | |
| 1223 "BINDSTATUS_REDIRECTING", | |
| 1224 "BINDSTATUS_BEGINDOWNLOADDATA", | |
| 1225 "BINDSTATUS_DOWNLOADINGDATA", | |
| 1226 "BINDSTATUS_ENDDOWNLOADDATA", | |
| 1227 "BINDSTATUS_BEGINDOWNLOADCOMPONENTS", | |
| 1228 "BINDSTATUS_INSTALLINGCOMPONENTS", | |
| 1229 "BINDSTATUS_ENDDOWNLOADCOMPONENTS", | |
| 1230 "BINDSTATUS_USINGCACHEDCOPY", | |
| 1231 "BINDSTATUS_SENDINGREQUEST", | |
| 1232 "BINDSTATUS_CLASSIDAVAILABLE", | |
| 1233 "BINDSTATUS_MIMETYPEAVAILABLE", | |
| 1234 "BINDSTATUS_CACHEFILENAMEAVAILABLE", | |
| 1235 "BINDSTATUS_BEGINSYNCOPERATION", | |
| 1236 "BINDSTATUS_ENDSYNCOPERATION", | |
| 1237 "BINDSTATUS_BEGINUPLOADDATA", | |
| 1238 "BINDSTATUS_UPLOADINGDATA", | |
| 1239 "BINDSTATUS_ENDUPLOADINGDATA", | |
| 1240 "BINDSTATUS_PROTOCOLCLASSID", | |
| 1241 "BINDSTATUS_ENCODING", | |
| 1242 "BINDSTATUS_VERFIEDMIMETYPEAVAILABLE", | |
| 1243 "BINDSTATUS_CLASSINSTALLLOCATION", | |
| 1244 "BINDSTATUS_DECODING", | |
| 1245 "BINDSTATUS_LOADINGMIMEHANDLER", | |
| 1246 "BINDSTATUS_CONTENTDISPOSITIONATTACH", | |
| 1247 "BINDSTATUS_FILTERREPORTMIMETYPE", | |
| 1248 "BINDSTATUS_CLSIDCANINSTANTIATE", | |
| 1249 "BINDSTATUS_IUNKNOWNAVAILABLE", | |
| 1250 "BINDSTATUS_DIRECTBIND", | |
| 1251 "BINDSTATUS_RAWMIMETYPE", | |
| 1252 "BINDSTATUS_PROXYDETECTING", | |
| 1253 "BINDSTATUS_ACCEPTRANGES", | |
| 1254 "BINDSTATUS_COOKIE_SENT", | |
| 1255 "BINDSTATUS_COMPACT_POLICY_RECEIVED", | |
| 1256 "BINDSTATUS_COOKIE_SUPPRESSED", | |
| 1257 "BINDSTATUS_COOKIE_STATE_UNKNOWN", | |
| 1258 "BINDSTATUS_COOKIE_STATE_ACCEPT", | |
| 1259 "BINDSTATUS_COOKIE_STATE_REJECT", | |
| 1260 "BINDSTATUS_COOKIE_STATE_PROMPT", | |
| 1261 "BINDSTATUS_COOKIE_STATE_LEASH", | |
| 1262 "BINDSTATUS_COOKIE_STATE_DOWNGRADE", | |
| 1263 "BINDSTATUS_POLICY_HREF", | |
| 1264 "BINDSTATUS_P3P_HEADER", | |
| 1265 "BINDSTATUS_SESSION_COOKIE_RECEIVED", | |
| 1266 "BINDSTATUS_PERSISTENT_COOKIE_RECEIVED", | |
| 1267 "BINDSTATUS_SESSION_COOKIES_ALLOWED", | |
| 1268 "BINDSTATUS_CACHECONTROL", | |
| 1269 "BINDSTATUS_CONTENTDISPOSITIONFILENAME", | |
| 1270 "BINDSTATUS_MIMETEXTPLAINMISMATCH", | |
| 1271 "BINDSTATUS_PUBLISHERAVAILABLE", | |
| 1272 "BINDSTATUS_DISPLAYNAMEAVAILABLE", | |
| 1273 "BINDSTATUS_SSLUX_NAVBLOCKED", | |
| 1274 "BINDSTATUS_SERVER_MIMETYPEAVAILABLE", | |
| 1275 "BINDSTATUS_SNIFFED_CLASSIDAVAILABLE", | |
| 1276 "BINDSTATUS_64BIT_PROGRESS" | |
| 1277 }; | |
| 1278 if (bind_status >= 1 && bind_status <= BINDSTATUS_64BIT_PROGRESS) | |
| 1279 s = bindstatus_txt[bind_status - 1]; | |
| 1280 else | |
| 1281 s = base::StringPrintf("UnDoc[%#x]", bind_status); | |
| 1282 return s; | |
| 1283 } | |
| 1284 | |
| 1285 std::string PiFlags2Str(DWORD flags) { | |
| 1286 #define ADD_PI_FLAG(x) \ | |
| 1287 if (flags & x) { \ | |
| 1288 s.append(#x ## " "); \ | |
| 1289 flags &= ~x; \ | |
| 1290 } | |
| 1291 | |
| 1292 std::string s = " flags "; | |
| 1293 ADD_PI_FLAG(PI_PARSE_URL); | |
| 1294 ADD_PI_FLAG(PI_FILTER_MODE); | |
| 1295 ADD_PI_FLAG(PI_FORCE_ASYNC); | |
| 1296 ADD_PI_FLAG(PI_USE_WORKERTHREAD); | |
| 1297 ADD_PI_FLAG(PI_MIMEVERIFICATION); | |
| 1298 ADD_PI_FLAG(PI_CLSIDLOOKUP); | |
| 1299 ADD_PI_FLAG(PI_DATAPROGRESS); | |
| 1300 ADD_PI_FLAG(PI_SYNCHRONOUS); | |
| 1301 ADD_PI_FLAG(PI_APARTMENTTHREADED); | |
| 1302 ADD_PI_FLAG(PI_CLASSINSTALL); | |
| 1303 ADD_PI_FLAG(PI_PASSONBINDCTX); | |
| 1304 ADD_PI_FLAG(PI_NOMIMEHANDLER); | |
| 1305 ADD_PI_FLAG(PI_LOADAPPDIRECT); | |
| 1306 ADD_PI_FLAG(PD_FORCE_SWITCH); | |
| 1307 ADD_PI_FLAG(PI_PREFERDEFAULTHANDLER); | |
| 1308 | |
| 1309 if (flags) | |
| 1310 s += base::StringPrintf("+UnDoc[%#x]", flags); | |
| 1311 return s; | |
| 1312 #undef ADD_PI_FLAG | |
| 1313 } | |
| 1314 | |
| 1315 std::string Bscf2Str(DWORD flags) { | |
| 1316 #define ADD_BSCF_FLAG(x) \ | |
| 1317 if (flags & x) {\ | |
| 1318 s.append(#x ## " "); \ | |
| 1319 flags &= ~x; \ | |
| 1320 } | |
| 1321 | |
| 1322 std::string s = " flags "; | |
| 1323 ADD_BSCF_FLAG(BSCF_FIRSTDATANOTIFICATION) | |
| 1324 ADD_BSCF_FLAG(BSCF_INTERMEDIATEDATANOTIFICATION) | |
| 1325 ADD_BSCF_FLAG(BSCF_LASTDATANOTIFICATION) | |
| 1326 ADD_BSCF_FLAG(BSCF_DATAFULLYAVAILABLE) | |
| 1327 ADD_BSCF_FLAG(BSCF_AVAILABLEDATASIZEUNKNOWN) | |
| 1328 ADD_BSCF_FLAG(BSCF_SKIPDRAINDATAFORFILEURLS) | |
| 1329 ADD_BSCF_FLAG(BSCF_64BITLENGTHDOWNLOAD) | |
| 1330 | |
| 1331 if (flags) | |
| 1332 s += base::StringPrintf("+UnDoc[%#x]", flags); | |
| 1333 return s; | |
| 1334 #undef ADD_BSCF_FLAG | |
| 1335 } | |
| 1336 | |
| 1337 // Reads data from a stream into a string. | |
| 1338 HRESULT ReadStream(IStream* stream, size_t size, std::string* data) { | |
| 1339 DCHECK(stream); | |
| 1340 DCHECK_GT(size, 0u); | |
| 1341 DCHECK(data); | |
| 1342 | |
| 1343 DWORD read = 0; | |
| 1344 HRESULT hr = stream->Read(WriteInto(data, size + 1), size, &read); | |
| 1345 DCHECK(hr == S_OK || hr == S_FALSE || hr == E_PENDING); | |
| 1346 if (read) { | |
| 1347 data->erase(read); | |
| 1348 DCHECK_EQ(read, data->length()); | |
| 1349 } else { | |
| 1350 data->clear(); | |
| 1351 // Return S_FALSE if the underlying stream returned S_OK and zero bytes. | |
| 1352 if (hr == S_OK) | |
| 1353 hr = S_FALSE; | |
| 1354 } | |
| 1355 | |
| 1356 return hr; | |
| 1357 } | |
| 1358 | |
| 1359 ChromeFrameUrl::ChromeFrameUrl() { | |
| 1360 Reset(); | |
| 1361 } | |
| 1362 | |
| 1363 bool ChromeFrameUrl::Parse(const std::wstring& url) { | |
| 1364 Reset(); | |
| 1365 parsed_url_ = GURL(url); | |
| 1366 | |
| 1367 if (parsed_url_.is_empty()) | |
| 1368 return false; | |
| 1369 | |
| 1370 is_chrome_protocol_ = parsed_url_.SchemeIs(kGCFProtocol); | |
| 1371 if (is_chrome_protocol_) { | |
| 1372 parsed_url_ = GURL(url.c_str() + lstrlen(kChromeProtocolPrefix)); | |
| 1373 return true; | |
| 1374 } | |
| 1375 | |
| 1376 return ParseAttachExternalTabUrl(); | |
| 1377 } | |
| 1378 | |
| 1379 bool ChromeFrameUrl::ParseAttachExternalTabUrl() { | |
| 1380 std::string query = parsed_url_.query(); | |
| 1381 if (!StartsWithASCII(query, kAttachExternalTabPrefix, false)) { | |
| 1382 return parsed_url_.is_valid(); | |
| 1383 } | |
| 1384 | |
| 1385 attach_to_external_tab_ = true; | |
| 1386 base::StringTokenizer tokenizer(query, "&"); | |
| 1387 // Skip over kChromeAttachExternalTabPrefix | |
| 1388 tokenizer.GetNext(); | |
| 1389 // Read the following items in order. | |
| 1390 // 1. cookie | |
| 1391 // 2. disposition | |
| 1392 // 3. dimension.x | |
| 1393 // 4. dimension.y | |
| 1394 // 5. dimension.width | |
| 1395 // 6. dimension.height. | |
| 1396 if (tokenizer.GetNext()) { | |
| 1397 char* end_ptr = 0; | |
| 1398 cookie_ = _strtoui64(tokenizer.token().c_str(), &end_ptr, 10); | |
| 1399 } else { | |
| 1400 return false; | |
| 1401 } | |
| 1402 | |
| 1403 if (tokenizer.GetNext()) { | |
| 1404 disposition_ = atoi(tokenizer.token().c_str()); | |
| 1405 } else { | |
| 1406 return false; | |
| 1407 } | |
| 1408 | |
| 1409 if (tokenizer.GetNext()) { | |
| 1410 dimensions_.set_x(atoi(tokenizer.token().c_str())); | |
| 1411 } else { | |
| 1412 return false; | |
| 1413 } | |
| 1414 | |
| 1415 if (tokenizer.GetNext()) { | |
| 1416 dimensions_.set_y(atoi(tokenizer.token().c_str())); | |
| 1417 } else { | |
| 1418 return false; | |
| 1419 } | |
| 1420 | |
| 1421 if (tokenizer.GetNext()) { | |
| 1422 dimensions_.set_width(atoi(tokenizer.token().c_str())); | |
| 1423 } else { | |
| 1424 return false; | |
| 1425 } | |
| 1426 | |
| 1427 if (tokenizer.GetNext()) { | |
| 1428 dimensions_.set_height(atoi(tokenizer.token().c_str())); | |
| 1429 } else { | |
| 1430 return false; | |
| 1431 } | |
| 1432 | |
| 1433 if (tokenizer.GetNext()) { | |
| 1434 profile_name_ = tokenizer.token(); | |
| 1435 // Escape out special characters like %20, etc. | |
| 1436 profile_name_ = net::UnescapeURLComponent(profile_name_, | |
| 1437 net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 1438 } else { | |
| 1439 return false; | |
| 1440 } | |
| 1441 | |
| 1442 return true; | |
| 1443 } | |
| 1444 | |
| 1445 void ChromeFrameUrl::Reset() { | |
| 1446 attach_to_external_tab_ = false; | |
| 1447 is_chrome_protocol_ = false; | |
| 1448 cookie_ = 0; | |
| 1449 dimensions_.SetRect(0, 0, 0, 0); | |
| 1450 disposition_ = 0; | |
| 1451 profile_name_.clear(); | |
| 1452 } | |
| 1453 | |
| 1454 bool CanNavigate(const GURL& url, | |
| 1455 NavigationConstraints* navigation_constraints) { | |
| 1456 if (!url.is_valid()) { | |
| 1457 DLOG(ERROR) << "Invalid URL passed to InitiateNavigation: " << url; | |
| 1458 return false; | |
| 1459 } | |
| 1460 | |
| 1461 if (!navigation_constraints) { | |
| 1462 NOTREACHED() << "Invalid NavigationConstraints passed in"; | |
| 1463 return false; | |
| 1464 } | |
| 1465 | |
| 1466 // No sanity checks if unsafe URLs are allowed | |
| 1467 if (navigation_constraints->AllowUnsafeUrls()) | |
| 1468 return true; | |
| 1469 | |
| 1470 if (!navigation_constraints->IsSchemeAllowed(url)) { | |
| 1471 DLOG(WARNING) << __FUNCTION__ << " Disallowing navigation to url: " << url; | |
| 1472 return false; | |
| 1473 } | |
| 1474 | |
| 1475 if (!navigation_constraints->IsZoneAllowed(url)) { | |
| 1476 DLOG(WARNING) << __FUNCTION__ | |
| 1477 << " Disallowing navigation to restricted url: " << url; | |
| 1478 return false; | |
| 1479 } | |
| 1480 return true; | |
| 1481 } | |
| 1482 | |
| 1483 void WaitWithMessageLoop(HANDLE* handles, int count, DWORD timeout) { | |
| 1484 base::Time now = base::Time::Now(); | |
| 1485 base::Time wait_until = now + base::TimeDelta::FromMilliseconds(timeout); | |
| 1486 | |
| 1487 while (wait_until >= now) { | |
| 1488 base::TimeDelta wait_time = wait_until - now; | |
| 1489 DWORD wait = MsgWaitForMultipleObjects( | |
| 1490 count, handles, FALSE, static_cast<DWORD>(wait_time.InMilliseconds()), | |
| 1491 QS_ALLINPUT); | |
| 1492 switch (wait) { | |
| 1493 case WAIT_OBJECT_0: | |
| 1494 case WAIT_TIMEOUT: | |
| 1495 return; | |
| 1496 | |
| 1497 case WAIT_OBJECT_0 + 1: { | |
| 1498 MSG msg = {0}; | |
| 1499 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | |
| 1500 TranslateMessage(&msg); | |
| 1501 DispatchMessage(&msg); | |
| 1502 } | |
| 1503 break; | |
| 1504 } | |
| 1505 | |
| 1506 default: { | |
| 1507 NOTREACHED() << "Unexpected return from MsgWaitForMultipleObjects :" | |
| 1508 << wait; | |
| 1509 return; | |
| 1510 } | |
| 1511 } | |
| 1512 now = base::Time::Now(); | |
| 1513 } | |
| 1514 } | |
| 1515 | |
| 1516 // Returns -1 if no directive is found, std::numeric_limits<int>::max() if the | |
| 1517 // directive matches all IE versions ('Chrome=1') or the maximum IE version | |
| 1518 // matched ('Chrome=IE7' => 7) | |
| 1519 int GetXUaCompatibleDirective(const std::string& directive, char delimiter) { | |
| 1520 net::HttpUtil::NameValuePairsIterator name_value_pairs(directive.begin(), | |
| 1521 directive.end(), | |
| 1522 delimiter); | |
| 1523 | |
| 1524 // Loop through the values until a valid 'Chrome=<FILTER>' entry is found | |
| 1525 while (name_value_pairs.GetNext()) { | |
| 1526 if (!LowerCaseEqualsASCII(name_value_pairs.name_begin(), | |
| 1527 name_value_pairs.name_end(), | |
| 1528 "chrome")) { | |
| 1529 continue; | |
| 1530 } | |
| 1531 std::string::const_iterator filter_begin = name_value_pairs.value_begin(); | |
| 1532 std::string::const_iterator filter_end = name_value_pairs.value_end(); | |
| 1533 | |
| 1534 size_t filter_length = filter_end - filter_begin; | |
| 1535 | |
| 1536 if (filter_length == 1 && *filter_begin == '1') { | |
| 1537 return std::numeric_limits<int>::max(); | |
| 1538 } | |
| 1539 | |
| 1540 if (filter_length < 3 || | |
| 1541 !LowerCaseEqualsASCII(filter_begin, filter_begin + 2, "ie") || | |
| 1542 !isdigit(*(filter_begin + 2))) { // ensure no leading +/- | |
| 1543 continue; | |
| 1544 } | |
| 1545 | |
| 1546 int header_ie_version = 0; | |
| 1547 if (!base::StringToInt(base::StringPiece(filter_begin + 2, | |
| 1548 filter_end), | |
| 1549 &header_ie_version) || | |
| 1550 header_ie_version == 0) { // ensure it's not a sequence of 0's | |
| 1551 continue; | |
| 1552 } | |
| 1553 | |
| 1554 // The first valid directive we find wins, whether it matches or not | |
| 1555 return header_ie_version; | |
| 1556 } | |
| 1557 return -1; | |
| 1558 } | |
| 1559 | |
| 1560 bool CheckXUaCompatibleDirective(const std::string& directive, | |
| 1561 int ie_major_version) { | |
| 1562 int header_ie_version = GetXUaCompatibleDirective(directive, ';'); | |
| 1563 if (header_ie_version == -1) { | |
| 1564 header_ie_version = GetXUaCompatibleDirective(directive, ','); | |
| 1565 } | |
| 1566 return header_ie_version >= ie_major_version; | |
| 1567 } | |
| 1568 | |
| 1569 void EnumerateKeyValues(HKEY parent_key, const wchar_t* sub_key_name, | |
| 1570 std::vector<std::wstring>* values) { | |
| 1571 DCHECK(values); | |
| 1572 base::win::RegistryValueIterator url_list(parent_key, sub_key_name); | |
| 1573 while (url_list.Valid()) { | |
| 1574 values->push_back(url_list.Value()); | |
| 1575 ++url_list; | |
| 1576 } | |
| 1577 } | |
| 1578 | |
| 1579 std::wstring GetCurrentModuleVersion() { | |
| 1580 scoped_ptr<FileVersionInfo> module_version_info( | |
| 1581 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | |
| 1582 DCHECK(module_version_info.get() != NULL); | |
| 1583 return module_version_info->file_version(); | |
| 1584 } | |
| 1585 | |
| 1586 bool IsChromeFrameDocument(IWebBrowser2* web_browser) { | |
| 1587 if (!web_browser) | |
| 1588 return false; | |
| 1589 | |
| 1590 base::win::ScopedComPtr<IDispatch> doc; | |
| 1591 web_browser->get_Document(doc.Receive()); | |
| 1592 if (doc) { | |
| 1593 // Detect if CF is rendering based on whether the document is a | |
| 1594 // ChromeActiveDocument. Detecting based on hwnd is problematic as | |
| 1595 // the CF Active Document window may not have been created yet. | |
| 1596 base::win::ScopedComPtr<IChromeFrame> chrome_frame; | |
| 1597 chrome_frame.QueryFrom(doc); | |
| 1598 return chrome_frame.get() != NULL; | |
| 1599 } | |
| 1600 return false; | |
| 1601 } | |
| 1602 | |
| 1603 bool IncreaseWinInetConnections(DWORD connections) { | |
| 1604 static bool wininet_connection_count_updated = false; | |
| 1605 if (wininet_connection_count_updated) { | |
| 1606 return true; | |
| 1607 } | |
| 1608 | |
| 1609 static int connection_options[] = { | |
| 1610 INTERNET_OPTION_MAX_CONNS_PER_SERVER, | |
| 1611 INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER, | |
| 1612 }; | |
| 1613 | |
| 1614 BOOL ret = FALSE; | |
| 1615 | |
| 1616 for (int option_index = 0; option_index < arraysize(connection_options); | |
| 1617 ++option_index) { | |
| 1618 DWORD connection_value_size = sizeof(DWORD); | |
| 1619 DWORD current_connection_limit = 0; | |
| 1620 InternetQueryOption(NULL, connection_options[option_index], | |
| 1621 ¤t_connection_limit, &connection_value_size); | |
| 1622 if (current_connection_limit > connections) { | |
| 1623 continue; | |
| 1624 } | |
| 1625 | |
| 1626 ret = InternetSetOption(NULL, connection_options[option_index], | |
| 1627 &connections, connection_value_size); | |
| 1628 if (!ret) { | |
| 1629 return false; | |
| 1630 } | |
| 1631 } | |
| 1632 wininet_connection_count_updated = true; | |
| 1633 return true; | |
| 1634 } | |
| 1635 | |
| 1636 void GetChromeFrameProfilePath(const base::string16& profile_name, | |
| 1637 base::FilePath* profile_path) { | |
| 1638 chrome::GetChromeFrameUserDataDirectory(profile_path); | |
| 1639 *profile_path = profile_path->Append(profile_name); | |
| 1640 DVLOG(1) << __FUNCTION__ << ": " << profile_path->value(); | |
| 1641 } | |
| OLD | NEW |