• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
IsFormSubmit(const NavigationEntry * entry)19 bool IsFormSubmit(const NavigationEntry* entry) {
20   return (PageTransition::StripQualifier(entry->transition_type()) ==
21           PageTransition::FORM_SUBMIT);
22 }
23 
24 }  // namespace
25 
SearchEngineTabHelper(TabContents * tab_contents)26 SearchEngineTabHelper::SearchEngineTabHelper(TabContents* tab_contents)
27     : TabContentsObserver(tab_contents) {
28   DCHECK(tab_contents);
29 }
30 
~SearchEngineTabHelper()31 SearchEngineTabHelper::~SearchEngineTabHelper() {
32 }
33 
DidNavigateMainFramePostCommit(const NavigationController::LoadCommittedDetails &,const ViewHostMsg_FrameNavigate_Params & params)34 void SearchEngineTabHelper::DidNavigateMainFramePostCommit(
35     const NavigationController::LoadCommittedDetails& /*details*/,
36     const ViewHostMsg_FrameNavigate_Params& params) {
37   GenerateKeywordIfNecessary(params);
38 }
39 
OnMessageReceived(const IPC::Message & message)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 
OnPageHasOSDD(int32 page_id,const GURL & doc_url,const search_provider::OSDDType & msg_provider_type)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 
GenerateKeywordIfNecessary(const ViewHostMsg_FrameNavigate_Params & params)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