history_tab_helper.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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#include "chrome/browser/prerender/prerender_contents.h"
12#include "chrome/browser/prerender/prerender_manager.h"
13#include "chrome/browser/prerender/prerender_manager_factory.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/common/render_messages.h"
16#include "content/public/browser/navigation_details.h"
17#include "content/public/browser/navigation_entry.h"
18#include "content/public/browser/notification_details.h"
19#include "content/public/browser/notification_source.h"
20#include "content/public/browser/notification_types.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
30using content::NavigationEntry;
31using content::WebContents;
32
33DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper);
34
35HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
36    : content::WebContentsObserver(web_contents),
37      received_page_title_(false) {
38  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
39                 content::Source<WebContents>(web_contents));
40}
41
42HistoryTabHelper::~HistoryTabHelper() {
43}
44
45void HistoryTabHelper::UpdateHistoryForNavigation(
46    const history::HistoryAddPageArgs& add_page_args) {
47  HistoryService* hs = GetHistoryService();
48  if (hs)
49    GetHistoryService()->AddPage(add_page_args);
50}
51
52void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
53  HistoryService* hs = GetHistoryService();
54  if (hs)
55    hs->SetPageTitle(entry.GetVirtualURL(),
56                     entry.GetTitleForDisplay(std::string()));
57}
58
59history::HistoryAddPageArgs
60HistoryTabHelper::CreateHistoryAddPageArgs(
61    const GURL& virtual_url,
62    base::Time timestamp,
63    bool did_replace_entry,
64    const content::FrameNavigateParams& params) {
65  history::HistoryAddPageArgs add_page_args(
66      params.url, timestamp, web_contents(), params.page_id,
67      params.referrer.url, params.redirects, params.transition,
68      history::SOURCE_BROWSED, did_replace_entry);
69  if (content::PageTransitionIsMainFrame(params.transition) &&
70      virtual_url != params.url) {
71    // Hack on the "virtual" URL so that it will appear in history. For some
72    // types of URLs, we will display a magic URL that is different from where
73    // the page is actually navigated. We want the user to see in history what
74    // they saw in the URL bar, so we add the virtual URL as a redirect.  This
75    // only applies to the main frame, as the virtual URL doesn't apply to
76    // sub-frames.
77    add_page_args.url = virtual_url;
78    if (!add_page_args.redirects.empty())
79      add_page_args.redirects.back() = virtual_url;
80  }
81  return add_page_args;
82}
83
84bool HistoryTabHelper::OnMessageReceived(const IPC::Message& message) {
85  bool handled = true;
86  IPC_BEGIN_MESSAGE_MAP(HistoryTabHelper, message)
87    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageContents, OnPageContents)
88    IPC_MESSAGE_UNHANDLED(handled = false)
89  IPC_END_MESSAGE_MAP()
90
91  return handled;
92}
93
94void HistoryTabHelper::DidNavigateMainFrame(
95    const content::LoadCommittedDetails& details,
96    const content::FrameNavigateParams& params) {
97  // Allow the new page to set the title again.
98  received_page_title_ = false;
99}
100
101void HistoryTabHelper::DidNavigateAnyFrame(
102    const content::LoadCommittedDetails& details,
103    const content::FrameNavigateParams& params) {
104  // Update history. Note that this needs to happen after the entry is complete,
105  // which WillNavigate[Main,Sub]Frame will do before this function is called.
106  if (!params.should_update_history)
107    return;
108
109  // Most of the time, the displayURL matches the loaded URL, but for about:
110  // URLs, we use a data: URL as the real value.  We actually want to save the
111  // about: URL to the history db and keep the data: URL hidden. This is what
112  // the WebContents' URL getter does.
113  const history::HistoryAddPageArgs& add_page_args =
114      CreateHistoryAddPageArgs(
115          web_contents()->GetURL(), details.entry->GetTimestamp(),
116          details.did_replace_entry, params);
117
118  prerender::PrerenderManager* prerender_manager =
119      prerender::PrerenderManagerFactory::GetForProfile(
120          Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
121  if (prerender_manager) {
122    prerender::PrerenderContents* prerender_contents =
123        prerender_manager->GetPrerenderContents(web_contents());
124    if (prerender_contents) {
125      prerender_contents->DidNavigate(add_page_args);
126      return;
127    }
128  }
129
130#if !defined(OS_ANDROID)
131  // Don't update history if this web contents isn't associatd with a tab.
132  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
133  if (!browser || browser->is_app())
134    return;
135#endif
136
137  UpdateHistoryForNavigation(add_page_args);
138}
139
140void HistoryTabHelper::Observe(int type,
141                               const content::NotificationSource& source,
142                               const content::NotificationDetails& details) {
143  DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED);
144  std::pair<content::NavigationEntry*, bool>* title =
145      content::Details<std::pair<content::NavigationEntry*, bool> >(
146          details).ptr();
147
148  if (received_page_title_)
149    return;
150
151  if (title->first) {
152    UpdateHistoryPageTitle(*title->first);
153    received_page_title_ = title->second;
154  }
155}
156
157void HistoryTabHelper::OnPageContents(const GURL& url,
158                                      int32 page_id,
159                                      const string16& contents) {
160  // Don't index any https pages. People generally don't want their bank
161  // accounts, etc. indexed on their computer, especially since some of these
162  // things are not marked cachable.
163  // TODO(brettw) we may want to consider more elaborate heuristics such as
164  // the cachability of the page. We may also want to consider subframes (this
165  // test will still index subframes if the subframe is SSL).
166  // TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable
167  // content indexing for chromeos in some future releases.
168#if !defined(OS_CHROMEOS)
169  if (!url.SchemeIsSecure()) {
170    HistoryService* hs = GetHistoryService();
171    if (hs)
172      hs->SetPageContents(url, contents);
173  }
174#endif
175}
176
177HistoryService* HistoryTabHelper::GetHistoryService() {
178  Profile* profile =
179      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
180  if (profile->IsOffTheRecord())
181    return NULL;
182
183  return HistoryServiceFactory::GetForProfile(profile,
184                                              Profile::IMPLICIT_ACCESS);
185}
186
187void HistoryTabHelper::WebContentsDestroyed(WebContents* tab) {
188  // TODO(sky): nuke this since no one is using visit_duration (and this is all
189  // wrong).
190
191  // We update the history for this URL.
192  // The content returned from web_contents() has been destroyed by now.
193  // We need to use tab value directly.
194  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
195  if (profile->IsOffTheRecord())
196    return;
197
198  HistoryService* hs =
199      HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
200  if (hs) {
201    NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
202    if (entry) {
203      hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
204                                base::Time::Now());
205    }
206  }
207}
208