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"
31 using content::BrowserThread
;
33 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet
;
37 // Implementation of SearchTermsData that may be used on the I/O thread.
38 class IOThreadSearchTermsData
: public SearchTermsData
{
40 explicit IOThreadSearchTermsData(const std::string
& google_base_url
);
42 // Implementation of SearchTermsData.
43 virtual std::string
GoogleBaseURLValue() const OVERRIDE
;
46 std::string google_base_url_
;
48 DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData
);
51 IOThreadSearchTermsData::IOThreadSearchTermsData(
52 const std::string
& google_base_url
) : google_base_url_(google_base_url
) {
55 std::string
IOThreadSearchTermsData::GoogleBaseURLValue() const {
56 return google_base_url_
;
59 // Handles telling SearchProviderInstallData about changes to the google base
60 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
61 // deleted on the correct thread.)
62 class GoogleURLChangeNotifier
63 : public base::RefCountedThreadSafe
<GoogleURLChangeNotifier
,
64 BrowserThread::DeleteOnIOThread
> {
66 explicit GoogleURLChangeNotifier(
67 const base::WeakPtr
<SearchProviderInstallData
>& install_data
);
69 // Called on the I/O thread with the Google base URL whenever the value
71 void OnChange(const std::string
& google_base_url
);
74 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
75 friend class base::DeleteHelper
<GoogleURLChangeNotifier
>;
77 ~GoogleURLChangeNotifier() {}
79 base::WeakPtr
<SearchProviderInstallData
> install_data_
;
81 DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier
);
84 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
85 const base::WeakPtr
<SearchProviderInstallData
>& install_data
)
86 : install_data_(install_data
) {
89 void GoogleURLChangeNotifier::OnChange(const std::string
& google_base_url
) {
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
91 if (install_data_
.get())
92 install_data_
->OnGoogleURLChange(google_base_url
);
95 // Notices changes in the Google base URL and sends them along
96 // to the SearchProviderInstallData on the I/O thread.
97 class GoogleURLObserver
: public content::NotificationObserver
{
99 GoogleURLObserver(Profile
* profile
,
100 GoogleURLChangeNotifier
* change_notifier
,
101 int ui_death_notification
,
102 const content::NotificationSource
& ui_death_source
);
104 // Implementation of content::NotificationObserver.
105 virtual void Observe(int type
,
106 const content::NotificationSource
& source
,
107 const content::NotificationDetails
& details
) OVERRIDE
;
110 virtual ~GoogleURLObserver() {}
112 scoped_refptr
<GoogleURLChangeNotifier
> change_notifier_
;
113 content::NotificationRegistrar registrar_
;
115 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver
);
118 GoogleURLObserver::GoogleURLObserver(
120 GoogleURLChangeNotifier
* change_notifier
,
121 int ui_death_notification
,
122 const content::NotificationSource
& ui_death_source
)
123 : change_notifier_(change_notifier
) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
125 registrar_
.Add(this, chrome::NOTIFICATION_GOOGLE_URL_UPDATED
,
126 content::Source
<Profile
>(profile
->GetOriginalProfile()));
127 registrar_
.Add(this, ui_death_notification
, ui_death_source
);
130 void GoogleURLObserver::Observe(int type
,
131 const content::NotificationSource
& source
,
132 const content::NotificationDetails
& details
) {
133 if (type
== chrome::NOTIFICATION_GOOGLE_URL_UPDATED
) {
134 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
135 base::Bind(&GoogleURLChangeNotifier::OnChange
, change_notifier_
.get(),
136 content::Details
<GoogleURLTracker::UpdatedDetails
>(details
)->second
.
139 // This must be the death notification.
144 // Indicates if the two inputs have the same security origin.
145 // |requested_origin| should only be a security origin (no path, etc.).
146 // It is ok if |template_url| is NULL.
147 static bool IsSameOrigin(const GURL
& requested_origin
,
148 TemplateURL
* template_url
,
149 const SearchTermsData
& search_terms_data
) {
150 DCHECK(requested_origin
== requested_origin
.GetOrigin());
151 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
152 return requested_origin
==
153 TemplateURLService::GenerateSearchURLUsingTermsData(template_url
,
154 search_terms_data
).GetOrigin();
159 SearchProviderInstallData::SearchProviderInstallData(
161 int ui_death_notification
,
162 const content::NotificationSource
& ui_death_source
)
163 : web_service_(WebDataService::FromBrowserContext(profile
)),
165 google_base_url_(UIThreadSearchTermsData(profile
).GoogleBaseURLValue()) {
166 // GoogleURLObserver is responsible for killing itself when
167 // the given notification occurs.
168 new GoogleURLObserver(profile
, new GoogleURLChangeNotifier(AsWeakPtr()),
169 ui_death_notification
, ui_death_source
);
172 SearchProviderInstallData::~SearchProviderInstallData() {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
176 DCHECK(web_service_
.get());
177 web_service_
->CancelRequest(load_handle_
);
181 void SearchProviderInstallData::CallWhenLoaded(const base::Closure
& closure
) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
184 if (provider_map_
.get()) {
189 closure_queue_
.push_back(closure
);
193 if (web_service_
.get())
194 load_handle_
= web_service_
->GetKeywords(this);
199 SearchProviderInstallData::State
SearchProviderInstallData::GetInstallState(
200 const GURL
& requested_origin
) {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
202 DCHECK(provider_map_
.get());
204 // First check to see if the origin is the default search provider.
205 if (requested_origin
.spec() == default_search_origin_
)
206 return INSTALLED_AS_DEFAULT
;
208 // Is the url any search provider?
209 const TemplateURLSet
* urls
= provider_map_
->GetURLsForHost(
210 requested_origin
.host());
212 return NOT_INSTALLED
;
214 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
215 for (TemplateURLSet::const_iterator i
= urls
->begin();
216 i
!= urls
->end(); ++i
) {
217 if (IsSameOrigin(requested_origin
, *i
, search_terms_data
))
218 return INSTALLED_BUT_NOT_DEFAULT
;
220 return NOT_INSTALLED
;
223 void SearchProviderInstallData::OnGoogleURLChange(
224 const std::string
& google_base_url
) {
225 google_base_url_
= google_base_url
;
228 void SearchProviderInstallData::OnWebDataServiceRequestDone(
229 WebDataService::Handle h
,
230 const WDTypedResult
* result
) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
233 // Reset the load_handle so that we don't try and cancel the load in
238 // Results are null if the database went away or (most likely) wasn't
244 TemplateURL
* default_search_provider
= NULL
;
245 int new_resource_keyword_version
= 0;
246 std::vector
<TemplateURL
*> extracted_template_urls
;
247 GetSearchProvidersUsingKeywordResult(*result
, NULL
, NULL
,
248 &extracted_template_urls
, &default_search_provider
,
249 &new_resource_keyword_version
, NULL
);
250 template_urls_
.get().insert(template_urls_
.get().begin(),
251 extracted_template_urls
.begin(),
252 extracted_template_urls
.end());
253 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
254 provider_map_
.reset(new SearchHostToURLsMap());
255 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
256 SetDefault(default_search_provider
);
260 void SearchProviderInstallData::SetDefault(const TemplateURL
* template_url
) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
264 default_search_origin_
.clear();
268 DCHECK(template_url
->GetType() != TemplateURL::OMNIBOX_API_EXTENSION
);
270 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
271 const GURL
url(TemplateURLService::GenerateSearchURLUsingTermsData(
272 template_url
, search_terms_data
));
273 if (!url
.is_valid() || !url
.has_host()) {
274 default_search_origin_
.clear();
277 default_search_origin_
= url
.GetOrigin().spec();
280 void SearchProviderInstallData::OnLoadFailed() {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
283 provider_map_
.reset(new SearchHostToURLsMap());
284 IOThreadSearchTermsData
search_terms_data(google_base_url_
);
285 provider_map_
->Init(template_urls_
.get(), search_terms_data
);
290 void SearchProviderInstallData::NotifyLoaded() {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
293 std::vector
<base::Closure
> closure_queue
;
294 closure_queue
.swap(closure_queue_
);
296 std::for_each(closure_queue
.begin(),
298 std::mem_fun_ref(&base::Closure::Run
));
300 // Since we expect this request to be rare, clear out the information. This
301 // also keeps the responses current as the search providers change.
302 provider_map_
.reset();