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/chrome_notification_types.h"
18 #include "chrome/browser/google/google_url_tracker.h"
19 #include "chrome/browser/google/google_url_tracker_factory.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
22 #include "chrome/browser/search_engines/search_terms_data.h"
23 #include "chrome/browser/search_engines/template_url.h"
24 #include "chrome/browser/search_engines/template_url_service.h"
25 #include "chrome/browser/search_engines/template_url_service_factory.h"
26 #include "chrome/browser/search_engines/util.h"
27 #include "chrome/browser/webdata/web_data_service.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_process_host_observer.h"
32 using content::BrowserThread
;
34 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet
;
38 void LoadDataOnUIThread(TemplateURLService
* template_url_service
,
39 const base::Callback
<void(ScopedVector
<TemplateURL
>,
40 TemplateURL
*)>& callback
) {
41 ScopedVector
<TemplateURL
> template_url_copies
;
42 TemplateURL
* default_provider_copy
= NULL
;
43 TemplateURLService::TemplateURLVector original_template_urls
=
44 template_url_service
->GetTemplateURLs();
45 TemplateURL
* original_default_provider
=
46 template_url_service
->GetDefaultSearchProvider();
47 for (TemplateURLService::TemplateURLVector::const_iterator it
=
48 original_template_urls
.begin();
49 it
!= original_template_urls
.end();
51 template_url_copies
.push_back(new TemplateURL(NULL
, (*it
)->data()));
52 if (*it
== original_default_provider
)
53 default_provider_copy
= template_url_copies
.back();
55 BrowserThread::PostTask(BrowserThread::IO
,
58 base::Passed(template_url_copies
.Pass()),
59 base::Unretained(default_provider_copy
)));
62 // Implementation of SearchTermsData that may be used on the I/O thread.
63 class IOThreadSearchTermsData
: public SearchTermsData
{
65 explicit IOThreadSearchTermsData(const std::string
& google_base_url
);
67 // Implementation of SearchTermsData.
68 virtual std::string
GoogleBaseURLValue() const OVERRIDE
;
71 std::string google_base_url_
;
73 DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData
);
76 IOThreadSearchTermsData::IOThreadSearchTermsData(
77 const std::string
& google_base_url
) : google_base_url_(google_base_url
) {
80 std::string
IOThreadSearchTermsData::GoogleBaseURLValue() const {
81 return google_base_url_
;
84 // Handles telling SearchProviderInstallData about changes to the google base
85 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
86 // deleted on the correct thread.)
87 class GoogleURLChangeNotifier
88 : public base::RefCountedThreadSafe
<GoogleURLChangeNotifier
,
89 BrowserThread::DeleteOnIOThread
> {
91 explicit GoogleURLChangeNotifier(
92 const base::WeakPtr
<SearchProviderInstallData
>& install_data
);
94 // Called on the I/O thread with the Google base URL whenever the value
96 void OnChange(const std::string
& google_base_url
);
99 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
100 friend class base::DeleteHelper
<GoogleURLChangeNotifier
>;
102 ~GoogleURLChangeNotifier() {}
104 base::WeakPtr
<SearchProviderInstallData
> install_data_
;
106 DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier
);
109 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
110 const base::WeakPtr
<SearchProviderInstallData
>& install_data
)
111 : install_data_(install_data
) {
114 void GoogleURLChangeNotifier::OnChange(const std::string
& google_base_url
) {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
116 if (install_data_
.get())
117 install_data_
->OnGoogleURLChange(google_base_url
);
120 // Notices changes in the Google base URL and sends them along
121 // to the SearchProviderInstallData on the I/O thread.
122 class GoogleURLObserver
: public content::RenderProcessHostObserver
{
124 GoogleURLObserver(Profile
* profile
,
125 GoogleURLChangeNotifier
* change_notifier
,
126 content::RenderProcessHost
* host
);
128 // Implementation of content::RenderProcessHostObserver.
129 virtual void RenderProcessHostDestroyed(
130 content::RenderProcessHost
* host
) OVERRIDE
;
133 virtual ~GoogleURLObserver() {}
135 // Callback that is called when the Google URL is updated.
136 void OnGoogleURLUpdated(GURL old_url
, GURL new_url
);
138 scoped_refptr
<GoogleURLChangeNotifier
> change_notifier_
;
140 scoped_ptr
<GoogleURLTracker::Subscription
> google_url_updated_subscription_
;
142 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver
);
145 GoogleURLObserver::GoogleURLObserver(
147 GoogleURLChangeNotifier
* change_notifier
,
148 content::RenderProcessHost
* host
)
149 : change_notifier_(change_notifier
) {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
151 GoogleURLTracker
* google_url_tracker
=
152 GoogleURLTrackerFactory::GetForProfile(profile
);
154 // GoogleURLTracker is not created in tests.
155 if (google_url_tracker
) {
156 google_url_updated_subscription_
=
157 google_url_tracker
->RegisterCallback(base::Bind(
158 &GoogleURLObserver::OnGoogleURLUpdated
, base::Unretained(this)));
160 host
->AddObserver(this);
163 void GoogleURLObserver::OnGoogleURLUpdated(GURL old_url
, GURL new_url
) {
164 BrowserThread::PostTask(BrowserThread::IO
,
166 base::Bind(&GoogleURLChangeNotifier::OnChange
,
167 change_notifier_
.get(),
171 void GoogleURLObserver::RenderProcessHostDestroyed(
172 content::RenderProcessHost
* host
) {
176 // Indicates if the two inputs have the same security origin.
177 // |requested_origin| should only be a security origin (no path, etc.).
178 // It is ok if |template_url| is NULL.
179 static bool IsSameOrigin(const GURL
& requested_origin
,
180 TemplateURL
* template_url
,
181 const SearchTermsData
& search_terms_data
) {
182 DCHECK(requested_origin
== requested_origin
.GetOrigin());
183 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
184 return requested_origin
==
185 TemplateURLService::GenerateSearchURLUsingTermsData(template_url
,
186 search_terms_data
).GetOrigin();
191 SearchProviderInstallData::SearchProviderInstallData(
193 content::RenderProcessHost
* host
)
194 : template_url_service_(TemplateURLServiceFactory::GetForProfile(profile
)),
195 google_base_url_(UIThreadSearchTermsData(profile
).GoogleBaseURLValue()),
196 weak_factory_(this) {
197 // GoogleURLObserver is responsible for killing itself when
198 // the given notification occurs.
199 new GoogleURLObserver(profile
,
200 new GoogleURLChangeNotifier(weak_factory_
.GetWeakPtr()),
204 SearchProviderInstallData::~SearchProviderInstallData() {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
208 void SearchProviderInstallData::CallWhenLoaded(const base::Closure
& closure
) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
211 if (provider_map_
.get()) {
216 bool do_load
= closure_queue_
.empty();
217 closure_queue_
.push_back(closure
);
219 // If the queue wasn't empty, there was already a load in progress.
223 if (template_url_service_
) {
224 BrowserThread::PostTask(
227 base::Bind(&LoadDataOnUIThread
,
228 template_url_service_
,
229 base::Bind(&SearchProviderInstallData::OnTemplateURLsLoaded
,
230 weak_factory_
.GetWeakPtr())));
236 SearchProviderInstallData::State
SearchProviderInstallData::GetInstallState(
237 const GURL
& requested_origin
) {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
239 DCHECK(provider_map_
.get());
241 // First check to see if the origin is the default search provider.
242 if (requested_origin
.spec() == default_search_origin_
)
243 return INSTALLED_AS_DEFAULT
;
245 // Is the url any search provider?
246 const TemplateURLSet
* urls
= provider_map_
->GetURLsForHost(
247 requested_origin
.host());
249 return NOT_INSTALLED
;
251 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
252 for (TemplateURLSet::const_iterator i
= urls
->begin();
253 i
!= urls
->end(); ++i
) {
254 if (IsSameOrigin(requested_origin
, *i
, search_terms_data
))
255 return INSTALLED_BUT_NOT_DEFAULT
;
257 return NOT_INSTALLED
;
260 void SearchProviderInstallData::OnGoogleURLChange(
261 const std::string
& google_base_url
) {
262 google_base_url_
= google_base_url
;
265 void SearchProviderInstallData::OnTemplateURLsLoaded(
266 ScopedVector
<TemplateURL
> template_urls
,
267 TemplateURL
* default_provider
) {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
270 template_urls_
= template_urls
.Pass();
272 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
273 provider_map_
.reset(new SearchHostToURLsMap());
274 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
275 SetDefault(default_provider
);
279 void SearchProviderInstallData::SetDefault(const TemplateURL
* template_url
) {
280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
283 default_search_origin_
.clear();
287 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
289 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
290 const GURL
url(TemplateURLService::GenerateSearchURLUsingTermsData(
291 template_url
, search_terms_data
));
292 if (!url
.is_valid() || !url
.has_host()) {
293 default_search_origin_
.clear();
296 default_search_origin_
= url
.GetOrigin().spec();
299 void SearchProviderInstallData::OnLoadFailed() {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
302 provider_map_
.reset(new SearchHostToURLsMap());
303 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
304 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
309 void SearchProviderInstallData::NotifyLoaded() {
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
312 std::vector
<base::Closure
> closure_queue
;
313 closure_queue
.swap(closure_queue_
);
315 std::for_each(closure_queue
.begin(),
317 std::mem_fun_ref(&base::Closure::Run
));
319 // Since we expect this request to be rare, clear out the information. This
320 // also keeps the responses current as the search providers change.
321 provider_map_
.reset();