diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/LoadDataWithBaseUrlTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/LoadDataWithBaseUrlTest.java index 177f8c73e89de..6fb0b3d6f36d4 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/LoadDataWithBaseUrlTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/LoadDataWithBaseUrlTest.java @@ -373,4 +373,37 @@ public void testLoadLargeData() throws Throwable { assertEquals("true", executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, "window.gotToEndOfBody")); } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedWhenInterrupted() throws Throwable { + // See crbug.com/594001 -- when a javascript: URL is loaded, the pending entry + // gets discarded and the previous load goes through a different path + // inside NavigationController. + final String pageHtml = "Hello, world!"; + final String baseUrl = "http://example.com/"; + final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mContentsClient.getOnPageFinishedHelper(); + final int callCount = onPageFinishedHelper.getCallCount(); + loadDataWithBaseUrlAsync(mAwContents, pageHtml, "text/html", false, baseUrl, null); + loadUrlAsync(mAwContents, "javascript:42"); + onPageFinishedHelper.waitForCallback(callCount); + assertEquals(baseUrl, onPageFinishedHelper.getUrl()); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testOnPageFinishedWithInvalidBaseUrlWhenInterrupted() throws Throwable { + final String pageHtml = CommonResources.ABOUT_HTML; + final String invalidBaseUrl = "http://"; + final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mContentsClient.getOnPageFinishedHelper(); + final int callCount = onPageFinishedHelper.getCallCount(); + getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true); + loadDataWithBaseUrlAsync(mAwContents, pageHtml, "text/html", false, invalidBaseUrl, null); + loadUrlAsync(mAwContents, "javascript:42"); + onPageFinishedHelper.waitForCallback(callCount); + // Verify that the load succeeds. The actual base url is undefined. + assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread(mAwContents)); + } } diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc index 4b5b388ce16f7..0483fd867f004 100644 --- a/content/browser/android/web_contents_observer_proxy.cc +++ b/content/browser/android/web_contents_observer_proxy.cc @@ -93,6 +93,9 @@ void WebContentsObserverProxy::DidStartLoading() { ScopedJavaLocalRef obj(java_observer_); ScopedJavaLocalRef jstring_url( ConvertUTF8ToJavaString(env, web_contents()->GetVisibleURL().spec())); + if (auto entry = web_contents()->GetController().GetPendingEntry()) { + base_url_of_last_started_data_url_ = entry->GetBaseURLForDataURL(); + } Java_WebContentsObserverProxy_didStartLoading(env, obj.obj(), jstring_url.obj()); } @@ -102,6 +105,8 @@ void WebContentsObserverProxy::DidStopLoading() { ScopedJavaLocalRef obj(java_observer_); std::string url_string = web_contents()->GetLastCommittedURL().spec(); SetToBaseURLForDataURLIfNeeded(&url_string); + // DidStopLoading is the last event we should get. + base_url_of_last_started_data_url_ = GURL::EmptyGURL(); ScopedJavaLocalRef jstring_url(ConvertUTF8ToJavaString( env, url_string)); Java_WebContentsObserverProxy_didStopLoading(env, obj.obj(), @@ -317,8 +322,16 @@ void WebContentsObserverProxy::SetToBaseURLForDataURLIfNeeded( NavigationEntry* entry = web_contents()->GetController().GetLastCommittedEntry(); // Note that GetBaseURLForDataURL is only used by the Android WebView. - if (entry && !entry->GetBaseURLForDataURL().is_empty()) + // FIXME: Should we only return valid specs and "about:blank" for invalid + // ones? This may break apps. + if (entry && !entry->GetBaseURLForDataURL().is_empty()) { *url = entry->GetBaseURLForDataURL().possibly_invalid_spec(); + } else if (!base_url_of_last_started_data_url_.is_empty()) { + // NavigationController can lose the pending entry and recreate it without + // a base URL if there has been a loadUrl("javascript:...") after + // loadDataWithBaseUrl. + *url = base_url_of_last_started_data_url_.possibly_invalid_spec(); + } } bool RegisterWebContentsObserverProxy(JNIEnv* env) { diff --git a/content/browser/android/web_contents_observer_proxy.h b/content/browser/android/web_contents_observer_proxy.h index 1005a68497edf..d37f718c64d04 100644 --- a/content/browser/android/web_contents_observer_proxy.h +++ b/content/browser/android/web_contents_observer_proxy.h @@ -84,6 +84,7 @@ class WebContentsObserverProxy : public WebContentsObserver { bool was_ignored_by_handler); base::android::ScopedJavaGlobalRef java_observer_; + GURL base_url_of_last_started_data_url_; DISALLOW_COPY_AND_ASSIGN(WebContentsObserverProxy); };