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