Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / search_engines / search_provider_install_data.cc
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.
4
5 #include "chrome/browser/search_engines/search_provider_install_data.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <vector>
10
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/profiles/profile.h"
20 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
21 #include "chrome/browser/search_engines/search_terms_data.h"
22 #include "chrome/browser/search_engines/template_url.h"
23 #include "chrome/browser/search_engines/template_url_service.h"
24 #include "chrome/browser/search_engines/template_url_service_factory.h"
25 #include "chrome/browser/search_engines/util.h"
26 #include "chrome/browser/webdata/web_data_service.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/notification_observer.h"
29 #include "content/public/browser/notification_registrar.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/notification_source.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/render_process_host_observer.h"
34
35 using content::BrowserThread;
36
37 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
38
39 namespace {
40
41 void LoadDataOnUIThread(TemplateURLService* template_url_service,
42                         const base::Callback<void(ScopedVector<TemplateURL>,
43                                                   TemplateURL*)>& callback) {
44   ScopedVector<TemplateURL> template_url_copies;
45   TemplateURL* default_provider_copy = NULL;
46   TemplateURLService::TemplateURLVector original_template_urls =
47       template_url_service->GetTemplateURLs();
48   TemplateURL* original_default_provider =
49       template_url_service->GetDefaultSearchProvider();
50   for (TemplateURLService::TemplateURLVector::const_iterator it =
51            original_template_urls.begin();
52        it != original_template_urls.end();
53        ++it) {
54     template_url_copies.push_back(new TemplateURL(NULL, (*it)->data()));
55     if (*it == original_default_provider)
56       default_provider_copy = template_url_copies.back();
57   }
58   BrowserThread::PostTask(BrowserThread::IO,
59                           FROM_HERE,
60                           base::Bind(callback,
61                                      base::Passed(template_url_copies.Pass()),
62                                      base::Unretained(default_provider_copy)));
63 }
64
65 // Implementation of SearchTermsData that may be used on the I/O thread.
66 class IOThreadSearchTermsData : public SearchTermsData {
67  public:
68   explicit IOThreadSearchTermsData(const std::string& google_base_url);
69
70   // Implementation of SearchTermsData.
71   virtual std::string GoogleBaseURLValue() const OVERRIDE;
72
73  private:
74   std::string google_base_url_;
75
76   DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData);
77 };
78
79 IOThreadSearchTermsData::IOThreadSearchTermsData(
80     const std::string& google_base_url) : google_base_url_(google_base_url) {
81 }
82
83 std::string IOThreadSearchTermsData::GoogleBaseURLValue() const {
84   return google_base_url_;
85 }
86
87 // Handles telling SearchProviderInstallData about changes to the google base
88 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
89 // deleted on the correct thread.)
90 class GoogleURLChangeNotifier
91     : public base::RefCountedThreadSafe<GoogleURLChangeNotifier,
92                                         BrowserThread::DeleteOnIOThread> {
93  public:
94   explicit GoogleURLChangeNotifier(
95       const base::WeakPtr<SearchProviderInstallData>& install_data);
96
97   // Called on the I/O thread with the Google base URL whenever the value
98   // changes.
99   void OnChange(const std::string& google_base_url);
100
101  private:
102   friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
103   friend class base::DeleteHelper<GoogleURLChangeNotifier>;
104
105   ~GoogleURLChangeNotifier() {}
106
107   base::WeakPtr<SearchProviderInstallData> install_data_;
108
109   DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier);
110 };
111
112 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
113     const base::WeakPtr<SearchProviderInstallData>& install_data)
114     : install_data_(install_data) {
115 }
116
117 void GoogleURLChangeNotifier::OnChange(const std::string& google_base_url) {
118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119   if (install_data_.get())
120     install_data_->OnGoogleURLChange(google_base_url);
121 }
122
123 // Notices changes in the Google base URL and sends them along
124 // to the SearchProviderInstallData on the I/O thread.
125 class GoogleURLObserver : public content::NotificationObserver,
126                           public content::RenderProcessHostObserver {
127  public:
128   GoogleURLObserver(Profile* profile,
129                     GoogleURLChangeNotifier* change_notifier,
130                     content::RenderProcessHost* host);
131
132   // Implementation of content::NotificationObserver.
133   virtual void Observe(int type,
134                        const content::NotificationSource& source,
135                        const content::NotificationDetails& details) OVERRIDE;
136
137   // Implementation of content::RenderProcessHostObserver.
138   virtual void RenderProcessHostDestroyed(
139         content::RenderProcessHost* host) OVERRIDE;
140
141  private:
142   virtual ~GoogleURLObserver() {}
143
144   scoped_refptr<GoogleURLChangeNotifier> change_notifier_;
145   content::NotificationRegistrar registrar_;
146
147   DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver);
148 };
149
150 GoogleURLObserver::GoogleURLObserver(
151     Profile* profile,
152     GoogleURLChangeNotifier* change_notifier,
153     content::RenderProcessHost* host)
154     : change_notifier_(change_notifier) {
155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156   registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
157                  content::Source<Profile>(profile->GetOriginalProfile()));
158   host->AddObserver(this);
159 }
160
161 void GoogleURLObserver::Observe(int type,
162                                 const content::NotificationSource& source,
163                                 const content::NotificationDetails& details) {
164   DCHECK_EQ(chrome::NOTIFICATION_GOOGLE_URL_UPDATED, type);
165   BrowserThread::PostTask(
166       BrowserThread::IO, FROM_HERE,
167       base::Bind(&GoogleURLChangeNotifier::OnChange,
168                  change_notifier_.get(),
169                  content::Details<GoogleURLTracker::UpdatedDetails>(details)->
170                      second.spec()));
171 }
172
173 void GoogleURLObserver::RenderProcessHostDestroyed(
174     content::RenderProcessHost* host) {
175   delete this;
176 }
177
178 // Indicates if the two inputs have the same security origin.
179 // |requested_origin| should only be a security origin (no path, etc.).
180 // It is ok if |template_url| is NULL.
181 static bool IsSameOrigin(const GURL& requested_origin,
182                          TemplateURL* template_url,
183                          const SearchTermsData& search_terms_data) {
184   DCHECK(requested_origin == requested_origin.GetOrigin());
185   DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
186   return requested_origin ==
187       TemplateURLService::GenerateSearchURLUsingTermsData(template_url,
188           search_terms_data).GetOrigin();
189 }
190
191 }  // namespace
192
193 SearchProviderInstallData::SearchProviderInstallData(
194     Profile* profile,
195     content::RenderProcessHost* host)
196     : template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)),
197       google_base_url_(UIThreadSearchTermsData(profile).GoogleBaseURLValue()),
198       weak_factory_(this) {
199   // GoogleURLObserver is responsible for killing itself when
200   // the given notification occurs.
201   new GoogleURLObserver(profile,
202                         new GoogleURLChangeNotifier(weak_factory_.GetWeakPtr()),
203                         host);
204 }
205
206 SearchProviderInstallData::~SearchProviderInstallData() {
207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208 }
209
210 void SearchProviderInstallData::CallWhenLoaded(const base::Closure& closure) {
211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
212
213   if (provider_map_.get()) {
214     closure.Run();
215     return;
216   }
217
218   bool do_load = closure_queue_.empty();
219   closure_queue_.push_back(closure);
220
221   // If the queue wasn't empty, there was already a load in progress.
222   if (!do_load)
223     return;
224
225   if (template_url_service_) {
226     BrowserThread::PostTask(
227         BrowserThread::UI,
228         FROM_HERE,
229         base::Bind(&LoadDataOnUIThread,
230                    template_url_service_,
231                    base::Bind(&SearchProviderInstallData::OnTemplateURLsLoaded,
232                               weak_factory_.GetWeakPtr())));
233   } else {
234     OnLoadFailed();
235   }
236 }
237
238 SearchProviderInstallData::State SearchProviderInstallData::GetInstallState(
239     const GURL& requested_origin) {
240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241   DCHECK(provider_map_.get());
242
243   // First check to see if the origin is the default search provider.
244   if (requested_origin.spec() == default_search_origin_)
245     return INSTALLED_AS_DEFAULT;
246
247   // Is the url any search provider?
248   const TemplateURLSet* urls = provider_map_->GetURLsForHost(
249       requested_origin.host());
250   if (!urls)
251     return NOT_INSTALLED;
252
253   IOThreadSearchTermsData search_terms_data(google_base_url_);
254   for (TemplateURLSet::const_iterator i = urls->begin();
255        i != urls->end(); ++i) {
256     if (IsSameOrigin(requested_origin, *i, search_terms_data))
257       return INSTALLED_BUT_NOT_DEFAULT;
258   }
259   return NOT_INSTALLED;
260 }
261
262 void SearchProviderInstallData::OnGoogleURLChange(
263     const std::string& google_base_url) {
264   google_base_url_ = google_base_url;
265 }
266
267 void SearchProviderInstallData::OnTemplateURLsLoaded(
268     ScopedVector<TemplateURL> template_urls,
269     TemplateURL* default_provider) {
270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
271
272   template_urls_ = template_urls.Pass();
273
274   IOThreadSearchTermsData search_terms_data(google_base_url_);
275   provider_map_.reset(new SearchHostToURLsMap());
276   provider_map_->Init(template_urls_.get(), search_terms_data);
277   SetDefault(default_provider);
278   NotifyLoaded();
279 }
280
281 void SearchProviderInstallData::SetDefault(const TemplateURL* template_url) {
282   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
283
284   if (!template_url) {
285     default_search_origin_.clear();
286     return;
287   }
288
289   DCHECK(template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION);
290
291   IOThreadSearchTermsData search_terms_data(google_base_url_);
292   const GURL url(TemplateURLService::GenerateSearchURLUsingTermsData(
293       template_url, search_terms_data));
294   if (!url.is_valid() || !url.has_host()) {
295     default_search_origin_.clear();
296     return;
297   }
298   default_search_origin_ = url.GetOrigin().spec();
299 }
300
301 void SearchProviderInstallData::OnLoadFailed() {
302   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
303
304   provider_map_.reset(new SearchHostToURLsMap());
305   IOThreadSearchTermsData search_terms_data(google_base_url_);
306   provider_map_->Init(template_urls_.get(), search_terms_data);
307   SetDefault(NULL);
308   NotifyLoaded();
309 }
310
311 void SearchProviderInstallData::NotifyLoaded() {
312   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
313
314   std::vector<base::Closure> closure_queue;
315   closure_queue.swap(closure_queue_);
316
317   std::for_each(closure_queue.begin(),
318                 closure_queue.end(),
319                 std::mem_fun_ref(&base::Closure::Run));
320
321   // Since we expect this request to be rare, clear out the information. This
322   // also keeps the responses current as the search providers change.
323   provider_map_.reset();
324   SetDefault(NULL);
325 }