summaryrefslogtreecommitdiff
path: root/chromium/content/browser/frame_host/navigation_controller_impl.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/content/browser/frame_host/navigation_controller_impl.cc
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/content/browser/frame_host/navigation_controller_impl.cc')
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.cc458
1 files changed, 344 insertions, 114 deletions
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.cc b/chromium/content/browser/frame_host/navigation_controller_impl.cc
index 4be5a3ce4a0..8339b73051b 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.cc
@@ -6,14 +6,16 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h" // Temporary
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/switches.h"
+#include "components/mime_util/mime_util.h"
+#include "content/browser/bad_message.h"
#include "content/browser/browser_url_handler_impl.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
@@ -37,6 +39,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "net/base/escape.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
@@ -129,9 +132,13 @@ bool AreURLsInPageNavigation(const GURL& existing_url,
// for now.
existing_url == GURL(url::kAboutBlankURL) ||
existing_url.GetOrigin() == new_url.GetOrigin() ||
- !prefs.web_security_enabled;
- if (!is_same_origin && renderer_says_in_page)
- rfh->GetProcess()->ReceivedBadMessage();
+ !prefs.web_security_enabled ||
+ (prefs.allow_universal_access_from_file_urls &&
+ existing_url.SchemeIs(url::kFileScheme));
+ if (!is_same_origin && renderer_says_in_page) {
+ bad_message::ReceivedBadMessage(rfh->GetProcess(),
+ bad_message::NC_IN_PAGE_NAVIGATION);
+ }
return is_same_origin && renderer_says_in_page;
}
@@ -163,11 +170,17 @@ NavigationEntry* NavigationController::CreateNavigationEntry(
bool is_renderer_initiated,
const std::string& extra_headers,
BrowserContext* browser_context) {
+ // Fix up the given URL before letting it be rewritten, so that any minor
+ // cleanup (e.g., removing leading dots) will not lead to a virtual URL.
+ GURL dest_url(url);
+ BrowserURLHandlerImpl::GetInstance()->FixupURLBeforeRewrite(&dest_url,
+ browser_context);
+
// Allow the browser URL handler to rewrite the URL. This will, for example,
// remove "view-source:" from the beginning of the URL to get the URL that
// will actually be loaded. This real URL won't be shown to the user, just
// used internally.
- GURL loaded_url(url);
+ GURL loaded_url(dest_url);
bool reverse_on_redirect = false;
BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
&loaded_url, browser_context, &reverse_on_redirect);
@@ -181,8 +194,8 @@ NavigationEntry* NavigationController::CreateNavigationEntry(
base::string16(),
transition,
is_renderer_initiated);
- entry->SetVirtualURL(url);
- entry->set_user_typed_url(url);
+ entry->SetVirtualURL(dest_url);
+ entry->set_user_typed_url(dest_url);
entry->set_update_virtual_url_with_url(reverse_on_redirect);
entry->set_extra_headers(extra_headers);
return entry;
@@ -214,6 +227,8 @@ NavigationControllerImpl::NavigationControllerImpl(
BrowserContext* browser_context)
: browser_context_(browser_context),
pending_entry_(NULL),
+ failed_pending_entry_id_(0),
+ failed_pending_entry_should_replace_(false),
last_committed_entry_index_(-1),
pending_entry_index_(-1),
transient_entry_index_(-1),
@@ -282,8 +297,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
if (transient_entry_index_ != -1) {
// If an interstitial is showing, treat a reload as a navigation to the
// transient entry's URL.
- NavigationEntryImpl* transient_entry =
- NavigationEntryImpl::FromNavigationEntry(GetTransientEntry());
+ NavigationEntryImpl* transient_entry = GetTransientEntry();
if (!transient_entry)
return;
LoadURL(transient_entry->GetURL(),
@@ -307,8 +321,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
DiscardNonCommittedEntriesInternal();
current_index = GetCurrentEntryIndex();
if (current_index != -1) {
- entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(current_index));
+ entry = GetEntryAtIndex(current_index);
}
}
@@ -424,7 +437,7 @@ void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) {
Details<NavigationEntry>(entry));
}
-NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetActiveEntry() const {
if (transient_entry_index_ != -1)
return entries_[transient_entry_index_].get();
if (pending_entry_)
@@ -432,7 +445,7 @@ NavigationEntry* NavigationControllerImpl::GetActiveEntry() const {
return GetLastCommittedEntry();
}
-NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetVisibleEntry() const {
if (transient_entry_index_ != -1)
return entries_[transient_entry_index_].get();
// The pending entry is safe to return for new (non-history), browser-
@@ -446,7 +459,7 @@ NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
bool safe_to_show_pending =
pending_entry_ &&
// Require a new navigation.
- pending_entry_->GetPageID() == -1 &&
+ pending_entry_index_ == -1 &&
// Require either browser-initiated or an unmodified new tab.
(!pending_entry_->is_renderer_initiated() || IsUnmodifiedBlankTab());
@@ -455,7 +468,7 @@ NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const {
// can script the new tab before it commits.
if (!safe_to_show_pending &&
pending_entry_ &&
- pending_entry_->GetPageID() != -1 &&
+ pending_entry_index_ != -1 &&
IsInitialNavigation() &&
!pending_entry_->is_renderer_initiated())
safe_to_show_pending = true;
@@ -473,7 +486,7 @@ int NavigationControllerImpl::GetCurrentEntryIndex() const {
return last_committed_entry_index_;
}
-NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetLastCommittedEntry() const {
if (last_committed_entry_index_ == -1)
return NULL;
return entries_[last_committed_entry_index_].get();
@@ -481,7 +494,8 @@ NavigationEntry* NavigationControllerImpl::GetLastCommittedEntry() const {
bool NavigationControllerImpl::CanViewSource() const {
const std::string& mime_type = delegate_->GetContentsMimeType();
- bool is_viewable_mime_type = net::IsSupportedNonImageMimeType(mime_type) &&
+ bool is_viewable_mime_type =
+ mime_util::IsSupportedNonImageMimeType(mime_type) &&
!net::IsSupportedMediaMimeType(mime_type);
NavigationEntry* visible_entry = GetVisibleEntry();
return visible_entry && !visible_entry->IsViewSourceMode() &&
@@ -497,12 +511,12 @@ int NavigationControllerImpl::GetEntryCount() const {
return static_cast<int>(entries_.size());
}
-NavigationEntry* NavigationControllerImpl::GetEntryAtIndex(
+NavigationEntryImpl* NavigationControllerImpl::GetEntryAtIndex(
int index) const {
return entries_.at(index).get();
}
-NavigationEntry* NavigationControllerImpl::GetEntryAtOffset(
+NavigationEntryImpl* NavigationControllerImpl::GetEntryAtOffset(
int offset) const {
int index = GetIndexForOffset(offset);
if (index < 0 || index >= GetEntryCount())
@@ -655,7 +669,7 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
if (HandleDebugURL(params.url, params.transition_type)) {
// If Telemetry is running, allow the URL load to proceed as if it's
// unhandled, otherwise Telemetry can't tell if Navigation completed.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking))
return;
}
@@ -719,17 +733,35 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
params.is_renderer_initiated,
params.extra_headers,
browser_context_));
+ if (!params.frame_name.empty()) {
+ // This is only used for navigating subframes in tests.
+ FrameTreeNode* named_frame =
+ delegate_->GetFrameTree()->FindByName(params.frame_name);
+ if (named_frame)
+ entry->set_frame_tree_node_id(named_frame->frame_tree_node_id());
+ }
if (params.frame_tree_node_id != -1)
entry->set_frame_tree_node_id(params.frame_tree_node_id);
+ entry->set_source_site_instance(
+ static_cast<SiteInstanceImpl*>(params.source_site_instance.get()));
if (params.redirect_chain.size() > 0)
entry->SetRedirectChain(params.redirect_chain);
- if (params.should_replace_current_entry)
+ // Don't allow an entry replacement if there is no entry to replace.
+ // http://crbug.com/457149
+ if (params.should_replace_current_entry && entries_.size() > 0)
entry->set_should_replace_entry(true);
entry->set_should_clear_history_list(params.should_clear_history_list);
entry->SetIsOverridingUserAgent(override);
entry->set_transferred_global_request_id(
params.transferred_global_request_id);
- entry->SetFrameToNavigate(params.frame_name);
+
+#if defined(OS_ANDROID)
+ if (params.intent_received_timestamp > 0) {
+ entry->set_intent_received_timestamp(
+ base::TimeTicks() +
+ base::TimeDelta::FromMilliseconds(params.intent_received_timestamp));
+ }
+#endif
switch (params.load_type) {
case LOAD_TYPE_DEFAULT:
@@ -753,7 +785,7 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
}
bool NavigationControllerImpl::RendererDidNavigate(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
LoadCommittedDetails* details) {
is_initial_navigation_ = false;
@@ -774,14 +806,37 @@ bool NavigationControllerImpl::RendererDidNavigate(
// If we are doing a cross-site reload, we need to replace the existing
// navigation entry, not add another entry to the history. This has the side
- // effect of removing forward browsing history, if such existed.
- // Or if we are doing a cross-site redirect navigation,
- // we will do a similar thing.
- details->did_replace_entry =
- pending_entry_ && pending_entry_->should_replace_entry();
+ // effect of removing forward browsing history, if such existed. Or if we are
+ // doing a cross-site redirect navigation, we will do a similar thing.
+ //
+ // If this is an error load, we may have already removed the pending entry
+ // when we got the notice of the load failure. If so, look at the copy of the
+ // pending parameters that were saved.
+ if (params.url_is_unreachable && failed_pending_entry_id_ != 0) {
+ details->did_replace_entry = failed_pending_entry_should_replace_;
+ } else {
+ details->did_replace_entry = pending_entry_ &&
+ pending_entry_->should_replace_entry();
+ }
// Do navigation-type specific actions. These will make and commit an entry.
details->type = ClassifyNavigation(rfh, params);
+#if DCHECK_IS_ON()
+ // For site-per-process, both ClassifyNavigation methods get it wrong (see
+ // http://crbug.com/464014) so don't worry about a mismatch if that's the
+ // case.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ NavigationType new_type = ClassifyNavigationWithoutPageID(rfh, params);
+ // There's constant disagreements over SAME_PAGE between the two classifiers
+ // so ignore disagreements if that's the case. Otherwise, enforce agreement.
+ // TODO(avi): Work this out.
+ if (details->type != NAVIGATION_TYPE_SAME_PAGE &&
+ new_type != NAVIGATION_TYPE_SAME_PAGE) {
+ DCHECK_EQ(details->type, new_type);
+ }
+ }
+#endif // DCHECK_IS_ON()
// is_in_page must be computed before the entry gets committed.
details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
@@ -838,8 +893,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// All committed entries should have nonempty content state so WebKit doesn't
// get confused when we go back to them (see the function for details).
DCHECK(params.page_state.IsValid());
- NavigationEntryImpl* active_entry =
- NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
+ NavigationEntryImpl* active_entry = GetLastCommittedEntry();
active_entry->SetTimestamp(timestamp);
active_entry->SetHttpStatusCode(params.http_status_code);
active_entry->SetPageState(params.page_state);
@@ -865,8 +919,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// Remember the bindings the renderer process has at this point, so that
// we do not grant this entry additional bindings if we come back to it.
- active_entry->SetBindings(
- static_cast<RenderFrameHostImpl*>(rfh)->GetEnabledBindings());
+ active_entry->SetBindings(rfh->GetEnabledBindings());
// Now prep the rest of the details for the notification and broadcast.
details->entry = active_entry;
@@ -880,15 +933,15 @@ bool NavigationControllerImpl::RendererDidNavigate(
}
NavigationType NavigationControllerImpl::ClassifyNavigation(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const {
if (params.page_id == -1) {
- // TODO(nasko, creis): An out-of-process child frame has no way of
- // knowing the page_id of its parent, so it is passing back -1. The
- // semantics here should be re-evaluated during session history refactor
- // (see http://crbug.com/236848). For now, we assume this means the
- // child frame loaded and proceed. Note that this may do the wrong thing
- // for cross-process AUTO_SUBFRAME navigations.
+ // TODO(nasko, creis): An out-of-process child frame has no way of knowing
+ // the page_id of its parent, so it is passing back -1. The semantics here
+ // should be re-evaluated during session history refactor (see
+ // http://crbug.com/236848 and in particular http://crbug.com/464014). For
+ // now, we assume this means the child frame loaded and proceed. Note that
+ // this may do the wrong thing for cross-process AUTO_SUBFRAME navigations.
if (rfh->IsCrossProcessSubframe())
return NAVIGATION_TYPE_NEW_SUBFRAME;
@@ -977,8 +1030,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
temp.append(",");
}
GURL url(temp);
- static_cast<RenderFrameHostImpl*>(rfh)->render_view_host()->Send(
- new ViewMsg_TempCrashWithData(url));
+ rfh->render_view_host()->Send(new ViewMsg_TempCrashWithData(url));
return NAVIGATION_TYPE_NAV_IGNORE;
}
NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
@@ -996,15 +1048,31 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
!pending_entry_->is_renderer_initiated() &&
existing_entry != pending_entry_ &&
pending_entry_->GetPageID() == -1 &&
- existing_entry == GetLastCommittedEntry()) {
- // In this case, we have a pending entry for a URL but WebCore didn't do a
- // new navigation. This happens when you press enter in the URL bar to
- // reload. We will create a pending entry, but WebKit will convert it to
- // a reload since it's the same page and not create a new entry for it
- // (the user doesn't want to have a new back/forward entry when they do
- // this). If this matches the last committed entry, we want to just ignore
- // the pending entry and go back to where we were (the "existing entry").
- return NAVIGATION_TYPE_SAME_PAGE;
+ existing_entry == GetLastCommittedEntry() &&
+ !params.was_within_same_page) {
+ // In order to prevent unrelated pending entries from interfering with
+ // this classification, make sure that the URL committed matches the URLs
+ // of both the existing entry and the pending entry. There might have been
+ // a redirection, though, so allow both the existing and pending entries
+ // to match either the final URL that committed, or the original one
+ // before redirection.
+ GURL original_url;
+ if (params.redirects.size())
+ original_url = params.redirects[0];
+
+ if ((params.url == existing_entry->GetURL() ||
+ original_url == existing_entry->GetURL()) &&
+ (params.url == pending_entry_->GetURL() ||
+ original_url == pending_entry_->GetURL())) {
+ // In this case, we have a pending entry for a URL but Blink didn't do a
+ // new navigation. This happens when you press enter in the URL bar to
+ // reload. We will create a pending entry, but Blink will convert it to a
+ // reload since it's the same page and not create a new entry for it (the
+ // user doesn't want to have a new back/forward entry when they do this).
+ // If this matches the last committed entry, we want to just ignore the
+ // pending entry and go back to where we were (the "existing entry").
+ return NAVIGATION_TYPE_SAME_PAGE;
+ }
}
// Any toplevel navigations with the same base (minus the reference fragment)
@@ -1022,8 +1090,123 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
return NAVIGATION_TYPE_EXISTING_PAGE;
}
+NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID(
+ RenderFrameHostImpl* rfh,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const {
+ if (params.did_create_new_entry) {
+ // A new entry. We may or may not have a pending entry for the page, and
+ // this may or may not be the main frame.
+ if (ui::PageTransitionIsMainFrame(params.transition)) {
+ // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit
+ // tests fake auto subframe commits by sending the main frame a
+ // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here.
+ return NAVIGATION_TYPE_NEW_PAGE;
+ }
+
+ // When this is a new subframe navigation, we should have a committed page
+ // in which it's a subframe. This may not be the case when an iframe is
+ // navigated on a popup navigated to about:blank (the iframe would be
+ // written into the popup by script on the main page). For these cases,
+ // there isn't any navigation stuff we can do, so just ignore it.
+ if (!GetLastCommittedEntry())
+ return NAVIGATION_TYPE_NAV_IGNORE;
+
+ // Valid subframe navigation.
+ return NAVIGATION_TYPE_NEW_SUBFRAME;
+ }
+
+ // We only clear the session history when navigating to a new page.
+ DCHECK(!params.history_list_was_cleared);
+
+ if (!ui::PageTransitionIsMainFrame(params.transition)) {
+ // All manual subframes would be did_create_new_entry and handled above, so
+ // we know this is auto.
+ if (GetLastCommittedEntry()) {
+ return NAVIGATION_TYPE_AUTO_SUBFRAME;
+ } else {
+ // We ignore subframes created in non-committed pages; we'd appreciate if
+ // people stopped doing that.
+ return NAVIGATION_TYPE_NAV_IGNORE;
+ }
+ }
+
+ if (params.nav_entry_id == 0) {
+ // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't
+ // create a new page.
+
+ // Just like above in the did_create_new_entry case, it's possible to
+ // scribble onto an uncommitted page. Again, there isn't any navigation
+ // stuff that we can do, so ignore it here as well.
+ if (!GetLastCommittedEntry())
+ return NAVIGATION_TYPE_NAV_IGNORE;
+
+ if (params.was_within_same_page) {
+ // This is history.replaceState(), which is renderer-initiated yet within
+ // the same page.
+ return NAVIGATION_TYPE_IN_PAGE;
+ } else {
+ // This is history.reload() or a client-side redirect.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+ }
+
+ if (pending_entry_ && pending_entry_index_ == -1 &&
+ pending_entry_->GetUniqueID() == params.nav_entry_id) {
+ // In this case, we have a pending entry for a load of a new URL but Blink
+ // didn't do a new navigation (params.did_create_new_entry). This happens
+ // when you press enter in the URL bar to reload. We will create a pending
+ // entry, but Blink will convert it to a reload since it's the same page and
+ // not create a new entry for it (the user doesn't want to have a new
+ // back/forward entry when they do this). Therefore we want to just ignore
+ // the pending entry and go back to where we were (the "existing entry").
+ return NAVIGATION_TYPE_SAME_PAGE;
+ }
+
+ if (params.intended_as_new_entry) {
+ // This was intended to be a navigation to a new entry but the pending entry
+ // got cleared in the meanwhile. Classify as EXISTING_PAGE because we may or
+ // may not have a pending entry.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+
+ if (params.url_is_unreachable && failed_pending_entry_id_ != 0 &&
+ params.nav_entry_id == failed_pending_entry_id_) {
+ // If the renderer was going to a new pending entry that got cleared because
+ // of an error, this is the case of the user trying to retry a failed load
+ // by pressing return. Classify as EXISTING_PAGE because we probably don't
+ // have a pending entry.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+ }
+
+ // Now we know that the notification is for an existing page. Find that entry.
+ int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id);
+ if (existing_entry_index == -1) {
+ // The page was not found. It could have been pruned because of the limit on
+ // back/forward entries (not likely since we'll usually tell it to navigate
+ // to such entries). It could also mean that the renderer is smoking crack.
+ // TODO(avi): Crash the renderer like we do in the old ClassifyNavigation?
+ NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id;
+ return NAVIGATION_TYPE_NAV_IGNORE;
+ }
+
+ // Any top-level navigations with the same base (minus the reference fragment)
+ // are in-page navigations. (We weeded out subframe navigations above.) Most
+ // of the time this doesn't matter since Blink doesn't tell us about subframe
+ // navigations that don't actually navigate, but it can happen when there is
+ // an encoding override (it always sends a navigation request).
+ NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
+ if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
+ params.was_within_same_page, rfh)) {
+ return NAVIGATION_TYPE_IN_PAGE;
+ }
+
+ // Since we weeded out "new" navigations above, we know this is an existing
+ // (back/forward) navigation.
+ return NAVIGATION_TYPE_EXISTING_PAGE;
+}
+
void NavigationControllerImpl::RendererDidNavigateToNewPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool replace_entry) {
NavigationEntryImpl* new_entry;
@@ -1034,12 +1217,8 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
if (pending_entry_ &&
(!pending_entry_->site_instance() ||
pending_entry_->site_instance() == rfh->GetSiteInstance())) {
- new_entry = new NavigationEntryImpl(*pending_entry_);
+ new_entry = pending_entry_->Clone();
- // Don't use the page type from the pending entry. Some interstitial page
- // may have set the type to interstitial. Once we commit, however, the page
- // type must always be normal.
- new_entry->set_page_type(PAGE_TYPE_NORMAL);
update_virtual_url = new_entry->update_virtual_url_with_url();
} else {
new_entry = new NavigationEntryImpl;
@@ -1060,8 +1239,11 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
update_virtual_url = needs_update;
}
- if (params.url_is_unreachable)
- new_entry->set_page_type(PAGE_TYPE_ERROR);
+ // Don't use the page type from the pending entry. Some interstitial page
+ // may have set the type to interstitial. Once we commit, however, the page
+ // type must always be normal or error.
+ new_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
new_entry->SetURL(params.url);
if (update_virtual_url)
UpdateVirtualURLToURL(new_entry, params.url);
@@ -1097,7 +1279,7 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
}
void NavigationControllerImpl::RendererDidNavigateToExistingPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
// We should only get here for main frame navigations.
DCHECK(ui::PageTransitionIsMainFrame(params.transition));
@@ -1112,6 +1294,8 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
NavigationEntryImpl* entry = entries_[entry_index].get();
// The URL may have changed due to redirects.
+ entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
entry->SetURL(params.url);
entry->SetReferrer(params.referrer);
if (entry->update_virtual_url_with_url())
@@ -1150,7 +1334,7 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
}
void NavigationControllerImpl::RendererDidNavigateToSamePage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
// This mode implies we have a pending entry that's the same as an existing
// entry for this page ID. This entry is guaranteed to exist by
@@ -1164,6 +1348,8 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage(
existing_entry->set_unique_id(pending_entry_->GetUniqueID());
// The URL may have changed due to redirects.
+ existing_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
if (existing_entry->update_virtual_url_with_url())
UpdateVirtualURLToURL(existing_entry, params.url);
existing_entry->SetURL(params.url);
@@ -1177,7 +1363,7 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage(
}
void NavigationControllerImpl::RendererDidNavigateInPage(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool* did_replace_entry) {
DCHECK(ui::PageTransitionIsMainFrame(params.transition)) <<
@@ -1190,6 +1376,8 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
// entry and it will be the same page as the new navigation (minus the
// reference fragments, of course). We'll update the URL of the existing
// entry without pruning the forward history.
+ existing_entry->set_page_type(params.url_is_unreachable ? PAGE_TYPE_ERROR
+ : PAGE_TYPE_NORMAL);
existing_entry->SetURL(params.url);
if (existing_entry->update_virtual_url_with_url())
UpdateVirtualURLToURL(existing_entry, params.url);
@@ -1209,11 +1397,26 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
}
void NavigationControllerImpl::RendererDidNavigateNewSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
- if (ui::PageTransitionCoreTypeIs(params.transition,
- ui::PAGE_TRANSITION_AUTO_SUBFRAME)) {
- // This is not user-initiated. Ignore.
+ if (!ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_MANUAL_SUBFRAME)) {
+ // There was a comment here that said, "This is not user-initiated. Ignore."
+ // But this makes no sense; non-user-initiated navigations should be
+ // determined to be of type NAVIGATION_TYPE_AUTO_SUBFRAME and sent to
+ // RendererDidNavigateAutoSubframe below.
+ //
+ // This if clause dates back to https://codereview.chromium.org/115919 and
+ // the handling of immediate redirects. TODO(avi): Is this still valid? I'm
+ // pretty sure that's there's nothing left of that code and that we should
+ // take this out.
+ //
+ // Except for cross-process iframes; this doesn't work yet for them.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ NOTREACHED();
+ }
+
DiscardNonCommittedEntriesInternal();
return;
}
@@ -1224,15 +1427,17 @@ void NavigationControllerImpl::RendererDidNavigateNewSubframe(
// band with the actual navigations.
DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee "
<< "that a last committed entry exists.";
- NavigationEntryImpl* new_entry = new NavigationEntryImpl(
- *NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry()));
+ NavigationEntryImpl* new_entry = GetLastCommittedEntry()->Clone();
new_entry->SetPageID(params.page_id);
InsertOrReplaceEntry(new_entry, false);
}
bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
- RenderFrameHost* rfh,
+ RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
+ DCHECK(ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME));
+
// We're guaranteed to have a previously committed entry, and we now need to
// handle navigation inside of a subframe in it without creating a new entry.
DCHECK(GetLastCommittedEntry());
@@ -1251,11 +1456,32 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
// Update the current navigation entry in case we're going back/forward.
if (entry_index != last_committed_entry_index_) {
+ // Make sure that a subframe commit isn't changing the main frame's origin.
+ // Otherwise the renderer process may be confused, leading to a URL spoof.
+ // We can't check the path since that may change (https://crbug.com/373041).
+ if (GetLastCommittedEntry()->GetURL().GetOrigin() !=
+ GetEntryAtIndex(entry_index)->GetURL().GetOrigin()) {
+ // TODO(creis): This is unexpectedly being encountered in practice. If
+ // you encounter this in practice, please post details to
+ // https://crbug.com/486916. Once that's resolved, we'll change this to
+ // kill the renderer process with bad_message::NC_AUTO_SUBFRAME.
+ NOTREACHED() << "Unexpected main frame origin change on AUTO_SUBFRAME.";
+ }
last_committed_entry_index_ = entry_index;
DiscardNonCommittedEntriesInternal();
return true;
}
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // This may be a "new auto" case where we add a new FrameNavigationEntry, or
+ // it may be a "history auto" case where we update an existing one.
+ NavigationEntryImpl* last_committed = GetLastCommittedEntry();
+ last_committed->AddOrUpdateFrameEntry(rfh->frame_tree_node(),
+ rfh->GetSiteInstance(), params.url,
+ params.referrer);
+ }
+
// We do not need to discard the pending entry in this case, since we will
// not generate commit notifications for this auto-subframe navigation.
return false;
@@ -1317,19 +1543,8 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
NavigationControllerImpl* source =
static_cast<NavigationControllerImpl*>(temp);
- // The SiteInstance and page_id of the last committed entry needs to be
- // remembered at this point, in case there is only one committed entry
- // and it is pruned. We use a scoped_refptr to ensure the SiteInstance
- // can't be freed during this time period.
- NavigationEntryImpl* last_committed =
- NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
- scoped_refptr<SiteInstance> site_instance(
- last_committed->site_instance());
- int32 minimum_page_id = last_committed->GetPageID();
- int32 max_page_id =
- delegate_->GetMaxPageIDForSiteInstance(site_instance.get());
-
- // Remove all the entries leaving the active entry.
+
+ // Remove all the entries leaving the last committed entry.
PruneAllButLastCommittedInternal();
// We now have one entry, possibly with a new pending entry. Ensure that
@@ -1339,7 +1554,7 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
source->PruneOldestEntryIfFull();
// Insert the entries from source. Don't use source->GetCurrentEntryIndex as
- // we don't want to copy over the transient entry. Ignore any pending entry,
+ // we don't want to copy over the transient entry. Ignore any pending entry,
// since it has not committed in source.
int max_source_index = source->last_committed_entry_index_;
if (max_source_index == -1)
@@ -1358,22 +1573,19 @@ void NavigationControllerImpl::CopyStateFromAndPrune(
// Adjust indices such that the last entry and pending are at the end now.
last_committed_entry_index_ = GetEntryCount() - 1;
- delegate_->SetHistoryLengthAndPrune(site_instance.get(),
- max_source_index,
- minimum_page_id);
+ delegate_->SetHistoryOffsetAndLength(last_committed_entry_index_,
+ GetEntryCount());
- // Copy the max page id map from the old tab to the new tab. This ensures
- // that new and existing navigations in the tab's current SiteInstances
- // are identified properly.
+ // Copy the max page id map from the old tab to the new tab. This ensures that
+ // new and existing navigations in the tab's current SiteInstances are
+ // identified properly.
+ NavigationEntryImpl* last_committed = GetLastCommittedEntry();
+ int32 site_max_page_id =
+ delegate_->GetMaxPageIDForSiteInstance(last_committed->site_instance());
delegate_->CopyMaxPageIDsFrom(source->delegate()->GetWebContents());
+ delegate_->UpdateMaxPageIDForSiteInstance(last_committed->site_instance(),
+ site_max_page_id);
max_restored_page_id_ = source->max_restored_page_id_;
-
- // If there is a last committed entry, be sure to include it in the new
- // max page ID map.
- if (max_page_id > -1) {
- delegate_->UpdateMaxPageIDForSiteInstance(site_instance.get(),
- max_page_id);
- }
}
bool NavigationControllerImpl::CanPruneAllButLastCommitted() {
@@ -1400,18 +1612,11 @@ bool NavigationControllerImpl::CanPruneAllButLastCommitted() {
void NavigationControllerImpl::PruneAllButLastCommitted() {
PruneAllButLastCommittedInternal();
- // We should still have a last committed entry.
- DCHECK_NE(-1, last_committed_entry_index_);
+ DCHECK_EQ(0, last_committed_entry_index_);
+ DCHECK_EQ(1, GetEntryCount());
- // We pass 0 instead of GetEntryCount() for the history_length parameter of
- // SetHistoryLengthAndPrune, because it will create history_length additional
- // history entries.
- // TODO(jochen): This API is confusing and we should clean it up.
- // http://crbug.com/178491
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(GetVisibleEntry());
- delegate_->SetHistoryLengthAndPrune(
- entry->site_instance(), 0, entry->GetPageID());
+ delegate_->SetHistoryOffsetAndLength(last_committed_entry_index_,
+ GetEntryCount());
}
void NavigationControllerImpl::PruneAllButLastCommittedInternal() {
@@ -1509,6 +1714,11 @@ bool NavigationControllerImpl::NeedsReload() const {
void NavigationControllerImpl::SetNeedsReload() {
needs_reload_ = true;
+
+ if (last_committed_entry_index_ != -1) {
+ entries_[last_committed_entry_index_]->SetTransitionType(
+ ui::PAGE_TRANSITION_RELOAD);
+ }
}
void NavigationControllerImpl::RemoveEntryAtIndexInternal(int index) {
@@ -1533,7 +1743,7 @@ void NavigationControllerImpl::DiscardNonCommittedEntries() {
}
}
-NavigationEntry* NavigationControllerImpl::GetPendingEntry() const {
+NavigationEntryImpl* NavigationControllerImpl::GetPendingEntry() const {
return pending_entry_;
}
@@ -1556,6 +1766,7 @@ void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry,
DiscardNonCommittedEntriesInternal();
int current_size = static_cast<int>(entries_.size());
+ DCHECK_IMPLIES(replace, current_size > 0);
if (current_size > 0) {
// Prune any entries which are in front of the current entry.
@@ -1720,17 +1931,25 @@ void NavigationControllerImpl::FinishRestore(int selected_index,
}
void NavigationControllerImpl::DiscardNonCommittedEntriesInternal() {
- DiscardPendingEntry();
+ DiscardPendingEntry(false);
DiscardTransientEntry();
}
-void NavigationControllerImpl::DiscardPendingEntry() {
+void NavigationControllerImpl::DiscardPendingEntry(bool was_failure) {
// It is not safe to call DiscardPendingEntry while NavigateToEntry is in
// progress, since this will cause a use-after-free. (We only allow this
// when the tab is being destroyed for shutdown, since it won't return to
// NavigateToEntry in that case.) http://crbug.com/347742.
CHECK(!in_navigate_to_pending_entry_ || delegate_->IsBeingDestroyed());
+ if (was_failure && pending_entry_) {
+ failed_pending_entry_id_ = pending_entry_->GetUniqueID();
+ failed_pending_entry_should_replace_ =
+ pending_entry_->should_replace_entry();
+ } else {
+ failed_pending_entry_id_ = 0;
+ }
+
if (pending_entry_index_ == -1)
delete pending_entry_;
pending_entry_ = NULL;
@@ -1756,7 +1975,16 @@ int NavigationControllerImpl::GetEntryIndexWithPageID(
return -1;
}
-NavigationEntry* NavigationControllerImpl::GetTransientEntry() const {
+int NavigationControllerImpl::GetEntryIndexWithUniqueID(
+ int nav_entry_id) const {
+ for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
+ if (entries_[i]->GetUniqueID() == nav_entry_id)
+ return i;
+ }
+ return -1;
+}
+
+NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const {
if (transient_entry_index_ == -1)
return NULL;
return entries_[transient_entry_index_].get();
@@ -1781,12 +2009,14 @@ void NavigationControllerImpl::InsertEntriesFrom(
DCHECK_LE(max_index, source.GetEntryCount());
size_t insert_index = 0;
for (int i = 0; i < max_index; i++) {
- // When cloning a tab, copy all entries except interstitial pages
- if (source.entries_[i].get()->GetPageType() !=
- PAGE_TYPE_INTERSTITIAL) {
+ // When cloning a tab, copy all entries except interstitial pages.
+ if (source.entries_[i].get()->GetPageType() != PAGE_TYPE_INTERSTITIAL) {
+ // TODO(creis): Once we start sharing FrameNavigationEntries between
+ // NavigationEntries, it will not be safe to share them with another tab.
+ // Must have a version of Clone that recreates them.
entries_.insert(entries_.begin() + insert_index++,
linked_ptr<NavigationEntryImpl>(
- new NavigationEntryImpl(*source.entries_[i])));
+ source.entries_[i]->Clone()));
}
}
}