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"
8 #include <atlsecurity.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/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/string_tokenizer.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/threading/thread_local.h"
25 #include "base/win/registry.h"
26 #include "base/win/scoped_bstr.h"
27 #include "base/win/scoped_comptr.h"
28 #include "base/win/scoped_variant.h"
29 #include "chrome/common/automation_messages.h"
30 #include "chrome/common/chrome_paths_internal.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/installer/util/chrome_frame_distribution.h"
33 #include "chrome_frame/chrome_tab.h"
34 #include "chrome_frame/extra_system_apis.h"
35 #include "chrome_frame/html_utils.h"
36 #include "chrome_frame/navigation_constraints.h"
37 #include "chrome_frame/policy_settings.h"
38 #include "chrome_frame/registry_list_preferences_holder.h"
39 #include "chrome_frame/simple_resource_loader.h"
40 #include "extensions/common/constants.h"
41 #include "grit/chromium_strings.h"
42 #include "net/base/escape.h"
43 #include "net/http/http_util.h"
44 #include "ui/base/models/menu_model.h"
46 #include "url/url_canon.h"
48 using base::win::RegKey
;
50 // Note that these values are all lower case and are compared to
51 // lower-case-transformed values.
52 const char kGCFProtocol
[] = "gcf";
53 const wchar_t kBodyTag
[] = L
"body";
54 const wchar_t kContentAttribName
[] = L
"content";
55 const wchar_t kChromeContentPrefix
[] = L
"chrome=";
56 const wchar_t kChromeMimeType
[] = L
"application/chromepage";
57 const wchar_t kChromeProtocolPrefix
[] = L
"gcf:";
58 const wchar_t kHttpEquivAttribName
[] = L
"http-equiv";
59 const wchar_t kIexploreProfileName
[] = L
"iexplore";
60 const wchar_t kMetaTag
[] = L
"meta";
61 const wchar_t kRundllProfileName
[] = L
"rundll32";
62 const wchar_t kXUACompatValue
[] = L
"x-ua-compatible";
64 // Registry key and value names related to Chrome Frame configuration options.
65 const wchar_t kAllowUnsafeURLs
[] = L
"AllowUnsafeURLs";
66 const wchar_t kChromeFrameConfigKey
[] = L
"Software\\Google\\ChromeFrame";
67 const wchar_t kEnableBuggyBhoIntercept
[] = L
"EnableBuggyBhoIntercept";
68 const wchar_t kEnableGCFRendererByDefault
[] = L
"IsDefaultRenderer";
69 const wchar_t kSkipGCFMetadataCheck
[] = L
"SkipGCFMetadataCheck";
70 const wchar_t kExcludeUAFromDomainList
[] = L
"ExcludeUAFromDomain";
71 const wchar_t kPatchProtocols
[] = L
"PatchProtocols";
72 const wchar_t kRenderInGCFUrlList
[] = L
"RenderInGcfUrls";
73 const wchar_t kRenderInHostUrlList
[] = L
"RenderInHostUrls";
75 static const wchar_t kChromeFramePersistNPAPIReg
[] = L
"PersistNPAPIReg";
77 const char kAttachExternalTabPrefix
[] = "attach_external_tab";
79 // Indicates that we are running in a test environment, where execptions, etc
80 // are handled by the chrome test crash server.
81 const wchar_t kChromeFrameHeadlessMode
[] = L
"ChromeFrameHeadlessMode";
83 // Indicates that we are running in an environment that expects chrome renderer
84 // accessibility to be enabled for use in automation tests.
85 const wchar_t kChromeFrameAccessibleMode
[] = L
"ChromeFrameAccessibleMode";
87 // Indicates that we are running in an environment that wishes to avoid
88 // DLL pinning, such as the perf tests.
89 const wchar_t kChromeFrameUnpinnedMode
[] = L
"kChromeFrameUnpinnedMode";
91 // Controls whether we download subresources, etc on the chrome frame page in
92 // the background worker thread. Defaults to true.
93 const wchar_t kUseBackgroundThreadForSubResources
[]
94 = L
"BackgroundHTTPWorkerThread";
96 // {1AF32B6C-A3BA-48B9-B24E-8AA9C41F6ECD}
97 static const IID IID_IWebBrowserPriv2IE7
= { 0x1AF32B6C, 0xA3BA, 0x48B9,
98 { 0xB2, 0x4E, 0x8A, 0xA9, 0xC4, 0x1F, 0x6E, 0xCD } };
100 // {3ED72303-6FFC-4214-BA90-FAF1862DEC8A}
101 static const IID IID_IWebBrowserPriv2IE8
= { 0x3ED72303, 0x6FFC, 0x4214,
102 { 0xBA, 0x90, 0xFA, 0xF1, 0x86, 0x2D, 0xEC, 0x8A } };
104 // {486F6159-9F3F-4827-82D4-283CEF397733}
105 static const IID IID_IWebBrowserPriv2IE8XP
= { 0x486F6159, 0x9F3F, 0x4827,
106 { 0x82, 0xD4, 0x28, 0x3C, 0xEF, 0x39, 0x77, 0x33 } };
108 // {38339692-0BC9-46CB-8E5C-4677A5C83DD5}
109 static const IID IID_IWebBrowserPriv2IE8XPBeta
= { 0x38339692, 0x0BC9, 0x46CB,
110 { 0x8E, 0x5C, 0x46, 0x77, 0xA5, 0xC8, 0x3D, 0xD5 } };
114 // A flag used to signal when an active browser instance on the current thread
115 // is loading a Chrome Frame document. There's no reference stored with the
116 // pointer so it should not be dereferenced and used for comparison against a
117 // living instance only.
118 base::LazyInstance
<base::ThreadLocalPointer
<IBrowserService
> >
119 g_tls_browser_for_cf_navigation
= LAZY_INSTANCE_INITIALIZER
;
121 // Holds the cached preferences for the per-url render type settings.
122 base::LazyInstance
<RegistryListPreferencesHolder
>::Leaky
123 g_render_type_for_url_holder
;
125 // Holds the cached preferences for the per-url user agent filter.
126 base::LazyInstance
<RegistryListPreferencesHolder
>::Leaky
127 g_user_agent_filter_holder
;
129 } // end anonymous namespace
131 HRESULT
UtilRegisterTypeLib(HINSTANCE tlb_instance
,
133 bool for_current_user_only
) {
135 CComPtr
<ITypeLib
> type_lib
;
136 HRESULT hr
= AtlLoadTypeLib(tlb_instance
, index
, &path
, &type_lib
);
138 hr
= UtilRegisterTypeLib(type_lib
, path
, NULL
, for_current_user_only
);
143 HRESULT
UtilUnRegisterTypeLib(HINSTANCE tlb_instance
,
145 bool for_current_user_only
) {
147 CComPtr
<ITypeLib
> type_lib
;
148 HRESULT hr
= AtlLoadTypeLib(tlb_instance
, index
, &path
, &type_lib
);
150 hr
= UtilUnRegisterTypeLib(type_lib
, for_current_user_only
);
155 HRESULT
UtilRegisterTypeLib(LPCWSTR typelib_path
,
156 bool for_current_user_only
) {
157 if (NULL
== typelib_path
) {
161 CComPtr
<ITypeLib
> type_lib
;
162 HRESULT hr
= ::LoadTypeLib(typelib_path
, &type_lib
);
164 hr
= UtilRegisterTypeLib(type_lib
,
167 for_current_user_only
);
172 HRESULT
UtilUnRegisterTypeLib(LPCWSTR typelib_path
,
173 bool for_current_user_only
) {
174 CComPtr
<ITypeLib
> type_lib
;
175 HRESULT hr
= ::LoadTypeLib(typelib_path
, &type_lib
);
177 hr
= UtilUnRegisterTypeLib(type_lib
, for_current_user_only
);
182 HRESULT
UtilRegisterTypeLib(ITypeLib
* typelib
,
183 LPCWSTR typelib_path
,
185 bool for_current_user_only
) {
186 typedef HRESULT(WINAPI
*RegisterTypeLibPrototype
)(ITypeLib FAR
* type_lib
,
187 OLECHAR FAR
* full_path
,
188 OLECHAR FAR
* help_dir
);
189 LPCSTR function_name
=
190 for_current_user_only
? "RegisterTypeLibForUser" : "RegisterTypeLib";
191 RegisterTypeLibPrototype reg_tlb
=
192 reinterpret_cast<RegisterTypeLibPrototype
>(
193 GetProcAddress(GetModuleHandle(_T("oleaut32.dll")),
195 if (NULL
== reg_tlb
) {
198 return reg_tlb(typelib
,
199 const_cast<OLECHAR
*>(typelib_path
),
200 const_cast<OLECHAR
*>(help_dir
));
203 HRESULT
UtilUnRegisterTypeLib(ITypeLib
* typelib
,
204 bool for_current_user_only
) {
205 if (NULL
== typelib
) {
208 typedef HRESULT(WINAPI
*UnRegisterTypeLibPrototype
)(
210 unsigned short wVerMajor
, // NOLINT
211 unsigned short wVerMinor
, // NOLINT
214 LPCSTR function_name
=
215 for_current_user_only
? "UnRegisterTypeLibForUser" : "UnRegisterTypeLib";
217 UnRegisterTypeLibPrototype unreg_tlb
=
218 reinterpret_cast<UnRegisterTypeLibPrototype
>(
219 GetProcAddress(GetModuleHandle(_T("oleaut32.dll")),
221 if (NULL
== unreg_tlb
) {
224 TLIBATTR
* tla
= NULL
;
225 HRESULT hr
= typelib
->GetLibAttr(&tla
);
227 hr
= unreg_tlb(tla
->guid
,
232 typelib
->ReleaseTLibAttr(tla
);
237 bool UtilRemovePersistentNPAPIMarker() {
238 BrowserDistribution
* cf_dist
= BrowserDistribution::GetDistribution();
239 std::wstring
cf_state_key_path(cf_dist
->GetStateKey());
242 LONG result
= cf_state_key
.Open(HKEY_LOCAL_MACHINE
, cf_state_key_path
.c_str(),
244 if (result
== ERROR_SUCCESS
)
245 result
= cf_state_key
.DeleteValue(kChromeFramePersistNPAPIReg
);
246 return (result
== ERROR_SUCCESS
|| result
== ERROR_FILE_NOT_FOUND
);
249 HRESULT
UtilGetXUACompatContentValue(const std::wstring
& html_string
,
250 std::wstring
* content_value
) {
251 if (!content_value
) {
255 // Fail fast if the string X-UA-Compatible isn't in html_string
256 if (StringToLowerASCII(html_string
).find(kXUACompatValue
) ==
257 std::wstring::npos
) {
261 HTMLScanner
scanner(html_string
.c_str());
263 // Build the list of meta tags that occur before the body tag is hit.
264 HTMLScanner::StringRangeList tag_list
;
265 scanner
.GetTagsByName(kMetaTag
, &tag_list
, kBodyTag
);
267 // Search the list of meta tags for one with an http-equiv="X-UA-Compatible"
269 HTMLScanner::StringRange attribute
;
270 std::string
search_attribute_ascii(WideToASCII(kXUACompatValue
));
271 HTMLScanner::StringRangeList::const_iterator
tag_list_iter(tag_list
.begin());
272 for (; tag_list_iter
!= tag_list
.end(); tag_list_iter
++) {
273 if (!tag_list_iter
->GetTagAttribute(kHttpEquivAttribName
, &attribute
)) {
277 // We found an http-equiv meta tag, check its value using the ascii
278 // case-insensitive comparison method.
279 if (!attribute
.LowerCaseEqualsASCII(search_attribute_ascii
.c_str())) {
283 // We found our X-UA-Compatible meta tag so look for and extract
284 // the value of the content attribute.
285 if (!tag_list_iter
->GetTagAttribute(kContentAttribName
, &attribute
)) {
289 // Found the content string, copy and return.
290 content_value
->assign(attribute
.Copy());
297 void DisplayVersionMismatchWarning(HWND parent
,
298 const std::string
& server_version
) {
299 // Obtain the current module version.
300 scoped_ptr
<FileVersionInfo
> module_version_info(
301 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
302 string16
version_string(module_version_info
->file_version());
303 std::wstring wide_server_version
;
304 if (server_version
.empty()) {
305 wide_server_version
= SimpleResourceLoader::Get(IDS_VERSIONUNKNOWN
);
307 wide_server_version
= ASCIIToWide(server_version
);
309 std::wstring title
= SimpleResourceLoader::Get(IDS_VERSIONMISMATCH_HEADER
);
310 std::wstring message
;
311 base::SStringPrintf(&message
,
312 SimpleResourceLoader::Get(IDS_VERSIONMISMATCH
).c_str(),
313 wide_server_version
.c_str(),
314 version_string
.c_str());
316 ::MessageBox(parent
, message
.c_str(), title
.c_str(), MB_OK
);
319 std::string
CreateJavascript(const std::string
& function_name
,
320 const std::string args
) {
321 std::string script_string
= "javascript:";
322 script_string
+= function_name
+ "(";
324 script_string
+= "'";
325 script_string
+= args
;
326 script_string
+= "'";
328 script_string
+= ")";
329 return script_string
;
332 AddRefModule::AddRefModule() {
333 // TODO(tommi): Override the module's Lock/Unlock methods to call
334 // npapi::SetValue(NPPVpluginKeepLibraryInMemory) and keep the dll loaded
335 // while the module's refcount is > 0. Only do this when we're being
336 // used as an NPAPI module.
341 AddRefModule::~AddRefModule() {
342 _pAtlModule
->Unlock();
345 bool IsChrome(RendererType renderer_type
) {
346 DCHECK_GE(renderer_type
, RENDERER_TYPE_UNDETERMINED
);
347 DCHECK_LE(renderer_type
, RENDERER_TYPE_OTHER
);
348 return renderer_type
>= RENDERER_TYPE_CHROME_MIN
&&
349 renderer_type
<= RENDERER_TYPE_CHROME_MAX
;
353 const char kIEImageName
[] = "iexplore.exe";
356 std::wstring
GetHostProcessName(bool include_extension
) {
358 if (PathService::Get(base::FILE_EXE
, &exe
))
359 exe
= exe
.BaseName();
360 if (!include_extension
) {
361 exe
= exe
.RemoveExtension();
366 BrowserType
GetBrowserType() {
367 static BrowserType browser_type
= BROWSER_INVALID
;
369 if (browser_type
== BROWSER_INVALID
) {
370 std::wstring
exe(GetHostProcessName(true));
372 std::wstring::const_iterator begin
= exe
.begin();
373 std::wstring::const_iterator end
= exe
.end();
374 if (LowerCaseEqualsASCII(begin
, end
, kIEImageName
)) {
375 browser_type
= BROWSER_IE
;
377 browser_type
= BROWSER_UNKNOWN
;
387 uint32
GetIEMajorVersion() {
388 static uint32 ie_major_version
= UINT_MAX
;
390 if (ie_major_version
== UINT_MAX
) {
391 wchar_t exe_path
[MAX_PATH
];
392 HMODULE mod
= GetModuleHandle(NULL
);
393 GetModuleFileName(mod
, exe_path
, arraysize(exe_path
) - 1);
394 std::wstring exe_name
= base::FilePath(exe_path
).BaseName().value();
395 if (!LowerCaseEqualsASCII(exe_name
, kIEImageName
)) {
396 ie_major_version
= 0;
400 if (GetModuleVersion(mod
, &high
, &low
)) {
401 ie_major_version
= HIWORD(high
);
403 ie_major_version
= 0;
408 return ie_major_version
;
411 IEVersion
GetIEVersion() {
412 static IEVersion ie_version
= IE_INVALID
;
414 if (ie_version
== IE_INVALID
) {
415 uint32 major_version
= GetIEMajorVersion();
416 switch (major_version
) {
433 ie_version
= (major_version
>= 10) ? IE_10
: IE_UNSUPPORTED
;
441 base::FilePath
GetIETemporaryFilesFolder() {
442 LPITEMIDLIST tif_pidl
= NULL
;
443 HRESULT hr
= SHGetFolderLocation(NULL
, CSIDL_INTERNET_CACHE
, NULL
,
444 SHGFP_TYPE_CURRENT
, &tif_pidl
);
445 if (SUCCEEDED(hr
) && tif_pidl
) {
446 base::win::ScopedComPtr
<IShellFolder
> parent_folder
;
447 LPITEMIDLIST relative_pidl
= NULL
;
448 hr
= SHBindToParent(tif_pidl
, IID_IShellFolder
,
449 reinterpret_cast<void**>(parent_folder
.Receive()),
450 const_cast<LPCITEMIDLIST
*>(&relative_pidl
));
451 if (SUCCEEDED(hr
) && relative_pidl
) {
453 hr
= parent_folder
->GetDisplayNameOf(relative_pidl
,
454 SHGDN_NORMAL
| SHGDN_FORPARSING
,
456 DCHECK(SUCCEEDED(hr
));
457 base::win::ScopedBstr temp_internet_files_bstr
;
458 StrRetToBSTR(&path
, relative_pidl
, temp_internet_files_bstr
.Receive());
459 base::FilePath
temp_internet_files(
460 static_cast<BSTR
>(temp_internet_files_bstr
));
462 return temp_internet_files
;
464 NOTREACHED() << "SHBindToParent failed with Error:" << hr
;
468 NOTREACHED() << "SHGetFolderLocation for internet cache failed. Error:"
471 // As a last ditch effort we use the SHGetFolderPath function to retrieve the
472 // path. This function has a limitation of MAX_PATH.
473 wchar_t path
[MAX_PATH
+ 1] = {0};
474 hr
= SHGetFolderPath(NULL
, CSIDL_INTERNET_CACHE
, NULL
, SHGFP_TYPE_CURRENT
,
477 return base::FilePath(path
);
479 NOTREACHED() << "SHGetFolderPath for internet cache failed. Error:"
482 return base::FilePath();
485 bool IsIEInPrivate() {
486 typedef BOOL (WINAPI
* IEIsInPrivateBrowsingPtr
)();
487 bool incognito_mode
= false;
488 HMODULE h
= GetModuleHandle(L
"ieframe.dll");
490 IEIsInPrivateBrowsingPtr IsInPrivate
=
491 reinterpret_cast<IEIsInPrivateBrowsingPtr
>(GetProcAddress(h
,
492 "IEIsInPrivateBrowsing"));
494 incognito_mode
= !!IsInPrivate();
498 return incognito_mode
;
501 HRESULT
DoFileDownloadInIE(const wchar_t* url
) {
504 HMODULE mod
= ::GetModuleHandleA("ieframe.dll");
506 mod
= ::GetModuleHandleA("shdocvw.dll");
513 typedef HRESULT (WINAPI
* DoFileDownloadFn
)(const wchar_t*);
514 DoFileDownloadFn fn
= reinterpret_cast<DoFileDownloadFn
>(
515 ::GetProcAddress(mod
, "DoFileDownload"));
517 return fn
? fn(url
) : E_UNEXPECTED
;
520 bool GetModuleVersion(HMODULE module
, uint32
* high
, uint32
* low
) {
521 DCHECK(module
!= NULL
)
522 << "Please use GetModuleHandle(NULL) to get the process name";
527 HRSRC res
= FindResource(module
,
528 reinterpret_cast<const wchar_t*>(VS_VERSION_INFO
), RT_VERSION
);
530 HGLOBAL res_data
= LoadResource(module
, res
);
531 DWORD version_resource_size
= SizeofResource(module
, res
);
532 const void* readonly_resource_data
= LockResource(res_data
);
533 if (readonly_resource_data
&& version_resource_size
) {
534 // Copy data as VerQueryValue tries to modify the data. This causes
535 // exceptions and heap corruption errors if debugger is attached.
536 scoped_ptr
<char[]> data(new char[version_resource_size
]);
538 memcpy(data
.get(), readonly_resource_data
, version_resource_size
);
539 VS_FIXEDFILEINFO
* ver_info
= NULL
;
541 if (VerQueryValue(data
.get(), L
"\\",
542 reinterpret_cast<void**>(&ver_info
), &info_size
)) {
543 *high
= ver_info
->dwFileVersionMS
;
545 *low
= ver_info
->dwFileVersionLS
;
549 UnlockResource(res_data
);
551 FreeResource(res_data
);
560 const int kMaxSubmenuDepth
= 10;
562 // Builds a Windows menu from the menu model sent from Chrome. The
563 // caller is responsible for closing the returned HMENU. This does
564 // not currently handle bitmaps (e.g. hbmpChecked, hbmpUnchecked or
565 // hbmpItem), so checkmarks, radio buttons, and custom icons won't work.
566 // It also copies over submenus up to a maximum depth of kMaxSubMenuDepth.
567 HMENU
BuildContextMenuImpl(const ContextMenuModel
* menu_model
, int depth
) {
568 if (depth
>= kMaxSubmenuDepth
)
571 HMENU menu
= CreatePopupMenu();
572 for (size_t i
= 0; i
< menu_model
->items
.size(); i
++) {
573 const ContextMenuModel::Item
& item
= menu_model
->items
[i
];
575 MENUITEMINFO item_info
= { 0 };
576 item_info
.cbSize
= sizeof(MENUITEMINFO
);
578 case ui::MenuModel::TYPE_COMMAND
:
579 case ui::MenuModel::TYPE_CHECK
:
580 item_info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
581 item_info
.fType
= MFT_STRING
;
582 item_info
.wID
= item
.item_id
;
583 item_info
.dwTypeData
= const_cast<LPWSTR
>(item
.label
.c_str());
585 case ui::MenuModel::TYPE_RADIO
:
586 item_info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
;
587 item_info
.fType
= MFT_STRING
| MFT_RADIOCHECK
;
588 item_info
.wID
= item
.item_id
;
589 item_info
.dwTypeData
= const_cast<LPWSTR
>(item
.label
.c_str());
591 case ui::MenuModel::TYPE_SEPARATOR
:
592 item_info
.fMask
= MIIM_FTYPE
;
593 item_info
.fType
= MFT_SEPARATOR
;
595 case ui::MenuModel::TYPE_SUBMENU
:
596 item_info
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STRING
| MIIM_SUBMENU
;
597 item_info
.fType
= MFT_STRING
;
598 item_info
.wID
= item
.item_id
;
599 item_info
.dwTypeData
= const_cast<LPWSTR
>(item
.label
.c_str());
600 item_info
.hSubMenu
= BuildContextMenuImpl(item
.submenu
, depth
+ 1);
603 NOTREACHED() << "Unsupported MenuModel::ItemType " << item
.type
;
607 item_info
.fMask
|= MIIM_STATE
;
609 (item
.checked
? MFS_CHECKED
: MFS_UNCHECKED
) |
610 (item
.enabled
? MFS_ENABLED
: (MFS_DISABLED
| MFS_GRAYED
));
612 InsertMenuItem(menu
, i
, TRUE
, &item_info
);
620 HMENU
BuildContextMenu(const ContextMenuModel
& menu_model
) {
621 return BuildContextMenuImpl(&menu_model
, 0);
624 std::string
ResolveURL(const std::string
& document
,
625 const std::string
& relative
) {
626 if (document
.empty()) {
627 return GURL(relative
).spec();
629 return GURL(document
).Resolve(relative
).spec();
633 bool HaveSameOrigin(const std::string
& url1
, const std::string
& url2
) {
634 GURL
a(url1
), b(url2
);
636 if (a
.is_valid() != b
.is_valid()) {
637 // Either (but not both) url is invalid, so they can't match.
639 } else if (!a
.is_valid()) {
640 // Both URLs are invalid (see first check). Just check if the opaque
641 // strings match exactly.
642 ret
= url1
.compare(url2
) == 0;
643 } else if (a
.GetOrigin() != b
.GetOrigin()) {
644 // The origins don't match.
654 int GetConfigInt(int default_value
, const wchar_t* value_name
) {
655 int ret
= default_value
;
657 if (config_key
.Open(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
658 KEY_QUERY_VALUE
) == ERROR_SUCCESS
) {
659 config_key
.ReadValueDW(value_name
, reinterpret_cast<DWORD
*>(&ret
));
665 int64
GetConfigInt64(int64 default_value
, const wchar_t* value_name
) {
666 int64 ret
= default_value
;
668 if (config_key
.Open(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
669 KEY_QUERY_VALUE
) == ERROR_SUCCESS
) {
670 config_key
.ReadInt64(value_name
, &ret
);
676 bool GetConfigBool(bool default_value
, const wchar_t* value_name
) {
677 DWORD value
= GetConfigInt(default_value
, value_name
);
678 return (value
!= FALSE
);
681 bool SetConfigInt(const wchar_t* value_name
, int value
) {
683 if (config_key
.Create(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
684 KEY_SET_VALUE
) == ERROR_SUCCESS
) {
685 if (config_key
.WriteValue(value_name
, value
) == ERROR_SUCCESS
) {
693 bool SetConfigBool(const wchar_t* value_name
, bool value
) {
694 return SetConfigInt(value_name
, value
);
697 bool SetConfigInt64(const wchar_t* value_name
, int64 value
) {
699 if (config_key
.Create(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
700 KEY_SET_VALUE
) == ERROR_SUCCESS
) {
701 if (config_key
.WriteValue(value_name
, &value
, sizeof(value
),
702 REG_QWORD
) == ERROR_SUCCESS
) {
710 bool DeleteConfigValue(const wchar_t* value_name
) {
712 if (config_key
.Open(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
713 KEY_WRITE
) == ERROR_SUCCESS
) {
714 if (config_key
.DeleteValue(value_name
) == ERROR_SUCCESS
) {
721 bool IsGcfDefaultRenderer() {
722 DWORD is_default
= 0; // NOLINT
724 // First check policy settings
725 PolicySettings::RendererForUrl renderer
=
726 PolicySettings::GetInstance()->default_renderer();
727 if (renderer
!= PolicySettings::RENDERER_NOT_SPECIFIED
) {
728 is_default
= (renderer
== PolicySettings::RENDER_IN_CHROME_FRAME
);
730 // TODO(tommi): Implement caching for this config value as it gets
731 // checked frequently.
733 if (config_key
.Open(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
734 KEY_READ
) == ERROR_SUCCESS
) {
735 config_key
.ReadValueDW(kEnableGCFRendererByDefault
, &is_default
);
739 return is_default
!= 0;
742 // Check for the registry key 'SkipGCFMetadataCheck' and if true, then
743 // ignore presence of <meta http-equiv="X-UA-Compatible" content="chrome=1">
744 bool SkipMetadataCheck() {
745 // Check policy settings
746 PolicySettings::SkipMetadataCheck metadataCheck
=
747 PolicySettings::GetInstance()->skip_metadata_check();
748 if (metadataCheck
!= PolicySettings::SKIP_METADATA_CHECK_NOT_SPECIFIED
)
749 return (metadataCheck
== PolicySettings::SKIP_METADATA_CHECK_YES
);
753 if (config_key
.Open(HKEY_CURRENT_USER
, kChromeFrameConfigKey
,
754 KEY_READ
) == ERROR_SUCCESS
) {
755 config_key
.ReadValueDW(kSkipGCFMetadataCheck
, &skip
);
760 RendererType
RendererTypeForUrl(const std::wstring
& url
) {
761 // First check if the default renderer settings are specified by policy.
762 // If so, then that overrides the user settings.
763 PolicySettings::RendererForUrl renderer
=
764 PolicySettings::GetInstance()->GetRendererForUrl(url
.c_str());
765 if (renderer
!= PolicySettings::RENDERER_NOT_SPECIFIED
) {
766 // We may know at this point that policy says do NOT render in Chrome Frame.
767 // To maintain consistency, we return RENDERER_TYPE_UNDETERMINED so that
768 // content sniffing, etc. still take place.
769 // TODO(tommi): Clarify the intent here.
770 return (renderer
== PolicySettings::RENDER_IN_CHROME_FRAME
) ?
771 RENDERER_TYPE_CHROME_OPT_IN_URL
: RENDERER_TYPE_UNDETERMINED
;
774 // TODO(robertshield): Move this into a holder-type class that listens
775 // for reg change events as well.
776 static int render_in_cf_by_default
= FALSE
;
778 RegistryListPreferencesHolder
& render_type_for_url_holder
=
779 g_render_type_for_url_holder
.Get();
780 if (!render_type_for_url_holder
.Valid()) {
781 const wchar_t* url_list_name
= kRenderInGCFUrlList
;
782 if (IsGcfDefaultRenderer()) {
783 url_list_name
= kRenderInHostUrlList
;
784 render_in_cf_by_default
= TRUE
;
786 render_in_cf_by_default
= FALSE
;
789 render_type_for_url_holder
.Init(HKEY_CURRENT_USER
,
790 kChromeFrameConfigKey
,
793 DCHECK(render_type_for_url_holder
.Valid());
795 RendererType renderer_type
=
796 render_in_cf_by_default
? RENDERER_TYPE_CHROME_DEFAULT_RENDERER
:
797 RENDERER_TYPE_UNDETERMINED
;
799 if (render_type_for_url_holder
.ListMatches(url
)) {
800 renderer_type
= render_in_cf_by_default
?
801 RENDERER_TYPE_UNDETERMINED
:
802 RENDERER_TYPE_CHROME_OPT_IN_URL
;
805 return renderer_type
;
808 bool ShouldRemoveUAForUrl(const string16
& url
) {
809 // TODO(robertshield): Wire up the stuff in PolicySettings here so the value
810 // can be specified via group policy.
811 // TODO(robertshield): Add a default list of exclusions here for site with
812 // known bad UA parsing.
813 RegistryListPreferencesHolder
& user_agent_filter_holder
=
814 g_user_agent_filter_holder
.Get();
815 if (!user_agent_filter_holder
.Valid()) {
816 user_agent_filter_holder
.Init(HKEY_CURRENT_USER
,
817 kChromeFrameConfigKey
,
818 kExcludeUAFromDomainList
);
820 DCHECK(user_agent_filter_holder
.Valid());
822 return user_agent_filter_holder
.ListMatches(url
);
825 RegistryListPreferencesHolder
& GetRendererTypePreferencesHolderForTesting() {
826 return g_render_type_for_url_holder
.Get();
829 RegistryListPreferencesHolder
& GetUserAgentPreferencesHolderForTesting() {
830 return g_user_agent_filter_holder
.Get();
833 HRESULT
NavigateBrowserToMoniker(IUnknown
* browser
, IMoniker
* moniker
,
834 const wchar_t* headers
, IBindCtx
* bind_ctx
,
835 const wchar_t* fragment
, IStream
* post_data
,
841 base::win::ScopedComPtr
<IWebBrowser2
> web_browser2
;
842 HRESULT hr
= DoQueryService(SID_SWebBrowserApp
, browser
,
843 web_browser2
.Receive());
844 DCHECK(web_browser2
);
845 DLOG_IF(WARNING
, FAILED(hr
)) << base::StringPrintf(L
"SWebBrowserApp 0x%08X",
850 // If the data to be downloaded was received in response to a post request
851 // then we need to reissue the post request.
852 base::win::ScopedVariant post_data_variant
;
854 RewindStream(post_data
);
856 CComSafeArray
<uint8
> safe_array_post
;
859 post_data
->Stat(&stat
, STATFLAG_NONAME
);
861 if (stat
.cbSize
.LowPart
> 0) {
865 while ((hr
= ReadStream(post_data
, 0xffff, &data
)) == S_OK
) {
868 reinterpret_cast<unsigned char*>(const_cast<char*>(data
.data())));
872 // If we get here it means that the navigation is being reissued for a
873 // POST request with no data. To ensure that the new window used as a
874 // target to handle the new navigation issues a POST request
875 // we need valid POST data. In this case we create a dummy 1 byte array.
876 // May not work as expected with some web sites.
877 DLOG(WARNING
) << "Reissuing navigation with empty POST data. May not"
878 << " work as expected";
879 safe_array_post
.Create(1);
881 post_data_variant
.Set(safe_array_post
.Detach());
883 // Create a new bind context that's not associated with our callback.
884 // Calling RevokeBindStatusCallback doesn't disassociate the callback with
885 // the bind context in IE7. The returned bind context has the same
886 // implementation of GetRunningObjectTable as the bind context we held which
887 // basically delegates to ole32's GetRunningObjectTable. The object table
888 // is then used to determine if the moniker is already running and via
889 // that mechanism is associated with the same internet request as has already
892 // TODO(tommi): See if we can get HlinkSimpleNavigateToMoniker to work
893 // instead. Looks like we'll need to support IHTMLDocument2 (get_URL in
894 // particular), access to IWebBrowser2 etc.
895 // HlinkSimpleNavigateToMoniker(moniker, url, NULL, host, bind_context,
898 base::win::ScopedComPtr
<IUriContainer
> uri_container
;
899 hr
= uri_container
.QueryFrom(moniker
);
901 base::win::ScopedVariant headers_var
;
902 if (headers
&& headers
[0])
903 headers_var
.Set(headers
);
907 const IID
* interface_ids
[] = {
908 &IID_IWebBrowserPriv2IE7
,
909 &IID_IWebBrowserPriv2IE8
,
910 &IID_IWebBrowserPriv2IE8XP
,
911 &IID_IWebBrowserPriv2IE8XPBeta
,
914 base::win::ScopedComPtr
<IWebBrowserPriv2Common
, NULL
> browser_priv2
;
915 for (int i
= 0; i
< arraysize(interface_ids
) && browser_priv2
== NULL
;
917 hr
= web_browser2
.QueryInterface(*interface_ids
[i
],
918 reinterpret_cast<void**>(browser_priv2
.Receive()));
921 DCHECK(browser_priv2
);
924 base::win::ScopedComPtr
<IUri
> uri_obj
;
925 uri_container
->GetIUri(uri_obj
.Receive());
928 if (GetIEVersion() < IE_9
) {
929 hr
= browser_priv2
->NavigateWithBindCtx2(
930 uri_obj
, flags
, NULL
, post_data_variant
.AsInput(),
931 headers_var
.AsInput(), bind_ctx
,
932 const_cast<wchar_t*>(fragment
));
934 IWebBrowserPriv2CommonIE9
* browser_priv2_ie9
=
935 reinterpret_cast<IWebBrowserPriv2CommonIE9
*>(browser_priv2
.get());
936 hr
= browser_priv2_ie9
->NavigateWithBindCtx2(
937 uri_obj
, flags
, NULL
, post_data_variant
.AsInput(),
938 headers_var
.AsInput(), bind_ctx
,
939 const_cast<wchar_t*>(fragment
), 0);
941 DLOG_IF(WARNING
, FAILED(hr
))
942 << base::StringPrintf(L
"NavigateWithBindCtx2 0x%08X", hr
);
947 if (SUCCEEDED(hr
= moniker
->GetDisplayName(bind_ctx
, NULL
, &url
))) {
948 DVLOG(1) << __FUNCTION__
<< " " << url
;
949 base::win::ScopedComPtr
<IWebBrowserPriv
> browser_priv
;
950 if (SUCCEEDED(hr
= browser_priv
.QueryFrom(web_browser2
))) {
951 GURL
target_url(url
);
952 // On IE6 if the original URL has a fragment then the navigation
953 // attempt is ignored. To workaround this we strip the fragment from
954 // the url and initiate the navigation. When the active document loads
955 // we retrieve the original url with the fragment from the Navigation
956 // manager and use it.
957 if (target_url
.has_ref()) {
958 url_parse::Component comp
;
959 GURL::Replacements replacements
;
960 replacements
.SetRef("", comp
);
962 target_url
= target_url
.ReplaceComponents(replacements
);
966 base::win::ScopedVariant
var_url(UTF8ToWide(target_url
.spec()).c_str());
967 hr
= browser_priv
->NavigateWithBindCtx(var_url
.AsInput(), flags
, NULL
,
968 post_data_variant
.AsInput(),
969 headers_var
.AsInput(), bind_ctx
,
970 const_cast<wchar_t*>(fragment
));
971 DLOG_IF(WARNING
, FAILED(hr
))
972 << base::StringPrintf(L
"NavigateWithBindCtx 0x%08X", hr
);
976 ::CoTaskMemFree(url
);
978 DLOG(ERROR
) << base::StringPrintf("GetDisplayName: 0x%08X", hr
);
985 void MarkBrowserOnThreadForCFNavigation(IBrowserService
* browser
) {
986 DCHECK(browser
!= NULL
);
987 DCHECK(g_tls_browser_for_cf_navigation
.Pointer()->Get() == NULL
||
988 g_tls_browser_for_cf_navigation
.Pointer()->Get() == browser
);
989 g_tls_browser_for_cf_navigation
.Pointer()->Set(browser
);
992 bool CheckForCFNavigation(IBrowserService
* browser
, bool clear_flag
) {
994 bool ret
= (g_tls_browser_for_cf_navigation
.Pointer()->Get() == browser
);
995 if (ret
&& clear_flag
)
996 g_tls_browser_for_cf_navigation
.Pointer()->Set(NULL
);
1000 bool IsValidUrlScheme(const GURL
& url
, bool is_privileged
) {
1004 if (url
.SchemeIs(content::kHttpScheme
) ||
1005 url
.SchemeIs(content::kHttpsScheme
) ||
1006 url
.SchemeIs(chrome::kAboutScheme
))
1009 // Additional checking for view-source. Allow only http and https
1010 // URLs in view source.
1011 if (url
.SchemeIs(content::kViewSourceScheme
)) {
1012 GURL
sub_url(url
.GetContent());
1013 if (sub_url
.SchemeIs(content::kHttpScheme
) ||
1014 sub_url
.SchemeIs(content::kHttpsScheme
))
1020 if (is_privileged
&&
1021 (url
.SchemeIs(chrome::kDataScheme
) ||
1022 url
.SchemeIs(extensions::kExtensionScheme
)))
1028 std::string
GetRawHttpHeaders(IWinInetHttpInfo
* info
) {
1036 HRESULT hr
= info
->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF
, NULL
, &size
,
1039 DLOG(WARNING
) << "Failed to query HTTP headers size. Error: " << hr
;
1041 buffer
.resize(size
+ 1);
1042 hr
= info
->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF
, &buffer
[0],
1043 &size
, &flags
, &reserved
);
1045 DLOG(WARNING
) << "Failed to query HTTP headers. Error: " << hr
;
1052 bool IsSubFrameRequest(IUnknown
* service_provider
) {
1053 DCHECK(service_provider
);
1055 // We need to be able to get at an IWebBrowser2 if we are to decide whether
1056 // this request originates from a non-top-level frame.
1057 base::win::ScopedComPtr
<IWebBrowser2
> web_browser
;
1058 HRESULT hr
= DoQueryService(IID_ITargetFrame2
, service_provider
,
1059 web_browser
.Receive());
1061 bool is_sub_frame_request
= false;
1063 // Now check to see if we are in a sub-frame.
1064 base::win::ScopedComPtr
<IHTMLWindow2
> current_frame
, parent_frame
;
1065 hr
= DoQueryService(IID_IHTMLWindow2
, service_provider
,
1066 current_frame
.Receive());
1067 if (current_frame
) {
1068 // Only the top level window will return self when get_parent is called.
1069 current_frame
->get_parent(parent_frame
.Receive());
1070 if (parent_frame
!= current_frame
) {
1071 DVLOG(1) << "Sub frame detected";
1072 is_sub_frame_request
= true;
1076 DVLOG(1) << "IsSubFrameRequest - no IWebBrowser2";
1077 is_sub_frame_request
= true;
1080 return is_sub_frame_request
;
1083 bool IsHeadlessMode() {
1084 bool headless
= GetConfigBool(false, kChromeFrameHeadlessMode
);
1088 bool IsAccessibleMode() {
1089 bool accessible
= GetConfigBool(false, kChromeFrameAccessibleMode
);
1093 bool IsUnpinnedMode() {
1094 // We only check this value once and then cache it since changing the registry
1095 // once we've pinned the DLL won't have any effect.
1096 static bool unpinned
= GetConfigBool(false, kChromeFrameUnpinnedMode
);
1100 std::wstring
GetActualUrlFromMoniker(IMoniker
* moniker
,
1101 IBindCtx
* bind_context
,
1102 const std::wstring
& bho_url
) {
1103 CComHeapPtr
<WCHAR
> display_name
;
1104 moniker
->GetDisplayName(bind_context
, NULL
, &display_name
);
1105 std::wstring moniker_url
= display_name
;
1107 GURL
parsed_url(WideToUTF8(bho_url
));
1108 if (!parsed_url
.has_ref())
1111 if (StartsWith(bho_url
, moniker_url
, false) &&
1112 bho_url
[moniker_url
.length()] == L
'#')
1118 bool IsTopLevelWindow(HWND window
) {
1119 long style
= GetWindowLong(window
, GWL_STYLE
); // NOLINT
1120 if (!(style
& WS_CHILD
))
1123 HWND parent
= GetParent(window
);
1124 return !parent
|| (parent
== GetDesktopWindow());
1127 HRESULT
RewindStream(IStream
* stream
) {
1128 HRESULT hr
= E_POINTER
;
1130 LARGE_INTEGER zero
= {0};
1131 ULARGE_INTEGER new_pos
= {0};
1132 hr
= stream
->Seek(zero
, STREAM_SEEK_SET
, &new_pos
);
1138 std::wstring
GuidToString(const GUID
& guid
) {
1140 ::StringFromGUID2(guid
, WriteInto(&ret
, 39), 39);
1144 int32
MapCookieStateToCookieAction(InternetCookieState cookie_state
) {
1145 int32 cookie_action
= COOKIEACTION_NONE
;
1147 switch (cookie_state
) {
1148 case COOKIE_STATE_UNKNOWN
:
1149 cookie_action
= COOKIEACTION_NONE
;
1151 case COOKIE_STATE_ACCEPT
:
1152 cookie_action
= COOKIEACTION_ACCEPT
;
1154 case COOKIE_STATE_LEASH
:
1155 cookie_action
= COOKIEACTION_LEASH
;
1157 case COOKIE_STATE_DOWNGRADE
:
1158 cookie_action
= COOKIEACTION_DOWNGRADE
;
1160 case COOKIE_STATE_REJECT
:
1161 cookie_action
= COOKIEACTION_REJECT
;
1164 cookie_action
= COOKIEACTION_REJECT
;
1167 return cookie_action
;
1170 GURL
GetUrlWithoutFragment(const wchar_t* url
) {
1171 GURL
parsed_url(url
);
1173 if (parsed_url
.has_ref()) {
1174 url_parse::Component comp
;
1175 GURL::Replacements replacements
;
1176 replacements
.SetRef("", comp
);
1178 parsed_url
= parsed_url
.ReplaceComponents(replacements
);
1183 bool CompareUrlsWithoutFragment(const wchar_t* url1
, const wchar_t* url2
) {
1184 GURL parsed_url1
= GetUrlWithoutFragment(url1
);
1185 GURL parsed_url2
= GetUrlWithoutFragment(url2
);
1186 return parsed_url1
== parsed_url2
;
1189 std::string
FindReferrerFromHeaders(const wchar_t* headers
,
1190 const wchar_t* additional_headers
) {
1191 std::string referrer
;
1193 const wchar_t* both_headers
[] = { headers
, additional_headers
};
1194 for (int i
= 0; referrer
.empty() && i
< arraysize(both_headers
); ++i
) {
1195 if (!both_headers
[i
])
1197 std::string raw_headers_utf8
= WideToUTF8(both_headers
[i
]);
1198 net::HttpUtil::HeadersIterator
it(raw_headers_utf8
.begin(),
1199 raw_headers_utf8
.end(), "\r\n");
1200 while (it
.GetNext()) {
1201 if (LowerCaseEqualsASCII(it
.name(), "referer")) {
1202 referrer
= it
.values();
1211 std::string
GetHttpHeadersFromBinding(IBinding
* binding
) {
1212 if (binding
== NULL
) {
1213 DLOG(WARNING
) << "GetHttpResponseStatus - no binding_";
1214 return std::string();
1217 base::win::ScopedComPtr
<IWinInetHttpInfo
> info
;
1218 if (FAILED(info
.QueryFrom(binding
))) {
1219 DLOG(WARNING
) << "Failed to QI for IWinInetHttpInfo";
1220 return std::string();
1223 return GetRawHttpHeaders(info
);
1226 int GetHttpResponseStatusFromBinding(IBinding
* binding
) {
1227 DVLOG(1) << __FUNCTION__
;
1228 if (binding
== NULL
) {
1229 DLOG(WARNING
) << "GetHttpResponseStatus - no binding_";
1233 int http_status
= 0;
1235 base::win::ScopedComPtr
<IWinInetHttpInfo
> info
;
1236 if (SUCCEEDED(info
.QueryFrom(binding
))) {
1237 char status
[10] = {0};
1238 DWORD buf_size
= sizeof(status
);
1241 if (SUCCEEDED(info
->QueryInfo(HTTP_QUERY_STATUS_CODE
, status
, &buf_size
,
1242 &flags
, &reserved
))) {
1243 base::StringToInt(status
, &http_status
);
1245 NOTREACHED() << "Failed to get HTTP status";
1248 NOTREACHED() << "failed to get IWinInetHttpInfo from binding_";
1254 CLIPFORMAT
GetTextHtmlClipboardFormat() {
1255 static const CLIPFORMAT text_html
= RegisterClipboardFormat(CFSTR_MIME_HTML
);
1259 bool IsTextHtmlMimeType(const wchar_t* mime_type
) {
1260 return IsTextHtmlClipFormat(RegisterClipboardFormatW(mime_type
));
1263 bool IsTextHtmlClipFormat(CLIPFORMAT cf
) {
1264 return cf
== GetTextHtmlClipboardFormat();
1267 bool IsSystemProcess() {
1268 bool is_system
= false;
1269 CAccessToken process_token
;
1270 if (process_token
.GetProcessToken(TOKEN_QUERY
, GetCurrentProcess())) {
1272 if (process_token
.GetUser(&logon_sid
)) {
1273 is_system
= logon_sid
== Sids::System();
1280 std::string
BindStatus2Str(ULONG bind_status
) {
1282 static const char* const bindstatus_txt
[] = {
1283 "BINDSTATUS_FINDINGRESOURCE",
1284 "BINDSTATUS_CONNECTING",
1285 "BINDSTATUS_REDIRECTING",
1286 "BINDSTATUS_BEGINDOWNLOADDATA",
1287 "BINDSTATUS_DOWNLOADINGDATA",
1288 "BINDSTATUS_ENDDOWNLOADDATA",
1289 "BINDSTATUS_BEGINDOWNLOADCOMPONENTS",
1290 "BINDSTATUS_INSTALLINGCOMPONENTS",
1291 "BINDSTATUS_ENDDOWNLOADCOMPONENTS",
1292 "BINDSTATUS_USINGCACHEDCOPY",
1293 "BINDSTATUS_SENDINGREQUEST",
1294 "BINDSTATUS_CLASSIDAVAILABLE",
1295 "BINDSTATUS_MIMETYPEAVAILABLE",
1296 "BINDSTATUS_CACHEFILENAMEAVAILABLE",
1297 "BINDSTATUS_BEGINSYNCOPERATION",
1298 "BINDSTATUS_ENDSYNCOPERATION",
1299 "BINDSTATUS_BEGINUPLOADDATA",
1300 "BINDSTATUS_UPLOADINGDATA",
1301 "BINDSTATUS_ENDUPLOADINGDATA",
1302 "BINDSTATUS_PROTOCOLCLASSID",
1303 "BINDSTATUS_ENCODING",
1304 "BINDSTATUS_VERFIEDMIMETYPEAVAILABLE",
1305 "BINDSTATUS_CLASSINSTALLLOCATION",
1306 "BINDSTATUS_DECODING",
1307 "BINDSTATUS_LOADINGMIMEHANDLER",
1308 "BINDSTATUS_CONTENTDISPOSITIONATTACH",
1309 "BINDSTATUS_FILTERREPORTMIMETYPE",
1310 "BINDSTATUS_CLSIDCANINSTANTIATE",
1311 "BINDSTATUS_IUNKNOWNAVAILABLE",
1312 "BINDSTATUS_DIRECTBIND",
1313 "BINDSTATUS_RAWMIMETYPE",
1314 "BINDSTATUS_PROXYDETECTING",
1315 "BINDSTATUS_ACCEPTRANGES",
1316 "BINDSTATUS_COOKIE_SENT",
1317 "BINDSTATUS_COMPACT_POLICY_RECEIVED",
1318 "BINDSTATUS_COOKIE_SUPPRESSED",
1319 "BINDSTATUS_COOKIE_STATE_UNKNOWN",
1320 "BINDSTATUS_COOKIE_STATE_ACCEPT",
1321 "BINDSTATUS_COOKIE_STATE_REJECT",
1322 "BINDSTATUS_COOKIE_STATE_PROMPT",
1323 "BINDSTATUS_COOKIE_STATE_LEASH",
1324 "BINDSTATUS_COOKIE_STATE_DOWNGRADE",
1325 "BINDSTATUS_POLICY_HREF",
1326 "BINDSTATUS_P3P_HEADER",
1327 "BINDSTATUS_SESSION_COOKIE_RECEIVED",
1328 "BINDSTATUS_PERSISTENT_COOKIE_RECEIVED",
1329 "BINDSTATUS_SESSION_COOKIES_ALLOWED",
1330 "BINDSTATUS_CACHECONTROL",
1331 "BINDSTATUS_CONTENTDISPOSITIONFILENAME",
1332 "BINDSTATUS_MIMETEXTPLAINMISMATCH",
1333 "BINDSTATUS_PUBLISHERAVAILABLE",
1334 "BINDSTATUS_DISPLAYNAMEAVAILABLE",
1335 "BINDSTATUS_SSLUX_NAVBLOCKED",
1336 "BINDSTATUS_SERVER_MIMETYPEAVAILABLE",
1337 "BINDSTATUS_SNIFFED_CLASSIDAVAILABLE",
1338 "BINDSTATUS_64BIT_PROGRESS"
1340 if (bind_status
>= 1 && bind_status
<= BINDSTATUS_64BIT_PROGRESS
)
1341 s
= bindstatus_txt
[bind_status
- 1];
1343 s
= base::StringPrintf("UnDoc[%#x]", bind_status
);
1347 std::string
PiFlags2Str(DWORD flags
) {
1348 #define ADD_PI_FLAG(x) \
1350 s.append(#x ## " "); \
1354 std::string s
= " flags ";
1355 ADD_PI_FLAG(PI_PARSE_URL
);
1356 ADD_PI_FLAG(PI_FILTER_MODE
);
1357 ADD_PI_FLAG(PI_FORCE_ASYNC
);
1358 ADD_PI_FLAG(PI_USE_WORKERTHREAD
);
1359 ADD_PI_FLAG(PI_MIMEVERIFICATION
);
1360 ADD_PI_FLAG(PI_CLSIDLOOKUP
);
1361 ADD_PI_FLAG(PI_DATAPROGRESS
);
1362 ADD_PI_FLAG(PI_SYNCHRONOUS
);
1363 ADD_PI_FLAG(PI_APARTMENTTHREADED
);
1364 ADD_PI_FLAG(PI_CLASSINSTALL
);
1365 ADD_PI_FLAG(PI_PASSONBINDCTX
);
1366 ADD_PI_FLAG(PI_NOMIMEHANDLER
);
1367 ADD_PI_FLAG(PI_LOADAPPDIRECT
);
1368 ADD_PI_FLAG(PD_FORCE_SWITCH
);
1369 ADD_PI_FLAG(PI_PREFERDEFAULTHANDLER
);
1372 s
+= base::StringPrintf("+UnDoc[%#x]", flags
);
1377 std::string
Bscf2Str(DWORD flags
) {
1378 #define ADD_BSCF_FLAG(x) \
1380 s.append(#x ## " "); \
1384 std::string s
= " flags ";
1385 ADD_BSCF_FLAG(BSCF_FIRSTDATANOTIFICATION
)
1386 ADD_BSCF_FLAG(BSCF_INTERMEDIATEDATANOTIFICATION
)
1387 ADD_BSCF_FLAG(BSCF_LASTDATANOTIFICATION
)
1388 ADD_BSCF_FLAG(BSCF_DATAFULLYAVAILABLE
)
1389 ADD_BSCF_FLAG(BSCF_AVAILABLEDATASIZEUNKNOWN
)
1390 ADD_BSCF_FLAG(BSCF_SKIPDRAINDATAFORFILEURLS
)
1391 ADD_BSCF_FLAG(BSCF_64BITLENGTHDOWNLOAD
)
1394 s
+= base::StringPrintf("+UnDoc[%#x]", flags
);
1396 #undef ADD_BSCF_FLAG
1399 // Reads data from a stream into a string.
1400 HRESULT
ReadStream(IStream
* stream
, size_t size
, std::string
* data
) {
1402 DCHECK_GT(size
, 0u);
1406 HRESULT hr
= stream
->Read(WriteInto(data
, size
+ 1), size
, &read
);
1407 DCHECK(hr
== S_OK
|| hr
== S_FALSE
|| hr
== E_PENDING
);
1410 DCHECK_EQ(read
, data
->length());
1413 // Return S_FALSE if the underlying stream returned S_OK and zero bytes.
1421 ChromeFrameUrl::ChromeFrameUrl() {
1425 bool ChromeFrameUrl::Parse(const std::wstring
& url
) {
1427 parsed_url_
= GURL(url
);
1429 if (parsed_url_
.is_empty())
1432 is_chrome_protocol_
= parsed_url_
.SchemeIs(kGCFProtocol
);
1433 if (is_chrome_protocol_
) {
1434 parsed_url_
= GURL(url
.c_str() + lstrlen(kChromeProtocolPrefix
));
1438 return ParseAttachExternalTabUrl();
1441 bool ChromeFrameUrl::ParseAttachExternalTabUrl() {
1442 std::string query
= parsed_url_
.query();
1443 if (!StartsWithASCII(query
, kAttachExternalTabPrefix
, false)) {
1444 return parsed_url_
.is_valid();
1447 attach_to_external_tab_
= true;
1448 base::StringTokenizer
tokenizer(query
, "&");
1449 // Skip over kChromeAttachExternalTabPrefix
1450 tokenizer
.GetNext();
1451 // Read the following items in order.
1456 // 5. dimension.width
1457 // 6. dimension.height.
1458 if (tokenizer
.GetNext()) {
1460 cookie_
= _strtoui64(tokenizer
.token().c_str(), &end_ptr
, 10);
1465 if (tokenizer
.GetNext()) {
1466 disposition_
= atoi(tokenizer
.token().c_str());
1471 if (tokenizer
.GetNext()) {
1472 dimensions_
.set_x(atoi(tokenizer
.token().c_str()));
1477 if (tokenizer
.GetNext()) {
1478 dimensions_
.set_y(atoi(tokenizer
.token().c_str()));
1483 if (tokenizer
.GetNext()) {
1484 dimensions_
.set_width(atoi(tokenizer
.token().c_str()));
1489 if (tokenizer
.GetNext()) {
1490 dimensions_
.set_height(atoi(tokenizer
.token().c_str()));
1495 if (tokenizer
.GetNext()) {
1496 profile_name_
= tokenizer
.token();
1497 // Escape out special characters like %20, etc.
1498 profile_name_
= net::UnescapeURLComponent(profile_name_
,
1499 net::UnescapeRule::SPACES
| net::UnescapeRule::URL_SPECIAL_CHARS
);
1507 void ChromeFrameUrl::Reset() {
1508 attach_to_external_tab_
= false;
1509 is_chrome_protocol_
= false;
1511 dimensions_
.SetRect(0, 0, 0, 0);
1513 profile_name_
.clear();
1516 bool CanNavigate(const GURL
& url
,
1517 NavigationConstraints
* navigation_constraints
) {
1518 if (!url
.is_valid()) {
1519 DLOG(ERROR
) << "Invalid URL passed to InitiateNavigation: " << url
;
1523 if (!navigation_constraints
) {
1524 NOTREACHED() << "Invalid NavigationConstraints passed in";
1528 // No sanity checks if unsafe URLs are allowed
1529 if (navigation_constraints
->AllowUnsafeUrls())
1532 if (!navigation_constraints
->IsSchemeAllowed(url
)) {
1533 DLOG(WARNING
) << __FUNCTION__
<< " Disallowing navigation to url: " << url
;
1537 if (!navigation_constraints
->IsZoneAllowed(url
)) {
1538 DLOG(WARNING
) << __FUNCTION__
1539 << " Disallowing navigation to restricted url: " << url
;
1545 void WaitWithMessageLoop(HANDLE
* handles
, int count
, DWORD timeout
) {
1546 base::Time now
= base::Time::Now();
1547 base::Time wait_until
= now
+ base::TimeDelta::FromMilliseconds(timeout
);
1549 while (wait_until
>= now
) {
1550 base::TimeDelta wait_time
= wait_until
- now
;
1551 DWORD wait
= MsgWaitForMultipleObjects(
1552 count
, handles
, FALSE
, static_cast<DWORD
>(wait_time
.InMilliseconds()),
1559 case WAIT_OBJECT_0
+ 1: {
1561 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
1562 TranslateMessage(&msg
);
1563 DispatchMessage(&msg
);
1569 NOTREACHED() << "Unexpected return from MsgWaitForMultipleObjects :"
1574 now
= base::Time::Now();
1578 // Returns -1 if no directive is found, std::numeric_limits<int>::max() if the
1579 // directive matches all IE versions ('Chrome=1') or the maximum IE version
1580 // matched ('Chrome=IE7' => 7)
1581 int GetXUaCompatibleDirective(const std::string
& directive
, char delimiter
) {
1582 net::HttpUtil::NameValuePairsIterator
name_value_pairs(directive
.begin(),
1586 // Loop through the values until a valid 'Chrome=<FILTER>' entry is found
1587 while (name_value_pairs
.GetNext()) {
1588 if (!LowerCaseEqualsASCII(name_value_pairs
.name_begin(),
1589 name_value_pairs
.name_end(),
1593 std::string::const_iterator filter_begin
= name_value_pairs
.value_begin();
1594 std::string::const_iterator filter_end
= name_value_pairs
.value_end();
1596 size_t filter_length
= filter_end
- filter_begin
;
1598 if (filter_length
== 1 && *filter_begin
== '1') {
1599 return std::numeric_limits
<int>::max();
1602 if (filter_length
< 3 ||
1603 !LowerCaseEqualsASCII(filter_begin
, filter_begin
+ 2, "ie") ||
1604 !isdigit(*(filter_begin
+ 2))) { // ensure no leading +/-
1608 int header_ie_version
= 0;
1609 if (!base::StringToInt(base::StringPiece(filter_begin
+ 2,
1611 &header_ie_version
) ||
1612 header_ie_version
== 0) { // ensure it's not a sequence of 0's
1616 // The first valid directive we find wins, whether it matches or not
1617 return header_ie_version
;
1622 bool CheckXUaCompatibleDirective(const std::string
& directive
,
1623 int ie_major_version
) {
1624 int header_ie_version
= GetXUaCompatibleDirective(directive
, ';');
1625 if (header_ie_version
== -1) {
1626 header_ie_version
= GetXUaCompatibleDirective(directive
, ',');
1628 return header_ie_version
>= ie_major_version
;
1631 void EnumerateKeyValues(HKEY parent_key
, const wchar_t* sub_key_name
,
1632 std::vector
<std::wstring
>* values
) {
1634 base::win::RegistryValueIterator
url_list(parent_key
, sub_key_name
);
1635 while (url_list
.Valid()) {
1636 values
->push_back(url_list
.Value());
1641 std::wstring
GetCurrentModuleVersion() {
1642 scoped_ptr
<FileVersionInfo
> module_version_info(
1643 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
1644 DCHECK(module_version_info
.get() != NULL
);
1645 return module_version_info
->file_version();
1648 bool IsChromeFrameDocument(IWebBrowser2
* web_browser
) {
1652 base::win::ScopedComPtr
<IDispatch
> doc
;
1653 web_browser
->get_Document(doc
.Receive());
1655 // Detect if CF is rendering based on whether the document is a
1656 // ChromeActiveDocument. Detecting based on hwnd is problematic as
1657 // the CF Active Document window may not have been created yet.
1658 base::win::ScopedComPtr
<IChromeFrame
> chrome_frame
;
1659 chrome_frame
.QueryFrom(doc
);
1660 return chrome_frame
.get() != NULL
;
1665 bool IncreaseWinInetConnections(DWORD connections
) {
1666 static bool wininet_connection_count_updated
= false;
1667 if (wininet_connection_count_updated
) {
1671 static int connection_options
[] = {
1672 INTERNET_OPTION_MAX_CONNS_PER_SERVER
,
1673 INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER
,
1678 for (int option_index
= 0; option_index
< arraysize(connection_options
);
1680 DWORD connection_value_size
= sizeof(DWORD
);
1681 DWORD current_connection_limit
= 0;
1682 InternetQueryOption(NULL
, connection_options
[option_index
],
1683 ¤t_connection_limit
, &connection_value_size
);
1684 if (current_connection_limit
> connections
) {
1688 ret
= InternetSetOption(NULL
, connection_options
[option_index
],
1689 &connections
, connection_value_size
);
1694 wininet_connection_count_updated
= true;
1698 void GetChromeFrameProfilePath(const string16
& profile_name
,
1699 base::FilePath
* profile_path
) {
1700 chrome::GetChromeFrameUserDataDirectory(profile_path
);
1701 *profile_path
= profile_path
->Append(profile_name
);
1702 DVLOG(1) << __FUNCTION__
<< ": " << profile_path
->value();