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