Home | History | Annotate | Download | only in chrome_frame
      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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    341 AddRefModule::~AddRefModule() {
    342   _pAtlModule->Unlock();
    343 }
    344 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    623 HMENU BuildContextMenu(const ContextMenuModel& menu_model) {
    624   return BuildContextMenuImpl(&menu_model, 0);
    625 }
    626 
    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 
    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 
    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 
    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 
    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 
    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 
    696 bool SetConfigBool(const wchar_t* value_name, bool value) {
    697   return SetConfigInt(value_name, value);
    698 }
    699 
    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 
    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 
    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">
    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 
    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 
    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 
    828 RegistryListPreferencesHolder& GetRendererTypePreferencesHolderForTesting() {
    829   return g_render_type_for_url_holder.Get();
    830 }
    831 
    832 RegistryListPreferencesHolder& GetUserAgentPreferencesHolderForTesting() {
    833   return g_user_agent_filter_holder.Get();
    834 }
    835 
    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 
    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 
    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 
   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 
   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 
   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 
   1086 bool IsHeadlessMode() {
   1087   bool headless = GetConfigBool(false, kChromeFrameHeadlessMode);
   1088   return headless;
   1089 }
   1090 
   1091 bool IsAccessibleMode() {
   1092   bool accessible = GetConfigBool(false, kChromeFrameAccessibleMode);
   1093   return accessible;
   1094 }
   1095 
   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 
   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 
   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 
   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 
   1141 std::wstring GuidToString(const GUID& guid) {
   1142   std::wstring ret;
   1143   ::StringFromGUID2(guid, WriteInto(&ret, 39), 39);
   1144   return ret;
   1145 }
   1146 
   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 
   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 
   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 
   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 
   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 
   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 
   1257 CLIPFORMAT GetTextHtmlClipboardFormat() {
   1258   static const CLIPFORMAT text_html = RegisterClipboardFormat(CFSTR_MIME_HTML);
   1259   return text_html;
   1260 }
   1261 
   1262 bool IsTextHtmlMimeType(const wchar_t* mime_type) {
   1263   return IsTextHtmlClipFormat(RegisterClipboardFormatW(mime_type));
   1264 }
   1265 
   1266 bool IsTextHtmlClipFormat(CLIPFORMAT cf) {
   1267   return cf == GetTextHtmlClipboardFormat();
   1268 }
   1269 
   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 
   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 
   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 
   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.
   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 
   1424 ChromeFrameUrl::ChromeFrameUrl() {
   1425   Reset();
   1426 }
   1427 
   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 
   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 
   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 
   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 
   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)
   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 
   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 
   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 
   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 
   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 
   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 
   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