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