зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1803245 - Add Timeout nsiTimer onto the Document to track active IdentityCredential requests, r=timhuang
This doesn't actually move the timer onto the document. Instead it is the correct manual juggling of pointers via `.forget()` and `NS_RELEASE()` and some additional testing to make sure it works properly. This passes tests where we resolve, reject immediately, and reject on timeout and has no leaks in all of those cases. Putting the timer on the document also required putting the pending promise onto the document with it and that had further wrinkles. I call that good enough. Differential Revision: https://phabricator.services.mozilla.com/D164260
This commit is contained in:
Родитель
de079e859b
Коммит
c823b35008
|
@ -84,6 +84,44 @@ IdentityCredential::DiscoverFromExternalSource(
|
|||
RefPtr<IdentityCredential::GetIdentityCredentialPromise::Private> result =
|
||||
new IdentityCredential::GetIdentityCredentialPromise::Private(__func__);
|
||||
|
||||
if (StaticPrefs::
|
||||
dom_security_credentialmanagement_identity_reject_delay_enabled()) {
|
||||
// This is used to give the promise the appropriate lifetime so it is not
|
||||
// freed before the callback below is called. This reference is taken as an
|
||||
// argument to that callback.
|
||||
RefPtr<IdentityCredential::GetIdentityCredentialPromise::Private>
|
||||
forCallbackResult = result;
|
||||
|
||||
RefPtr<nsITimer> timeout;
|
||||
nsresult rv = NS_NewTimerWithFuncCallback(
|
||||
getter_AddRefs(timeout),
|
||||
[](nsITimer* aTimer, void* aClosure) -> void {
|
||||
auto* promise = static_cast<
|
||||
IdentityCredential::GetIdentityCredentialPromise::Private*>(
|
||||
aClosure);
|
||||
if (!promise->IsResolved()) {
|
||||
promise->Reject(NS_ERROR_DOM_NETWORK_ERR, __func__);
|
||||
}
|
||||
// This releases the promise we forgot when we returned from
|
||||
// this function and the timer we forgot after we built this
|
||||
// callback.
|
||||
NS_RELEASE(promise);
|
||||
NS_RELEASE(aTimer);
|
||||
},
|
||||
do_AddRef(forCallbackResult).take(),
|
||||
StaticPrefs::
|
||||
dom_security_credentialmanagement_identity_reject_delay_duration_ms(),
|
||||
nsITimer::TYPE_ONE_SHOT, "IdentityCredentialTimeoutCallback");
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
result->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
// Do not clean this timer when we return form this function. This will be
|
||||
// done at the end of the callback above.
|
||||
Unused << timeout.forget();
|
||||
}
|
||||
|
||||
// Kick the request off to the main process and translate the result to the
|
||||
// expected type when we get a result.
|
||||
MOZ_ASSERT(aOptions.mIdentity.WasPassed());
|
||||
|
@ -101,13 +139,20 @@ IdentityCredential::DiscoverFromExternalSource(
|
|||
if (aResult.isSome()) {
|
||||
credential->CopyValuesFrom(aResult.value());
|
||||
result->Resolve(credential, __func__);
|
||||
} else {
|
||||
} else if (
|
||||
!StaticPrefs::
|
||||
dom_security_credentialmanagement_identity_reject_delay_enabled()) {
|
||||
result->Reject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
||||
}
|
||||
},
|
||||
[result](const WindowGlobalChild::
|
||||
DiscoverIdentityCredentialFromExternalSourcePromise::
|
||||
RejectValueType& aResult) { return; });
|
||||
RejectValueType& aResult) {
|
||||
if (!StaticPrefs::
|
||||
dom_security_credentialmanagement_identity_reject_delay_enabled()) {
|
||||
result->Reject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
||||
}
|
||||
});
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
prefs =
|
||||
dom.security.credentialmanagement.identity.enabled=true
|
||||
dom.security.credentialmanagement.identity.select_first_in_ui_lists=true
|
||||
dom.security.credentialmanagement.identity.reject_delay.enabled=false
|
||||
privacy.antitracking.enableWebcompat=false # disables opener heuristic
|
||||
scheme = https
|
||||
skip-if = xorigin
|
||||
|
@ -44,3 +45,4 @@ support-files =
|
|||
[test_get_without_providers.html]
|
||||
[test_empty_provider_list.html]
|
||||
[test_two_providers.html]
|
||||
[test_delay_reject.html]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Delay Reject</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [
|
||||
["dom.security.credentialmanagement.identity.reject_delay.enabled", "true" ],
|
||||
["dom.security.credentialmanagement.identity.reject_delay.duration_ms", "1000" ],
|
||||
] })
|
||||
.then(() => {setupTest("delay_reject")})
|
||||
.then(
|
||||
function () {
|
||||
return navigator.credentials.get({
|
||||
identity: {
|
||||
providers: []
|
||||
}
|
||||
});
|
||||
}
|
||||
).then((cred) => {
|
||||
ok(false, "incorrectly got a credential");
|
||||
}).catch((err) => {
|
||||
ok(true, "correctly got an error");
|
||||
}).finally(() => {
|
||||
SimpleTest.finish();
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">This test verifies that our rejections are delayed, checking for >500ms.</div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</html>
|
|
@ -8,7 +8,8 @@
|
|||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
setupTest("empty_provider_list").then(
|
||||
setupTest("empty_provider_list")
|
||||
.then(
|
||||
function () {
|
||||
return navigator.credentials.get({
|
||||
identity: {
|
||||
|
|
|
@ -3732,6 +3732,18 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# pref controls whether we should delay identity credential rejections at all
|
||||
- name: dom.security.credentialmanagement.identity.reject_delay.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# pref controls how long we should delay identity credential rejections if enabled
|
||||
- name: dom.security.credentialmanagement.identity.reject_delay.duration_ms
|
||||
type: uint32_t
|
||||
value: 120000
|
||||
mirror: always
|
||||
|
||||
# Whether or not selection events on text controls are enabled.
|
||||
- name: dom.select_events.textcontrols.selectionchange.enabled
|
||||
type: bool
|
||||
|
|
Загрузка…
Ссылка в новой задаче