diff options
-rw-r--r-- | chrome/browser/search_engines/keyword_editor_controller_unittest.cc | 35 | ||||
-rw-r--r-- | chrome/browser/search_engines/search_host_to_urls_map.cc | 204 | ||||
-rw-r--r-- | chrome/browser/search_engines/search_host_to_urls_map.h | 110 | ||||
-rw-r--r-- | chrome/browser/search_engines/search_host_to_urls_map_unittest.cc | 160 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url.h | 4 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_model.cc | 164 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_model.h | 16 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_model_unittest.cc | 15 | ||||
-rw-r--r-- | chrome/browser/search_engines/util.cc | 3 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 |
11 files changed, 600 insertions, 114 deletions
diff --git a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc index 3670b05..18a0abd 100644 --- a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc +++ b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,17 +16,11 @@ class KeywordEditorControllerTest : public testing::Test, public TableModelObserver { public: - virtual void SetUp() { - model_changed_count_ = items_changed_count_ = added_count_ = - removed_count_ = 0; + // Initializes all of the state. + void Init(bool simulate_load_failure); - profile_.reset(new TestingProfile()); - profile_->CreateTemplateURLModel(); - - model_ = profile_->GetTemplateURLModel(); - - controller_.reset(new KeywordEditorController(profile_.get())); - controller_->table_model()->SetObserver(this); + virtual void SetUp() { + Init(false); } virtual void OnModelChanged() { @@ -75,6 +69,23 @@ class KeywordEditorControllerTest : public testing::Test, int removed_count_; }; +void KeywordEditorControllerTest::Init(bool simulate_load_failure) { + ClearChangeCount(); + + // If init is called twice, make sure that the controller is destroyed before + // the profile is. + controller_.reset(); + profile_.reset(new TestingProfile()); + profile_->CreateTemplateURLModel(); + + model_ = profile_->GetTemplateURLModel(); + if (simulate_load_failure) + model_->OnWebDataServiceRequestDone(NULL, NULL); + + controller_.reset(new KeywordEditorController(profile_.get())); + controller_->table_model()->SetObserver(this); +} + // Tests adding a TemplateURL. TEST_F(KeywordEditorControllerTest, Add) { controller_->AddTemplateURL(L"a", L"b", "http://c"); @@ -136,7 +147,7 @@ TEST_F(KeywordEditorControllerTest, MakeDefault) { TEST_F(KeywordEditorControllerTest, MakeDefaultNoWebData) { // Simulate a failure to load Web Data. - model_->OnWebDataServiceRequestDone(NULL, NULL); + Init(true); controller_->AddTemplateURL(L"a", L"b", "http://c{searchTerms}"); ClearChangeCount(); diff --git a/chrome/browser/search_engines/search_host_to_urls_map.cc b/chrome/browser/search_engines/search_host_to_urls_map.cc new file mode 100644 index 0000000..ea24c72 --- /dev/null +++ b/chrome/browser/search_engines/search_host_to_urls_map.cc @@ -0,0 +1,204 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/search_engines/search_host_to_urls_map.h" + +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" + +SearchHostToURLsMap::SearchHostToURLsMap() + : initialized_(false) { +} + +void SearchHostToURLsMap::Init( + const std::vector<const TemplateURL*>& template_urls, + const TemplateURL* default_search_provider) { + DCHECK(CalledOnValidThread()); + DCHECK(!initialized_); + { + AutoLock locker(lock_); + for (size_t i = 0; i < template_urls.size(); ++i) { + AddNoLock(template_urls[i]); + } + SetDefaultNoLock(default_search_provider); + } + // Wait to set initialized until the lock is let go, which should force a + // memory write flush. + initialized_ = true; +} + +void SearchHostToURLsMap::Add(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + DCHECK(template_url); + + AutoLock locker(lock_); + AddNoLock(template_url); +} + +void SearchHostToURLsMap::Remove(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + DCHECK(template_url); + + AutoLock locker(lock_); + RemoveNoLock(template_url); +} + +void SearchHostToURLsMap::Update(const TemplateURL* existing_turl, + const TemplateURL& new_values) { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + DCHECK(existing_turl); + + AutoLock locker(lock_); + + RemoveNoLock(existing_turl); + + // Use the information from new_values but preserve existing_turl's id. + TemplateURL::IDType previous_id = existing_turl->id(); + TemplateURL* modifiable_turl = const_cast<TemplateURL*>(existing_turl); + *modifiable_turl = new_values; + modifiable_turl->set_id(previous_id); + + AddNoLock(existing_turl); +} + +void SearchHostToURLsMap::RemoveAll() { + DCHECK(CalledOnValidThread()); + + AutoLock locker(lock_); + host_to_urls_map_.clear(); +} + +void SearchHostToURLsMap::UpdateGoogleBaseURLs() { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + + AutoLock locker(lock_); + + // Create a list of the the TemplateURLs to update. + std::vector<const TemplateURL*> t_urls_using_base_url; + for (HostToURLsMap::iterator host_map_iterator = host_to_urls_map_.begin(); + host_map_iterator != host_to_urls_map_.end(); ++host_map_iterator) { + const TemplateURLSet& urls = host_map_iterator->second; + for (TemplateURLSet::const_iterator url_set_iterator = urls.begin(); + url_set_iterator != urls.end(); ++url_set_iterator) { + const TemplateURL* t_url = *url_set_iterator; + if ((t_url->url() && t_url->url()->HasGoogleBaseURLs()) || + (t_url->suggestions_url() && + t_url->suggestions_url()->HasGoogleBaseURLs())) { + t_urls_using_base_url.push_back(t_url); + } + } + } + + for (size_t i = 0; i < t_urls_using_base_url.size(); ++i) + RemoveByPointerNoLock(t_urls_using_base_url[i]); + + for (size_t i = 0; i < t_urls_using_base_url.size(); ++i) + AddNoLock(t_urls_using_base_url[i]); +} + +void SearchHostToURLsMap::SetDefault(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + + AutoLock locker(lock_); + SetDefaultNoLock(template_url); +} + +const TemplateURL* SearchHostToURLsMap::GetTemplateURLForHost( + const std::string& host) const { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + + HostToURLsMap::const_iterator iter = host_to_urls_map_.find(host); + if (iter == host_to_urls_map_.end() || iter->second.empty()) + return NULL; + return *(iter->second.begin()); // Return the 1st element. +} + +const SearchHostToURLsMap::TemplateURLSet* SearchHostToURLsMap::GetURLsForHost( + const std::string& host) const { + DCHECK(CalledOnValidThread()); + DCHECK(initialized_); + + HostToURLsMap::const_iterator urls_for_host = host_to_urls_map_.find(host); + if (urls_for_host == host_to_urls_map_.end() || urls_for_host->second.empty()) + return NULL; + return &urls_for_host->second; +} + +SearchHostToURLsMap::~SearchHostToURLsMap() { +} + +void SearchHostToURLsMap::AddNoLock(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + + lock_.AssertAcquired(); + const GURL url(TemplateURLModel::GenerateSearchURL(template_url)); + if (!url.is_valid() || !url.has_host()) + return; + + host_to_urls_map_[url.host()].insert(template_url); +} + +void SearchHostToURLsMap::RemoveNoLock(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + lock_.AssertAcquired(); + + const GURL url(TemplateURLModel::GenerateSearchURL(template_url)); + if (!url.is_valid() || !url.has_host()) + return; + + const std::string host(url.host()); + DCHECK(host_to_urls_map_.find(host) != host_to_urls_map_.end()); + + TemplateURLSet& urls = host_to_urls_map_[host]; + DCHECK(urls.find(template_url) != urls.end()); + + urls.erase(urls.find(template_url)); + if (urls.empty()) + host_to_urls_map_.erase(host_to_urls_map_.find(host)); +} + +void SearchHostToURLsMap::RemoveByPointerNoLock( + const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + lock_.AssertAcquired(); + + for (HostToURLsMap::iterator i = host_to_urls_map_.begin(); + i != host_to_urls_map_.end(); ++i) { + TemplateURLSet::iterator url_set_iterator = i->second.find(template_url); + if (url_set_iterator != i->second.end()) { + i->second.erase(url_set_iterator); + if (i->second.empty()) + host_to_urls_map_.erase(i); + // A given TemplateURL only occurs once in the map. As soon as we find the + // entry, stop. + return; + } + } +} + +void SearchHostToURLsMap::SetDefaultNoLock(const TemplateURL* template_url) { + DCHECK(CalledOnValidThread()); + lock_.AssertAcquired(); + + if (!template_url) { + default_search_origin_.clear(); + return; + } + + const GURL url(TemplateURLModel::GenerateSearchURL(template_url)); + if (!url.is_valid() || !url.has_host()) { + default_search_origin_.clear(); + return; + } + default_search_origin_ = url.GetOrigin().spec(); +} diff --git a/chrome/browser/search_engines/search_host_to_urls_map.h b/chrome/browser/search_engines/search_host_to_urls_map.h new file mode 100644 index 0000000..1a22ddc --- /dev/null +++ b/chrome/browser/search_engines/search_host_to_urls_map.h @@ -0,0 +1,110 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SEARCH_ENGINES_SEARCH_HOST_TO_URLS_MAP_H_ +#define CHROME_BROWSER_SEARCH_ENGINES_SEARCH_HOST_TO_URLS_MAP_H_ +#pragma once + +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/lock.h" +#include "base/thread_checker.h" +#include "base/ref_counted.h" + +class FilePath; +class GURL; +class Task; +class TemplateURL; +class WebDataService; + +// Holds the host to template url mappings for the search providers. All public +// methods should happen from the same thread except for +// GetSearchProviderInstallState which may be invoked on any thread. +// WARNING: This class does not own any TemplateURLs passed to it and it is +// up to the caller to ensure the right lifetime of them. +// TODO(levin): Add GetSearchProviderInstallState. +class SearchHostToURLsMap + : public base::RefCountedThreadSafe<SearchHostToURLsMap>, + public ThreadChecker { + public: + typedef std::set<const TemplateURL*> TemplateURLSet; + + SearchHostToURLsMap(); + + // Initializes the map. + void Init(const std::vector<const TemplateURL*>& template_urls, + const TemplateURL* default_search_provider); + + // Adds a new TemplateURL to the map. Since |template_url| is owned + // externally, Remove or RemoveAll should be called if it becomes invalid. + void Add(const TemplateURL* template_url); + + // Removes the TemplateURL from the lookup. + void Remove(const TemplateURL* template_url); + + // Removes all TemplateURLs. + void RemoveAll(); + + // Updates information in an existing TemplateURL. Note: Using Remove and + // then Add separately would lead to race conditions in reading because the + // lock would be released inbetween the calls. + void Update(const TemplateURL* existing_turl, const TemplateURL& new_values); + + // Updates all search providers which have a google base url. + void UpdateGoogleBaseURLs(); + + // Sets the default search provider. This method doesn't store a reference to + // the TemplateURL passed in. + void SetDefault(const TemplateURL* template_url); + + // Returns the first TemplateURL found with a URL using the specified |host|, + // or NULL if there are no such TemplateURLs + const TemplateURL* GetTemplateURLForHost(const std::string& host) const; + + // Return the TemplateURLSet for the given the |host| or NULL if there are + // none. + const TemplateURLSet* GetURLsForHost(const std::string& host) const; + + private: + friend class base::RefCountedThreadSafe<SearchHostToURLsMap>; + friend class SearchHostToURLsMapTest; + + typedef std::map<std::string, TemplateURLSet> HostToURLsMap; + + ~SearchHostToURLsMap(); + + // Same as Add but the lock should already be taken. + void AddNoLock(const TemplateURL* template_url); + + // Same as Remove but the lock should already be taken. + void RemoveNoLock(const TemplateURL* template_url); + + // Removes the given template_url using only the pointer instead of the value. + // This is useful when the value may have changed before being updated in the + // map. (Specifically when the GoogleBaseURLValue changes.) + void RemoveByPointerNoLock(const TemplateURL* template_url); + + // Same as SetDefaultNoLock but the lock should already be taken. + void SetDefaultNoLock(const TemplateURL* template_url); + + // Maps from host to set of TemplateURLs whose search url host is host. + HostToURLsMap host_to_urls_map_; + + // The security origin for the default search provider. + std::string default_search_origin_; + + // Has Init been called? + bool initialized_; + + // Used to guard writes from the UI thread and reads from other threads. + Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(SearchHostToURLsMap); +}; + +#endif // CHROME_BROWSER_SEARCH_ENGINES_SEARCH_HOST_TO_URLS_MAP_H_ diff --git a/chrome/browser/search_engines/search_host_to_urls_map_unittest.cc b/chrome/browser/search_engines/search_host_to_urls_map_unittest.cc new file mode 100644 index 0000000..f98fddb --- /dev/null +++ b/chrome/browser/search_engines/search_host_to_urls_map_unittest.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "chrome/browser/search_engines/search_host_to_urls_map.h" +#include "chrome/browser/search_engines/template_url.h" +#include "testing/gtest/include/gtest/gtest.h" + +typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet; + +// Basic functionality for the SearchHostToURLsMap tests. +class SearchHostToURLsMapTest : public testing::Test { + public: + SearchHostToURLsMapTest() {} + + virtual void SetUp(); + virtual void TearDown() { + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = NULL; + } + + protected: + void SetGoogleBaseURL(const std::string& base_url) const { + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = new std::string(base_url); + } + + void VerifyDefault(const std::string& origin) { + ASSERT_STREQ(origin.c_str(), provider_map_->default_search_origin_.c_str()); + } + + scoped_refptr<SearchHostToURLsMap> provider_map_; + TemplateURL t_urls_[2]; + std::string host_; + + DISALLOW_COPY_AND_ASSIGN(SearchHostToURLsMapTest); +}; + +void SearchHostToURLsMapTest::SetUp() { + // Add some entries to the search host map. + host_ = "www.unittest.com"; + t_urls_[0].SetURL("http://" + host_ + "/path1", 0, 0); + t_urls_[1].SetURL("http://" + host_ + "/path2", 0, 0); + + std::vector<const TemplateURL*> template_urls; + template_urls.push_back(&t_urls_[0]); + template_urls.push_back(&t_urls_[1]); + + provider_map_ = new SearchHostToURLsMap; + provider_map_->Init(template_urls, NULL); +} + +TEST_F(SearchHostToURLsMapTest, Add) { + std::string new_host = "example.com"; + TemplateURL new_t_url; + new_t_url.SetURL("http://" + new_host + "/", 0, 0); + provider_map_->Add(&new_t_url); + + ASSERT_EQ(&new_t_url, provider_map_->GetTemplateURLForHost(new_host)); +} + +TEST_F(SearchHostToURLsMapTest, Remove) { + provider_map_->Remove(&t_urls_[0]); + + const TemplateURL* found_url = provider_map_->GetTemplateURLForHost(host_); + ASSERT_TRUE(found_url == &t_urls_[1]); + + const TemplateURLSet* urls = provider_map_->GetURLsForHost(host_); + ASSERT_TRUE(urls != NULL); + + int url_count = 0; + for (TemplateURLSet::const_iterator i = urls->begin(); + i != urls->end(); ++i) { + url_count++; + ASSERT_TRUE(*i == &t_urls_[1]); + } + ASSERT_EQ(1, url_count); +} + +TEST_F(SearchHostToURLsMapTest, RemoveAll) { + provider_map_->RemoveAll(); + + const TemplateURL* found_url = provider_map_->GetTemplateURLForHost(host_); + ASSERT_TRUE(found_url == NULL); + + const TemplateURLSet* urls = provider_map_->GetURLsForHost(host_); + ASSERT_TRUE(urls == NULL); +} + +TEST_F(SearchHostToURLsMapTest, Update) { + std::string new_host = "example.com"; + TemplateURL new_values; + new_values.SetURL("http://" + new_host + "/", 0, 0); + + provider_map_->Update(&t_urls_[0], new_values); + + ASSERT_EQ(&t_urls_[0], provider_map_->GetTemplateURLForHost(new_host)); + ASSERT_EQ(&t_urls_[1], provider_map_->GetTemplateURLForHost(host_)); +} + +TEST_F(SearchHostToURLsMapTest, UpdateGoogleBaseURLs) { + std::string google_base_url = "google.com"; + SetGoogleBaseURL("http://" + google_base_url +"/"); + + // Add in a url with the templated Google base url. + TemplateURL new_t_url; + new_t_url.SetURL("{google:baseURL}?q={searchTerms}", 0, 0); + provider_map_->Add(&new_t_url); + ASSERT_EQ(&new_t_url, provider_map_->GetTemplateURLForHost(google_base_url)); + + // Now change the Google base url and verify the result. + std::string new_google_base_url = "other.com"; + SetGoogleBaseURL("http://" + new_google_base_url +"/"); + provider_map_->UpdateGoogleBaseURLs(); + ASSERT_EQ(&new_t_url, provider_map_->GetTemplateURLForHost( + new_google_base_url)); +} + +TEST_F(SearchHostToURLsMapTest, SetDefault) { + provider_map_->SetDefault(&t_urls_[0]); + VerifyDefault("http://" + host_ + "/"); +} + +TEST_F(SearchHostToURLsMapTest, GetTemplateURLForKnownHost) { + const TemplateURL* found_url = provider_map_->GetTemplateURLForHost(host_); + ASSERT_TRUE(found_url == &t_urls_[0] || found_url == &t_urls_[1]); +} + +TEST_F(SearchHostToURLsMapTest, GetTemplateURLForUnknownHost) { + const TemplateURL* found_url = provider_map_->GetTemplateURLForHost( + "a" + host_); + ASSERT_TRUE(found_url == NULL); +} + +TEST_F(SearchHostToURLsMapTest, GetURLsForKnownHost) { + const TemplateURLSet* urls = provider_map_->GetURLsForHost(host_); + ASSERT_TRUE(urls != NULL); + + bool found_urls[arraysize(t_urls_)] = { 0 }; + + for (TemplateURLSet::const_iterator i = urls->begin(); + i != urls->end(); ++i) { + const TemplateURL* url = *i; + for (size_t i = 0; i < arraysize(found_urls); ++i) { + if (url == &t_urls_[i]) { + found_urls[i] = true; + break; + } + } + } + + for (size_t i = 0; i < arraysize(found_urls); ++i) + ASSERT_TRUE(found_urls[i]); +} + +TEST_F(SearchHostToURLsMapTest, GetURLsForUnknownHost) { + const TemplateURLSet* urls = provider_map_->GetURLsForHost("a" + host_); + ASSERT_TRUE(urls == NULL); +} diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h index 1cee283..64a6510 100644 --- a/chrome/browser/search_engines/template_url.h +++ b/chrome/browser/search_engines/template_url.h @@ -114,6 +114,7 @@ class TemplateURLRef { bool HasGoogleBaseURLs() const; private: + friend class SearchHostToURLsMapTest; friend class TemplateURL; friend class TemplateURLModelTest; friend class TemplateURLTest; @@ -447,9 +448,10 @@ class TemplateURL { WebDataService* service, std::vector<TemplateURL*>* template_urls, const TemplateURL** default_search_provider); + friend class SearchHostToURLsMap; + friend class TemplateURLModel; friend class WebDatabaseTest; friend class WebDatabase; - friend class TemplateURLModel; // Invalidates cached values on this object and its child TemplateURLRefs. void InvalidateCachedValues() const; diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc index d6081b3..fca7941 100644 --- a/chrome/browser/search_engines/template_url_model.cc +++ b/chrome/browser/search_engines/template_url_model.cc @@ -18,6 +18,7 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/rlz/rlz.h" +#include "chrome/browser/search_engines/search_host_to_urls_map.h" #include "chrome/browser/search_engines/template_url_prepopulate_data.h" #include "chrome/browser/search_engines/util.h" #include "chrome/common/chrome_switches.h" @@ -29,6 +30,7 @@ #include "net/base/net_util.h" using base::Time; +typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet; // String in the URL that is replaced by the search term. static const char kSearchTermParameter[] = "{searchTerms}"; @@ -77,7 +79,7 @@ TemplateURLModel::TemplateURLModel(Profile* profile) TemplateURLModel::TemplateURLModel(const Initializer* initializers, const int count) : profile_(NULL), - loaded_(true), + loaded_(false), load_failed_(false), load_handle_(0), service_(NULL), @@ -92,6 +94,7 @@ TemplateURLModel::~TemplateURLModel() { service_->CancelRequest(load_handle_); } + provider_map_->RemoveAll(); STLDeleteElements(&template_urls_); } @@ -221,10 +224,7 @@ const TemplateURL* TemplateURLModel::GetTemplateURLForKeyword( const TemplateURL* TemplateURLModel::GetTemplateURLForHost( const std::string& host) const { - HostToURLsMap::const_iterator iter = host_to_urls_map_.find(host); - if (iter == host_to_urls_map_.end() || iter->second.empty()) - return NULL; - return *(iter->second.begin()); // Return the 1st element. + return provider_map_->GetTemplateURLForHost(host); } void TemplateURLModel::Add(TemplateURL* template_url) { @@ -413,6 +413,7 @@ void TemplateURLModel::SetDefaultSearchProvider(const TemplateURL* url) { service_->SetDefaultSearchProvider(url); if (loaded_) { + provider_map_->SetDefault(url); FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, OnTemplateURLModelChanged()); } @@ -461,7 +462,7 @@ void TemplateURLModel::Load() { if (service_.get()) { load_handle_ = service_->GetKeywords(this); } else { - loaded_ = true; + ChangeToLoadedState(); NotifyLoaded(); } } @@ -476,8 +477,8 @@ void TemplateURLModel::OnWebDataServiceRequestDone( if (!result) { // Results are null if the database went away or (most likely) wasn't // loaded. - loaded_ = true; load_failed_ = true; + ChangeToLoadedState(); NotifyLoaded(); return; } @@ -487,8 +488,8 @@ void TemplateURLModel::OnWebDataServiceRequestDone( prefs_default_search_provider_.reset(); std::vector<TemplateURL*> template_urls; - int new_resource_keyword_version = 0; const TemplateURL* default_search_provider = NULL; + int new_resource_keyword_version = 0; GetSearchProvidersUsingKeywordResult(*result, service_.get(), GetPrefs(), @@ -515,6 +516,10 @@ void TemplateURLModel::OnWebDataServiceRequestDone( SaveDefaultSearchProviderToPrefs(default_search_provider_); } + // This initializes provider_map_ which should be done before + // calling UpdateKeywordSearchTermsForURL. + ChangeToLoadedState(); + // Index any visits that occurred before we finished loading. for (size_t i = 0; i < visits_to_add_.size(); ++i) UpdateKeywordSearchTermsForURL(visits_to_add_[i]); @@ -523,8 +528,6 @@ void TemplateURLModel::OnWebDataServiceRequestDone( if (new_resource_keyword_version && service_.get()) service_->SetBuiltinKeywordVersion(new_resource_keyword_version); - loaded_ = true; - FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, OnTemplateURLModelChanged()); @@ -587,26 +590,33 @@ void TemplateURLModel::Init(const Initializer* initializers, } registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED, NotificationService::AllSources()); - - // Add specific initializers, if any. - for (int i(0); i < num_initializers; ++i) { - DCHECK(initializers[i].keyword); - DCHECK(initializers[i].url); - DCHECK(initializers[i].content); - - size_t template_position = - std::string(initializers[i].url).find(kTemplateParameter); - DCHECK(template_position != std::wstring::npos); - std::string osd_url(initializers[i].url); - osd_url.replace(template_position, arraysize(kTemplateParameter) - 1, - kSearchTermParameter); - - // TemplateURLModel ends up owning the TemplateURL, don't try and free it. - TemplateURL* template_url = new TemplateURL(); - template_url->set_keyword(initializers[i].keyword); - template_url->set_short_name(initializers[i].content); - template_url->SetURL(osd_url, 0, 0); - Add(template_url); + provider_map_ = new SearchHostToURLsMap(); + + if (num_initializers > 0) { + // This path is only hit by test code and is used to simulate a loaded + // TemplateURLModel. + ChangeToLoadedState(); + + // Add specific initializers, if any. + for (int i(0); i < num_initializers; ++i) { + DCHECK(initializers[i].keyword); + DCHECK(initializers[i].url); + DCHECK(initializers[i].content); + + size_t template_position = + std::string(initializers[i].url).find(kTemplateParameter); + DCHECK(template_position != std::wstring::npos); + std::string osd_url(initializers[i].url); + osd_url.replace(template_position, arraysize(kTemplateParameter) - 1, + kSearchTermParameter); + + // TemplateURLModel ends up owning the TemplateURL, don't try and free it. + TemplateURL* template_url = new TemplateURL(); + template_url->set_keyword(initializers[i].keyword); + template_url->set_short_name(initializers[i].content); + template_url->SetURL(osd_url, 0, 0); + Add(template_url); + } } // Request a server check for the correct Google URL if Google is the default @@ -622,23 +632,13 @@ void TemplateURLModel::Init(const Initializer* initializers, } void TemplateURLModel::RemoveFromMaps(const TemplateURL* template_url) { - if (!template_url->keyword().empty()) { + if (!template_url->keyword().empty()) keyword_to_template_map_.erase(template_url->keyword()); - } - - const GURL url(GenerateSearchURL(template_url)); - if (url.is_valid() && url.has_host()) { - const std::string host(url.host()); - DCHECK(host_to_urls_map_.find(host) != host_to_urls_map_.end()); - TemplateURLSet& urls = host_to_urls_map_[host]; - DCHECK(urls.find(template_url) != urls.end()); - urls.erase(urls.find(template_url)); - if (urls.empty()) - host_to_urls_map_.erase(host_to_urls_map_.find(host)); - } + if (loaded_) + provider_map_->Remove(template_url); } -void TemplateURLModel::RemoveFromMapsByPointer( +void TemplateURLModel::RemoveFromKeywordMapByPointer( const TemplateURL* template_url) { DCHECK(template_url); for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin(); @@ -650,28 +650,13 @@ void TemplateURLModel::RemoveFromMapsByPointer( break; } } - - for (HostToURLsMap::iterator i = host_to_urls_map_.begin(); - i != host_to_urls_map_.end(); ++i) { - TemplateURLSet::iterator url_set_iterator = i->second.find(template_url); - if (url_set_iterator != i->second.end()) { - i->second.erase(url_set_iterator); - if (i->second.empty()) - host_to_urls_map_.erase(i); - // A given TemplateURL only occurs once in the map. As soon as we find the - // entry, stop. - return; - } - } } void TemplateURLModel::AddToMaps(const TemplateURL* template_url) { if (!template_url->keyword().empty()) keyword_to_template_map_[template_url->keyword()] = template_url; - - const GURL url(GenerateSearchURL(template_url)); - if (url.is_valid() && url.has_host()) - host_to_urls_map_[url.host()].insert(template_url); + if (loaded_) + provider_map_->Add(template_url); } void TemplateURLModel::SetTemplateURLs(const std::vector<TemplateURL*>& urls) { @@ -699,6 +684,13 @@ void TemplateURLModel::SetTemplateURLs(const std::vector<TemplateURL*>& urls) { } } +void TemplateURLModel::ChangeToLoadedState() { + DCHECK(!loaded_); + + provider_map_->Init(template_urls_, default_search_provider_); + loaded_ = true; +} + void TemplateURLModel::NotifyLoaded() { NotificationService::current()->Notify( NotificationType::TEMPLATE_URL_MODEL_LOADED, @@ -811,11 +803,10 @@ void TemplateURLModel::RegisterPrefs(PrefService* prefs) { bool TemplateURLModel::CanReplaceKeywordForHost( const std::string& host, const TemplateURL** to_replace) { - const HostToURLsMap::iterator matching_urls = host_to_urls_map_.find(host); - const bool have_matching_urls = (matching_urls != host_to_urls_map_.end()); - if (have_matching_urls) { - TemplateURLSet& urls = matching_urls->second; - for (TemplateURLSet::iterator i = urls.begin(); i != urls.end(); ++i) { + const TemplateURLSet* urls = provider_map_->GetURLsForHost(host); + if (urls) { + for (TemplateURLSet::const_iterator i = urls->begin(); + i != urls->end(); ++i) { const TemplateURL* url = *i; if (CanReplace(url)) { if (to_replace) @@ -827,7 +818,7 @@ bool TemplateURLModel::CanReplaceKeywordForHost( if (to_replace) *to_replace = NULL; - return !have_matching_urls; + return !urls; } bool TemplateURLModel::CanReplace(const TemplateURL* t_url) { @@ -837,19 +828,19 @@ bool TemplateURLModel::CanReplace(const TemplateURL* t_url) { void TemplateURLModel::Update(const TemplateURL* existing_turl, const TemplateURL& new_values) { + DCHECK(loaded_); DCHECK(existing_turl); DCHECK(find(template_urls_.begin(), template_urls_.end(), existing_turl) != template_urls_.end()); - RemoveFromMaps(existing_turl); + if (!existing_turl->keyword().empty()) + keyword_to_template_map_.erase(existing_turl->keyword()); - // Use the information from new_values but preserve existing_turl's id. - TemplateURL::IDType previous_id = existing_turl->id(); - TemplateURL* modifiable_turl = const_cast<TemplateURL*>(existing_turl); - *modifiable_turl = new_values; - modifiable_turl->set_id(previous_id); + // This call handles copying over the values (while retaining the id). + provider_map_->Update(existing_turl, new_values); - AddToMaps(existing_turl); + if (!existing_turl->keyword().empty()) + keyword_to_template_map_[existing_turl->keyword()] = existing_turl; if (service_.get()) service_->UpdateKeyword(*existing_turl); @@ -861,10 +852,8 @@ void TemplateURLModel::Update(const TemplateURL* existing_turl, SetDefaultSearchProvider(existing_turl); } - if (loaded_) { - FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, - OnTemplateURLModelChanged()); - } + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); } PrefService* TemplateURLModel::GetPrefs() { @@ -879,21 +868,18 @@ void TemplateURLModel::UpdateKeywordSearchTermsForURL( return; } - HostToURLsMap::const_iterator t_urls_for_host_iterator = - host_to_urls_map_.find(row.url().host()); - if (t_urls_for_host_iterator == host_to_urls_map_.end() || - t_urls_for_host_iterator->second.empty()) { + const TemplateURLSet* urls_for_host = + provider_map_->GetURLsForHost(row.url().host()); + if (!urls_for_host) return; - } - const TemplateURLSet& urls_for_host = t_urls_for_host_iterator->second; QueryTerms query_terms; bool built_terms = false; // Most URLs won't match a TemplateURLs host; // so we lazily build the query_terms. const std::string path = row.url().path(); - for (TemplateURLSet::const_iterator i = urls_for_host.begin(); - i != urls_for_host.end(); ++i) { + for (TemplateURLSet::const_iterator i = urls_for_host->begin(); + i != urls_for_host->end(); ++i) { const TemplateURLRef* search_ref = (*i)->url(); // Count the URL against a TemplateURL if the host and path of the @@ -1000,14 +986,16 @@ void TemplateURLModel::GoogleBaseURLChanged() { if ((t_url->url() && t_url->url()->HasGoogleBaseURLs()) || (t_url->suggestions_url() && t_url->suggestions_url()->HasGoogleBaseURLs())) { - RemoveFromMapsByPointer(t_url); + RemoveFromKeywordMapByPointer(t_url); t_url->InvalidateCachedValues(); - AddToMaps(t_url); + if (!t_url->keyword().empty()) + keyword_to_template_map_[t_url->keyword()] = t_url; something_changed = true; } } if (something_changed && loaded_) { + provider_map_->UpdateGoogleBaseURLs(); FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, OnTemplateURLModelChanged()); } diff --git a/chrome/browser/search_engines/template_url_model.h b/chrome/browser/search_engines/template_url_model.h index cf4e62c..8e18279 100644 --- a/chrome/browser/search_engines/template_url_model.h +++ b/chrome/browser/search_engines/template_url_model.h @@ -19,6 +19,7 @@ class GURL; class Extension; class PrefService; class Profile; +class SearchHostToURLsMap; namespace history { struct URLVisitedDetails; @@ -240,8 +241,6 @@ class TemplateURLModel : public WebDataServiceConsumer, typedef std::map<std::wstring, const TemplateURL*> KeywordToTemplateMap; typedef std::vector<const TemplateURL*> TemplateURLVector; - typedef std::set<const TemplateURL*> TemplateURLSet; - typedef std::map<std::string, TemplateURLSet> HostToURLsMap; // Helper functor for FindMatchingKeywords(), for finding the range of // keywords which begin with a prefix. @@ -251,10 +250,10 @@ class TemplateURLModel : public WebDataServiceConsumer, void RemoveFromMaps(const TemplateURL* template_url); - // Removes the supplied template_url from the maps. This searches through all - // entries in the maps and does not generate the host or keyword. - // This is used when the cached content of the TemplateURL changes. - void RemoveFromMapsByPointer(const TemplateURL* template_url); + // Removes the supplied template_url from the keyword maps. This searches + // through all entries in the keyword map and does not generate the host or + // keyword. This is used when the cached content of the TemplateURL changes. + void RemoveFromKeywordMapByPointer(const TemplateURL* template_url); void AddToMaps(const TemplateURL* template_url); @@ -262,7 +261,8 @@ class TemplateURLModel : public WebDataServiceConsumer, // This does NOT notify the delegate or the database. void SetTemplateURLs(const std::vector<TemplateURL*>& urls); - void DeleteGeneratedKeywordsMatchingHost(const std::wstring& host); + // Transitions to the loaded state. + void ChangeToLoadedState(); // If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED // notification. @@ -334,7 +334,7 @@ class TemplateURLModel : public WebDataServiceConsumer, ObserverList<TemplateURLModelObserver> model_observers_; // Maps from host to set of TemplateURLs whose search url host is host. - HostToURLsMap host_to_urls_map_; + scoped_refptr<SearchHostToURLsMap> provider_map_; // Used to obtain the WebDataService. // When Load is invoked, if we haven't yet loaded, the WebDataService is diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc index a4805be..32b91bc 100644 --- a/chrome/browser/search_engines/template_url_model_unittest.cc +++ b/chrome/browser/search_engines/template_url_model_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/history_notifications.h" +#include "chrome/browser/search_engines/search_host_to_urls_map.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/search_engines/template_url_prepopulate_data.h" #include "chrome/browser/webdata/web_database.h" @@ -196,8 +197,10 @@ class TemplateURLModelTest : public testing::Test, // load). Since this avoids setting the built-in keyword version, the next // load will do a merge from prepopulated data. void ChangeModelToLoadState() { + model_->ChangeToLoadedState(); + // Initialize the web data service so that the database gets updated with + // any changes made. model_->service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); - model_->loaded_ = true; } // Creates a new TemplateURLModel. @@ -546,6 +549,7 @@ TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) { } TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) { + ChangeModelToLoadState(); ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", GURL(), NULL)); TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo1", L"name1", true, Time()); @@ -562,6 +566,7 @@ TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) { } TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) { + ChangeModelToLoadState(); ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", GURL("http://foo.com"), NULL)); TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo.com", L"name1", true, Time()); @@ -692,6 +697,7 @@ TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) { { "http://x/foo?q=b&q=xx", L"" }, }; + ChangeModelToLoadState(); AddKeywordWithDate(L"x", false, "http://x/foo?q={searchTerms}", L"name", false, Time()); @@ -713,6 +719,7 @@ TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) { { "http://x/foo?y=xx" }, }; + ChangeModelToLoadState(); AddKeywordWithDate(L"x", false, "http://x/foo", L"name", false, Time()); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { @@ -728,6 +735,7 @@ TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) { // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data, // which also has a {google:baseURL} keyword in it, which will confuse this // test. + ChangeModelToLoadState(); SetGoogleBaseURL("http://google.com/"); const TemplateURL* t_url = AddKeywordWithDate(std::wstring(), true, "{google:baseURL}?q={searchTerms}", L"name", false, Time()); @@ -736,8 +744,7 @@ TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) { EXPECT_EQ(L"google.com", t_url->keyword()); // Change the Google base url. - model_->loaded_ = true; // Hack to make sure we get notified of the base URL - // changing. + changed_count_ = 0; SetGoogleBaseURL("http://foo.com/"); model_->GoogleBaseURLChanged(); VerifyObserverCount(1); diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc index f27643e..8273800 100644 --- a/chrome/browser/search_engines/util.cc +++ b/chrome/browser/search_engines/util.cc @@ -116,8 +116,9 @@ void MergeEnginesFromPrepopulateData( t_url->set_id(current_t_url->id()); *current_t_url = *t_url; - if (service) + if (service) { service->UpdateKeyword(*current_t_url); + } id_to_turl.erase(existing_url_iter); } else { template_urls->push_back(t_url.release()); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index e515aad..464ad67 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2399,6 +2399,8 @@ 'browser/search_engines/edit_search_engine_controller.h', 'browser/search_engines/keyword_editor_controller.cc', 'browser/search_engines/keyword_editor_controller.h', + 'browser/search_engines/search_host_to_urls_map.h', + 'browser/search_engines/search_host_to_urls_map.cc', 'browser/search_engines/search_provider_install_state_dispatcher_host.cc', 'browser/search_engines/search_provider_install_state_dispatcher_host.h', 'browser/search_engines/template_url.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index f1c716d..9d096fb 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1205,6 +1205,7 @@ 'browser/safe_browsing/safe_browsing_store_unittest_helper.cc', 'browser/safe_browsing/safe_browsing_util_unittest.cc', 'browser/search_engines/keyword_editor_controller_unittest.cc', + 'browser/search_engines/search_host_to_urls_map_unittest.cc', 'browser/search_engines/template_url_model_unittest.cc', 'browser/search_engines/template_url_parser_unittest.cc', 'browser/search_engines/template_url_prepopulate_data_unittest.cc', |