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.
4
5 #include "chrome/browser/history/history_tab_helper.h"
6
7 #include <utility>
8
9 #include "chrome/browser/history/history_service.h"
10 #include "chrome/browser/history/history_service_factory.h"
11 #if !defined(OS_ANDROID)
12 #include "chrome/browser/network_time/navigation_time_helper.h"
13 #endif
14 #include "chrome/browser/prerender/prerender_contents.h"
15 #include "chrome/browser/prerender/prerender_manager.h"
16 #include "chrome/browser/prerender/prerender_manager_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/render_messages.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/common/frame_navigate_params.h"
24
25 #if !defined(OS_ANDROID)
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_finder.h"
28 #endif
29
30 using content::NavigationEntry;
31 using content::WebContents;
32
33 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper);
34
HistoryTabHelper(WebContents * web_contents)35 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
36 : content::WebContentsObserver(web_contents),
37 received_page_title_(false) {
38 }
39
~HistoryTabHelper()40 HistoryTabHelper::~HistoryTabHelper() {
41 }
42
UpdateHistoryForNavigation(const history::HistoryAddPageArgs & add_page_args)43 void HistoryTabHelper::UpdateHistoryForNavigation(
44 const history::HistoryAddPageArgs& add_page_args) {
45 HistoryService* hs = GetHistoryService();
46 if (hs)
47 GetHistoryService()->AddPage(add_page_args);
48 }
49
UpdateHistoryPageTitle(const NavigationEntry & entry)50 void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
51 HistoryService* hs = GetHistoryService();
52 if (hs)
53 hs->SetPageTitle(entry.GetVirtualURL(),
54 entry.GetTitleForDisplay(std::string()));
55 }
56
57 history::HistoryAddPageArgs
CreateHistoryAddPageArgs(const GURL & virtual_url,base::Time timestamp,bool did_replace_entry,const content::FrameNavigateParams & params)58 HistoryTabHelper::CreateHistoryAddPageArgs(
59 const GURL& virtual_url,
60 base::Time timestamp,
61 bool did_replace_entry,
62 const content::FrameNavigateParams& params) {
63 history::HistoryAddPageArgs add_page_args(
64 params.url, timestamp, web_contents(), params.page_id,
65 params.referrer.url, params.redirects, params.transition,
66 history::SOURCE_BROWSED, did_replace_entry);
67 if (content::PageTransitionIsMainFrame(params.transition) &&
68 virtual_url != params.url) {
69 // Hack on the "virtual" URL so that it will appear in history. For some
70 // types of URLs, we will display a magic URL that is different from where
71 // the page is actually navigated. We want the user to see in history what
72 // they saw in the URL bar, so we add the virtual URL as a redirect. This
73 // only applies to the main frame, as the virtual URL doesn't apply to
74 // sub-frames.
75 add_page_args.url = virtual_url;
76 if (!add_page_args.redirects.empty())
77 add_page_args.redirects.back() = virtual_url;
78 }
79 return add_page_args;
80 }
81
DidNavigateMainFrame(const content::LoadCommittedDetails & details,const content::FrameNavigateParams & params)82 void HistoryTabHelper::DidNavigateMainFrame(
83 const content::LoadCommittedDetails& details,
84 const content::FrameNavigateParams& params) {
85 // Allow the new page to set the title again.
86 received_page_title_ = false;
87 }
88
DidNavigateAnyFrame(const content::LoadCommittedDetails & details,const content::FrameNavigateParams & params)89 void HistoryTabHelper::DidNavigateAnyFrame(
90 const content::LoadCommittedDetails& details,
91 const content::FrameNavigateParams& params) {
92 // Update history. Note that this needs to happen after the entry is complete,
93 // which WillNavigate[Main,Sub]Frame will do before this function is called.
94 if (!params.should_update_history)
95 return;
96
97 #if !defined(OS_ANDROID)
98 base::Time navigation_time =
99 NavigationTimeHelper::FromWebContents(web_contents())->GetNavigationTime(
100 details.entry);
101 #else
102 base::Time navigation_time = details.entry->GetTimestamp();
103 #endif
104
105 // Most of the time, the displayURL matches the loaded URL, but for about:
106 // URLs, we use a data: URL as the real value. We actually want to save the
107 // about: URL to the history db and keep the data: URL hidden. This is what
108 // the WebContents' URL getter does.
109 const history::HistoryAddPageArgs& add_page_args =
110 CreateHistoryAddPageArgs(
111 web_contents()->GetURL(), navigation_time,
112 details.did_replace_entry, params);
113
114 prerender::PrerenderManager* prerender_manager =
115 prerender::PrerenderManagerFactory::GetForProfile(
116 Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
117 if (prerender_manager) {
118 prerender::PrerenderContents* prerender_contents =
119 prerender_manager->GetPrerenderContents(web_contents());
120 if (prerender_contents) {
121 prerender_contents->DidNavigate(add_page_args);
122 return;
123 }
124 }
125
126 #if !defined(OS_ANDROID)
127 // Don't update history if this web contents isn't associatd with a tab.
128 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
129 if (!browser || browser->is_app())
130 return;
131 #endif
132
133 UpdateHistoryForNavigation(add_page_args);
134 }
135
TitleWasSet(NavigationEntry * entry,bool explicit_set)136 void HistoryTabHelper::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
137 if (received_page_title_)
138 return;
139
140 if (entry) {
141 UpdateHistoryPageTitle(*entry);
142 received_page_title_ = explicit_set;
143 }
144 }
145
GetHistoryService()146 HistoryService* HistoryTabHelper::GetHistoryService() {
147 Profile* profile =
148 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
149 if (profile->IsOffTheRecord())
150 return NULL;
151
152 return HistoryServiceFactory::GetForProfile(profile,
153 Profile::IMPLICIT_ACCESS);
154 }
155
WebContentsDestroyed(WebContents * tab)156 void HistoryTabHelper::WebContentsDestroyed(WebContents* tab) {
157 // TODO(sky): nuke this since no one is using visit_duration (and this is all
158 // wrong).
159
160 // We update the history for this URL.
161 // The content returned from web_contents() has been destroyed by now.
162 // We need to use tab value directly.
163 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
164 if (profile->IsOffTheRecord())
165 return;
166
167 HistoryService* hs =
168 HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
169 if (hs) {
170 NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
171 if (entry) {
172 hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
173 base::Time::Now());
174 }
175 }
176 }
177