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 35 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents) 36 : content::WebContentsObserver(web_contents), 37 received_page_title_(false) { 38 } 39 40 HistoryTabHelper::~HistoryTabHelper() { 41 } 42 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 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 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 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 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 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 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 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