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/ui/search_engines/search_engine_tab_helper.h"
      6 
      7 #include "chrome/browser/profiles/profile.h"
      8 #include "chrome/browser/search_engines/template_url.h"
      9 #include "chrome/browser/search_engines/template_url_fetcher.h"
     10 #include "chrome/browser/search_engines/template_url_model.h"
     11 #include "chrome/browser/ui/search_engines/template_url_fetcher_ui_callbacks.h"
     12 #include "chrome/common/render_messages.h"
     13 #include "content/common/view_messages.h"
     14 #include "content/browser/tab_contents/tab_contents.h"
     15 
     16 namespace {
     17 
     18 // Returns true if the entry's transition type is FORM_SUBMIT.
     19 bool IsFormSubmit(const NavigationEntry* entry) {
     20   return (PageTransition::StripQualifier(entry->transition_type()) ==
     21           PageTransition::FORM_SUBMIT);
     22 }
     23 
     24 }  // namespace
     25 
     26 SearchEngineTabHelper::SearchEngineTabHelper(TabContents* tab_contents)
     27     : TabContentsObserver(tab_contents) {
     28   DCHECK(tab_contents);
     29 }
     30 
     31 SearchEngineTabHelper::~SearchEngineTabHelper() {
     32 }
     33 
     34 void SearchEngineTabHelper::DidNavigateMainFramePostCommit(
     35     const NavigationController::LoadCommittedDetails& /*details*/,
     36     const ViewHostMsg_FrameNavigate_Params& params) {
     37   GenerateKeywordIfNecessary(params);
     38 }
     39 
     40 bool SearchEngineTabHelper::OnMessageReceived(const IPC::Message& message) {
     41   bool handled = true;
     42   IPC_BEGIN_MESSAGE_MAP(SearchEngineTabHelper, message)
     43     IPC_MESSAGE_HANDLER(ViewHostMsg_PageHasOSDD, OnPageHasOSDD)
     44     IPC_MESSAGE_UNHANDLED(handled = false)
     45   IPC_END_MESSAGE_MAP()
     46 
     47   return handled;
     48 }
     49 
     50 void SearchEngineTabHelper::OnPageHasOSDD(
     51     int32 page_id,
     52     const GURL& doc_url,
     53     const search_provider::OSDDType& msg_provider_type) {
     54   // Checks to see if we should generate a keyword based on the OSDD, and if
     55   // necessary uses TemplateURLFetcher to download the OSDD and create a
     56   // keyword.
     57 
     58   // Make sure page_id is the current page and other basic checks.
     59   DCHECK(doc_url.is_valid());
     60   if (!tab_contents()->IsActiveEntry(page_id))
     61     return;
     62   if (!tab_contents()->profile()->GetTemplateURLFetcher())
     63     return;
     64   if (tab_contents()->profile()->IsOffTheRecord())
     65     return;
     66 
     67   TemplateURLFetcher::ProviderType provider_type;
     68   switch (msg_provider_type) {
     69     case search_provider::AUTODETECTED_PROVIDER:
     70       provider_type = TemplateURLFetcher::AUTODETECTED_PROVIDER;
     71       break;
     72 
     73     case search_provider::EXPLICIT_DEFAULT_PROVIDER:
     74       provider_type = TemplateURLFetcher::EXPLICIT_DEFAULT_PROVIDER;
     75       break;
     76 
     77     case search_provider::EXPLICIT_PROVIDER:
     78       provider_type = TemplateURLFetcher::EXPLICIT_PROVIDER;
     79       break;
     80 
     81     default:
     82       NOTREACHED();
     83       return;
     84   }
     85 
     86   const NavigationController& controller = tab_contents()->controller();
     87   const NavigationEntry* entry = controller.GetLastCommittedEntry();
     88   DCHECK(entry);
     89 
     90   const NavigationEntry* base_entry = entry;
     91   if (IsFormSubmit(base_entry)) {
     92     // If the current page is a form submit, find the last page that was not
     93     // a form submit and use its url to generate the keyword from.
     94     int index = controller.last_committed_entry_index() - 1;
     95     while (index >= 0 && IsFormSubmit(controller.GetEntryAtIndex(index)))
     96       index--;
     97     if (index >= 0)
     98       base_entry = controller.GetEntryAtIndex(index);
     99     else
    100       base_entry = NULL;
    101   }
    102 
    103   // We want to use the user typed URL if available since that represents what
    104   // the user typed to get here, and fall back on the regular URL if not.
    105   if (!base_entry)
    106     return;
    107   GURL keyword_url = base_entry->user_typed_url().is_valid() ?
    108           base_entry->user_typed_url() : base_entry->url();
    109   if (!keyword_url.is_valid())
    110     return;
    111 
    112   string16 keyword = TemplateURLModel::GenerateKeyword(
    113       keyword_url,
    114       provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER);
    115 
    116   // Download the OpenSearch description document. If this is successful, a
    117   // new keyword will be created when done.
    118   tab_contents()->profile()->GetTemplateURLFetcher()->ScheduleDownload(
    119       keyword,
    120       doc_url,
    121       base_entry->favicon().url(),
    122       new TemplateURLFetcherUICallbacks(this, tab_contents()),
    123       provider_type);
    124 }
    125 
    126 void SearchEngineTabHelper::GenerateKeywordIfNecessary(
    127     const ViewHostMsg_FrameNavigate_Params& params) {
    128   if (!params.searchable_form_url.is_valid())
    129     return;
    130 
    131   if (tab_contents()->profile()->IsOffTheRecord())
    132     return;
    133 
    134   const NavigationController& controller = tab_contents()->controller();
    135   int last_index = controller.last_committed_entry_index();
    136   // When there was no previous page, the last index will be 0. This is
    137   // normally due to a form submit that opened in a new tab.
    138   // TODO(brettw) bug 916126: we should support keywords when form submits
    139   //              happen in new tabs.
    140   if (last_index <= 0)
    141     return;
    142   const NavigationEntry* previous_entry =
    143       controller.GetEntryAtIndex(last_index - 1);
    144   if (IsFormSubmit(previous_entry)) {
    145     // Only generate a keyword if the previous page wasn't itself a form
    146     // submit.
    147     return;
    148   }
    149 
    150   GURL keyword_url = previous_entry->user_typed_url().is_valid() ?
    151           previous_entry->user_typed_url() : previous_entry->url();
    152   string16 keyword =
    153       TemplateURLModel::GenerateKeyword(keyword_url, true);  // autodetected
    154   if (keyword.empty())
    155     return;
    156 
    157   TemplateURLModel* url_model =
    158       tab_contents()->profile()->GetTemplateURLModel();
    159   if (!url_model)
    160     return;
    161 
    162   if (!url_model->loaded()) {
    163     url_model->Load();
    164     return;
    165   }
    166 
    167   const TemplateURL* current_url;
    168   GURL url = params.searchable_form_url;
    169   if (!url_model->CanReplaceKeyword(keyword, url, &current_url))
    170     return;
    171 
    172   if (current_url) {
    173     if (current_url->originating_url().is_valid()) {
    174       // The existing keyword was generated from an OpenSearch description
    175       // document, don't regenerate.
    176       return;
    177     }
    178     url_model->Remove(current_url);
    179   }
    180   TemplateURL* new_url = new TemplateURL();
    181   new_url->set_keyword(keyword);
    182   new_url->set_short_name(keyword);
    183   new_url->SetURL(url.spec(), 0, 0);
    184   new_url->add_input_encoding(params.searchable_form_encoding);
    185   DCHECK(controller.GetLastCommittedEntry());
    186   const GURL& favicon_url =
    187       controller.GetLastCommittedEntry()->favicon().url();
    188   if (favicon_url.is_valid()) {
    189     new_url->SetFaviconURL(favicon_url);
    190   } else {
    191     // The favicon url isn't valid. This means there really isn't a favicon,
    192     // or the favicon url wasn't obtained before the load started. This assumes
    193     // the later.
    194     // TODO(sky): Need a way to set the favicon that doesn't involve generating
    195     // its url.
    196     new_url->SetFaviconURL(TemplateURL::GenerateFaviconURL(params.referrer));
    197   }
    198   new_url->set_safe_for_autoreplace(true);
    199   url_model->Add(new_url);
    200 }
    201