summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller_unittest.cc35
-rw-r--r--chrome/browser/search_engines/search_host_to_urls_map.cc204
-rw-r--r--chrome/browser/search_engines/search_host_to_urls_map.h110
-rw-r--r--chrome/browser/search_engines/search_host_to_urls_map_unittest.cc160
-rw-r--r--chrome/browser/search_engines/template_url.h4
-rw-r--r--chrome/browser/search_engines/template_url_model.cc164
-rw-r--r--chrome/browser/search_engines/template_url_model.h16
-rw-r--r--chrome/browser/search_engines/template_url_model_unittest.cc15
-rw-r--r--chrome/browser/search_engines/util.cc3
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
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',