Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / search_engines / search_provider_install_data.cc
blobe650a264c62802e96291dd4878aaf66e2860a070
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"
7 #include <algorithm>
8 #include <functional>
9 #include <vector>
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;
35 namespace {
37 // Implementation of SearchTermsData that may be used on the I/O thread.
38 class IOThreadSearchTermsData : public SearchTermsData {
39 public:
40 explicit IOThreadSearchTermsData(const std::string& google_base_url);
42 // Implementation of SearchTermsData.
43 virtual std::string GoogleBaseURLValue() const OVERRIDE;
45 private:
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> {
65 public:
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
70 // changes.
71 void OnChange(const std::string& google_base_url);
73 private:
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 {
98 public:
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;
109 private:
110 virtual ~GoogleURLObserver() {}
112 scoped_refptr<GoogleURLChangeNotifier> change_notifier_;
113 content::NotificationRegistrar registrar_;
115 DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver);
118 GoogleURLObserver::GoogleURLObserver(
119 Profile* profile,
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.
137 spec()));
138 } else {
139 // This must be the death notification.
140 delete this;
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();
157 } // namespace
159 SearchProviderInstallData::SearchProviderInstallData(
160 Profile* profile,
161 int ui_death_notification,
162 const content::NotificationSource& ui_death_source)
163 : web_service_(WebDataService::FromBrowserContext(profile)),
164 load_handle_(0),
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));
175 if (load_handle_) {
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()) {
185 closure.Run();
186 return;
189 closure_queue_.push_back(closure);
190 if (load_handle_)
191 return;
193 if (web_service_.get())
194 load_handle_ = web_service_->GetKeywords(this);
195 else
196 OnLoadFailed();
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());
211 if (!urls)
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
234 // the destructor.
235 load_handle_ = 0;
237 if (!result) {
238 // Results are null if the database went away or (most likely) wasn't
239 // loaded.
240 OnLoadFailed();
241 return;
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);
257 NotifyLoaded();
260 void SearchProviderInstallData::SetDefault(const TemplateURL* template_url) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263 if (!template_url) {
264 default_search_origin_.clear();
265 return;
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();
275 return;
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);
286 SetDefault(NULL);
287 NotifyLoaded();
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(),
297 closure_queue.end(),
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();
303 SetDefault(NULL);