1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/search_engines/search_provider_install_data.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequenced_task_runner_helpers.h"
17 #include "chrome/browser/google/google_url_tracker_factory.h"
18 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
19 #include "chrome/browser/search_engines/template_url.h"
20 #include "chrome/browser/search_engines/template_url_service.h"
21 #include "chrome/browser/search_engines/template_url_service_factory.h"
22 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
23 #include "chrome/browser/search_engines/util.h"
24 #include "components/google/core/browser/google_url_tracker.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/render_process_host_observer.h"
29 using content::BrowserThread;
31 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
35 void LoadDataOnUIThread(TemplateURLService* template_url_service,
36 const base::Callback<void(ScopedVector<TemplateURL>,
37 TemplateURL*)>& callback) {
38 ScopedVector<TemplateURL> template_url_copies;
39 TemplateURL* default_provider_copy = NULL;
40 TemplateURLService::TemplateURLVector original_template_urls =
41 template_url_service->GetTemplateURLs();
42 TemplateURL* original_default_provider =
43 template_url_service->GetDefaultSearchProvider();
44 for (TemplateURLService::TemplateURLVector::const_iterator it =
45 original_template_urls.begin();
46 it != original_template_urls.end();
48 template_url_copies.push_back(new TemplateURL((*it)->data()));
49 if (*it == original_default_provider)
50 default_provider_copy = template_url_copies.back();
52 BrowserThread::PostTask(BrowserThread::IO,
55 base::Passed(template_url_copies.Pass()),
56 base::Unretained(default_provider_copy)));
59 // Implementation of SearchTermsData that may be used on the I/O thread.
60 class IOThreadSearchTermsData : public SearchTermsData {
62 explicit IOThreadSearchTermsData(const std::string& google_base_url);
64 // Implementation of SearchTermsData.
65 virtual std::string GoogleBaseURLValue() const OVERRIDE;
68 std::string google_base_url_;
70 DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData);
73 IOThreadSearchTermsData::IOThreadSearchTermsData(
74 const std::string& google_base_url) : google_base_url_(google_base_url) {
77 std::string IOThreadSearchTermsData::GoogleBaseURLValue() const {
78 return google_base_url_;
81 // Handles telling SearchProviderInstallData about changes to the google base
82 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
83 // deleted on the correct thread.)
84 class GoogleURLChangeNotifier
85 : public base::RefCountedThreadSafe<GoogleURLChangeNotifier,
86 BrowserThread::DeleteOnIOThread> {
88 explicit GoogleURLChangeNotifier(
89 const base::WeakPtr<SearchProviderInstallData>& install_data);
91 // Called on the I/O thread with the Google base URL whenever the value
93 void OnChange(const std::string& google_base_url);
96 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
97 friend class base::DeleteHelper<GoogleURLChangeNotifier>;
99 ~GoogleURLChangeNotifier() {}
101 base::WeakPtr<SearchProviderInstallData> install_data_;
103 DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier);
106 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
107 const base::WeakPtr<SearchProviderInstallData>& install_data)
108 : install_data_(install_data) {
111 void GoogleURLChangeNotifier::OnChange(const std::string& google_base_url) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
113 if (install_data_.get())
114 install_data_->OnGoogleURLChange(google_base_url);
117 // Notices changes in the Google base URL and sends them along
118 // to the SearchProviderInstallData on the I/O thread.
119 class GoogleURLObserver : public content::RenderProcessHostObserver {
121 GoogleURLObserver(Profile* profile,
122 GoogleURLChangeNotifier* change_notifier,
123 content::RenderProcessHost* host);
125 // Implementation of content::RenderProcessHostObserver.
126 virtual void RenderProcessHostDestroyed(
127 content::RenderProcessHost* host) OVERRIDE;
130 virtual ~GoogleURLObserver() {}
132 // Callback that is called when the Google URL is updated.
133 void OnGoogleURLUpdated(GURL old_url, GURL new_url);
135 scoped_refptr<GoogleURLChangeNotifier> change_notifier_;
137 scoped_ptr<GoogleURLTracker::Subscription> google_url_updated_subscription_;
139 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver);
142 GoogleURLObserver::GoogleURLObserver(
144 GoogleURLChangeNotifier* change_notifier,
145 content::RenderProcessHost* host)
146 : change_notifier_(change_notifier) {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
148 GoogleURLTracker* google_url_tracker =
149 GoogleURLTrackerFactory::GetForProfile(profile);
151 // GoogleURLTracker is not created in tests.
152 if (google_url_tracker) {
153 google_url_updated_subscription_ =
154 google_url_tracker->RegisterCallback(base::Bind(
155 &GoogleURLObserver::OnGoogleURLUpdated, base::Unretained(this)));
157 host->AddObserver(this);
160 void GoogleURLObserver::OnGoogleURLUpdated(GURL old_url, GURL new_url) {
161 BrowserThread::PostTask(BrowserThread::IO,
163 base::Bind(&GoogleURLChangeNotifier::OnChange,
164 change_notifier_.get(),
168 void GoogleURLObserver::RenderProcessHostDestroyed(
169 content::RenderProcessHost* host) {
173 // Indicates if the two inputs have the same security origin.
174 // |requested_origin| should only be a security origin (no path, etc.).
175 // It is ok if |template_url| is NULL.
176 static bool IsSameOrigin(const GURL& requested_origin,
177 TemplateURL* template_url,
178 const SearchTermsData& search_terms_data) {
179 DCHECK(requested_origin == requested_origin.GetOrigin());
180 DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
181 return requested_origin ==
182 template_url->GenerateSearchURL(search_terms_data).GetOrigin();
187 SearchProviderInstallData::SearchProviderInstallData(
189 content::RenderProcessHost* host)
190 : template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)),
191 google_base_url_(UIThreadSearchTermsData(profile).GoogleBaseURLValue()),
192 weak_factory_(this) {
193 // GoogleURLObserver is responsible for killing itself when
194 // the given notification occurs.
195 new GoogleURLObserver(profile,
196 new GoogleURLChangeNotifier(weak_factory_.GetWeakPtr()),
200 SearchProviderInstallData::~SearchProviderInstallData() {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204 void SearchProviderInstallData::CallWhenLoaded(const base::Closure& closure) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
207 if (provider_map_.get()) {
212 bool do_load = closure_queue_.empty();
213 closure_queue_.push_back(closure);
215 // If the queue wasn't empty, there was already a load in progress.
219 if (template_url_service_) {
220 BrowserThread::PostTask(
223 base::Bind(&LoadDataOnUIThread,
224 template_url_service_,
225 base::Bind(&SearchProviderInstallData::OnTemplateURLsLoaded,
226 weak_factory_.GetWeakPtr())));
232 SearchProviderInstallData::State SearchProviderInstallData::GetInstallState(
233 const GURL& requested_origin) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
235 DCHECK(provider_map_.get());
237 // First check to see if the origin is the default search provider.
238 if (requested_origin.spec() == default_search_origin_)
239 return INSTALLED_AS_DEFAULT;
241 // Is the url any search provider?
242 const TemplateURLSet* urls = provider_map_->GetURLsForHost(
243 requested_origin.host());
245 return NOT_INSTALLED;
247 IOThreadSearchTermsData search_terms_data(google_base_url_);
248 for (TemplateURLSet::const_iterator i = urls->begin();
249 i != urls->end(); ++i) {
250 if (IsSameOrigin(requested_origin, *i, search_terms_data))
251 return INSTALLED_BUT_NOT_DEFAULT;
253 return NOT_INSTALLED;
256 void SearchProviderInstallData::OnGoogleURLChange(
257 const std::string& google_base_url) {
258 google_base_url_ = google_base_url;
261 void SearchProviderInstallData::OnTemplateURLsLoaded(
262 ScopedVector<TemplateURL> template_urls,
263 TemplateURL* default_provider) {
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
266 template_urls_ = template_urls.Pass();
268 IOThreadSearchTermsData search_terms_data(google_base_url_);
269 provider_map_.reset(new SearchHostToURLsMap());
270 provider_map_->Init(template_urls_.get(), search_terms_data);
271 SetDefault(default_provider);
275 void SearchProviderInstallData::SetDefault(const TemplateURL* template_url) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
279 default_search_origin_.clear();
283 DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
285 IOThreadSearchTermsData search_terms_data(google_base_url_);
286 const GURL url(template_url->GenerateSearchURL(search_terms_data));
287 if (!url.is_valid() || !url.has_host()) {
288 default_search_origin_.clear();
291 default_search_origin_ = url.GetOrigin().spec();
294 void SearchProviderInstallData::OnLoadFailed() {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
297 provider_map_.reset(new SearchHostToURLsMap());
298 IOThreadSearchTermsData search_terms_data(google_base_url_);
299 provider_map_->Init(template_urls_.get(), search_terms_data);
304 void SearchProviderInstallData::NotifyLoaded() {
305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
307 std::vector<base::Closure> closure_queue;
308 closure_queue.swap(closure_queue_);
310 std::for_each(closure_queue.begin(),
312 std::mem_fun_ref(&base::Closure::Run));
314 // Since we expect this request to be rare, clear out the information. This
315 // also keeps the responses current as the search providers change.
316 provider_map_.reset();