diff options
author | gsennton <gsennton@chromium.org> | 2015-10-05 05:03:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-05 12:04:34 +0000 |
commit | e5c3091df04749b232359b6ef22938006af840d5 (patch) | |
tree | a799e646553e566351c397e48ec9cf7afa097065 /android_webview | |
parent | 36d974b6b1d6166a25bd03b894bfdf646872a0b1 (diff) | |
download | chromium_src-e5c3091df04749b232359b6ef22938006af840d5.zip chromium_src-e5c3091df04749b232359b6ef22938006af840d5.tar.gz chromium_src-e5c3091df04749b232359b6ef22938006af840d5.tar.bz2 |
Revert "Use resource throttle to implement shouldOverrideUrlLoading, core change"
Reverting because of crbug.com/534758, to fix that bug we will have to
make a blink change adding a callback to let WebView know when a
document is not longer loading. The current callback DidFinishLoad does
not fire if a new load is in its provisional state, which is sometimes
the case if we load a webpage containing a redirect in the form of a
href assignment: window.location.href = '...'.
This revert was not clean because of the transition to using
NavigationThrottles over in https://codereview.chromium.org/1363483007
This reverts commit 777bb78a111aee919e07f5206267915a87639f88.
TBR=palmer@chromium.org,jam@chromium.org
BUG=534758
Review URL: https://codereview.chromium.org/1375993004
Cr-Commit-Position: refs/heads/master@{#352318}
Diffstat (limited to 'android_webview')
11 files changed, 171 insertions, 129 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index ab14d49..0c027e1 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc @@ -28,6 +28,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" @@ -46,6 +47,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 { @@ -59,8 +61,15 @@ 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* ignore_navigation); void OnSubFrameCreated(int parent_render_frame_id, int child_render_frame_id); private: @@ -79,15 +88,44 @@ 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* 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); + } 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( @@ -494,10 +532,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.h b/android_webview/browser/aw_contents_client_bridge_base.h index 9cd9206..31c965f 100644 --- a/android_webview/browser/aw_contents_client_bridge_base.h +++ b/android_webview/browser/aw_contents_client_bridge_base.h @@ -62,6 +62,10 @@ 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) = 0; }; } // namespace android_webview diff --git a/android_webview/common/render_view_messages.h b/android_webview/common/render_view_messages.h index 91dbb5b..bdd6711 100644 --- a/android_webview/common/render_view_messages.h +++ b/android_webview/common/render_view_messages.h @@ -104,6 +104,19 @@ IPC_MESSAGE_ROUTED1(AwViewHostMsg_PageScaleFactorChanged, 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_CONTROL4_1(AwViewHostMsg_ShouldOverrideUrlLoading, + int /* render_frame_id id */, + base::string16 /* in - url */, + bool /* in - has_user_gesture */, + bool /* in - is_redirect */, + 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 89eff61..7962c18 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -279,6 +279,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; @@ -488,42 +492,26 @@ 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) { - if (!mContentsClient.hasWebViewClient()) { - ignoreNavigation = AwContentsClient.sendBrowsingIntent(mContext, url, - navigationParams.hasUserGesture - || navigationParams.hasUserGestureCarryover, - navigationParams.isRedirect); - } else { - ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url); + 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) { + if (!mContentsClient.hasWebViewClient()) { + ignoreNavigation = AwContentsClient.sendBrowsingIntent(mContext, url, + navigationParams.hasUserGesture + || navigationParams.hasUserGestureCarryover, + navigationParams.isRedirect); + } else { + ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url); + } } } - // 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; @@ -1010,6 +998,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/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java index c1b03a1..76cb761 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java @@ -259,6 +259,16 @@ public class AwContentsClientBridge { mClient.handleJsBeforeUnload(url, message, handler); } + @CalledByNative + private boolean shouldOverrideUrlLoading( + String url, boolean hasUserGesture, boolean isRedirect) { + if (mClient.hasWebViewClient()) { + return mClient.shouldOverrideUrlLoading(url); + } else { + return AwContentsClient.sendBrowsingIntent(mContext, url, 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 53715c6..85cf90c 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java @@ -53,13 +53,9 @@ 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); } } 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 86d082d..6aadfd8 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 @@ -11,7 +11,6 @@ import android.util.Pair; import org.chromium.android_webview.AwContents; 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.DisabledTest; import org.chromium.base.test.util.Feature; @@ -27,7 +26,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; /** @@ -1040,92 +1038,4 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { getActivity().setIgnoreStartActivity(false); } } - - @SmallTest - @Feature({"AndroidWebView"}) - public void testXhrInLink() throws Throwable { - final TestAwContentsClient contentsClient = new TestAwContentsClient(); - final AwTestContainerView testContainerView = - createAwTestContainerViewOnMainSync(contentsClient); - final AwContents awContents = testContainerView.getAwContents(); - TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = - contentsClient.getShouldOverrideUrlLoadingHelper(); - - 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(mWebServer, startPath, pageWithXhrLink); - - enableJavaScriptOnUiThread(awContents); - final BooleanValueJavascriptObserver jsInterface = new BooleanValueJavascriptObserver(); - - // add javascript interface - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - jsInterface.register(awContents.getContentViewCore(), "jsInterface"); - } - }); - - loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), startUrl); - - setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); - final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); - - clickOnLinkUsingJs(awContents, contentsClient); - - // Make the server xhr response wait until the navigation request is intercepted. - shouldOverrideUrlLoadingHelper.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; - } - } } diff --git a/android_webview/native/aw_contents_client_bridge.cc b/android_webview/native/aw_contents_client_bridge.cc index 9e570af..6890955 100644 --- a/android_webview/native/aw_contents_client_bridge.cc +++ b/android_webview/native/aw_contents_client_bridge.cc @@ -340,6 +340,20 @@ 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) { + 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); +} + void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env, jobject, int id, diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h index 74f13e0..0595ba0 100644 --- a/android_webview/native/aw_contents_client_bridge.h +++ b/android_webview/native/aw_contents_client_bridge.h @@ -54,6 +54,9 @@ 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) override; // Methods called from Java. void ProceedSslError(JNIEnv* env, jobject obj, jboolean proceed, jint id); diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc index 34f4b75..db1eb0a 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,60 @@ void AwContentRendererClient::RenderThreadStarted() { blink::WebSecurityPolicy::registerURLSchemeAsSecure(aw_scheme); } +bool AwContentRendererClient::HandleNavigation( + content::RenderFrame* render_frame, + content::DocumentState* document_state, + 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 = + !document_state->navigation_state()->IsContentInitiated() || + type == blink::WebNavigationTypeBackForward; + + // Don't offer application-initiated navigations unless it's a redirect. + if (application_initiated && !is_redirect) + return false; + + 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 (frame->parent() && + (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, &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 f58da53..8d05aab 100644 --- a/android_webview/renderer/aw_content_renderer_client.h +++ b/android_webview/renderer/aw_content_renderer_client.h @@ -37,6 +37,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, + content::DocumentState* document_state, + 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; |