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