Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / search_engines / search_engine_tab_helper.cc
blob7ebda485ad15dabd61e25fce9c850aa16a4cd25a
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/ui/search_engines/search_engine_tab_helper.h"
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_fetcher_factory.h"
11 #include "chrome/browser/search_engines/template_url_service.h"
12 #include "chrome/browser/search_engines/template_url_service_factory.h"
13 #include "chrome/browser/ui/search_engines/template_url_fetcher_ui_callbacks.h"
14 #include "chrome/common/render_messages.h"
15 #include "chrome/common/url_constants.h"
16 #include "content/public/browser/favicon_status.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/frame_navigate_params.h"
22 using content::NavigationController;
23 using content::NavigationEntry;
24 using content::WebContents;
26 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchEngineTabHelper);
28 namespace {
30 // Returns true if the entry's transition type is FORM_SUBMIT.
31 bool IsFormSubmit(const NavigationEntry* entry) {
32 return (content::PageTransitionStripQualifier(entry->GetTransitionType()) ==
33 content::PAGE_TRANSITION_FORM_SUBMIT);
36 base::string16 GenerateKeywordFromNavigationEntry(
37 const NavigationEntry* entry) {
38 // Don't autogenerate keywords for pages that are the result of form
39 // submissions.
40 if (IsFormSubmit(entry))
41 return base::string16();
43 // We want to use the user typed URL if available since that represents what
44 // the user typed to get here, and fall back on the regular URL if not.
45 GURL url = entry->GetUserTypedURL();
46 if (!url.is_valid()) {
47 url = entry->GetURL();
48 if (!url.is_valid())
49 return base::string16();
52 // Don't autogenerate keywords for referrers that are anything other than HTTP
53 // or have a path.
55 // If we relax the path constraint, we need to be sure to sanitize the path
56 // elements and update AutocompletePopup to look for keywords using the path.
57 // See http://b/issue?id=863583.
58 if (!url.SchemeIs(content::kHttpScheme) || (url.path().length() > 1))
59 return base::string16();
61 return TemplateURLService::GenerateKeyword(url);
64 } // namespace
66 SearchEngineTabHelper::~SearchEngineTabHelper() {
69 void SearchEngineTabHelper::DidNavigateMainFrame(
70 const content::LoadCommittedDetails& /*details*/,
71 const content::FrameNavigateParams& params) {
72 GenerateKeywordIfNecessary(params);
75 bool SearchEngineTabHelper::OnMessageReceived(const IPC::Message& message) {
76 bool handled = true;
77 IPC_BEGIN_MESSAGE_MAP(SearchEngineTabHelper, message)
78 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageHasOSDD, OnPageHasOSDD)
79 IPC_MESSAGE_UNHANDLED(handled = false)
80 IPC_END_MESSAGE_MAP()
82 return handled;
85 SearchEngineTabHelper::SearchEngineTabHelper(WebContents* web_contents)
86 : content::WebContentsObserver(web_contents) {
87 DCHECK(web_contents);
90 void SearchEngineTabHelper::OnPageHasOSDD(
91 int32 page_id,
92 const GURL& doc_url,
93 const search_provider::OSDDType& msg_provider_type) {
94 // Checks to see if we should generate a keyword based on the OSDD, and if
95 // necessary uses TemplateURLFetcher to download the OSDD and create a
96 // keyword.
98 // Make sure page_id is the current page and other basic checks.
99 if (!doc_url.is_valid())
100 return;
101 Profile* profile =
102 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
103 if (!web_contents()->IsActiveEntry(page_id) ||
104 !TemplateURLFetcherFactory::GetForProfile(profile) ||
105 profile->IsOffTheRecord())
106 return;
108 TemplateURLFetcher::ProviderType provider_type =
109 (msg_provider_type == search_provider::AUTODETECTED_PROVIDER) ?
110 TemplateURLFetcher::AUTODETECTED_PROVIDER :
111 TemplateURLFetcher::EXPLICIT_PROVIDER;
113 // If the current page is a form submit, find the last page that was not a
114 // form submit and use its url to generate the keyword from.
115 const NavigationController& controller = web_contents()->GetController();
116 const NavigationEntry* entry = controller.GetLastCommittedEntry();
117 for (int index = controller.GetLastCommittedEntryIndex();
118 (index > 0) && IsFormSubmit(entry);
119 entry = controller.GetEntryAtIndex(index))
120 --index;
121 if (IsFormSubmit(entry))
122 return;
124 // Autogenerate a keyword for the autodetected case; in the other cases we'll
125 // generate a keyword later after fetching the OSDD.
126 base::string16 keyword;
127 if (provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER) {
128 keyword = GenerateKeywordFromNavigationEntry(entry);
129 if (keyword.empty())
130 return;
133 // Download the OpenSearch description document. If this is successful, a
134 // new keyword will be created when done.
135 TemplateURLFetcherFactory::GetForProfile(profile)->ScheduleDownload(
136 keyword, doc_url, entry->GetFavicon().url, web_contents(),
137 new TemplateURLFetcherUICallbacks(this, web_contents()), provider_type);
140 void SearchEngineTabHelper::GenerateKeywordIfNecessary(
141 const content::FrameNavigateParams& params) {
142 if (!params.searchable_form_url.is_valid())
143 return;
145 Profile* profile =
146 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
147 if (profile->IsOffTheRecord())
148 return;
150 const NavigationController& controller = web_contents()->GetController();
151 int last_index = controller.GetLastCommittedEntryIndex();
152 // When there was no previous page, the last index will be 0. This is
153 // normally due to a form submit that opened in a new tab.
154 // TODO(brettw) bug 916126: we should support keywords when form submits
155 // happen in new tabs.
156 if (last_index <= 0)
157 return;
159 base::string16 keyword(GenerateKeywordFromNavigationEntry(
160 controller.GetEntryAtIndex(last_index - 1)));
161 if (keyword.empty())
162 return;
164 TemplateURLService* url_service =
165 TemplateURLServiceFactory::GetForProfile(profile);
166 if (!url_service)
167 return;
169 if (!url_service->loaded()) {
170 url_service->Load();
171 return;
174 TemplateURL* current_url;
175 GURL url = params.searchable_form_url;
176 if (!url_service->CanReplaceKeyword(keyword, url, &current_url))
177 return;
179 if (current_url) {
180 if (current_url->originating_url().is_valid()) {
181 // The existing keyword was generated from an OpenSearch description
182 // document, don't regenerate.
183 return;
185 url_service->Remove(current_url);
188 TemplateURLData data;
189 data.short_name = keyword;
190 data.SetKeyword(keyword);
191 data.SetURL(url.spec());
192 DCHECK(controller.GetLastCommittedEntry());
193 const GURL& current_favicon =
194 controller.GetLastCommittedEntry()->GetFavicon().url;
195 // If the favicon url isn't valid, it means there really isn't a favicon, or
196 // the favicon url wasn't obtained before the load started. This assumes the
197 // latter.
198 // TODO(sky): Need a way to set the favicon that doesn't involve generating
199 // its url.
200 data.favicon_url = current_favicon.is_valid() ?
201 current_favicon : TemplateURL::GenerateFaviconURL(params.referrer.url);
202 data.safe_for_autoreplace = true;
203 data.input_encodings.push_back(params.searchable_form_encoding);
204 url_service->Add(new TemplateURL(profile, data));