history_tab_helper.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.h"
10#include "chrome/browser/history/history_service_factory.h"
11#include "chrome/browser/instant/instant_loader.h"
12#include "chrome/browser/prerender/prerender_contents.h"
13#include "chrome/browser/prerender/prerender_manager.h"
14#include "chrome/browser/prerender/prerender_manager_factory.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/render_messages.h"
17#include "content/public/browser/navigation_details.h"
18#include "content/public/browser/navigation_entry.h"
19#include "content/public/browser/notification_details.h"
20#include "content/public/browser/notification_source.h"
21#include "content/public/browser/notification_types.h"
22#include "content/public/browser/web_contents.h"
23#include "content/public/browser/web_contents_delegate.h"
24#include "content/public/common/frame_navigate_params.h"
25
26#if !defined(OS_ANDROID)
27#include "chrome/browser/ui/browser.h"
28#include "chrome/browser/ui/browser_finder.h"
29#endif
30
31using content::NavigationEntry;
32using content::WebContents;
33
34DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper)
35
36HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
37    : content::WebContentsObserver(web_contents),
38      received_page_title_(false) {
39  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
40                 content::Source<WebContents>(web_contents));
41}
42
43HistoryTabHelper::~HistoryTabHelper() {
44}
45
46void HistoryTabHelper::UpdateHistoryForNavigation(
47    const history::HistoryAddPageArgs& add_page_args) {
48  HistoryService* hs = GetHistoryService();
49  if (hs)
50    GetHistoryService()->AddPage(add_page_args);
51}
52
53void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
54  HistoryService* hs = GetHistoryService();
55  if (hs)
56    hs->SetPageTitle(entry.GetVirtualURL(), entry.GetTitleForDisplay(""));
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  InstantLoader* instant_loader =
131      InstantLoader::FromWebContents(web_contents());
132  if (instant_loader) {
133    instant_loader->DidNavigate(add_page_args);
134    return;
135  }
136
137#if !defined(OS_ANDROID)
138  // Don't update history if this web contents isn't associatd with a tab.
139  Browser* browser = browser::FindBrowserWithWebContents(web_contents());
140  if (!browser || browser->is_app())
141    return;
142#endif
143
144  UpdateHistoryForNavigation(add_page_args);
145}
146
147void HistoryTabHelper::Observe(int type,
148                               const content::NotificationSource& source,
149                               const content::NotificationDetails& details) {
150  DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED);
151  std::pair<content::NavigationEntry*, bool>* title =
152      content::Details<std::pair<content::NavigationEntry*, bool> >(
153          details).ptr();
154
155  if (received_page_title_)
156    return;
157
158  if (title->first) {
159    UpdateHistoryPageTitle(*title->first);
160    received_page_title_ = title->second;
161  }
162}
163
164void HistoryTabHelper::OnPageContents(const GURL& url,
165                                      int32 page_id,
166                                      const string16& contents) {
167  // Don't index any https pages. People generally don't want their bank
168  // accounts, etc. indexed on their computer, especially since some of these
169  // things are not marked cachable.
170  // TODO(brettw) we may want to consider more elaborate heuristics such as
171  // the cachability of the page. We may also want to consider subframes (this
172  // test will still index subframes if the subframe is SSL).
173  // TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable
174  // content indexing for chromeos in some future releases.
175#if !defined(OS_CHROMEOS)
176  if (!url.SchemeIsSecure()) {
177    HistoryService* hs = GetHistoryService();
178    if (hs)
179      hs->SetPageContents(url, contents);
180  }
181#endif
182}
183
184HistoryService* HistoryTabHelper::GetHistoryService() {
185  Profile* profile =
186      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
187  if (profile->IsOffTheRecord())
188    return NULL;
189
190  return HistoryServiceFactory::GetForProfile(profile,
191                                              Profile::IMPLICIT_ACCESS);
192}
193
194void HistoryTabHelper::WebContentsDestroyed(WebContents* tab) {
195  // We update the history for this URL.
196  // The content returned from web_contents() has been destroyed by now.
197  // We need to use tab value directly.
198  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
199  if (profile->IsOffTheRecord())
200    return;
201
202  HistoryService* hs =
203      HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
204  if (hs) {
205    NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
206    if (entry) {
207      hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
208                                base::Time::Now());
209    }
210  }
211}
212