зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1596825 - Add NavigationDelegate.onSubframeLoadRequest to handle non-top-level load requests. r=snorp,mattwoodrow,geckoview-reviewers,agi
Differential Revision: https://phabricator.services.mozilla.com/D74939
This commit is contained in:
Родитель
42e3da4a1c
Коммит
2157c7820c
|
@ -744,6 +744,7 @@ package org.mozilla.geckoview {
|
|||
method @UiThread @Nullable default public GeckoResult<AllowOrDeny> onLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest);
|
||||
method @UiThread default public void onLocationChange(@NonNull GeckoSession, @Nullable String);
|
||||
method @UiThread @Nullable default public GeckoResult<GeckoSession> onNewSession(@NonNull GeckoSession, @NonNull String);
|
||||
method @UiThread @Nullable default public GeckoResult<AllowOrDeny> onSubframeLoadRequest(@NonNull GeckoSession, @NonNull GeckoSession.NavigationDelegate.LoadRequest);
|
||||
field public static final int LOAD_REQUEST_IS_REDIRECT = 8388608;
|
||||
field public static final int TARGET_WINDOW_CURRENT = 1;
|
||||
field public static final int TARGET_WINDOW_NEW = 2;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Hello, world!</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello, world! From Top Level.</p>
|
||||
<iframe src="foo://bar"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -69,6 +69,7 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
|
|||
const val OPEN_WINDOW_PATH = "/assets/www/worker/open_window.html"
|
||||
const val OPEN_WINDOW_TARGET_PATH = "/assets/www/worker/open_window_target.html"
|
||||
const val DATA_URI_PATH = "/assets/www/data_uri.html"
|
||||
const val IFRAME_UNKNOWN_PROTOCOL = "/assets/www/iframe_unknown_protocol.html"
|
||||
|
||||
const val TEST_ENDPOINT = GeckoSessionTestRule.TEST_ENDPOINT
|
||||
}
|
||||
|
|
|
@ -207,6 +207,31 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
WebRequestError.ERROR_UNKNOWN_PROTOCOL)
|
||||
}
|
||||
|
||||
@Test fun loadUnknownProtocolIframe() {
|
||||
// Should match iframe URI from IFRAME_UNKNOWN_PROTOCOL
|
||||
val iframeUri = "foo://bar"
|
||||
sessionRule.session.loadTestPath(IFRAME_UNKNOWN_PROTOCOL)
|
||||
sessionRule.session.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLoadRequest(session: GeckoSession, request: LoadRequest) : GeckoResult<AllowOrDeny>? {
|
||||
assertThat("URI should not be null", request.uri, notNullValue())
|
||||
assertThat("URI should match", request.uri, endsWith(IFRAME_UNKNOWN_PROTOCOL))
|
||||
return null
|
||||
}
|
||||
|
||||
@AssertCalled(count = 1)
|
||||
override fun onSubframeLoadRequest(session: GeckoSession,
|
||||
request: LoadRequest):
|
||||
GeckoResult<AllowOrDeny>? {
|
||||
assertThat("URI should not be null", request.uri, notNullValue())
|
||||
assertThat("URI should match", request.uri, endsWith(iframeUri))
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Setting(key = Setting.Key.USE_TRACKING_PROTECTION, value = "true")
|
||||
@Ignore // TODO: Bug 1564373
|
||||
@Test fun trackingProtection() {
|
||||
|
@ -309,11 +334,22 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
request: LoadRequest):
|
||||
GeckoResult<AllowOrDeny>? {
|
||||
assertThat("Session should not be null", session, notNullValue())
|
||||
assertThat("App requested this load", request.isDirectNavigation,
|
||||
equalTo(true))
|
||||
assertThat("App requested this load", request.isDirectNavigation, equalTo(true))
|
||||
assertThat("URI should not be null", request.uri, notNullValue())
|
||||
assertThat("URI should match", request.uri,
|
||||
startsWith(GeckoSessionTestRule.TEST_ENDPOINT))
|
||||
assertThat("URI should match", request.uri, endsWith(path))
|
||||
assertThat("isRedirect should match", request.isRedirect, equalTo(false))
|
||||
return null
|
||||
}
|
||||
|
||||
@AssertCalled(count = 2)
|
||||
override fun onSubframeLoadRequest(session: GeckoSession,
|
||||
request: LoadRequest):
|
||||
GeckoResult<AllowOrDeny>? {
|
||||
assertThat("Session should not be null", session, notNullValue())
|
||||
assertThat("App did not request this load", request.isDirectNavigation, equalTo(false))
|
||||
assertThat("URI should not be null", request.uri, notNullValue())
|
||||
assertThat("isRedirect should match", request.isRedirect,
|
||||
equalTo(forEachCall(false, true)))
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1149,7 +1149,7 @@ public class GeckoSession implements Parcelable {
|
|||
@WrapForJNI(calledFrom = "gecko")
|
||||
private GeckoResult<Boolean> onLoadRequest(final @NonNull String uri, final int windowType,
|
||||
final int flags, final @Nullable String triggeringUri,
|
||||
final boolean hasUserGesture) {
|
||||
final boolean hasUserGesture, final boolean isTopLevel) {
|
||||
final GeckoSession session = (mOwner == null) ? null : mOwner.get();
|
||||
if (session == null) {
|
||||
// Don't handle any load request if we can't get the session for some reason.
|
||||
|
@ -1170,7 +1170,9 @@ public class GeckoSession implements Parcelable {
|
|||
final String trigger = TextUtils.isEmpty(triggeringUri) ? null : triggeringUri;
|
||||
final NavigationDelegate.LoadRequest req = new NavigationDelegate.LoadRequest(uri,
|
||||
trigger, windowType, flags, hasUserGesture, false /* isDirectNavigation */);
|
||||
final GeckoResult<AllowOrDeny> reqResponse = delegate.onLoadRequest(session, req);
|
||||
final GeckoResult<AllowOrDeny> reqResponse = isTopLevel ?
|
||||
delegate.onLoadRequest(session, req) :
|
||||
delegate.onSubframeLoadRequest(session, req);
|
||||
|
||||
if (reqResponse == null) {
|
||||
res.complete(false);
|
||||
|
@ -3705,6 +3707,24 @@ public class GeckoSession implements Parcelable {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to load a URI in a non-top-level context.
|
||||
*
|
||||
* @param session The GeckoSession that initiated the callback.
|
||||
* @param request The {@link LoadRequest} containing the request details.
|
||||
*
|
||||
* @return A {@link GeckoResult} with a {@link AllowOrDeny} value which indicates whether
|
||||
* or not the load was handled. If unhandled, Gecko will continue the
|
||||
* load as normal. If handled (a {@link AllowOrDeny#DENY DENY} value), Gecko
|
||||
* will abandon the load. A null return value is interpreted as
|
||||
* {@link AllowOrDeny#ALLOW ALLOW} (unhandled).
|
||||
*/
|
||||
@UiThread
|
||||
default @Nullable GeckoResult<AllowOrDeny> onSubframeLoadRequest(@NonNull GeckoSession session,
|
||||
@NonNull LoadRequest request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A request has been made to open a new session. The URI is provided only for
|
||||
* informational purposes. Do not call GeckoSession.loadUri() here. Additionally, the
|
||||
|
|
|
@ -25,11 +25,14 @@ exclude: true
|
|||
- Added `cookieStoreId` field to [`WebExtension.CreateTabDetails`][78.3]. This adds the optional
|
||||
ability to create a tab with a given cookie store ID for its [`contextual identity`][78.4].
|
||||
([bug 1622500]({{bugzilla}}1622500))
|
||||
- Added [`NavigationDelegate.onSubframeLoadRequest`][78.5] to allow intercepting
|
||||
non-top-level navigations.
|
||||
|
||||
[78.1]: {{javadoc_uri}}/WebExtensionController.html#installBuiltIn-java.lang.String-
|
||||
[78.2]: {{javadoc_uri}}/ContentBlocking.CookieBehavior.html#ACCEPT_FIRST_PARTY_AND_ISOLATE_OTHERS
|
||||
[78.3]: {{javadoc_uri}}/WebExtension.CreateTabDetails.html
|
||||
[78.4]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/contextualIdentities
|
||||
[78.5]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onSubframeLoadRequest-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest-
|
||||
|
||||
## v77
|
||||
- Added [`GeckoRuntime.appendAppNotesToCrashReport`][77.1] For adding app notes to the crash report.
|
||||
|
@ -693,4 +696,4 @@ exclude: true
|
|||
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: {{javadoc_uri}}/GeckoResult.html
|
||||
|
||||
[api-version]: 5460cbfe03322d19964ce94082ac2ae99af6d791
|
||||
[api-version]: bde8001c948235193636d0d21f684baeb551e739
|
||||
|
|
|
@ -1664,7 +1664,19 @@ public class GeckoViewActivity
|
|||
Log.d(LOGTAG, "onLoadRequest=" + request.uri +
|
||||
" triggerUri=" + request.triggerUri +
|
||||
" where=" + request.target +
|
||||
" isRedirect=" + request.isRedirect);
|
||||
" isRedirect=" + request.isRedirect +
|
||||
" isDirectNavigation=" + request.isDirectNavigation);
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeckoResult<AllowOrDeny> onSubframeLoadRequest(final GeckoSession session,
|
||||
final LoadRequest request) {
|
||||
Log.d(LOGTAG, "onSubframeLoadRequest=" + request.uri +
|
||||
" triggerUri=" + request.triggerUri +
|
||||
" isRedirect=" + request.isRedirect +
|
||||
"isDirectNavigation=" + request.isDirectNavigation);
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW);
|
||||
}
|
||||
|
|
|
@ -482,7 +482,6 @@ bool DocumentLoadListener::Open(
|
|||
if (aLoadState->LoadType() != LOAD_ERROR_PAGE &&
|
||||
!(aLoadState->HasLoadFlags(
|
||||
nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE)) &&
|
||||
browsingContext->IsTopContent() &&
|
||||
!(aLoadState->LoadType() & LOAD_HISTORY)) {
|
||||
nsCOMPtr<nsIWidget> widget =
|
||||
browsingContext->GetParentProcessWidgetContaining();
|
||||
|
@ -492,7 +491,7 @@ bool DocumentLoadListener::Open(
|
|||
promise = window->OnLoadRequest(
|
||||
aLoadState->URI(), nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
|
||||
aLoadState->LoadFlags(), aLoadState->TriggeringPrincipal(),
|
||||
aHasGesture);
|
||||
aHasGesture, browsingContext->IsTopContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1841,15 +1840,14 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
mParentChannelListener->GetBrowsingContext();
|
||||
|
||||
RefPtr<MozPromise<bool, bool, false>> promise;
|
||||
if (bc->IsTopContent()) {
|
||||
nsCOMPtr<nsIWidget> widget = bc->GetParentProcessWidgetContaining();
|
||||
RefPtr<nsWindow> window = nsWindow::From(widget);
|
||||
nsCOMPtr<nsIWidget> widget = bc->GetParentProcessWidgetContaining();
|
||||
RefPtr<nsWindow> window = nsWindow::From(widget);
|
||||
|
||||
if (window) {
|
||||
promise = window->OnLoadRequest(
|
||||
uriBeingLoaded, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
|
||||
nsIWebNavigation::LOAD_FLAGS_IS_REDIRECT, nullptr, false);
|
||||
}
|
||||
if (window) {
|
||||
promise = window->OnLoadRequest(uriBeingLoaded,
|
||||
nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
|
||||
nsIWebNavigation::LOAD_FLAGS_IS_REDIRECT,
|
||||
nullptr, false, bc->IsTopContent());
|
||||
}
|
||||
|
||||
if (promise) {
|
||||
|
|
|
@ -364,7 +364,8 @@ class nsWindow::GeckoViewSupport final
|
|||
|
||||
auto OnLoadRequest(mozilla::jni::String::Param aUri, int32_t aWindowType,
|
||||
int32_t aFlags, mozilla::jni::String::Param aTriggeringUri,
|
||||
bool aHasUserGesture) const -> java::GeckoResult::LocalRef;
|
||||
bool aHasUserGesture, bool aIsTopLevel) const
|
||||
-> java::GeckoResult::LocalRef;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1665,7 +1666,8 @@ nsIWidget* nsWindow::GetParent() { return mParent; }
|
|||
|
||||
RefPtr<MozPromise<bool, bool, false>> nsWindow::OnLoadRequest(
|
||||
nsIURI* aUri, int32_t aWindowType, int32_t aFlags,
|
||||
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture) {
|
||||
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture,
|
||||
bool aIsTopLevel) {
|
||||
if (!mGeckoViewSupport) {
|
||||
return MozPromise<bool, bool, false>::CreateAndResolve(false, __func__);
|
||||
}
|
||||
|
@ -1690,7 +1692,8 @@ RefPtr<MozPromise<bool, bool, false>> nsWindow::OnLoadRequest(
|
|||
|
||||
auto geckoResult = mGeckoViewSupport->OnLoadRequest(
|
||||
spec.get(), aWindowType, aFlags,
|
||||
isNullPrincipal ? nullptr : triggeringSpec.get(), aHasUserGesture);
|
||||
isNullPrincipal ? nullptr : triggeringSpec.get(), aHasUserGesture,
|
||||
aIsTopLevel);
|
||||
return geckoResult
|
||||
? MozPromise<bool, bool, false>::FromGeckoResult(geckoResult)
|
||||
: nullptr;
|
||||
|
@ -2416,14 +2419,14 @@ void nsWindow::UpdateSafeAreaInsets(const ScreenIntMargin& aSafeAreaInsets) {
|
|||
|
||||
auto nsWindow::GeckoViewSupport::OnLoadRequest(
|
||||
mozilla::jni::String::Param aUri, int32_t aWindowType, int32_t aFlags,
|
||||
mozilla::jni::String::Param aTriggeringUri, bool aHasUserGesture) const
|
||||
-> java::GeckoResult::LocalRef {
|
||||
mozilla::jni::String::Param aTriggeringUri, bool aHasUserGesture,
|
||||
bool aIsTopLevel) const -> java::GeckoResult::LocalRef {
|
||||
GeckoSession::Window::LocalRef window(mGeckoViewWindow);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
return window->OnLoadRequest(aUri, aWindowType, aFlags, aTriggeringUri,
|
||||
aHasUserGesture);
|
||||
aHasUserGesture, aIsTopLevel);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
|
||||
|
|
|
@ -61,7 +61,8 @@ class nsWindow final : public nsBaseWidget {
|
|||
void OnGeckoViewReady();
|
||||
RefPtr<mozilla::MozPromise<bool, bool, false>> OnLoadRequest(
|
||||
nsIURI* aUri, int32_t aWindowType, int32_t aFlags,
|
||||
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture);
|
||||
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture,
|
||||
bool aIsTopLevel);
|
||||
|
||||
private:
|
||||
uint32_t mScreenId;
|
||||
|
|
Загрузка…
Ссылка в новой задаче