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