summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_webview/browser/aw_content_browser_client.cc48
-rw-r--r--android_webview/browser/aw_contents_client_bridge_base.cc12
-rw-r--r--android_webview/browser/aw_contents_client_bridge_base.h7
-rw-r--r--android_webview/common/render_view_messages.h14
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java44
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsClient.java2
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java7
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java7
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java168
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java26
-rw-r--r--android_webview/native/aw_contents_client_bridge.cc15
-rw-r--r--android_webview/native/aw_contents_client_bridge.h4
-rw-r--r--android_webview/renderer/aw_content_renderer_client.cc58
-rw-r--r--android_webview/renderer/aw_content_renderer_client.h8
-rw-r--r--components/navigation_interception/intercept_navigation_throttle.cc3
-rw-r--r--content/browser/web_contents/web_contents_impl_browsertest.cc54
-rw-r--r--content/public/renderer/content_renderer_client.cc14
-rw-r--r--content/public/renderer/content_renderer_client.h19
-rw-r--r--content/renderer/render_frame_impl.cc12
-rw-r--r--third_party/WebKit/Source/core/loader/DocumentLoader.cpp3
-rw-r--r--third_party/WebKit/Source/core/loader/FrameLoader.cpp11
21 files changed, 293 insertions, 243 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 5c3aaf9..96ed105 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -33,6 +33,7 @@
#include "components/navigation_interception/intercept_navigation_delegate.h"
#include "content/public/browser/access_token_store.h"
#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/navigation_handle.h"
@@ -51,6 +52,7 @@
#include "ui/base/resource/resource_bundle_android.h"
#include "ui/resources/grit/ui_resources.h"
+using content::BrowserThread;
using content::ResourceType;
namespace android_webview {
@@ -64,8 +66,16 @@ public:
explicit AwContentsMessageFilter(int process_id);
// BrowserMessageFilter methods.
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
bool OnMessageReceived(const IPC::Message& message) override;
+ void OnShouldOverrideUrlLoading(int routing_id,
+ const base::string16& url,
+ bool has_user_gesture,
+ bool is_redirect,
+ bool is_main_frame,
+ bool* ignore_navigation);
void OnSubFrameCreated(int parent_render_frame_id, int child_render_frame_id);
private:
@@ -84,15 +94,45 @@ AwContentsMessageFilter::AwContentsMessageFilter(int process_id)
AwContentsMessageFilter::~AwContentsMessageFilter() {
}
+void AwContentsMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (message.type() == AwViewHostMsg_ShouldOverrideUrlLoading::ID) {
+ *thread = BrowserThread::UI;
+ }
+}
+
bool AwContentsMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(AwContentsMessageFilter, message)
+ IPC_MESSAGE_HANDLER(AwViewHostMsg_ShouldOverrideUrlLoading,
+ OnShouldOverrideUrlLoading)
IPC_MESSAGE_HANDLER(AwViewHostMsg_SubFrameCreated, OnSubFrameCreated)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
+void AwContentsMessageFilter::OnShouldOverrideUrlLoading(
+ int render_frame_id,
+ const base::string16& url,
+ bool has_user_gesture,
+ bool is_redirect,
+ bool is_main_frame,
+ bool* ignore_navigation) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ *ignore_navigation = false;
+ AwContentsClientBridgeBase* client =
+ AwContentsClientBridgeBase::FromID(process_id_, render_frame_id);
+ if (client) {
+ *ignore_navigation = client->ShouldOverrideUrlLoading(
+ url, has_user_gesture, is_redirect, is_main_frame);
+ } else {
+ LOG(WARNING) << "Failed to find the associated render view host for url: "
+ << url;
+ }
+}
+
void AwContentsMessageFilter::OnSubFrameCreated(int parent_render_frame_id,
int child_render_frame_id) {
AwContentsIoThreadClient::SubFrameCreated(
@@ -520,10 +560,10 @@ ScopedVector<content::NavigationThrottle>
AwContentBrowserClient::CreateThrottlesForNavigation(
content::NavigationHandle* navigation_handle) {
ScopedVector<content::NavigationThrottle> throttles;
- if (navigation_handle->IsInMainFrame() ||
- (!navigation_handle->GetURL().SchemeIs(url::kHttpScheme) &&
- !navigation_handle->GetURL().SchemeIs(url::kHttpsScheme) &&
- !navigation_handle->GetURL().SchemeIs(url::kAboutScheme))) {
+ // We allow intercepting only navigations within main frames. This
+ // is used to post onPageStarted. We handle shouldOverrideUrlLoading
+ // via a sync IPC.
+ if (navigation_handle->IsInMainFrame()) {
throttles.push_back(
navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
navigation_handle));
diff --git a/android_webview/browser/aw_contents_client_bridge_base.cc b/android_webview/browser/aw_contents_client_bridge_base.cc
index d86e76a..d684d40 100644
--- a/android_webview/browser/aw_contents_client_bridge_base.cc
+++ b/android_webview/browser/aw_contents_client_bridge_base.cc
@@ -53,6 +53,18 @@ AwContentsClientBridgeBase* AwContentsClientBridgeBase::FromWebContents(
return UserData::GetContents(web_contents);
}
+// static
+AwContentsClientBridgeBase* AwContentsClientBridgeBase::FromID(
+ int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ content::RenderFrameHost* rfh =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(rfh);
+ return UserData::GetContents(web_contents);
+}
+
AwContentsClientBridgeBase::~AwContentsClientBridgeBase() {
}
diff --git a/android_webview/browser/aw_contents_client_bridge_base.h b/android_webview/browser/aw_contents_client_bridge_base.h
index c03cb36..6ac592b 100644
--- a/android_webview/browser/aw_contents_client_bridge_base.h
+++ b/android_webview/browser/aw_contents_client_bridge_base.h
@@ -35,6 +35,8 @@ class AwContentsClientBridgeBase {
AwContentsClientBridgeBase* handler);
static AwContentsClientBridgeBase* FromWebContents(
content::WebContents* web_contents);
+ static AwContentsClientBridgeBase* FromID(int render_process_id,
+ int render_frame_id);
virtual ~AwContentsClientBridgeBase();
@@ -60,6 +62,11 @@ class AwContentsClientBridgeBase {
const base::string16& message_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback)
= 0;
+
+ virtual bool ShouldOverrideUrlLoading(const base::string16& url,
+ bool has_user_gesture,
+ bool is_redirect,
+ bool is_main_frame) = 0;
};
} // namespace android_webview
diff --git a/android_webview/common/render_view_messages.h b/android_webview/common/render_view_messages.h
index 4c42f3d..24df3cd 100644
--- a/android_webview/common/render_view_messages.h
+++ b/android_webview/common/render_view_messages.h
@@ -100,6 +100,20 @@ IPC_MESSAGE_ROUTED1(AwViewHostMsg_UpdateHitTestData,
IPC_MESSAGE_ROUTED1(AwViewHostMsg_OnContentsSizeChanged,
gfx::Size /* contents_size */)
+// Sent immediately before a top level navigation is initiated within Blink.
+// There are some exlusions, the most important ones are it is not sent
+// when creating a popup window, and not sent for application initiated
+// navigations. See AwContentRendererClient::HandleNavigation for all
+// cornercases. This is sent before updating the NavigationController state
+// or creating a URLRequest for the main frame resource.
+IPC_SYNC_MESSAGE_CONTROL5_1(AwViewHostMsg_ShouldOverrideUrlLoading,
+ int /* render_frame_id id */,
+ base::string16 /* in - url */,
+ bool /* in - has_user_gesture */,
+ bool /* in - is_redirect */,
+ bool /* in - is_main_frame */,
+ bool /* out - result */)
+
// Sent when a subframe is created.
IPC_MESSAGE_CONTROL2(AwViewHostMsg_SubFrameCreated,
int /* parent_render_frame_id */,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 2352b57..c2ce4c9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -291,6 +291,10 @@ public class AwContents implements SmartClipProvider,
private PostMessageSender mPostMessageSender;
+ // This flag indicates that ShouldOverrideUrlNavigation should be posted
+ // through the resourcethrottle. This is only used for popup windows.
+ private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup;
+
// This is a workaround for some qualcomm devices discarding buffer on
// Activity restore.
private boolean mInvalidateRootViewOnNextDraw;
@@ -500,38 +504,23 @@ public class AwContents implements SmartClipProvider,
@Override
public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
final String url = navigationParams.url;
-
- final int transitionType = navigationParams.pageTransitionType;
- final boolean isLoadUrl = (transitionType & PageTransition.FROM_API) != 0;
- final boolean isBackForward = (transitionType & PageTransition.FORWARD_BACK) != 0;
- final boolean isReload =
- (transitionType & PageTransition.CORE_MASK) == PageTransition.RELOAD;
- final boolean isRedirect = navigationParams.isRedirect;
-
boolean ignoreNavigation = false;
- // Any navigation from loadUrl, goBack/Forward, or reload, are considered application
- // initiated and hence will not yield a shouldOverrideUrlLoading() callback.
- if ((!isLoadUrl || isRedirect) && !isBackForward && !isReload
- && !navigationParams.isPost) {
- ignoreNavigation = mContentsClient.shouldIgnoreNavigation(mContext, url,
- navigationParams.isMainFrame,
- navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
- navigationParams.isRedirect);
+ if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) {
+ mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false;
+ // If this is used for all navigations in future, cases for application initiated
+ // load, redirect and backforward should also be filtered out.
+ if (!navigationParams.isPost) {
+ ignoreNavigation = mContentsClient.shouldIgnoreNavigation(
+ mContext, url, navigationParams.isMainFrame,
+ navigationParams.hasUserGesture
+ || navigationParams.hasUserGestureCarryover,
+ navigationParams.isRedirect);
+ }
}
-
// The shouldOverrideUrlLoading call might have resulted in posting messages to the
// UI thread. Using sendMessage here (instead of calling onPageStarted directly)
// will allow those to run in order.
- if (isRedirect) {
- mContentsClient.getCallbackHelper().postOnPageStarted(url);
- // We can post onPageFinished here since we know that the navigation will fail.
- // Also AwWebContentsObserver.didFail does not call OnPageFinished when the
- // navigation is overridden because we don't want an onPageFinished for such a
- // navigation unless it is a redirect.
- if (ignoreNavigation) {
- mContentsClient.getCallbackHelper().postOnPageFinished(url);
- }
- } else if (!ignoreNavigation) {
+ if (!ignoreNavigation) {
mContentsClient.getCallbackHelper().postOnPageStarted(url);
}
return ignoreNavigation;
@@ -1030,6 +1019,7 @@ public class AwContents implements SmartClipProvider,
// Recap: supplyContentsForPopup() is called on the parent window's content, this method is
// called on the popup window's content.
private void receivePopupContents(long popupNativeAwContents) {
+ mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true;
// Save existing view state.
final boolean wasAttached = mIsAttachedToWindow;
final boolean wasViewVisible = mIsViewVisible;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
index ba9385f..47d0f28 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
@@ -334,8 +334,6 @@ public abstract class AwContentsClient {
public abstract void onPageCommitVisible(String url);
- public void onFailedLoadForTesting(String url) {}
-
public final void onReceivedError(AwWebResourceRequest request, AwWebResourceError error) {
// Only one of these callbacks actually reaches out the client code. The first callback
// is used on API versions up to and including L, the second on subsequent releases.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
index efca3d0..8c29c2d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
@@ -250,6 +250,13 @@ public class AwContentsClientBridge {
mClient.handleJsBeforeUnload(url, message, handler);
}
+ @CalledByNative
+ private boolean shouldOverrideUrlLoading(
+ String url, boolean hasUserGesture, boolean isRedirect, boolean isMainFrame) {
+ return mClient.shouldIgnoreNavigation(
+ mContext, url, isMainFrame, hasUserGesture, isRedirect);
+ }
+
void confirmJsResult(int id, String prompt) {
if (mNativeContentsClientBridge == 0) return;
nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
index d9b709a..3c08c30 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -72,16 +72,11 @@ public class AwWebContentsObserver extends WebContentsObserver {
String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
boolean isErrorUrl =
unreachableWebDataUrl != null && unreachableWebDataUrl.equals(failingUrl);
- if (isMainFrame && !isErrorUrl && errorCode == NetError.ERR_ABORTED
- && !wasIgnoredByHandler) {
+ if (isMainFrame && !isErrorUrl && errorCode == NetError.ERR_ABORTED) {
// Need to call onPageFinished for backwards compatibility with the classic webview.
// See also AwContents.IoThreadClientImpl.onReceivedError.
- // If the navigation was ignored because of shouldOverrideUrlLoading we have already
- // called onPageFinished in
- // AwContents.InterceptNavigationDelegateImpl.shouldIgnoreNavigation instead.
client.getCallbackHelper().postOnPageFinished(failingUrl);
}
- client.onFailedLoadForTesting(failingUrl);
}
@Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
index 0694501..e27672f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -9,10 +9,8 @@ import android.util.Pair;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.AwContentsClient;
-import org.chromium.android_webview.test.TestAwContentsClient.OnFailedLoadHelper;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.android_webview.test.util.JSUtils;
-import org.chromium.android_webview.test.util.JavascriptEventObserver;
import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
@@ -20,7 +18,6 @@ import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.content.browser.test.util.DOMUtils;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
-import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
import org.chromium.content.common.ContentSwitches;
@@ -30,7 +27,6 @@ import org.chromium.net.test.util.TestWebServer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -736,9 +732,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase {
assertEquals(redirectTarget,
mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
assertEquals(serverSideRedirect, mShouldOverrideUrlLoadingHelper.isRedirect());
- // We keep the user gesture from the initial navigation for serverside redirects but drop
- // the user gesture for browser initiated redirects.
- assertEquals(serverSideRedirect, mShouldOverrideUrlLoadingHelper.hasUserGesture());
+ assertFalse(mShouldOverrideUrlLoadingHelper.hasUserGesture());
assertTrue(mShouldOverrideUrlLoadingHelper.isMainFrame());
}
@@ -1086,164 +1080,4 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase {
public void testClickableAddressInIframe() throws Throwable {
doTestClickableContent(TEST_ADDRESS, TEST_ADDRESS_URI, false);
}
-
- @SmallTest
- @Feature({"AndroidWebView"})
- public void testXhrInLink() throws Throwable {
- standardSetup();
- final CountDownLatch shouldOverrideUrlLoadingSignal = new CountDownLatch(1);
-
- final String xhrPath = "/xhrPath.html";
- final String xhrUrl = mWebServer.setResponseWithRunnableAction(
- xhrPath, CommonResources.makeHtmlPageFrom("", ""), null, new Runnable() {
- @Override
- public void run() {
- try {
- shouldOverrideUrlLoadingSignal.await();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- });
-
- final String xhrJs = "function xhrFunction() {"
- + " var xhr = new XMLHttpRequest();"
- + " xhr.onload=function() {"
- + " console.info('xhr loaded');"
- + " window.jsInterface.setValue(true);"
- + " };"
- + " xhr.onerror=function() {"
- + " console.info('xhr failed, status ' + xhr.status);"
- + " window.jsInterface.setValue(false);"
- + " };"
- + " xhr.open('GET', '" + xhrUrl + "', true);"
- + " xhr.send();"
- + "};";
-
- String pageWithXhrLink = makeHtmlPageFrom(
- "<script>" + xhrJs + "</script>", "<img onclick=\"xhrFunction(); location.href='"
- + "thiswillbe://intercepted/"
- + "'\" class=\"big\" id=\"link\" />");
-
- final String startPath = "/startPath.html";
- final String startUrl = addPageToTestServer(startPath, pageWithXhrLink);
-
- enableJavaScriptOnUiThread(mAwContents);
- final BooleanValueJavascriptObserver jsInterface = new BooleanValueJavascriptObserver();
-
- // add javascript interface
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- jsInterface.register(mAwContents.getContentViewCore(), "jsInterface");
- }
- });
-
- loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), startUrl);
-
- setShouldOverrideUrlLoadingReturnValueOnUiThread(true);
- final int shouldOverrideUrlLoadingCallCount =
- mShouldOverrideUrlLoadingHelper.getCallCount();
-
- assertEquals(0, mWebServer.getRequestCount(xhrPath));
-
- clickOnLinkUsingJs();
-
- // Make the server xhr response wait until the navigation request is intercepted.
- mShouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
- shouldOverrideUrlLoadingSignal.countDown();
-
- jsInterface.waitForEvent(WAIT_TIMEOUT_MS);
- assertTrue(jsInterface.getValue());
- assertEquals(1, mWebServer.getRequestCount(xhrPath));
- }
-
- private static class BooleanValueJavascriptObserver extends JavascriptEventObserver {
- private boolean mValue = false;
-
- public void setValue(boolean value) {
- mValue = value;
- notifyJava();
- }
-
- public boolean getValue() {
- return mValue;
- }
- }
-
- /**
- * This is to test a bug where a JS redirect failing in its provisional state would prevent us
- * from posting onPageFinished for the original page load.
- * The original page contains an iframe so that we can commit the original load but then
- * prevent it from finishing until the JS redirect fails by having the test server defer the
- * response to the iframe.
- */
- @SmallTest
- @Feature({"AndroidWebView"})
- public void testOnPageFinishedOnFailedJSRedirect() throws Throwable {
- final CountDownLatch jsRedirectSignal = new CountDownLatch(1);
-
- final String redirectTargetPath = "/redirectTargetPath.html";
- final String redirectTargetUrl = mWebServer.setResponse(
- redirectTargetPath, CommonResources.makeHtmlPageFrom("", ""), null);
-
- class DelayingOverrideClient extends TestAwContentsClient {
- @Override
- public boolean shouldOverrideUrlLoading(AwWebResourceRequest request) {
- if (redirectTargetUrl.equals(request.url)) {
- try {
- // Wait here to make sure the load reaches its provisional state before we
- // cancel it. Waiting for a callback to the WebContentsObserver to make sure
- // we have reached the provisional state causes a deadlock here.
- Thread.sleep(Math.min(WAIT_TIMEOUT_MS / 2, 2000));
- } catch (InterruptedException e) {
- }
- return true;
- }
- return false;
- }
- }
- mContentsClient = new DelayingOverrideClient();
- setupWithProvidedContentsClient(mContentsClient);
-
- final String redirectJs = "window.location.href='" + redirectTargetUrl + "';";
-
- final String iframePath = "/iframePath.html";
- final String iframeUrl = mWebServer.setResponseWithRunnableAction(
- iframePath, CommonResources.makeHtmlPageFrom("", ""), null, new Runnable() {
- @Override
- public void run() {
- try {
- mAwContents.evaluateJavaScriptForTests(redirectJs, null);
- jsRedirectSignal.await();
- } catch (InterruptedException e) {
- }
- }
- });
- final String iframeJs = "<iframe src='" + iframeUrl + "'></iframe>";
-
- String startPage = makeHtmlPageFrom("", iframeJs);
- final String startPath = "/startPath.html";
- final String startUrl = addPageToTestServer(startPath, startPage);
-
- enableJavaScriptOnUiThread(mAwContents);
-
- OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper();
- int onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
-
- OnFailedLoadHelper onFailedLoadHelper = mContentsClient.getOnFailedLoadHelper();
- int onFailedLoadCallCount = onFailedLoadHelper.getCallCount();
-
- // load start url -> iframe -> JS redirect -> fail JS redirect -> finish start URL
- loadUrlAsync(mAwContents, startUrl);
-
- onFailedLoadHelper.waitForCallback(onFailedLoadCallCount);
- assertEquals(redirectTargetUrl, onFailedLoadHelper.getUrl());
-
- // let iframe finish
- jsRedirectSignal.countDown();
-
- onPageFinishedHelper.waitForCallback(onPageFinishedCallCount);
- assertEquals(startUrl, onPageFinishedHelper.getUrl());
- }
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index 428e97c..084b446 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -31,7 +31,6 @@ public class TestAwContentsClient extends NullContentsClient {
private boolean mAllowSslError;
private final OnPageStartedHelper mOnPageStartedHelper;
private final OnPageFinishedHelper mOnPageFinishedHelper;
- private final OnFailedLoadHelper mOnFailedLoadHelper;
private final OnPageCommitVisibleHelper mOnPageCommitVisibleHelper;
private final OnReceivedErrorHelper mOnReceivedErrorHelper;
private final OnReceivedError2Helper mOnReceivedError2Helper;
@@ -54,7 +53,6 @@ public class TestAwContentsClient extends NullContentsClient {
super(ThreadUtils.getUiThreadLooper());
mOnPageStartedHelper = new OnPageStartedHelper();
mOnPageFinishedHelper = new OnPageFinishedHelper();
- mOnFailedLoadHelper = new OnFailedLoadHelper();
mOnPageCommitVisibleHelper = new OnPageCommitVisibleHelper();
mOnReceivedErrorHelper = new OnReceivedErrorHelper();
mOnReceivedError2Helper = new OnReceivedError2Helper();
@@ -87,25 +85,6 @@ public class TestAwContentsClient extends NullContentsClient {
return mOnPageFinishedHelper;
}
- /**
- * CallbackHelper for OnFailedLoad.
- */
- public static class OnFailedLoadHelper extends CallbackHelper {
- private String mUrl;
- public void notifyCalled(String url) {
- mUrl = url;
- notifyCalled();
- }
- public String getUrl() {
- assert getCallCount() > 0;
- return mUrl;
- }
- }
-
- public OnFailedLoadHelper getOnFailedLoadHelper() {
- return mOnFailedLoadHelper;
- }
-
public OnReceivedErrorHelper getOnReceivedErrorHelper() {
return mOnReceivedErrorHelper;
}
@@ -236,11 +215,6 @@ public class TestAwContentsClient extends NullContentsClient {
}
@Override
- public void onFailedLoadForTesting(String url) {
- mOnFailedLoadHelper.notifyCalled(url);
- }
-
- @Override
public void onReceivedError(int errorCode, String description, String failingUrl) {
mOnReceivedErrorHelper.notifyCalled(errorCode, description, failingUrl);
}
diff --git a/android_webview/native/aw_contents_client_bridge.cc b/android_webview/native/aw_contents_client_bridge.cc
index 02db65b..4d2fd4dcb 100644
--- a/android_webview/native/aw_contents_client_bridge.cc
+++ b/android_webview/native/aw_contents_client_bridge.cc
@@ -341,6 +341,21 @@ void AwContentsClientBridge::RunBeforeUnloadDialog(
env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
}
+bool AwContentsClientBridge::ShouldOverrideUrlLoading(const base::string16& url,
+ bool has_user_gesture,
+ bool is_redirect,
+ bool is_main_frame) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return false;
+ ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url);
+ devtools_instrumentation::ScopedEmbedderCallbackTask(
+ "shouldOverrideUrlLoading");
+ return Java_AwContentsClientBridge_shouldOverrideUrlLoading(
+ env, obj.obj(), jurl.obj(), has_user_gesture, is_redirect, is_main_frame);
+}
+
void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env,
const JavaRef<jobject>&,
int id,
diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h
index 5372fb0..2af63ca 100644
--- a/android_webview/native/aw_contents_client_bridge.h
+++ b/android_webview/native/aw_contents_client_bridge.h
@@ -54,6 +54,10 @@ class AwContentsClientBridge : public AwContentsClientBridgeBase {
const base::string16& message_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback)
override;
+ bool ShouldOverrideUrlLoading(const base::string16& url,
+ bool has_user_gesture,
+ bool is_redirect,
+ bool is_main_frame) override;
// Methods called from Java.
void ProceedSslError(JNIEnv* env,
diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc
index f25b936..7203f90 100644
--- a/android_webview/renderer/aw_content_renderer_client.cc
+++ b/android_webview/renderer/aw_content_renderer_client.cc
@@ -29,6 +29,8 @@
#include "components/printing/renderer/print_web_view_helper.h"
#include "components/visitedlink/renderer/visitedlink_slave.h"
#include "content/public/common/url_constants.h"
+#include "content/public/renderer/document_state.h"
+#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
@@ -39,6 +41,7 @@
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebNavigationType.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
@@ -76,6 +79,61 @@ void AwContentRendererClient::RenderThreadStarted() {
blink::WebSecurityPolicy::registerURLSchemeAsSecure(aw_scheme);
}
+bool AwContentRendererClient::HandleNavigation(
+ content::RenderFrame* render_frame,
+ bool is_content_initiated,
+ int opener_id,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& request,
+ blink::WebNavigationType type,
+ blink::WebNavigationPolicy default_policy,
+ bool is_redirect) {
+ // Only GETs can be overridden.
+ if (!request.httpMethod().equals("GET"))
+ return false;
+
+ // Any navigation from loadUrl, and goBack/Forward are considered application-
+ // initiated and hence will not yield a shouldOverrideUrlLoading() callback.
+ // Webview classic does not consider reload application-initiated so we
+ // continue the same behavior.
+ // TODO(sgurun) is_content_initiated is normally false for cross-origin
+ // navigations but since android_webview does not swap out renderers, this
+ // works fine. This will stop working if android_webview starts swapping out
+ // renderers on navigation.
+ bool application_initiated =
+ !is_content_initiated || type == blink::WebNavigationTypeBackForward;
+
+ // Don't offer application-initiated navigations unless it's a redirect.
+ if (application_initiated && !is_redirect)
+ return false;
+
+ bool is_main_frame = !frame->parent();
+ const GURL& gurl = request.url();
+ // For HTTP schemes, only top-level navigations can be overridden. Similarly,
+ // WebView Classic lets app override only top level about:blank navigations.
+ // So we filter out non-top about:blank navigations here.
+ if (!is_main_frame &&
+ (gurl.SchemeIs(url::kHttpScheme) || gurl.SchemeIs(url::kHttpsScheme) ||
+ gurl.SchemeIs(url::kAboutScheme)))
+ return false;
+
+ // use NavigationInterception throttle to handle the call as that can
+ // be deferred until after the java side has been constructed.
+ if (opener_id != MSG_ROUTING_NONE) {
+ return false;
+ }
+
+ bool ignore_navigation = false;
+ base::string16 url = request.url().string();
+ bool has_user_gesture = request.hasUserGesture();
+
+ int render_frame_id = render_frame->GetRoutingID();
+ RenderThread::Get()->Send(new AwViewHostMsg_ShouldOverrideUrlLoading(
+ render_frame_id, url, has_user_gesture, is_redirect, is_main_frame,
+ &ignore_navigation));
+ return ignore_navigation;
+}
+
void AwContentRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
new AwContentSettingsClient(render_frame);
diff --git a/android_webview/renderer/aw_content_renderer_client.h b/android_webview/renderer/aw_content_renderer_client.h
index 8f05468..a1717de 100644
--- a/android_webview/renderer/aw_content_renderer_client.h
+++ b/android_webview/renderer/aw_content_renderer_client.h
@@ -38,6 +38,14 @@ class AwContentRendererClient : public content::ContentRendererClient {
bool IsLinkVisited(unsigned long long link_hash) override;
void AddKeySystems(std::vector<media::KeySystemInfo>* key_systems) override;
+ bool HandleNavigation(content::RenderFrame* render_frame,
+ bool is_content_initiated,
+ int opener_id,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& request,
+ blink::WebNavigationType type,
+ blink::WebNavigationPolicy default_policy,
+ bool is_redirect) override;
bool ShouldOverridePageVisibilityState(
const content::RenderFrame* render_frame,
blink::WebPageVisibilityState* override_state) override;
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc
index a58bce9..4ad87b2 100644
--- a/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -65,8 +65,7 @@ InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation(bool is_redirect) {
navigation_handle()->GetURL(), navigation_handle()->GetReferrer(),
navigation_handle()->HasUserGesture(), navigation_handle()->IsPost(),
navigation_handle()->GetPageTransition(), is_redirect,
- navigation_handle()->IsExternalProtocol(),
- navigation_handle()->IsInMainFrame());
+ navigation_handle()->IsExternalProtocol(), true);
if (run_callback_synchronously_) {
bool should_ignore_navigation = should_ignore_callback_.Run(
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index a0a9c40..532cf01 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -189,6 +189,60 @@ class LoadingStateChangedDelegate : public WebContentsDelegate {
int loadingStateToDifferentDocumentCount_;
};
+// See: http://crbug.com/298193
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
+#else
+#define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
+#endif
+
+// Test that DidStopLoading includes the correct URL in the details.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ MAYBE_DidStopLoadingDetails) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ LoadStopNotificationObserver load_observer(
+ &shell()->web_contents()->GetController());
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+ load_observer.Wait();
+
+ EXPECT_EQ("/title1.html", load_observer.url_.path());
+ EXPECT_EQ(0, load_observer.session_index_);
+ EXPECT_EQ(&shell()->web_contents()->GetController(),
+ load_observer.controller_);
+}
+
+// See: http://crbug.com/298193
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_DidStopLoadingDetailsWithPending \
+ DISABLED_DidStopLoadingDetailsWithPending
+#else
+#define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending
+#endif
+
+// Test that DidStopLoading includes the correct URL in the details when a
+// pending entry is present.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ MAYBE_DidStopLoadingDetailsWithPending) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ GURL url("data:text/html,<div>test</div>");
+
+ // Listen for the first load to stop.
+ LoadStopNotificationObserver load_observer(
+ &shell()->web_contents()->GetController());
+ // Start a new pending navigation as soon as the first load commits.
+ // We will hear a DidStopLoading from the first load as the new load
+ // is started.
+ NavigateOnCommitObserver commit_observer(
+ shell(), embedded_test_server()->GetURL("/title2.html"));
+ NavigateToURL(shell(), url);
+ load_observer.Wait();
+
+ EXPECT_EQ(url, load_observer.url_);
+ EXPECT_EQ(0, load_observer.session_index_);
+ EXPECT_EQ(&shell()->web_contents()->GetController(),
+ load_observer.controller_);
+}
// Test that a renderer-initiated navigation to an invalid URL does not leave
// around a pending entry that could be used in a URL spoof. We test this in
// a browser test because our unit test framework incorrectly calls
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 32004d1..3d0316f 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -98,6 +98,20 @@ bool ContentRendererClient::AllowPopup() {
return false;
}
+#ifdef OS_ANDROID
+bool ContentRendererClient::HandleNavigation(
+ RenderFrame* render_frame,
+ bool is_content_initiated,
+ int opener_id,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& request,
+ blink::WebNavigationType type,
+ blink::WebNavigationPolicy default_policy,
+ bool is_redirect) {
+ return false;
+}
+#endif
+
bool ContentRendererClient::ShouldFork(blink::WebLocalFrame* frame,
const GURL& url,
const std::string& http_method,
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index fd2f3af..45686b5 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -18,6 +18,8 @@
#include "base/strings/string16.h"
#include "content/public/common/content_client.h"
#include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/web/WebNavigationPolicy.h"
+#include "third_party/WebKit/public/web/WebNavigationType.h"
#include "ui/base/page_transition_types.h"
#include "v8/include/v8.h"
@@ -192,6 +194,23 @@ class CONTENT_EXPORT ContentRendererClient {
// Returns true if a popup window should be allowed.
virtual bool AllowPopup();
+#ifdef OS_ANDROID
+ // TODO(sgurun) This callback is deprecated and will be removed as soon
+ // as android webview completes implementation of a resource throttle based
+ // shouldoverrideurl implementation. See crbug.com/325351
+ //
+ // Returns true if the navigation was handled by the embedder and should be
+ // ignored by WebKit. This method is used by CEF and android_webview.
+ virtual bool HandleNavigation(RenderFrame* render_frame,
+ bool is_content_initiated,
+ int opener_id,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& request,
+ blink::WebNavigationType type,
+ blink::WebNavigationPolicy default_policy,
+ bool is_redirect);
+#endif
+
// Returns true if we should fork a new process for the given navigation.
// If |send_referrer| is set to false (which is the default), no referrer
// header will be send for the navigation. Otherwise, the referrer header is
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 88306cc..76ffb69 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4614,6 +4614,18 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
(pending_navigation_params_ &&
!pending_navigation_params_->request_params.redirects.empty());
+#ifdef OS_ANDROID
+ // The handlenavigation API is deprecated and will be removed once
+ // crbug.com/325351 is resolved.
+ if (info.urlRequest.url() != GURL(kSwappedOutURL) &&
+ GetContentClient()->renderer()->HandleNavigation(
+ this, is_content_initiated, render_view_->opener_id_, frame_,
+ info.urlRequest, info.navigationType, info.defaultPolicy,
+ is_redirect)) {
+ return blink::WebNavigationPolicyIgnore;
+ }
+#endif
+
Referrer referrer(
RenderViewImpl::GetReferrerFromRequest(frame_, info.urlRequest));
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 87826d6..bdbd77a 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -231,8 +231,7 @@ void DocumentLoader::mainReceivedError(const ResourceError& error)
m_applicationCacheHost->failedLoadingMainResource();
if (!frameLoader())
return;
- if (m_state < MainResourceDone)
- m_state = MainResourceDone;
+ m_state = MainResourceDone;
frameLoader()->receivedMainResourceError(this, error);
clearMainResourceHandle();
}
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index fb74068..a578f07 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1220,18 +1220,15 @@ void FrameLoader::receivedMainResourceError(DocumentLoader* loader, const Resour
if (loader != m_provisionalDocumentLoader)
return;
detachDocumentLoader(m_provisionalDocumentLoader);
- // If the provisional load failed, and we haven't yet rendered anything
- // into the frame, then act as though the non-provisional loader failed
- // as well. If we don't do this, the main load will never finish.
- if (!stateMachine()->committedFirstRealDocumentLoad())
- m_documentLoader->setSentDidFinishLoad();
+ m_progressTracker->progressCompleted();
} else {
ASSERT(loader == m_documentLoader);
if (m_frame->document()->parser())
m_frame->document()->parser()->stopParsing();
- if (!m_documentLoader->sentDidFinishLoad()) {
+ m_documentLoader->setSentDidFinishLoad();
+ if (!m_provisionalDocumentLoader && m_frame->isLoading()) {
client()->dispatchDidFailLoad(error, historyCommitType);
- m_documentLoader->setSentDidFinishLoad();
+ m_progressTracker->progressCompleted();
}
}
checkCompleted();