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 "components/google/core/browser/google_url_tracker.h"
18 #include "components/search_engines/search_host_to_urls_map.h"
19 #include "components/search_engines/search_terms_data.h"
20 #include "components/search_engines/template_url.h"
21 #include "components/search_engines/template_url_service.h"
22 #include "components/search_engines/util.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_process_host_observer.h"
27 using content::BrowserThread
;
29 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet
;
33 void LoadDataOnUIThread(TemplateURLService
* template_url_service
,
34 const base::Callback
<void(ScopedVector
<TemplateURL
>,
35 TemplateURL
*)>& callback
) {
36 ScopedVector
<TemplateURL
> template_url_copies
;
37 TemplateURL
* default_provider_copy
= NULL
;
38 TemplateURLService::TemplateURLVector original_template_urls
=
39 template_url_service
->GetTemplateURLs();
40 TemplateURL
* original_default_provider
=
41 template_url_service
->GetDefaultSearchProvider();
42 for (TemplateURLService::TemplateURLVector::const_iterator it
=
43 original_template_urls
.begin();
44 it
!= original_template_urls
.end();
46 template_url_copies
.push_back(new TemplateURL((*it
)->data()));
47 if (*it
== original_default_provider
)
48 default_provider_copy
= template_url_copies
.back();
50 BrowserThread::PostTask(BrowserThread::IO
,
53 base::Passed(template_url_copies
.Pass()),
54 base::Unretained(default_provider_copy
)));
57 // Implementation of SearchTermsData that may be used on the I/O thread.
58 class IOThreadSearchTermsData
: public SearchTermsData
{
60 explicit IOThreadSearchTermsData(const std::string
& google_base_url
);
62 // Implementation of SearchTermsData.
63 std::string
GoogleBaseURLValue() const override
;
66 std::string google_base_url_
;
68 DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData
);
71 IOThreadSearchTermsData::IOThreadSearchTermsData(
72 const std::string
& google_base_url
) : google_base_url_(google_base_url
) {
75 std::string
IOThreadSearchTermsData::GoogleBaseURLValue() const {
76 return google_base_url_
;
79 // Handles telling SearchProviderInstallData about changes to the google base
80 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
81 // deleted on the correct thread.)
82 class GoogleURLChangeNotifier
83 : public base::RefCountedThreadSafe
<GoogleURLChangeNotifier
,
84 BrowserThread::DeleteOnIOThread
> {
86 explicit GoogleURLChangeNotifier(
87 const base::WeakPtr
<SearchProviderInstallData
>& install_data
);
89 // Called on the I/O thread with the Google base URL whenever the value
91 void OnChange(const std::string
& google_base_url
);
94 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
95 friend class base::DeleteHelper
<GoogleURLChangeNotifier
>;
97 ~GoogleURLChangeNotifier() {}
99 base::WeakPtr
<SearchProviderInstallData
> install_data_
;
101 DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier
);
104 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
105 const base::WeakPtr
<SearchProviderInstallData
>& install_data
)
106 : install_data_(install_data
) {
109 void GoogleURLChangeNotifier::OnChange(const std::string
& google_base_url
) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
111 if (install_data_
.get())
112 install_data_
->OnGoogleURLChange(google_base_url
);
115 // Notices changes in the Google base URL and sends them along
116 // to the SearchProviderInstallData on the I/O thread.
117 class GoogleURLObserver
: public content::RenderProcessHostObserver
{
119 GoogleURLObserver(GoogleURLTracker
* google_url_tracker
,
120 GoogleURLChangeNotifier
* change_notifier
,
121 content::RenderProcessHost
* host
);
123 // Implementation of content::RenderProcessHostObserver.
124 void RenderProcessHostDestroyed(content::RenderProcessHost
* host
) override
;
127 ~GoogleURLObserver() override
{}
129 // Callback that is called when the Google URL is updated.
130 void OnGoogleURLUpdated();
132 GoogleURLTracker
* google_url_tracker_
;
133 scoped_refptr
<GoogleURLChangeNotifier
> change_notifier_
;
135 scoped_ptr
<GoogleURLTracker::Subscription
> google_url_updated_subscription_
;
137 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver
);
140 GoogleURLObserver::GoogleURLObserver(
141 GoogleURLTracker
* google_url_tracker
,
142 GoogleURLChangeNotifier
* change_notifier
,
143 content::RenderProcessHost
* host
)
144 : google_url_tracker_(google_url_tracker
),
145 change_notifier_(change_notifier
) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
147 google_url_updated_subscription_
=
148 google_url_tracker_
->RegisterCallback(base::Bind(
149 &GoogleURLObserver::OnGoogleURLUpdated
, base::Unretained(this)));
150 host
->AddObserver(this);
153 void GoogleURLObserver::OnGoogleURLUpdated() {
154 BrowserThread::PostTask(BrowserThread::IO
,
156 base::Bind(&GoogleURLChangeNotifier::OnChange
,
157 change_notifier_
.get(),
158 google_url_tracker_
->google_url().spec()));
161 void GoogleURLObserver::RenderProcessHostDestroyed(
162 content::RenderProcessHost
* host
) {
166 // Indicates if the two inputs have the same security origin.
167 // |requested_origin| should only be a security origin (no path, etc.).
168 // It is ok if |template_url| is NULL.
169 static bool IsSameOrigin(const GURL
& requested_origin
,
170 TemplateURL
* template_url
,
171 const SearchTermsData
& search_terms_data
) {
172 DCHECK(requested_origin
== requested_origin
.GetOrigin());
173 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
174 return requested_origin
==
175 template_url
->GenerateSearchURL(search_terms_data
).GetOrigin();
180 SearchProviderInstallData::SearchProviderInstallData(
181 TemplateURLService
* template_url_service
,
182 const std::string
& google_base_url
,
183 GoogleURLTracker
* google_url_tracker
,
184 content::RenderProcessHost
* host
)
185 : template_url_service_(template_url_service
),
186 google_base_url_(google_base_url
),
187 weak_factory_(this) {
188 // GoogleURLTracker is not created in tests.
189 if (google_url_tracker
) {
190 // GoogleURLObserver is responsible for killing itself when
191 // the given notification occurs.
192 new GoogleURLObserver(
194 new GoogleURLChangeNotifier(weak_factory_
.GetWeakPtr()),
199 SearchProviderInstallData::~SearchProviderInstallData() {
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
203 void SearchProviderInstallData::CallWhenLoaded(const base::Closure
& closure
) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
206 if (provider_map_
.get()) {
211 bool do_load
= closure_queue_
.empty();
212 closure_queue_
.push_back(closure
);
214 // If the queue wasn't empty, there was already a load in progress.
218 if (template_url_service_
) {
219 BrowserThread::PostTask(
222 base::Bind(&LoadDataOnUIThread
,
223 template_url_service_
,
224 base::Bind(&SearchProviderInstallData::OnTemplateURLsLoaded
,
225 weak_factory_
.GetWeakPtr())));
231 SearchProviderInstallData::State
SearchProviderInstallData::GetInstallState(
232 const GURL
& requested_origin
) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
234 DCHECK(provider_map_
.get());
236 // First check to see if the origin is the default search provider.
237 if (requested_origin
.spec() == default_search_origin_
)
238 return INSTALLED_AS_DEFAULT
;
240 // Is the url any search provider?
241 const TemplateURLSet
* urls
= provider_map_
->GetURLsForHost(
242 requested_origin
.host());
244 return NOT_INSTALLED
;
246 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
247 for (TemplateURLSet::const_iterator i
= urls
->begin();
248 i
!= urls
->end(); ++i
) {
249 if (IsSameOrigin(requested_origin
, *i
, search_terms_data
))
250 return INSTALLED_BUT_NOT_DEFAULT
;
252 return NOT_INSTALLED
;
255 void SearchProviderInstallData::OnGoogleURLChange(
256 const std::string
& google_base_url
) {
257 google_base_url_
= google_base_url
;
260 void SearchProviderInstallData::OnTemplateURLsLoaded(
261 ScopedVector
<TemplateURL
> template_urls
,
262 TemplateURL
* default_provider
) {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
265 template_urls_
= template_urls
.Pass();
267 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
268 provider_map_
.reset(new SearchHostToURLsMap());
269 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
270 SetDefault(default_provider
);
274 void SearchProviderInstallData::SetDefault(const TemplateURL
* template_url
) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
278 default_search_origin_
.clear();
282 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
284 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
285 const GURL
url(template_url
->GenerateSearchURL(search_terms_data
));
286 if (!url
.is_valid() || !url
.has_host()) {
287 default_search_origin_
.clear();
290 default_search_origin_
= url
.GetOrigin().spec();
293 void SearchProviderInstallData::OnLoadFailed() {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
296 provider_map_
.reset(new SearchHostToURLsMap());
297 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
298 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
303 void SearchProviderInstallData::NotifyLoaded() {
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
306 std::vector
<base::Closure
> closure_queue
;
307 closure_queue
.swap(closure_queue_
);
309 std::for_each(closure_queue
.begin(),
311 std::mem_fun_ref(&base::Closure::Run
));
313 // Since we expect this request to be rare, clear out the information. This
314 // also keeps the responses current as the search providers change.
315 provider_map_
.reset();