1// Copyright (c) 2013 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// The order of these includes is important.
6#include <windows.h>
7#include <unknwn.h>
8#include <intshcut.h>
9#include <propvarutil.h>
10#include <shlguid.h>
11#include <shlobj.h>
12#include <urlhist.h>
13
14#include <algorithm>
15#include <vector>
16
17#include "base/bind.h"
18#include "base/compiler_specific.h"
19#include "base/file_util.h"
20#include "base/files/scoped_temp_dir.h"
21#include "base/message_loop/message_loop.h"
22#include "base/path_service.h"
23#include "base/stl_util.h"
24#include "base/strings/string16.h"
25#include "base/strings/string_util.h"
26#include "base/strings/utf_string_conversions.h"
27#include "base/win/registry.h"
28#include "base/win/scoped_comptr.h"
29#include "base/win/scoped_propvariant.h"
30#include "base/win/windows_version.h"
31#include "chrome/browser/importer/external_process_importer_host.h"
32#include "chrome/browser/importer/importer_progress_observer.h"
33#include "chrome/browser/importer/importer_unittest_utils.h"
34#include "chrome/browser/search_engines/template_url.h"
35#include "chrome/browser/ui/browser.h"
36#include "chrome/common/chrome_paths.h"
37#include "chrome/common/importer/ie_importer_test_registry_overrider_win.h"
38#include "chrome/common/importer/ie_importer_utils_win.h"
39#include "chrome/common/importer/imported_bookmark_entry.h"
40#include "chrome/common/importer/imported_favicon_usage.h"
41#include "chrome/common/importer/importer_bridge.h"
42#include "chrome/common/importer/importer_data_types.h"
43#include "chrome/common/importer/pstore_declarations.h"
44#include "chrome/test/base/in_process_browser_test.h"
45#include "chrome/test/base/testing_profile.h"
46#include "components/autofill/core/common/password_form.h"
47#include "components/webdata/encryptor/ie7_password_win.h"
48#include "testing/gtest/include/gtest/gtest.h"
49
50namespace {
51
52const BookmarkInfo kIEBookmarks[] = {
53  {true, 2, {L"Links", L"SubFolderOfLinks"},
54   L"SubLink",
55   "http://www.links-sublink.com/"},
56  {true, 1, {L"Links"},
57   L"TheLink",
58   "http://www.links-thelink.com/"},
59  {false, 0, {},
60   L"Google Home Page",
61   "http://www.google.com/"},
62  {false, 0, {},
63   L"TheLink",
64   "http://www.links-thelink.com/"},
65  {false, 1, {L"SubFolder"},
66   L"Title",
67   "http://www.link.com/"},
68  {false, 0, {},
69   L"WithPortAndQuery",
70   "http://host:8080/cgi?q=query"},
71  {false, 1, {L"a"},
72   L"\x4E2D\x6587",
73   "http://chinese-title-favorite/"},
74  {false, 0, {},
75   L"SubFolder",
76   "http://www.subfolder.com/"},
77};
78
79const BookmarkInfo kIESortedBookmarks[] = {
80  {false, 0, {}, L"a", "http://www.google.com/0"},
81  {false, 1, {L"b"}, L"a", "http://www.google.com/1"},
82  {false, 1, {L"b"}, L"b", "http://www.google.com/2"},
83  {false, 0, {}, L"c", "http://www.google.com/3"},
84};
85
86const char16 kIEIdentifyUrl[] =
87    L"http://A79029D6-753E-4e27-B807-3D46AB1545DF.com:8080/path?key=value";
88const char16 kIEIdentifyTitle[] =
89    L"Unittest GUID";
90
91const char16 kFaviconStreamSuffix[] = L"url:favicon:$DATA";
92const char kDummyFaviconImageData[] =
93    "\x42\x4D"          // Magic signature 'BM'
94    "\x1E\x00\x00\x00"  // File size
95    "\x00\x00\x00\x00"  // Reserved
96    "\x1A\x00\x00\x00"  // Offset of the pixel data
97    "\x0C\x00\x00\x00"  // Header Size
98    "\x01\x00\x01\x00"  // Size: 1x1
99    "\x01\x00"          // Reserved
100    "\x18\x00"          // 24-bits
101    "\x00\xFF\x00\x00"; // The pixel
102
103struct FaviconGroup {
104  const char16* favicon_url;
105  const char16* site_url[2];
106};
107
108const FaviconGroup kIEFaviconGroup[2] = {
109  {L"http://www.google.com/favicon.ico",
110   {L"http://www.google.com/",
111    L"http://www.subfolder.com/"}},
112  {L"http://example.com/favicon.ico",
113   {L"http://host:8080/cgi?q=query",
114    L"http://chinese-title-favorite/"}},
115};
116
117bool CreateOrderBlob(const base::FilePath& favorites_folder,
118                     const base::string16& path,
119                     const std::vector<base::string16>& entries) {
120  if (entries.size() > 255)
121    return false;
122
123  // Create a binary sequence for setting a specific order of favorites.
124  // The format depends on the version of Shell32.dll, so we cannot embed
125  // a binary constant here.
126  std::vector<uint8> blob(20, 0);
127  blob[16] = static_cast<uint8>(entries.size());
128
129  for (size_t i = 0; i < entries.size(); ++i) {
130    PIDLIST_ABSOLUTE id_list_full = ILCreateFromPath(
131        favorites_folder.Append(path).Append(entries[i]).value().c_str());
132    PUITEMID_CHILD id_list = ILFindLastID(id_list_full);
133    // Include the trailing zero-length item id.  Don't include the single
134    // element array.
135    size_t id_list_size = id_list->mkid.cb + sizeof(id_list->mkid.cb);
136
137    blob.resize(blob.size() + 8);
138    uint32 total_size = id_list_size + 8;
139    memcpy(&blob[blob.size() - 8], &total_size, 4);
140    uint32 sort_index = i;
141    memcpy(&blob[blob.size() - 4], &sort_index, 4);
142    blob.resize(blob.size() + id_list_size);
143    memcpy(&blob[blob.size() - id_list_size], id_list, id_list_size);
144    ILFree(id_list_full);
145  }
146
147  base::string16 key_path(importer::GetIEFavoritesOrderKey());
148  if (!path.empty())
149    key_path += L"\\" + path;
150  base::win::RegKey key;
151  if (key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE) !=
152      ERROR_SUCCESS) {
153    return false;
154  }
155  if (key.WriteValue(L"Order", &blob[0], blob.size(), REG_BINARY) !=
156      ERROR_SUCCESS) {
157    return false;
158  }
159  return true;
160}
161
162bool CreateUrlFileWithFavicon(const base::FilePath& file,
163                              const base::string16& url,
164                              const base::string16& favicon_url) {
165  base::win::ScopedComPtr<IUniformResourceLocator> locator;
166  HRESULT result = locator.CreateInstance(CLSID_InternetShortcut, NULL,
167                                          CLSCTX_INPROC_SERVER);
168  if (FAILED(result))
169    return false;
170  base::win::ScopedComPtr<IPersistFile> persist_file;
171  result = persist_file.QueryFrom(locator);
172  if (FAILED(result))
173    return false;
174  result = locator->SetURL(url.c_str(), 0);
175  if (FAILED(result))
176    return false;
177
178  // Write favicon url if specified.
179  if (!favicon_url.empty()) {
180    base::win::ScopedComPtr<IPropertySetStorage> property_set_storage;
181    if (FAILED(property_set_storage.QueryFrom(locator)))
182      return false;
183    base::win::ScopedComPtr<IPropertyStorage> property_storage;
184    if (FAILED(property_set_storage->Open(FMTID_Intshcut,
185                                          STGM_WRITE,
186                                          property_storage.Receive()))) {
187      return false;
188    }
189    PROPSPEC properties[] = {{PRSPEC_PROPID, PID_IS_ICONFILE}};
190    // WriteMultiple takes an array of PROPVARIANTs, but since this code only
191    // needs an array of size 1: a pointer to |pv_icon| is equivalent.
192    base::win::ScopedPropVariant pv_icon;
193    if (FAILED(InitPropVariantFromString(favicon_url.c_str(),
194                                         pv_icon.Receive())) ||
195        FAILED(property_storage->WriteMultiple(1, properties, &pv_icon, 0))) {
196      return false;
197    }
198  }
199
200  // Save the .url file.
201  result = persist_file->Save(file.value().c_str(), TRUE);
202  if (FAILED(result))
203    return false;
204
205  // Write dummy favicon image data in NTFS alternate data stream.
206  return favicon_url.empty() || (file_util::WriteFile(
207      file.ReplaceExtension(kFaviconStreamSuffix), kDummyFaviconImageData,
208      sizeof kDummyFaviconImageData) != -1);
209}
210
211bool CreateUrlFile(const base::FilePath& file, const base::string16& url) {
212  return CreateUrlFileWithFavicon(file, url, base::string16());
213}
214
215void ClearPStoreType(IPStore* pstore, const GUID* type, const GUID* subtype) {
216  base::win::ScopedComPtr<IEnumPStoreItems, NULL> item;
217  HRESULT result = pstore->EnumItems(0, type, subtype, 0, item.Receive());
218  if (result == PST_E_OK) {
219    char16* item_name;
220    while (SUCCEEDED(item->Next(1, &item_name, 0))) {
221      pstore->DeleteItem(0, type, subtype, item_name, NULL, 0);
222      CoTaskMemFree(item_name);
223    }
224  }
225  pstore->DeleteSubtype(0, type, subtype, 0);
226  pstore->DeleteType(0, type, 0);
227}
228
229void WritePStore(IPStore* pstore, const GUID* type, const GUID* subtype) {
230  struct PStoreItem {
231    char16* name;
232    int data_size;
233    char* data;
234  } items[] = {
235    {L"http://localhost:8080/security/index.htm#ref:StringData", 8,
236     "\x31\x00\x00\x00\x32\x00\x00\x00"},
237    {L"http://localhost:8080/security/index.htm#ref:StringIndex", 20,
238     "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00"
239     "\x00\x00\x2f\x00\x74\x00\x01\x00\x00\x00"},
240    {L"user:StringData", 4,
241     "\x31\x00\x00\x00"},
242    {L"user:StringIndex", 20,
243     "\x57\x49\x43\x4b\x18\x00\x00\x00\x01\x00"
244     "\x00\x00\x2f\x00\x74\x00\x00\x00\x00\x00"},
245  };
246
247  for (int i = 0; i < arraysize(items); ++i) {
248    HRESULT res = pstore->WriteItem(0, type, subtype, items[i].name,
249        items[i].data_size, reinterpret_cast<BYTE*>(items[i].data),
250        NULL, 0, 0);
251    ASSERT_TRUE(res == PST_E_OK);
252  }
253}
254
255class TestObserver : public ProfileWriter,
256                     public importer::ImporterProgressObserver {
257 public:
258  enum TestIEVersion {
259    IE6,
260    IE7,
261  };
262
263  explicit TestObserver(uint16 importer_items, TestIEVersion ie_version)
264      : ProfileWriter(NULL),
265        bookmark_count_(0),
266        history_count_(0),
267        password_count_(0),
268        favicon_count_(0),
269        homepage_count_(0),
270        ie7_password_count_(0),
271        importer_items_(importer_items),
272        ie_version_(ie_version) {
273  }
274
275  // importer::ImporterProgressObserver:
276  virtual void ImportStarted() OVERRIDE {}
277  virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
278  virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
279  virtual void ImportEnded() OVERRIDE {
280    base::MessageLoop::current()->Quit();
281    if (importer_items_ & importer::FAVORITES) {
282      EXPECT_EQ(arraysize(kIEBookmarks), bookmark_count_);
283      EXPECT_EQ(arraysize(kIEFaviconGroup), favicon_count_);
284    }
285    if (importer_items_ & importer::HISTORY)
286      EXPECT_EQ(1, history_count_);
287    if (importer_items_ & importer::HOME_PAGE)
288      EXPECT_EQ(1, homepage_count_);
289    if ((importer_items_ & importer::PASSWORDS) && (ie_version_ == IE7))
290      EXPECT_EQ(1, ie7_password_count_);
291    // We need to test the IE6 password importer code.
292    // https://crbug.com/257100
293    // EXPECT_EQ(1, password_count_);
294  }
295
296  virtual bool BookmarkModelIsLoaded() const {
297    // Profile is ready for writing.
298    return true;
299  }
300
301  virtual bool TemplateURLServiceIsLoaded() const {
302    return true;
303  }
304
305  virtual void AddPasswordForm(const autofill::PasswordForm& form) {
306    // Importer should obtain this password form only.
307    EXPECT_EQ(GURL("http://localhost:8080/security/index.htm"), form.origin);
308    EXPECT_EQ("http://localhost:8080/", form.signon_realm);
309    EXPECT_EQ(L"user", form.username_element);
310    EXPECT_EQ(L"1", form.username_value);
311    EXPECT_EQ(L"", form.password_element);
312    EXPECT_EQ(L"2", form.password_value);
313    EXPECT_EQ("", form.action.spec());
314    ++password_count_;
315  }
316
317  virtual void AddHistoryPage(const history::URLRows& page,
318                              history::VisitSource visit_source) {
319    // Importer should read the specified URL.
320    for (size_t i = 0; i < page.size(); ++i) {
321      if (page[i].title() == kIEIdentifyTitle &&
322          page[i].url() == GURL(kIEIdentifyUrl))
323        ++history_count_;
324    }
325    EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_source);
326  }
327
328  virtual void AddBookmarks(
329      const std::vector<ImportedBookmarkEntry>& bookmarks,
330      const base::string16& top_level_folder_name) OVERRIDE {
331    ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kIEBookmarks));
332    // Importer should import the IE Favorites folder the same as the list,
333    // in the same order.
334    for (size_t i = 0; i < bookmarks.size(); ++i) {
335      EXPECT_NO_FATAL_FAILURE(
336          TestEqualBookmarkEntry(bookmarks[i],
337                                 kIEBookmarks[bookmark_count_])) << i;
338      ++bookmark_count_;
339    }
340  }
341
342  virtual void AddKeyword(std::vector<TemplateURL*> template_url,
343                          int default_keyword_index) {
344    // TODO(jcampan): bug 1169230: we should test keyword importing for IE.
345    // In order to do that we'll probably need to mock the Windows registry.
346    NOTREACHED();
347    STLDeleteContainerPointers(template_url.begin(), template_url.end());
348  }
349
350  virtual void AddFavicons(
351      const std::vector<ImportedFaviconUsage>& usage) OVERRIDE {
352    // Importer should group the favicon information for each favicon URL.
353    for (size_t i = 0; i < arraysize(kIEFaviconGroup); ++i) {
354      GURL favicon_url(kIEFaviconGroup[i].favicon_url);
355      std::set<GURL> urls;
356      for (size_t j = 0; j < arraysize(kIEFaviconGroup[i].site_url); ++j)
357        urls.insert(GURL(kIEFaviconGroup[i].site_url[j]));
358
359      SCOPED_TRACE(testing::Message() << "Expected Favicon: " << favicon_url);
360
361      bool expected_favicon_url_found = false;
362      for (size_t j = 0; j < usage.size(); ++j) {
363        if (usage[j].favicon_url == favicon_url) {
364          EXPECT_EQ(urls, usage[j].urls);
365          expected_favicon_url_found = true;
366          break;
367        }
368      }
369      EXPECT_TRUE(expected_favicon_url_found);
370    }
371
372    favicon_count_ += usage.size();
373  }
374
375  virtual void AddIE7PasswordInfo(const IE7PasswordInfo& info) {
376    // This function also gets called for the IEImporter test. Ignore.
377    if (ie_version_ == IE7) {
378      EXPECT_EQ(L"Test1", info.url_hash);
379      EXPECT_EQ(1, info.encrypted_data[0]);
380      EXPECT_EQ(4, info.encrypted_data.size());
381      ++ie7_password_count_;
382    }
383  }
384
385  virtual void AddHomepage(const GURL& homepage) {
386    EXPECT_EQ(homepage.spec(), "http://www.test.com/");
387    ++homepage_count_;
388  }
389
390 private:
391  ~TestObserver() {}
392
393  size_t bookmark_count_;
394  size_t history_count_;
395  size_t password_count_;
396  size_t favicon_count_;
397  size_t homepage_count_;
398  size_t ie7_password_count_;
399  uint16 importer_items_;
400  TestIEVersion ie_version_;
401};
402
403class MalformedFavoritesRegistryTestObserver
404    : public ProfileWriter,
405      public importer::ImporterProgressObserver {
406 public:
407  MalformedFavoritesRegistryTestObserver() : ProfileWriter(NULL) {
408    bookmark_count_ = 0;
409  }
410
411  // importer::ImporterProgressObserver:
412  virtual void ImportStarted() OVERRIDE {}
413  virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
414  virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
415  virtual void ImportEnded() OVERRIDE {
416    base::MessageLoop::current()->Quit();
417    EXPECT_EQ(arraysize(kIESortedBookmarks), bookmark_count_);
418  }
419
420  virtual bool BookmarkModelIsLoaded() const { return true; }
421  virtual bool TemplateURLServiceIsLoaded() const { return true; }
422
423  virtual void AddPasswordForm(const autofill::PasswordForm& form) {}
424  virtual void AddHistoryPage(const history::URLRows& page,
425                              history::VisitSource visit_source) {}
426  virtual void AddKeyword(std::vector<TemplateURL*> template_url,
427                          int default_keyword_index) {}
428  virtual void AddBookmarks(
429      const std::vector<ImportedBookmarkEntry>& bookmarks,
430      const base::string16& top_level_folder_name) OVERRIDE {
431    ASSERT_LE(bookmark_count_ + bookmarks.size(),
432              arraysize(kIESortedBookmarks));
433    for (size_t i = 0; i < bookmarks.size(); ++i) {
434      EXPECT_NO_FATAL_FAILURE(
435          TestEqualBookmarkEntry(bookmarks[i],
436                                 kIESortedBookmarks[bookmark_count_])) << i;
437      ++bookmark_count_;
438    }
439  }
440
441 private:
442  ~MalformedFavoritesRegistryTestObserver() {}
443
444  size_t bookmark_count_;
445};
446
447}  // namespace
448
449// These tests need to be browser tests in order to be able to run the OOP
450// import (via ExternalProcessImporterHost) which launches a utility process.
451class IEImporterBrowserTest : public InProcessBrowserTest {
452 protected:
453  virtual void SetUp() OVERRIDE {
454    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
455
456    // This will launch the browser test and thus needs to happen last.
457    InProcessBrowserTest::SetUp();
458  }
459
460  base::ScopedTempDir temp_dir_;
461
462  // Overrides the default registry key for IE registry keys like favorites,
463  // settings, password store, etc.
464  IEImporterTestRegistryOverrider test_registry_overrider_;
465};
466
467IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest, IEImporter) {
468  // Sets up a favorites folder.
469  base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
470  CreateDirectory(path.value().c_str(), NULL);
471  CreateDirectory(path.AppendASCII("SubFolder").value().c_str(), NULL);
472  base::FilePath links_path = path.AppendASCII("Links");
473  CreateDirectory(links_path.value().c_str(), NULL);
474  CreateDirectory(links_path.AppendASCII("SubFolderOfLinks").value().c_str(),
475                  NULL);
476  CreateDirectory(path.AppendASCII("\x0061").value().c_str(), NULL);
477  ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("Google Home Page.url"),
478                                       L"http://www.google.com/",
479                                       L"http://www.google.com/favicon.ico"));
480  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("SubFolder\\Title.url"),
481                            L"http://www.link.com/"));
482  ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("SubFolder.url"),
483                                       L"http://www.subfolder.com/",
484                                       L"http://www.google.com/favicon.ico"));
485  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("TheLink.url"),
486                            L"http://www.links-thelink.com/"));
487  ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("WithPortAndQuery.url"),
488                                       L"http://host:8080/cgi?q=query",
489                                       L"http://example.com/favicon.ico"));
490  ASSERT_TRUE(CreateUrlFileWithFavicon(
491      path.AppendASCII("\x0061").Append(L"\x4E2D\x6587.url"),
492      L"http://chinese-title-favorite/",
493      L"http://example.com/favicon.ico"));
494  ASSERT_TRUE(CreateUrlFile(links_path.AppendASCII("TheLink.url"),
495                            L"http://www.links-thelink.com/"));
496  ASSERT_TRUE(CreateUrlFile(
497      links_path.AppendASCII("SubFolderOfLinks").AppendASCII("SubLink.url"),
498      L"http://www.links-sublink.com/"));
499  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("IEDefaultLink.url"),
500                            L"http://go.microsoft.com/fwlink/?linkid=140813"));
501  file_util::WriteFile(path.AppendASCII("InvalidUrlFile.url"), "x", 1);
502  file_util::WriteFile(path.AppendASCII("PlainTextFile.txt"), "x", 1);
503
504  const char16* root_links[] = {
505    L"Links",
506    L"Google Home Page.url",
507    L"TheLink.url",
508    L"SubFolder",
509    L"WithPortAndQuery.url",
510    L"a",
511    L"SubFolder.url",
512  };
513  ASSERT_TRUE(CreateOrderBlob(
514      base::FilePath(path), L"",
515      std::vector<base::string16>(root_links,
516                                  root_links + arraysize(root_links))));
517
518  HRESULT res;
519
520  // Sets up a special history link.
521  base::win::ScopedComPtr<IUrlHistoryStg2> url_history_stg2;
522  res = url_history_stg2.CreateInstance(CLSID_CUrlHistory, NULL,
523                                        CLSCTX_INPROC_SERVER);
524  ASSERT_TRUE(res == S_OK);
525  res = url_history_stg2->AddUrl(kIEIdentifyUrl, kIEIdentifyTitle, 0);
526  ASSERT_TRUE(res == S_OK);
527
528  // Starts to import the above settings.
529  // Deletes itself.
530  ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
531  TestObserver* observer = new TestObserver(
532      importer::HISTORY | importer::PASSWORDS | importer::FAVORITES,
533      TestObserver::IE6);
534  host->set_observer(observer);
535
536  importer::SourceProfile source_profile;
537  source_profile.importer_type = importer::TYPE_IE;
538  source_profile.source_path = temp_dir_.path();
539
540  host->StartImportSettings(
541      source_profile,
542      browser()->profile(),
543      importer::HISTORY | importer::PASSWORDS | importer::FAVORITES,
544      observer);
545  base::MessageLoop::current()->Run();
546
547  // Cleans up.
548  url_history_stg2->DeleteUrl(kIEIdentifyUrl, 0);
549  url_history_stg2.Release();
550}
551
552IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest,
553                       IEImporterMalformedFavoritesRegistry) {
554  // Sets up a favorites folder.
555  base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
556  CreateDirectory(path.value().c_str(), NULL);
557  CreateDirectory(path.AppendASCII("b").value().c_str(), NULL);
558  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("a.url"),
559                            L"http://www.google.com/0"));
560  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("a.url"),
561                            L"http://www.google.com/1"));
562  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("b.url"),
563                            L"http://www.google.com/2"));
564  ASSERT_TRUE(CreateUrlFile(path.AppendASCII("c.url"),
565                            L"http://www.google.com/3"));
566
567  struct BadBinaryData {
568    const char* data;
569    int length;
570  };
571  static const BadBinaryData kBadBinary[] = {
572    // number_of_items field is truncated
573    {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
574     "\x00\xff\xff\xff", 17},
575    // number_of_items = 0xffff, but the byte sequence is too short.
576    {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
577     "\xff\xff\x00\x00", 20},
578    // number_of_items = 1, size_of_item is too big.
579    {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
580     "\x01\x00\x00\x00"
581     "\xff\xff\x00\x00\x00\x00\x00\x00"
582     "\x00\x00\x00\x00", 32},
583    // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
584    {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
585     "\x01\x00\x00\x00"
586     "\x10\x00\x00\x00\x00\x00\x00\x00"
587     "\xff\x7f\x00\x00" "\x00\x00\x00\x00", 36},
588    // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
589    {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
590     "\x01\x00\x00\x00"
591     "\x10\x00\x00\x00\x00\x00\x00\x00"
592     "\x06\x00\x00\x00" "\x00\x00\x00\x00", 36},
593  };
594
595  // Verify malformed registry data are safely ignored and alphabetical
596  // sort is performed.
597  for (size_t i = 0; i < arraysize(kBadBinary); ++i) {
598    base::string16 key_path(importer::GetIEFavoritesOrderKey());
599    base::win::RegKey key;
600    ASSERT_EQ(ERROR_SUCCESS,
601              key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE));
602    ASSERT_EQ(ERROR_SUCCESS,
603              key.WriteValue(L"Order", kBadBinary[i].data, kBadBinary[i].length,
604                             REG_BINARY));
605
606    // Starts to import the above settings.
607    // Deletes itself.
608    ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
609    MalformedFavoritesRegistryTestObserver* observer =
610        new MalformedFavoritesRegistryTestObserver();
611    host->set_observer(observer);
612
613    importer::SourceProfile source_profile;
614    source_profile.importer_type = importer::TYPE_IE;
615    source_profile.source_path = temp_dir_.path();
616
617    host->StartImportSettings(
618        source_profile,
619        browser()->profile(),
620        importer::FAVORITES,
621        observer);
622    base::MessageLoop::current()->Run();
623  }
624}
625
626IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest, IE7ImporterPasswordsTest) {
627  // Starts to import the IE7 passwords.
628  // Deletes itself.
629  ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
630  TestObserver* observer = new TestObserver(importer::PASSWORDS,
631                                            TestObserver::IE7);
632  host->set_observer(observer);
633
634  base::string16 key_path(importer::GetIE7PasswordsKey());
635  base::win::RegKey key;
636  ASSERT_EQ(ERROR_SUCCESS,
637            key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE));
638  key.WriteValue(L"Test1", 1);
639
640  importer::SourceProfile source_profile;
641  source_profile.importer_type = importer::TYPE_IE;
642  source_profile.source_path = temp_dir_.path();
643
644  host->StartImportSettings(
645      source_profile,
646      browser()->profile(),
647      importer::PASSWORDS,
648      observer);
649  base::MessageLoop::current()->Run();
650}
651
652IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest, IEImporterHomePageTest) {
653  // Starts to import the IE home page.
654  // Deletes itself.
655  ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
656  TestObserver* observer = new TestObserver(importer::HOME_PAGE,
657                                            TestObserver::IE6);
658  host->set_observer(observer);
659
660  base::string16 key_path(importer::GetIESettingsKey());
661  base::win::RegKey key;
662  ASSERT_EQ(ERROR_SUCCESS,
663            key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE));
664  key.WriteValue(L"Start Page", L"http://www.test.com/");
665
666  importer::SourceProfile source_profile;
667  source_profile.importer_type = importer::TYPE_IE;
668  source_profile.source_path = temp_dir_.path();
669
670  host->StartImportSettings(
671      source_profile,
672      browser()->profile(),
673      importer::HOME_PAGE,
674      observer);
675  base::MessageLoop::current()->Run();
676}
677
678