Commit 8d5cb21f authored by japhet@chromium.org's avatar japhet@chromium.org

Trust the renderer's same-document navigation flag if it is a same-origin nav.

Currently in AreURLsInPageNavigation, we only trust renderer_says_in_page if
the before and after urls are identical. This prevents us from correctly
classifying history.pushState and history.replaceState navigations as in-page.
Navigations via the history API are required to be same-origin, but can differ
by more than just the ref component, so we get the correct behavior without
the renderer process being able to lie about a cross-origin navigation.

BUG=138324
TEST=Added cases to NavigationControllerTest.IsInPageNavigation

Review URL: https://codereview.chromium.org/304763002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274734 0039d316-1c4b-4281-b951-d872f2087c98
parent ce3651bc
...@@ -89,10 +89,10 @@ public abstract class AwContentsClient { ...@@ -89,10 +89,10 @@ public abstract class AwContentsClient {
@Override @Override
public void didNavigateMainFrame(String url, String baseUrl, public void didNavigateMainFrame(String url, String baseUrl,
boolean isNavigationToDifferentPage, boolean isNavigationInPage) { boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {
// This is here to emulate the Classic WebView firing onPageFinished for main frame // This is here to emulate the Classic WebView firing onPageFinished for main frame
// navigations where only the hash fragment changes. // navigations where only the hash fragment changes.
if (isNavigationInPage) { if (isFragmentNavigation) {
AwContentsClient.this.onPageFinished(url); AwContentsClient.this.onPageFinished(url);
} }
} }
......
...@@ -219,9 +219,9 @@ TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) { ...@@ -219,9 +219,9 @@ TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) {
EXPECT_TRUE(controller()->GetActionForExtension(extension)); EXPECT_TRUE(controller()->GetActionForExtension(extension));
EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id())); EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
// Navigate away. This should remove the pending injection, and we should not // Reload. This should remove the pending injection, and we should not
// execute anything. // execute anything.
NavigateAndCommit(GURL("https://www.google.com")); Reload();
EXPECT_FALSE(controller()->GetActionForExtension(extension)); EXPECT_FALSE(controller()->GetActionForExtension(extension));
EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id())); EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
...@@ -281,7 +281,7 @@ TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsUseActiveTabPermissions) { ...@@ -281,7 +281,7 @@ TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsUseActiveTabPermissions) {
EXPECT_FALSE(controller()->RequiresUserConsentForScriptInjection(extension)); EXPECT_FALSE(controller()->RequiresUserConsentForScriptInjection(extension));
// Also test that granting active tab runs any pending tasks. // Also test that granting active tab runs any pending tasks.
NavigateAndCommit(GURL("https://www.google.com")); Reload();
// Navigating should mean we need permission again. // Navigating should mean we need permission again.
EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension)); EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension));
......
...@@ -291,7 +291,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) { ...@@ -291,7 +291,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) {
base::string16 text_0 = infobar_delegate_0->GetButtonLabel( base::string16 text_0 = infobar_delegate_0->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_OK); ConfirmInfoBarDelegate::BUTTON_OK);
NavigateAndCommit(requesting_frame); Reload();
MockGoogleLocationSettingsHelper::SetLocationStatus(true, false); MockGoogleLocationSettingsHelper::SetLocationStatus(true, false);
EXPECT_EQ(0U, infobar_service()->infobar_count()); EXPECT_EQ(0U, infobar_service()->infobar_count());
RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
...@@ -303,7 +303,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) { ...@@ -303,7 +303,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) {
ConfirmInfoBarDelegate::BUTTON_OK); ConfirmInfoBarDelegate::BUTTON_OK);
EXPECT_NE(text_0, text_1); EXPECT_NE(text_0, text_1);
NavigateAndCommit(requesting_frame); Reload();
MockGoogleLocationSettingsHelper::SetLocationStatus(false, false); MockGoogleLocationSettingsHelper::SetLocationStatus(false, false);
EXPECT_EQ(0U, infobar_service()->infobar_count()); EXPECT_EQ(0U, infobar_service()->infobar_count());
RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
......
...@@ -94,7 +94,10 @@ class TranslateManagerRenderViewHostTest ...@@ -94,7 +94,10 @@ class TranslateManagerRenderViewHostTest
void SimulateNavigation(const GURL& url, void SimulateNavigation(const GURL& url,
const std::string& lang, const std::string& lang,
bool page_translatable) { bool page_translatable) {
NavigateAndCommit(url); if (rvh()->GetMainFrame()->GetLastCommittedURL() == url)
Reload();
else
NavigateAndCommit(url);
SimulateOnTranslateLanguageDetermined(lang, page_translatable); SimulateOnTranslateLanguageDetermined(lang, page_translatable);
} }
...@@ -794,7 +797,8 @@ TEST_F(TranslateManagerRenderViewHostTest, ReloadFromLocationBar) { ...@@ -794,7 +797,8 @@ TEST_F(TranslateManagerRenderViewHostTest, ReloadFromLocationBar) {
NavEntryCommittedObserver nav_observer(web_contents()); NavEntryCommittedObserver nav_observer(web_contents());
web_contents()->GetController().LoadURL( web_contents()->GetController().LoadURL(
url, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string()); url, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
rvh_tester()->SendNavigate(0, url); rvh_tester()->SendNavigateWithTransition(
0, url, content::PAGE_TRANSITION_TYPED);
// Test that we are really getting a same page navigation, the test would be // Test that we are really getting a same page navigation, the test would be
// useless if it was not the case. // useless if it was not the case.
......
...@@ -129,12 +129,23 @@ void WebContentsObserverAndroid::DidNavigateMainFrame( ...@@ -129,12 +129,23 @@ void WebContentsObserverAndroid::DidNavigateMainFrame(
ConvertUTF8ToJavaString(env, params.url.spec())); ConvertUTF8ToJavaString(env, params.url.spec()));
ScopedJavaLocalRef<jstring> jstring_base_url( ScopedJavaLocalRef<jstring> jstring_base_url(
ConvertUTF8ToJavaString(env, params.base_url.spec())); ConvertUTF8ToJavaString(env, params.base_url.spec()));
// See http://crbug.com/251330 for why it's determined this way. // See http://crbug.com/251330 for why it's determined this way.
bool in_page_navigation = url::Replacements<char> replacements;
details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page; replacements.ClearRef();
bool urls_same_ignoring_fragment =
params.url.ReplaceComponents(replacements) ==
details.previous_url.ReplaceComponents(replacements);
// is_fragment_navigation is indicative of the intent of this variable.
// However, there isn't sufficient information here to determine whether this
// is actually a fragment navigation, or a history API navigation to a URL
// that would also be valid for a fragment navigation.
bool is_fragment_navigation = urls_same_ignoring_fragment &&
(details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page);
Java_WebContentsObserverAndroid_didNavigateMainFrame( Java_WebContentsObserverAndroid_didNavigateMainFrame(
env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(), env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
details.is_navigation_to_different_page(), in_page_navigation); details.is_navigation_to_different_page(), is_fragment_navigation);
} }
void WebContentsObserverAndroid::DidNavigateAnyFrame( void WebContentsObserverAndroid::DidNavigateAnyFrame(
......
...@@ -109,7 +109,7 @@ bool AreURLsInPageNavigation(const GURL& existing_url, ...@@ -109,7 +109,7 @@ bool AreURLsInPageNavigation(const GURL& existing_url,
const GURL& new_url, const GURL& new_url,
bool renderer_says_in_page, bool renderer_says_in_page,
NavigationType navigation_type) { NavigationType navigation_type) {
if (existing_url == new_url) if (existing_url.GetOrigin() == new_url.GetOrigin())
return renderer_says_in_page; return renderer_says_in_page;
if (!new_url.has_ref()) { if (!new_url.has_ref()) {
......
...@@ -159,15 +159,11 @@ class CONTENT_EXPORT NavigationControllerImpl ...@@ -159,15 +159,11 @@ class CONTENT_EXPORT NavigationControllerImpl
// whether a navigation happened without loading anything, the same URL could // whether a navigation happened without loading anything, the same URL could
// be a reload, while only a different ref would be in-page (pages can't clear // be a reload, while only a different ref would be in-page (pages can't clear
// refs without reload, only change to "#" which we don't count as empty). // refs without reload, only change to "#" which we don't count as empty).
bool IsURLInPageNavigation(const GURL& url) const { //
return IsURLInPageNavigation(url, false, NAVIGATION_TYPE_UNKNOWN);
}
// The situation is made murkier by history.replaceState(), which could // The situation is made murkier by history.replaceState(), which could
// provide the same URL as part of an in-page navigation, not a reload. So // provide the same URL as part of an in-page navigation, not a reload. So
// we need this form which lets the (untrustworthy) renderer resolve the // we need to let the (untrustworthy) renderer resolve the ambiguity, but
// ambiguity, but only when the URLs are equal. This should be safe since the // only when the URLs are on the same origin.
// origin isn't changing.
bool IsURLInPageNavigation( bool IsURLInPageNavigation(
const GURL& url, const GURL& url,
bool renderer_says_in_page, bool renderer_says_in_page,
......
...@@ -2163,6 +2163,7 @@ TEST_F(NavigationControllerTest, InPage_Replace) { ...@@ -2163,6 +2163,7 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
params.gesture = NavigationGestureUser; params.gesture = NavigationGestureUser;
params.is_post = false; params.is_post = false;
params.page_state = PageState::CreateFromURL(url2); params.page_state = PageState::CreateFromURL(url2);
params.was_within_same_page = true;
// This should NOT generate a new entry, nor prune the list. // This should NOT generate a new entry, nor prune the list.
LoadCommittedDetails details; LoadCommittedDetails details;
...@@ -2214,6 +2215,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) { ...@@ -2214,6 +2215,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
params.gesture = NavigationGestureUnknown; params.gesture = NavigationGestureUnknown;
params.is_post = false; params.is_post = false;
params.page_state = PageState::CreateFromURL(url); params.page_state = PageState::CreateFromURL(url);
params.was_within_same_page = true;
// This should NOT generate a new entry, nor prune the list. // This should NOT generate a new entry, nor prune the list.
LoadCommittedDetails details; LoadCommittedDetails details;
...@@ -3077,21 +3079,28 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) { ...@@ -3077,21 +3079,28 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) {
main_test_rfh()->SendNavigate(0, url); main_test_rfh()->SendNavigate(0, url);
// Reloading the page is not an in-page navigation. // Reloading the page is not an in-page navigation.
EXPECT_FALSE(controller.IsURLInPageNavigation(url)); EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
NAVIGATION_TYPE_UNKNOWN));
const GURL other_url("http://www.google.com/add.html"); const GURL other_url("http://www.google.com/add.html");
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url)); EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
NAVIGATION_TYPE_UNKNOWN));
const GURL url_with_ref("http://www.google.com/home.html#my_ref"); const GURL url_with_ref("http://www.google.com/home.html#my_ref");
EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref)); EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
NAVIGATION_TYPE_UNKNOWN));
// Navigate to URL with refs. // Navigate to URL with refs.
main_test_rfh()->SendNavigate(1, url_with_ref); main_test_rfh()->SendNavigate(1, url_with_ref);
// Reloading the page is not an in-page navigation. // Reloading the page is not an in-page navigation.
EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref)); EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref, false,
EXPECT_FALSE(controller.IsURLInPageNavigation(url)); NAVIGATION_TYPE_UNKNOWN));
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url)); EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
NAVIGATION_TYPE_UNKNOWN));
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
NAVIGATION_TYPE_UNKNOWN));
const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref"); const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref)); EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref, true,
NAVIGATION_TYPE_UNKNOWN));
// Going to the same url again will be considered in-page // Going to the same url again will be considered in-page
// if the renderer says it is even if the navigation type isn't IN_PAGE. // if the renderer says it is even if the navigation type isn't IN_PAGE.
...@@ -3102,6 +3111,17 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) { ...@@ -3102,6 +3111,17 @@ TEST_F(NavigationControllerTest, IsInPageNavigation) {
// type is IN_PAGE. // type is IN_PAGE.
EXPECT_TRUE(controller.IsURLInPageNavigation(url, true, EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
NAVIGATION_TYPE_IN_PAGE)); NAVIGATION_TYPE_IN_PAGE));
// If the renderer says this is a same-origin in-page navigation, believe it.
// This is the pushState/replaceState case.
EXPECT_TRUE(controller.IsURLInPageNavigation(other_url, true,
NAVIGATION_TYPE_UNKNOWN));
// Don't believe the renderer if it claims a cross-origin navigation is
// in-page.
const GURL different_origin_url("http://www.example.com");
EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
NAVIGATION_TYPE_UNKNOWN));
} }
// Some pages can have subframes with the same base URL (minus the reference) as // Some pages can have subframes with the same base URL (minus the reference) as
......
...@@ -619,7 +619,7 @@ public class ContentViewCore ...@@ -619,7 +619,7 @@ public class ContentViewCore
mWebContentsObserver = new WebContentsObserverAndroid(this) { mWebContentsObserver = new WebContentsObserverAndroid(this) {
@Override @Override
public void didNavigateMainFrame(String url, String baseUrl, public void didNavigateMainFrame(String url, String baseUrl,
boolean isNavigationToDifferentPage, boolean isNavigationInPage) { boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {
if (!isNavigationToDifferentPage) return; if (!isNavigationToDifferentPage) return;
hidePopups(); hidePopups();
resetScrollInProgress(); resetScrollInProgress();
......
...@@ -55,12 +55,12 @@ public abstract class WebContentsObserverAndroid { ...@@ -55,12 +55,12 @@ public abstract class WebContentsObserverAndroid {
* @param url The validated url for the page. * @param url The validated url for the page.
* @param baseUrl The validated base url for the page. * @param baseUrl The validated base url for the page.
* @param isNavigationToDifferentPage Whether the main frame navigated to a different page. * @param isNavigationToDifferentPage Whether the main frame navigated to a different page.
* @param isNavigationInPage Whether the main frame navigation did not cause changes to the * @param isFragmentNavigation Whether the main frame navigation did not cause changes to the
* document (for example scrolling to a named anchor or PopState). * document (for example scrolling to a named anchor or PopState).
*/ */
@CalledByNative @CalledByNative
public void didNavigateMainFrame(String url, String baseUrl, public void didNavigateMainFrame(String url, String baseUrl,
boolean isNavigationToDifferentPage, boolean isNavigationInPage) { boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {
} }
/** /**
......
...@@ -150,7 +150,8 @@ void RenderViewHostTestHarness::Reload() { ...@@ -150,7 +150,8 @@ void RenderViewHostTestHarness::Reload() {
DCHECK(entry); DCHECK(entry);
controller().Reload(false); controller().Reload(false);
static_cast<TestRenderViewHost*>( static_cast<TestRenderViewHost*>(
rvh())->SendNavigate(entry->GetPageID(), entry->GetURL()); rvh())->SendNavigateWithTransition(
entry->GetPageID(), entry->GetURL(), PAGE_TRANSITION_RELOAD);
} }
void RenderViewHostTestHarness::FailedReload() { void RenderViewHostTestHarness::FailedReload() {
......
...@@ -46,7 +46,7 @@ void TestRenderFrameHost::SendNavigateWithTransition( ...@@ -46,7 +46,7 @@ void TestRenderFrameHost::SendNavigateWithTransition(
void TestRenderFrameHost::SendFailedNavigate(int page_id, const GURL& url) { void TestRenderFrameHost::SendFailedNavigate(int page_id, const GURL& url) {
SendNavigateWithTransitionAndResponseCode( SendNavigateWithTransitionAndResponseCode(
page_id, url, PAGE_TRANSITION_LINK, 500); page_id, url, PAGE_TRANSITION_RELOAD, 500);
} }
void TestRenderFrameHost::SendNavigateWithTransitionAndResponseCode( void TestRenderFrameHost::SendNavigateWithTransitionAndResponseCode(
...@@ -113,13 +113,19 @@ void TestRenderFrameHost::SendNavigateWithParameters( ...@@ -113,13 +113,19 @@ void TestRenderFrameHost::SendNavigateWithParameters(
params.gesture = NavigationGestureUser; params.gesture = NavigationGestureUser;
params.contents_mime_type = contents_mime_type_; params.contents_mime_type = contents_mime_type_;
params.is_post = false; params.is_post = false;
params.was_within_same_page = false;
params.http_status_code = response_code; params.http_status_code = response_code;
params.socket_address.set_host("2001:db8::1"); params.socket_address.set_host("2001:db8::1");
params.socket_address.set_port(80); params.socket_address.set_port(80);
params.history_list_was_cleared = simulate_history_list_was_cleared_; params.history_list_was_cleared = simulate_history_list_was_cleared_;
params.original_request_url = original_request_url; params.original_request_url = original_request_url;
url::Replacements<char> replacements;
replacements.ClearRef();
params.was_within_same_page = transition != PAGE_TRANSITION_RELOAD &&
transition != PAGE_TRANSITION_TYPED &&
url.ReplaceComponents(replacements) ==
GetLastCommittedURL().ReplaceComponents(replacements);
params.page_state = PageState::CreateForTesting( params.page_state = PageState::CreateForTesting(
url, url,
false, false,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment