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