Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / search_engines / search_engine_tab_helper.cc
blob085afa16a2b7c27e5f0d0d49a4ba8069ffc9f206
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 "base/prefs/pref_service.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/search_engines/template_url_fetcher_factory.h"
10 #include "chrome/browser/search_engines/template_url_service_factory.h"
11 #include "chrome/browser/ui/search_engines/search_engine_tab_helper_delegate.h"
12 #include "chrome/common/pref_names.h"
13 #include "chrome/common/render_messages.h"
14 #include "chrome/common/url_constants.h"
15 #include "components/search_engines/template_url.h"
16 #include "components/search_engines/template_url_fetcher.h"
17 #include "components/search_engines/template_url_service.h"
18 #include "content/public/browser/favicon_status.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/frame_navigate_params.h"
25 #include "content/public/common/url_fetcher.h"
27 using content::NavigationController;
28 using content::NavigationEntry;
29 using content::WebContents;
31 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchEngineTabHelper);
33 namespace {
35 // Returns true if the entry's transition type is FORM_SUBMIT.
36 bool IsFormSubmit(const NavigationEntry* entry) {
37 return (ui::PageTransitionStripQualifier(entry->GetTransitionType()) ==
38 ui::PAGE_TRANSITION_FORM_SUBMIT);
41 base::string16 GenerateKeywordFromNavigationEntry(
42 const NavigationEntry* entry,
43 const std::string& accept_languages) {
44 // Don't autogenerate keywords for pages that are the result of form
45 // submissions.
46 if (IsFormSubmit(entry))
47 return base::string16();
49 // We want to use the user typed URL if available since that represents what
50 // the user typed to get here, and fall back on the regular URL if not.
51 GURL url = entry->GetUserTypedURL();
52 if (!url.is_valid()) {
53 url = entry->GetURL();
54 if (!url.is_valid())
55 return base::string16();
58 // Don't autogenerate keywords for referrers that are anything other than HTTP
59 // or have a path.
61 // If we relax the path constraint, we need to be sure to sanitize the path
62 // elements and update AutocompletePopup to look for keywords using the path.
63 // See http://b/issue?id=863583.
64 if (!url.SchemeIs(url::kHttpScheme) || (url.path().length() > 1))
65 return base::string16();
67 return TemplateURL::GenerateKeyword(url, accept_languages);
70 void AssociateURLFetcherWithWebContents(content::WebContents* web_contents,
71 net::URLFetcher* url_fetcher) {
72 content::AssociateURLFetcherWithRenderFrame(
73 url_fetcher,
74 web_contents->GetURL(),
75 web_contents->GetRenderProcessHost()->GetID(),
76 web_contents->GetMainFrame()->GetRoutingID());
79 } // namespace
81 SearchEngineTabHelper::~SearchEngineTabHelper() {
84 void SearchEngineTabHelper::DidNavigateMainFrame(
85 const content::LoadCommittedDetails& /*details*/,
86 const content::FrameNavigateParams& params) {
87 GenerateKeywordIfNecessary(params);
90 bool SearchEngineTabHelper::OnMessageReceived(const IPC::Message& message) {
91 bool handled = true;
92 IPC_BEGIN_MESSAGE_MAP(SearchEngineTabHelper, message)
93 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageHasOSDD, OnPageHasOSDD)
94 IPC_MESSAGE_UNHANDLED(handled = false)
95 IPC_END_MESSAGE_MAP()
97 return handled;
100 SearchEngineTabHelper::SearchEngineTabHelper(WebContents* web_contents)
101 : content::WebContentsObserver(web_contents),
102 delegate_(nullptr),
103 weak_ptr_factory_(this) {
104 DCHECK(web_contents);
107 void SearchEngineTabHelper::OnPageHasOSDD(
108 const GURL& page_url,
109 const GURL& osdd_url,
110 const search_provider::OSDDType& msg_provider_type) {
111 // Checks to see if we should generate a keyword based on the OSDD, and if
112 // necessary uses TemplateURLFetcher to download the OSDD and create a
113 // keyword.
115 // Make sure that the page is the current page and other basic checks.
116 // When |page_url| has file: scheme, this method doesn't work because of
117 // http://b/issue?id=863583. For that reason, this doesn't check and allow
118 // urls referring to osdd urls with same schemes.
119 if (!osdd_url.is_valid() || !osdd_url.SchemeIsHTTPOrHTTPS())
120 return;
122 Profile* profile =
123 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
124 if (page_url != web_contents()->GetLastCommittedURL() ||
125 !TemplateURLFetcherFactory::GetForProfile(profile) ||
126 profile->IsOffTheRecord())
127 return;
129 TemplateURLFetcher::ProviderType provider_type =
130 (msg_provider_type == search_provider::AUTODETECTED_PROVIDER) ?
131 TemplateURLFetcher::AUTODETECTED_PROVIDER :
132 TemplateURLFetcher::EXPLICIT_PROVIDER;
134 // If the current page is a form submit, find the last page that was not a
135 // form submit and use its url to generate the keyword from.
136 const NavigationController& controller = web_contents()->GetController();
137 const NavigationEntry* entry = controller.GetLastCommittedEntry();
138 for (int index = controller.GetLastCommittedEntryIndex();
139 (index > 0) && IsFormSubmit(entry);
140 entry = controller.GetEntryAtIndex(index))
141 --index;
142 if (!entry || IsFormSubmit(entry))
143 return;
145 // Autogenerate a keyword for the autodetected case; in the other cases we'll
146 // generate a keyword later after fetching the OSDD.
147 base::string16 keyword;
148 if (provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER) {
149 keyword = GenerateKeywordFromNavigationEntry(
150 entry, profile->GetPrefs()->GetString(prefs::kAcceptLanguages));
151 if (keyword.empty())
152 return;
155 // Download the OpenSearch description document. If this is successful, a
156 // new keyword will be created when done.
157 TemplateURLFetcherFactory::GetForProfile(profile)->ScheduleDownload(
158 keyword, osdd_url, entry->GetFavicon().url,
159 base::Bind(&AssociateURLFetcherWithWebContents, web_contents()),
160 base::Bind(&SearchEngineTabHelper::OnDownloadedOSDD,
161 weak_ptr_factory_.GetWeakPtr()),
162 provider_type);
165 void SearchEngineTabHelper::OnDownloadedOSDD(
166 scoped_ptr<TemplateURL> template_url) {
167 Profile* profile =
168 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
169 delegate_->ConfirmAddSearchProvider(template_url.release(), profile);
172 void SearchEngineTabHelper::GenerateKeywordIfNecessary(
173 const content::FrameNavigateParams& params) {
174 if (!params.searchable_form_url.is_valid())
175 return;
177 Profile* profile =
178 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
179 if (profile->IsOffTheRecord())
180 return;
182 const NavigationController& controller = web_contents()->GetController();
183 int last_index = controller.GetLastCommittedEntryIndex();
184 // When there was no previous page, the last index will be 0. This is
185 // normally due to a form submit that opened in a new tab.
186 // TODO(brettw) bug 916126: we should support keywords when form submits
187 // happen in new tabs.
188 if (last_index <= 0)
189 return;
191 base::string16 keyword(GenerateKeywordFromNavigationEntry(
192 controller.GetEntryAtIndex(last_index - 1),
193 profile->GetPrefs()->GetString(prefs::kAcceptLanguages)));
194 if (keyword.empty())
195 return;
197 TemplateURLService* url_service =
198 TemplateURLServiceFactory::GetForProfile(profile);
199 if (!url_service)
200 return;
202 if (!url_service->loaded()) {
203 url_service->Load();
204 return;
207 TemplateURL* current_url;
208 GURL url = params.searchable_form_url;
209 if (!url_service->CanAddAutogeneratedKeyword(keyword, url, &current_url))
210 return;
212 if (current_url) {
213 if (current_url->originating_url().is_valid()) {
214 // The existing keyword was generated from an OpenSearch description
215 // document, don't regenerate.
216 return;
218 url_service->Remove(current_url);
221 TemplateURLData data;
222 data.SetShortName(keyword);
223 data.SetKeyword(keyword);
224 data.SetURL(url.spec());
225 DCHECK(controller.GetLastCommittedEntry());
226 const GURL& current_favicon =
227 controller.GetLastCommittedEntry()->GetFavicon().url;
228 // If the favicon url isn't valid, it means there really isn't a favicon, or
229 // the favicon url wasn't obtained before the load started. This assumes the
230 // latter.
231 // TODO(sky): Need a way to set the favicon that doesn't involve generating
232 // its url.
233 data.favicon_url = current_favicon.is_valid() ?
234 current_favicon : TemplateURL::GenerateFaviconURL(params.referrer.url);
235 data.safe_for_autoreplace = true;
236 data.input_encodings.push_back(params.searchable_form_encoding);
237 url_service->Add(new TemplateURL(data));