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/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/sequenced_task_runner_helpers.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/google/google_url_tracker.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
20 #include "chrome/browser/search_engines/search_terms_data.h"
21 #include "chrome/browser/search_engines/template_url.h"
22 #include "chrome/browser/search_engines/template_url_service.h"
23 #include "chrome/browser/search_engines/util.h"
24 #include "chrome/browser/webdata/web_data_service.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_observer.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_source.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_process_host_observer.h"
33 using content::BrowserThread
;
35 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet
;
39 // Implementation of SearchTermsData that may be used on the I/O thread.
40 class IOThreadSearchTermsData
: public SearchTermsData
{
42 explicit IOThreadSearchTermsData(const std::string
& google_base_url
);
44 // Implementation of SearchTermsData.
45 virtual std::string
GoogleBaseURLValue() const OVERRIDE
;
48 std::string google_base_url_
;
50 DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData
);
53 IOThreadSearchTermsData::IOThreadSearchTermsData(
54 const std::string
& google_base_url
) : google_base_url_(google_base_url
) {
57 std::string
IOThreadSearchTermsData::GoogleBaseURLValue() const {
58 return google_base_url_
;
61 // Handles telling SearchProviderInstallData about changes to the google base
62 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
63 // deleted on the correct thread.)
64 class GoogleURLChangeNotifier
65 : public base::RefCountedThreadSafe
<GoogleURLChangeNotifier
,
66 BrowserThread::DeleteOnIOThread
> {
68 explicit GoogleURLChangeNotifier(
69 const base::WeakPtr
<SearchProviderInstallData
>& install_data
);
71 // Called on the I/O thread with the Google base URL whenever the value
73 void OnChange(const std::string
& google_base_url
);
76 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
77 friend class base::DeleteHelper
<GoogleURLChangeNotifier
>;
79 ~GoogleURLChangeNotifier() {}
81 base::WeakPtr
<SearchProviderInstallData
> install_data_
;
83 DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier
);
86 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
87 const base::WeakPtr
<SearchProviderInstallData
>& install_data
)
88 : install_data_(install_data
) {
91 void GoogleURLChangeNotifier::OnChange(const std::string
& google_base_url
) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
93 if (install_data_
.get())
94 install_data_
->OnGoogleURLChange(google_base_url
);
97 // Notices changes in the Google base URL and sends them along
98 // to the SearchProviderInstallData on the I/O thread.
99 class GoogleURLObserver
: public content::NotificationObserver
,
100 public content::RenderProcessHostObserver
{
102 GoogleURLObserver(Profile
* profile
,
103 GoogleURLChangeNotifier
* change_notifier
,
104 content::RenderProcessHost
* host
);
106 // Implementation of content::NotificationObserver.
107 virtual void Observe(int type
,
108 const content::NotificationSource
& source
,
109 const content::NotificationDetails
& details
) OVERRIDE
;
111 // Implementation of content::RenderProcessHostObserver.
112 virtual void RenderProcessHostDestroyed(
113 content::RenderProcessHost
* host
) OVERRIDE
;
116 virtual ~GoogleURLObserver() {}
118 scoped_refptr
<GoogleURLChangeNotifier
> change_notifier_
;
119 content::NotificationRegistrar registrar_
;
121 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver
);
124 GoogleURLObserver::GoogleURLObserver(
126 GoogleURLChangeNotifier
* change_notifier
,
127 content::RenderProcessHost
* host
)
128 : change_notifier_(change_notifier
) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
130 registrar_
.Add(this, chrome::NOTIFICATION_GOOGLE_URL_UPDATED
,
131 content::Source
<Profile
>(profile
->GetOriginalProfile()));
132 host
->AddObserver(this);
135 void GoogleURLObserver::Observe(int type
,
136 const content::NotificationSource
& source
,
137 const content::NotificationDetails
& details
) {
138 DCHECK_EQ(chrome::NOTIFICATION_GOOGLE_URL_UPDATED
, type
);
139 BrowserThread::PostTask(
140 BrowserThread::IO
, FROM_HERE
,
141 base::Bind(&GoogleURLChangeNotifier::OnChange
,
142 change_notifier_
.get(),
143 content::Details
<GoogleURLTracker::UpdatedDetails
>(details
)->
147 void GoogleURLObserver::RenderProcessHostDestroyed(
148 content::RenderProcessHost
* host
) {
152 // Indicates if the two inputs have the same security origin.
153 // |requested_origin| should only be a security origin (no path, etc.).
154 // It is ok if |template_url| is NULL.
155 static bool IsSameOrigin(const GURL
& requested_origin
,
156 TemplateURL
* template_url
,
157 const SearchTermsData
& search_terms_data
) {
158 DCHECK(requested_origin
== requested_origin
.GetOrigin());
159 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
160 return requested_origin
==
161 TemplateURLService::GenerateSearchURLUsingTermsData(template_url
,
162 search_terms_data
).GetOrigin();
167 SearchProviderInstallData::SearchProviderInstallData(
168 Profile
* profile
, content::RenderProcessHost
* host
)
169 : web_service_(WebDataService::FromBrowserContext(profile
)),
171 google_base_url_(UIThreadSearchTermsData(profile
).GoogleBaseURLValue()),
172 weak_factory_(this) {
173 // GoogleURLObserver is responsible for killing itself when
174 // the given notification occurs.
175 new GoogleURLObserver(profile
,
176 new GoogleURLChangeNotifier(weak_factory_
.GetWeakPtr()),
180 SearchProviderInstallData::~SearchProviderInstallData() {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
184 DCHECK(web_service_
.get());
185 web_service_
->CancelRequest(load_handle_
);
189 void SearchProviderInstallData::CallWhenLoaded(const base::Closure
& closure
) {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
192 if (provider_map_
.get()) {
197 closure_queue_
.push_back(closure
);
201 if (web_service_
.get())
202 load_handle_
= web_service_
->GetKeywords(this);
207 SearchProviderInstallData::State
SearchProviderInstallData::GetInstallState(
208 const GURL
& requested_origin
) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
210 DCHECK(provider_map_
.get());
212 // First check to see if the origin is the default search provider.
213 if (requested_origin
.spec() == default_search_origin_
)
214 return INSTALLED_AS_DEFAULT
;
216 // Is the url any search provider?
217 const TemplateURLSet
* urls
= provider_map_
->GetURLsForHost(
218 requested_origin
.host());
220 return NOT_INSTALLED
;
222 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
223 for (TemplateURLSet::const_iterator i
= urls
->begin();
224 i
!= urls
->end(); ++i
) {
225 if (IsSameOrigin(requested_origin
, *i
, search_terms_data
))
226 return INSTALLED_BUT_NOT_DEFAULT
;
228 return NOT_INSTALLED
;
231 void SearchProviderInstallData::OnGoogleURLChange(
232 const std::string
& google_base_url
) {
233 google_base_url_
= google_base_url
;
236 void SearchProviderInstallData::OnWebDataServiceRequestDone(
237 WebDataService::Handle h
,
238 const WDTypedResult
* result
) {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
241 // Reset the load_handle so that we don't try and cancel the load in
246 // Results are null if the database went away or (most likely) wasn't
252 TemplateURL
* default_search_provider
= NULL
;
253 int new_resource_keyword_version
= 0;
254 std::vector
<TemplateURL
*> extracted_template_urls
;
255 GetSearchProvidersUsingKeywordResult(*result
, NULL
, NULL
,
256 &extracted_template_urls
, &default_search_provider
,
257 &new_resource_keyword_version
, NULL
);
258 template_urls_
.get().insert(template_urls_
.get().begin(),
259 extracted_template_urls
.begin(),
260 extracted_template_urls
.end());
261 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
262 provider_map_
.reset(new SearchHostToURLsMap());
263 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
264 SetDefault(default_search_provider
);
268 void SearchProviderInstallData::SetDefault(const TemplateURL
* template_url
) {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
272 default_search_origin_
.clear();
276 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
278 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
279 const GURL
url(TemplateURLService::GenerateSearchURLUsingTermsData(
280 template_url
, search_terms_data
));
281 if (!url
.is_valid() || !url
.has_host()) {
282 default_search_origin_
.clear();
285 default_search_origin_
= url
.GetOrigin().spec();
288 void SearchProviderInstallData::OnLoadFailed() {
289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
291 provider_map_
.reset(new SearchHostToURLsMap());
292 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
293 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
298 void SearchProviderInstallData::NotifyLoaded() {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
301 std::vector
<base::Closure
> closure_queue
;
302 closure_queue
.swap(closure_queue_
);
304 std::for_each(closure_queue
.begin(),
306 std::mem_fun_ref(&base::Closure::Run
));
308 // Since we expect this request to be rare, clear out the information. This
309 // also keeps the responses current as the search providers change.
310 provider_map_
.reset();