Update device/bluetooth/OWNERS
[chromium-blink-merge.git] / chrome_frame / test / ie_configurator.cc
blobd68818dd00bde2cffa1f7d085fffd99fc6228f75
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome_frame/test/ie_configurator.h"
7 #include <windows.h>
8 #include <objbase.h>
10 #include <ios>
11 #include <list>
12 #include <vector>
14 #include "base/compiler_specific.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/string16.h"
17 #include "base/time.h"
18 #include "base/win/registry.h"
19 #include "chrome_frame/chrome_tab.h"
20 #include "chrome_frame/test/chrome_frame_test_utils.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 namespace chrome_frame_test {
25 namespace {
27 const wchar_t kKeyIEApprovedExtensions[] =
28 L"Software\\Microsoft\\Internet Explorer\\Approved Extensions\\";
29 const wchar_t kKeyIEInformationBar[] =
30 L"Software\\Microsoft\\Internet Explorer\\InformationBar";
31 const wchar_t kKeyIEMain[] =
32 L"Software\\Microsoft\\Internet Explorer\\Main";
33 const wchar_t kKeyIEPhishingFilter[] =
34 L"Software\\Microsoft\\Internet Explorer\\PhishingFilter";
35 const wchar_t kKeyIEBrowserEmulation[] =
36 L"Software\\Microsoft\\Internet Explorer\\BrowserEmulation";
37 const wchar_t kKeyPoliciesExt[] =
38 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Ext";
39 const wchar_t kValueEnabledV9[] = L"EnabledV9";
40 const wchar_t kValueFirstTime[] = L"FirstTime";
41 const wchar_t kValueIE9Completed[] = L"IE9RunOncePerInstallCompleted";
42 const wchar_t kValueIE9CompletionTime[] = L"IE9RunOnceCompletionTime";
43 const wchar_t kValueIE9LastShown[] = L"IE9RunOnceLastShown";
44 const wchar_t kValueIE9TourNoShow[] = L"IE9TourNoShow";
45 const wchar_t kValueIE10Completed[] = L"IE10RunOncePerInstallCompleted";
46 const wchar_t kValueIE10CompletionTime[] = L"IE10RunOnceCompletionTime";
47 const wchar_t kValueIgnoreFrameApprovalCheck[] = L"IgnoreFrameApprovalCheck";
48 const wchar_t kValueMSCompatibilityMode[] = L"MSCompatibilityMode";
50 // A helper class that accumulate a set of registry mutations and corresponding
51 // undo data via calls to its Add*() methods. The mutations can be applied to
52 // the registry (repeatedly, if desired) via a call to Apply(). Revert() can be
53 // called to apply the accumulated undo data.
54 class RegistrySetter {
55 public:
56 RegistrySetter();
57 ~RegistrySetter();
59 // Adds a mutation that sets a REG_DWORD registry value, creating any
60 // intermediate keys as necessary. |key| and |value| must remain valid
61 // throughout all calls to Apply().
62 void AddDWORDValue(HKEY root, const wchar_t* key, const wchar_t* value,
63 DWORD data);
65 // Adds a mutation that assigns a FILETIME to a REG_BINARY registry value,
66 // creating any intermediate keys as necessary. |key| and |value| must remain
67 // valid throughout all calls to Apply().
68 void AddFILETIMEValue(HKEY root, const wchar_t* key, const wchar_t* value,
69 FILETIME data);
71 // Applies all mutations in the order they were added. Errors encountered
72 // along the way are logged, but do not stop progress.
73 void Apply() const;
75 // Applies the undo data in the reverse order that their corresponding
76 // mutations were added.
77 void Revert() const;
79 private:
80 // The data for an individual registry value. A non-existent value is
81 // indicated by type = REG_NONE and empty data.
82 struct RegistryData {
83 HKEY root;
84 const wchar_t* key;
85 const wchar_t* value;
86 DWORD type;
87 std::vector<uint8> data;
90 typedef std::list<RegistryData> RegistryDataList;
92 // Adds a mutation to the end of the apply list with the given data, and a
93 // mutation to the revert list with the current state of the value.
94 void AddValue(HKEY root, const wchar_t* key, const wchar_t* value, DWORD type,
95 const uint8* value_begin, size_t value_len);
97 // Add a mutation to the revert list that restores a registry value to its
98 // current state. This only adds entries to set or remove |value|. If
99 // portions of the hierarchy identified by |key| do not exist, but are created
100 // between the invocation of this method and the time the revert list is
101 // applied, only |value| is deleted upon revert (intermediate keys are not
102 // deleted).
103 void SaveCurrentValue(HKEY root, const wchar_t* key, const wchar_t* value);
105 // Applies all mutations in |data_list| in order.
106 static void ApplyList(const RegistryDataList& data_list);
108 RegistryDataList apply_list_;
109 RegistryDataList revert_list_;
111 DISALLOW_COPY_AND_ASSIGN(RegistrySetter);
114 // A Google Test event listener that delegates to a configurator.
115 class ConfiguratorDriver : public testing::EmptyTestEventListener {
116 public:
117 explicit ConfiguratorDriver(IEConfigurator* configurator);
118 virtual ~ConfiguratorDriver();
120 virtual void OnTestProgramStart(const testing::UnitTest& unit_test) OVERRIDE;
121 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE;
122 virtual void OnTestProgramEnd(const testing::UnitTest& unit_test) OVERRIDE;
124 private:
125 scoped_ptr<IEConfigurator> configurator_;
126 DISALLOW_COPY_AND_ASSIGN(ConfiguratorDriver);
129 // A configurator for Internet Explorer 7.
130 class IE7Configurator : public IEConfigurator {
131 public:
132 IE7Configurator();
133 virtual ~IE7Configurator();
135 virtual void Initialize() OVERRIDE;
136 virtual void ApplySettings() OVERRIDE;
137 virtual void RevertSettings() OVERRIDE;
139 private:
140 RegistrySetter setter_;
142 DISALLOW_COPY_AND_ASSIGN(IE7Configurator);
145 // A configurator for Internet Explorer 9 and 10.
146 class ModernIEConfigurator : public IEConfigurator {
147 public:
148 explicit ModernIEConfigurator(IEVersion ie_version);
149 virtual ~ModernIEConfigurator();
151 virtual void Initialize() OVERRIDE;
152 virtual void ApplySettings() OVERRIDE;
153 virtual void RevertSettings() OVERRIDE;
155 private:
156 // The names of the registry values used to determine if IE's one-time
157 // initialization has been completed.
158 struct RunOnceValueNames {
159 // This DWORD value is non-zero once initialization has been completed.
160 const wchar_t* completed;
161 // This 8-byte binary value is the FILETIME of completion.
162 const wchar_t* completion_time;
165 static const RunOnceValueNames kIE9ValueNames;
166 static const RunOnceValueNames kIE10ValueNames;
168 static const RunOnceValueNames* RunOnceNamesForVersion(IEVersion ie_version);
169 bool IsPerUserSetupComplete();
170 static string16 GetChromeFrameBHOCLSID();
171 static bool IsAddonPromptDisabledForChromeFrame();
173 const IEVersion ie_version_;
174 const RunOnceValueNames* run_once_value_names_;
175 RegistrySetter setter_;
177 DISALLOW_COPY_AND_ASSIGN(ModernIEConfigurator);
180 // RegistrySetter implementation.
182 RegistrySetter::RegistrySetter() {
185 RegistrySetter::~RegistrySetter() {
188 void RegistrySetter::AddValue(HKEY root,
189 const wchar_t* key,
190 const wchar_t* value,
191 DWORD type,
192 const uint8* value_begin,
193 size_t value_len) {
194 RegistryData the_data = {
195 root,
196 key,
197 value,
198 type,
199 std::vector<uint8>(value_begin, value_begin + value_len)
201 apply_list_.push_back(the_data);
202 SaveCurrentValue(root, key, value);
205 void RegistrySetter::SaveCurrentValue(HKEY root,
206 const wchar_t* key,
207 const wchar_t* value) {
208 base::win::RegKey the_key;
209 RegistryData the_data = { root, key, value, REG_NONE };
211 LONG result = the_key.Open(root, key, KEY_QUERY_VALUE);
212 if (result == ERROR_SUCCESS) {
213 DWORD size = 0;
214 result = the_key.ReadValue(value, NULL, &size, &the_data.type);
215 if (result == ERROR_FILE_NOT_FOUND) {
216 // Add a mutation to delete the value.
217 the_data.type = REG_NONE;
218 revert_list_.push_front(the_data);
219 } else if (result == ERROR_SUCCESS) {
220 the_data.data.resize(size);
221 result = the_key.ReadValue(value, &the_data.data[0], &size,
222 &the_data.type);
223 if (result == ERROR_SUCCESS) {
224 revert_list_.push_front(the_data);
225 } else {
226 ::SetLastError(result);
227 PLOG(ERROR) << __FUNCTION__ << " unexpected error reading data for "
228 << value << " from key " << key
229 << ". The current value will not be restored upon revert.";
231 } else {
232 ::SetLastError(result);
233 PLOG(ERROR) << __FUNCTION__ << " unexpected error reading " << value
234 << " from key " << key
235 << ". The current value will not be restored upon revert.";
237 } else if (result == ERROR_FILE_NOT_FOUND) {
238 // Add a mutation to delete the value (but not any keys).
239 revert_list_.push_front(the_data);
240 } else {
241 ::SetLastError(result);
242 PLOG(ERROR) << __FUNCTION__ << " unexpected error opening key " << key
243 << " to read value " << value
244 << ". The current value will not be restored upon revert.";
248 void RegistrySetter::AddDWORDValue(HKEY root,
249 const wchar_t* key,
250 const wchar_t* value,
251 DWORD data) {
252 const uint8* data_ptr = reinterpret_cast<uint8*>(&data);
253 AddValue(root, key, value, REG_DWORD, data_ptr, sizeof(data));
256 void RegistrySetter::AddFILETIMEValue(HKEY root,
257 const wchar_t* key,
258 const wchar_t* value,
259 FILETIME data) {
260 const uint8* data_ptr = reinterpret_cast<uint8*>(&data);
261 AddValue(root, key, value, REG_BINARY, data_ptr, sizeof(data));
264 // static
265 void RegistrySetter::ApplyList(const RegistryDataList& data_list) {
266 base::win::RegKey key;
267 LONG result = ERROR_SUCCESS;
268 for (RegistryDataList::const_iterator scan(data_list.begin());
269 scan != data_list.end(); ++scan) {
270 const RegistryData& data = *scan;
271 const bool do_delete = (data.type == REG_NONE && data.data.empty());
272 result = do_delete ?
273 key.Open(data.root, data.key, KEY_SET_VALUE) :
274 key.Create(data.root, data.key, KEY_SET_VALUE);
275 if (result == ERROR_SUCCESS) {
276 if (do_delete) {
277 result = key.DeleteValue(data.value);
278 } else {
279 result = key.WriteValue(data.value,
280 data.data.empty() ? NULL : &data.data[0],
281 data.data.size(), data.type);
283 if (result != ERROR_SUCCESS) {
284 ::SetLastError(result);
285 PLOG(ERROR) << "Failed to " << (do_delete ? "delete" : "set")
286 << " value " << data.value
287 << " in registry key " << data.key
288 << " in hive " << std::hex <<data.root << std::dec;
290 } else if (!do_delete || result != ERROR_FILE_NOT_FOUND) {
291 ::SetLastError(result);
292 PLOG(ERROR) << "Failed to create/open registry key " << data.key
293 << " in hive " << std::hex << data.root << std::dec;
298 void RegistrySetter::Apply() const {
299 ApplyList(apply_list_);
302 void RegistrySetter::Revert() const {
303 ApplyList(revert_list_);
306 // ConfiguratorDriver implementation.
308 ConfiguratorDriver::ConfiguratorDriver(IEConfigurator* configurator)
309 : configurator_(configurator) {
310 DCHECK(configurator);
313 ConfiguratorDriver::~ConfiguratorDriver() {
316 void ConfiguratorDriver::OnTestProgramStart(
317 const testing::UnitTest& unit_test) {
318 configurator_->Initialize();
321 void ConfiguratorDriver::OnTestStart(const testing::TestInfo& test_info) {
322 configurator_->ApplySettings();
325 void ConfiguratorDriver::OnTestProgramEnd(const testing::UnitTest& unit_test) {
326 configurator_->RevertSettings();
329 // IE7Configurator implementation
331 IE7Configurator::IE7Configurator() {
334 IE7Configurator::~IE7Configurator() {
337 void IE7Configurator::Initialize() {
338 // Suppress the friendly "Hi! I popped up an info bar for you. Did you see
339 // the info bar I just showed you? There's a yellow thing in your IE window
340 // that wasn't there before! I call it an Information Bar. Did you notice
341 // the Information Bar?" dialog that it likes to show.
342 setter_.AddDWORDValue(HKEY_CURRENT_USER, kKeyIEInformationBar,
343 kValueFirstTime, 0);
346 void IE7Configurator::ApplySettings() {
347 setter_.Apply();
350 void IE7Configurator::RevertSettings() {
351 setter_.Revert();
354 // ModernIEConfigurator implementation
356 const ModernIEConfigurator::RunOnceValueNames
357 ModernIEConfigurator::kIE9ValueNames = {
358 kValueIE9Completed,
359 kValueIE9CompletionTime,
362 const ModernIEConfigurator::RunOnceValueNames
363 ModernIEConfigurator::kIE10ValueNames = {
364 kValueIE10Completed,
365 kValueIE10CompletionTime,
368 ModernIEConfigurator::ModernIEConfigurator(IEVersion ie_version)
369 : ie_version_(ie_version),
370 run_once_value_names_(RunOnceNamesForVersion(ie_version)) {
373 ModernIEConfigurator::~ModernIEConfigurator() {
376 // static
377 const ModernIEConfigurator::RunOnceValueNames*
378 ModernIEConfigurator::RunOnceNamesForVersion(
379 IEVersion ie_version) {
380 switch (ie_version) {
381 case IE_9:
382 return &kIE9ValueNames;
383 break;
384 case IE_10:
385 return &kIE10ValueNames;
386 break;
387 default:
388 NOTREACHED();
390 return NULL;
393 // Returns true if the per-user setup is complete.
394 bool ModernIEConfigurator::IsPerUserSetupComplete() {
395 bool is_complete = false;
396 base::win::RegKey key_main;
398 if (key_main.Open(HKEY_CURRENT_USER, kKeyIEMain,
399 KEY_QUERY_VALUE) == ERROR_SUCCESS) {
400 DWORD completed = 0;
401 FILETIME completion_time = {};
402 DWORD size = sizeof(completion_time);
404 if (key_main.ReadValueDW(run_once_value_names_->completed,
405 &completed) == ERROR_SUCCESS &&
406 completed != 0 &&
407 key_main.ReadValue(run_once_value_names_->completion_time,
408 &completion_time, &size, NULL) == ERROR_SUCCESS &&
409 size == sizeof(completion_time)) {
410 is_complete = true;
414 return is_complete;
417 // Returns the path to the IE9 Approved Extensions key for Chrome Frame.
418 // static
419 string16 ModernIEConfigurator::GetChromeFrameBHOCLSID() {
420 string16 bho_guid(39, L'\0');
421 int guid_len = StringFromGUID2(CLSID_ChromeFrameBHO, &bho_guid[0],
422 bho_guid.size());
423 DCHECK_EQ(guid_len, static_cast<int>(bho_guid.size()));
424 bho_guid.resize(guid_len - 1);
425 return bho_guid;
428 // Returns true if the add-on enablement prompt is disabled by Group Policy.
429 // static
430 bool ModernIEConfigurator::IsAddonPromptDisabledForChromeFrame() {
431 bool is_disabled = false;
432 base::win::RegKey key;
434 // See if the prompt is disabled for this user of IE.
435 if (key.Open(HKEY_CURRENT_USER, kKeyIEApprovedExtensions,
436 KEY_QUERY_VALUE) == ERROR_SUCCESS) {
437 DWORD type = REG_NONE;
438 DWORD size = 0;
439 if (key.ReadValue(GetChromeFrameBHOCLSID().c_str(), NULL, &size,
440 &type) == ERROR_SUCCESS &&
441 type == REG_BINARY) {
442 is_disabled = true;
446 // Now check if the prompt is disabled for all add-ons via Group Policy.
447 if (!is_disabled &&
448 key.Open(HKEY_LOCAL_MACHINE, kKeyPoliciesExt,
449 KEY_QUERY_VALUE) == ERROR_SUCCESS) {
450 DWORD ignore = 0;
451 if (key.ReadValueDW(kValueIgnoreFrameApprovalCheck,
452 &ignore) == ERROR_SUCCESS &&
453 ignore != 0) {
454 is_disabled = true;
458 return is_disabled;
461 void ModernIEConfigurator::Initialize() {
462 // Check for per-user IE setup.
463 if (!IsPerUserSetupComplete()) {
464 const HKEY root = HKEY_CURRENT_USER;
465 // Suppress the "Set up Internet Explorer" dialog.
466 setter_.AddDWORDValue(root, kKeyIEMain, run_once_value_names_->completed,
468 setter_.AddFILETIMEValue(root, kKeyIEMain,
469 run_once_value_names_->completion_time,
470 base::Time::Now().ToFileTime());
471 if (ie_version_ == IE_9) {
472 setter_.AddDWORDValue(root, kKeyIEMain, kValueIE9LastShown, 1);
473 // Don't show a tour of IE 9.
474 setter_.AddDWORDValue(root, kKeyIEMain, kValueIE9TourNoShow, 1);
476 // Turn off the phishing filter.
477 setter_.AddDWORDValue(root, kKeyIEPhishingFilter, kValueEnabledV9, 0);
478 // Don't download compatibility view lists.
479 setter_.AddDWORDValue(root, kKeyIEBrowserEmulation,
480 kValueMSCompatibilityMode, 0);
483 // Turn off the "'Foo' add-on from 'Bar' is ready for use." prompt via Group
484 // Policy.
485 if (!IsAddonPromptDisabledForChromeFrame()) {
486 setter_.AddDWORDValue(HKEY_LOCAL_MACHINE, kKeyPoliciesExt,
487 kValueIgnoreFrameApprovalCheck, 1);
491 void ModernIEConfigurator::ApplySettings() {
492 setter_.Apply();
495 void ModernIEConfigurator::RevertSettings() {
496 setter_.Revert();
499 } // namespace
501 // Configurator implementation.
503 IEConfigurator::IEConfigurator() {
506 IEConfigurator::~IEConfigurator() {
509 IEConfigurator* CreateConfigurator() {
510 IEConfigurator* configurator = NULL;
512 IEVersion ie_version = GetInstalledIEVersion();
513 switch (ie_version) {
514 case IE_7:
515 configurator = new IE7Configurator();
516 break;
517 case IE_9:
518 case IE_10:
519 configurator = new ModernIEConfigurator(ie_version);
520 break;
521 default:
522 break;
525 return configurator;
528 void InstallIEConfigurator() {
529 IEConfigurator* configurator = CreateConfigurator();
531 if (configurator != NULL) {
532 testing::UnitTest::GetInstance()->listeners().Append(
533 new ConfiguratorDriver(configurator));
537 } // namespace chrome_frame_test