Home | History | Annotate | Download | only in search_engines
      1 // Copyright (c) 2011 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 <vector>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/task.h"
     13 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
     14 #include "chrome/browser/search_engines/search_terms_data.h"
     15 #include "chrome/browser/search_engines/template_url.h"
     16 #include "chrome/browser/search_engines/template_url_model.h"
     17 #include "chrome/browser/search_engines/util.h"
     18 #include "chrome/browser/webdata/web_data_service.h"
     19 #include "content/browser/browser_thread.h"
     20 #include "content/common/notification_observer.h"
     21 #include "content/common/notification_registrar.h"
     22 #include "content/common/notification_service.h"
     23 #include "content/common/notification_source.h"
     24 #include "content/common/notification_type.h"
     25 
     26 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
     27 
     28 namespace {
     29 
     30 // Implementation of SearchTermsData that may be used on the I/O thread.
     31 class IOThreadSearchTermsData : public SearchTermsData {
     32  public:
     33   explicit IOThreadSearchTermsData(const std::string& google_base_url);
     34 
     35   // Implementation of SearchTermsData.
     36   virtual std::string GoogleBaseURLValue() const;
     37   virtual std::string GetApplicationLocale() const;
     38 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
     39   virtual string16 GetRlzParameterValue() const {
     40     // This value doesn't matter for our purposes.
     41     return string16();
     42   }
     43 #endif
     44 
     45  private:
     46   std::string google_base_url_;
     47 
     48   DISALLOW_COPY_AND_ASSIGN(IOThreadSearchTermsData);
     49 };
     50 
     51 IOThreadSearchTermsData::IOThreadSearchTermsData(
     52     const std::string& google_base_url) : google_base_url_(google_base_url) {
     53 }
     54 
     55 std::string IOThreadSearchTermsData::GoogleBaseURLValue() const {
     56   return google_base_url_;
     57 }
     58 
     59 std::string IOThreadSearchTermsData::GetApplicationLocale() const {
     60   // This value doesn't matter for our purposes.
     61   return "yy";
     62 }
     63 
     64 // Handles telling SearchProviderInstallData about changes to the google base
     65 // url. (Ensure that this is deleted on the I/O thread so that the WeakPtr is
     66 // deleted on the correct thread.)
     67 class GoogleURLChangeNotifier
     68     : public base::RefCountedThreadSafe<GoogleURLChangeNotifier,
     69                                         BrowserThread::DeleteOnIOThread> {
     70  public:
     71   explicit GoogleURLChangeNotifier(
     72       const base::WeakPtr<SearchProviderInstallData>& install_data);
     73 
     74   // Called on the I/O thread with the Google base URL whenever the value
     75   // changes.
     76   void OnChange(const std::string& google_base_url);
     77 
     78  private:
     79   friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
     80   friend class DeleteTask<GoogleURLChangeNotifier>;
     81 
     82   ~GoogleURLChangeNotifier() {}
     83 
     84   base::WeakPtr<SearchProviderInstallData> install_data_;
     85 
     86   DISALLOW_COPY_AND_ASSIGN(GoogleURLChangeNotifier);
     87 };
     88 
     89 GoogleURLChangeNotifier::GoogleURLChangeNotifier(
     90     const base::WeakPtr<SearchProviderInstallData>& install_data)
     91     : install_data_(install_data) {
     92 }
     93 
     94 void GoogleURLChangeNotifier::OnChange(const std::string& google_base_url) {
     95   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     96   if (install_data_)
     97     install_data_->OnGoogleURLChange(google_base_url);
     98 }
     99 
    100 // Notices changes in the Google base URL and sends them along
    101 // to the SearchProviderInstallData on the I/O thread.
    102 class GoogleURLObserver : public NotificationObserver {
    103  public:
    104   GoogleURLObserver(
    105       GoogleURLChangeNotifier* change_notifier,
    106       NotificationType ui_death_notification,
    107       const NotificationSource& ui_death_source);
    108 
    109   // Implementation of NotificationObserver.
    110   virtual void Observe(NotificationType type,
    111                        const NotificationSource& source,
    112                        const NotificationDetails& details);
    113 
    114  private:
    115   virtual ~GoogleURLObserver() {}
    116 
    117   scoped_refptr<GoogleURLChangeNotifier> change_notifier_;
    118   NotificationRegistrar registrar_;
    119 
    120   DISALLOW_COPY_AND_ASSIGN(GoogleURLObserver);
    121 };
    122 
    123 GoogleURLObserver::GoogleURLObserver(
    124       GoogleURLChangeNotifier* change_notifier,
    125       NotificationType ui_death_notification,
    126       const NotificationSource& ui_death_source)
    127     : change_notifier_(change_notifier) {
    128   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    129   registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED,
    130                  NotificationService::AllSources());
    131   registrar_.Add(this, ui_death_notification, ui_death_source);
    132 }
    133 
    134 void GoogleURLObserver::Observe(NotificationType type,
    135                                 const NotificationSource& source,
    136                                 const NotificationDetails& details) {
    137   if (type == NotificationType::GOOGLE_URL_UPDATED) {
    138     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    139         NewRunnableMethod(change_notifier_.get(),
    140                           &GoogleURLChangeNotifier::OnChange,
    141                           UIThreadSearchTermsData().GoogleBaseURLValue()));
    142   } else {
    143     // This must be the death notification.
    144     delete this;
    145   }
    146 }
    147 
    148 // Indicates if the two inputs have the same security origin.
    149 // |requested_origin| should only be a security origin (no path, etc.).
    150 // It is ok if |template_url| is NULL.
    151 static bool IsSameOrigin(const GURL& requested_origin,
    152                          const TemplateURL* template_url,
    153                          const SearchTermsData& search_terms_data) {
    154   DCHECK(requested_origin == requested_origin.GetOrigin());
    155   return template_url && requested_origin ==
    156       TemplateURLModel::GenerateSearchURLUsingTermsData(
    157           template_url,
    158           search_terms_data).GetOrigin();
    159 }
    160 
    161 }  // namespace
    162 
    163 SearchProviderInstallData::SearchProviderInstallData(
    164     WebDataService* web_service,
    165     NotificationType ui_death_notification,
    166     const NotificationSource& ui_death_source)
    167     : web_service_(web_service),
    168       load_handle_(0),
    169       google_base_url_(UIThreadSearchTermsData().GoogleBaseURLValue()) {
    170   // GoogleURLObserver is responsible for killing itself when
    171   // the given notification occurs.
    172   new GoogleURLObserver(new GoogleURLChangeNotifier(AsWeakPtr()),
    173                         ui_death_notification, ui_death_source);
    174   DetachFromThread();
    175 }
    176 
    177 SearchProviderInstallData::~SearchProviderInstallData() {
    178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    179 
    180   if (load_handle_) {
    181     DCHECK(web_service_.get());
    182     web_service_->CancelRequest(load_handle_);
    183   }
    184 }
    185 
    186 void SearchProviderInstallData::CallWhenLoaded(Task* task) {
    187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    188 
    189   if (provider_map_.get()) {
    190     task->Run();
    191     delete task;
    192     return;
    193   }
    194 
    195   task_queue_.Push(task);
    196   if (load_handle_)
    197     return;
    198 
    199   if (web_service_.get())
    200     load_handle_ = web_service_->GetKeywords(this);
    201   else
    202     OnLoadFailed();
    203 }
    204 
    205 SearchProviderInstallData::State SearchProviderInstallData::GetInstallState(
    206     const GURL& requested_origin) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    208   DCHECK(provider_map_.get());
    209 
    210   // First check to see if the origin is the default search provider.
    211   if (requested_origin.spec() == default_search_origin_)
    212     return INSTALLED_AS_DEFAULT;
    213 
    214   // Is the url any search provider?
    215   const TemplateURLSet* urls = provider_map_->GetURLsForHost(
    216       requested_origin.host());
    217   if (!urls)
    218     return NOT_INSTALLED;
    219 
    220   IOThreadSearchTermsData search_terms_data(google_base_url_);
    221   for (TemplateURLSet::const_iterator i = urls->begin();
    222        i != urls->end(); ++i) {
    223     const TemplateURL* template_url = *i;
    224     if (IsSameOrigin(requested_origin, template_url, search_terms_data))
    225       return INSTALLED_BUT_NOT_DEFAULT;
    226   }
    227   return NOT_INSTALLED;
    228 }
    229 
    230 void SearchProviderInstallData::OnGoogleURLChange(
    231     const std::string& google_base_url) {
    232   google_base_url_ = google_base_url;
    233 }
    234 
    235 void SearchProviderInstallData::OnWebDataServiceRequestDone(
    236     WebDataService::Handle h,
    237     const WDTypedResult* result) {
    238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    239 
    240   // Reset the load_handle so that we don't try and cancel the load in
    241   // the destructor.
    242   load_handle_ = 0;
    243 
    244   if (!result) {
    245     // Results are null if the database went away or (most likely) wasn't
    246     // loaded.
    247     OnLoadFailed();
    248     return;
    249   }
    250 
    251   const TemplateURL* default_search_provider = NULL;
    252   int new_resource_keyword_version = 0;
    253   std::vector<TemplateURL*> extracted_template_urls;
    254   GetSearchProvidersUsingKeywordResult(*result,
    255                                        NULL,
    256                                        NULL,
    257                                        &extracted_template_urls,
    258                                        &default_search_provider,
    259                                        &new_resource_keyword_version);
    260   template_urls_.get().insert(template_urls_.get().begin(),
    261                               extracted_template_urls.begin(),
    262                               extracted_template_urls.end());
    263   IOThreadSearchTermsData search_terms_data(google_base_url_);
    264   provider_map_.reset(new SearchHostToURLsMap());
    265   provider_map_->Init(template_urls_.get(), search_terms_data);
    266   SetDefault(default_search_provider);
    267   NotifyLoaded();
    268 }
    269 
    270 void SearchProviderInstallData::SetDefault(const TemplateURL* template_url) {
    271   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    272 
    273   if (!template_url) {
    274     default_search_origin_.clear();
    275     return;
    276   }
    277 
    278   IOThreadSearchTermsData search_terms_data(google_base_url_);
    279   const GURL url(TemplateURLModel::GenerateSearchURLUsingTermsData(
    280       template_url, search_terms_data));
    281   if (!url.is_valid() || !url.has_host()) {
    282     default_search_origin_.clear();
    283     return;
    284   }
    285   default_search_origin_ = url.GetOrigin().spec();
    286 }
    287 
    288 void SearchProviderInstallData::OnLoadFailed() {
    289   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    290 
    291   provider_map_.reset(new SearchHostToURLsMap());
    292   IOThreadSearchTermsData search_terms_data(google_base_url_);
    293   provider_map_->Init(template_urls_.get(), search_terms_data);
    294   SetDefault(NULL);
    295   NotifyLoaded();
    296 }
    297 
    298 void SearchProviderInstallData::NotifyLoaded() {
    299   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    300 
    301   task_queue_.Run();
    302 
    303   // Since we expect this request to be rare, clear out the information. This
    304   // also keeps the responses current as the search providers change.
    305   provider_map_.reset();
    306   SetDefault(NULL);
    307 }
    308