Bug 1935127 - Part 1: Throw NS_ERROR_NOT_AVAILABLE error when the ClipboardDataSnapshot is no longer valid; r=nika

Differential Revision: https://phabricator.services.mozilla.com/D231809
This commit is contained in:
Edgar Chen
2025-01-06 15:53:05 +00:00
parent 0b0d54b069
commit b7c113fdd4
6 changed files with 93 additions and 54 deletions

View File

@@ -74,7 +74,7 @@ IPCResult ClipboardReadRequestParent::RecvGetData(
bool valid = false; bool valid = false;
if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) { if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
Unused << PClipboardReadRequestParent::Send__delete__(this); Unused << PClipboardReadRequestParent::Send__delete__(this);
aResolver(NS_ERROR_FAILURE); aResolver(NS_ERROR_NOT_AVAILABLE);
return IPC_OK(); return IPC_OK();
} }
@@ -130,7 +130,7 @@ IPCResult ClipboardReadRequestParent::RecvGetDataSync(
bool valid = false; bool valid = false;
if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) { if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
destroySoon(); destroySoon();
*aTransferableDataOrError = NS_ERROR_FAILURE; *aTransferableDataOrError = NS_ERROR_NOT_AVAILABLE;
return IPC_OK(); return IPC_OK();
} }

View File

@@ -1010,7 +1010,7 @@ NS_IMETHODIMP nsBaseClipboard::ClipboardDataSnapshot::GetData(
} }
if (!IsValid()) { if (!IsValid()) {
aCallback->OnComplete(NS_ERROR_FAILURE); aCallback->OnComplete(NS_ERROR_NOT_AVAILABLE);
return NS_OK; return NS_OK;
} }
@@ -1066,7 +1066,7 @@ NS_IMETHODIMP nsBaseClipboard::ClipboardDataSnapshot::GetData(
// `IsValid()` checks the clipboard sequence number to ensure the data // `IsValid()` checks the clipboard sequence number to ensure the data
// we are requesting is still valid. // we are requesting is still valid.
if (!self->IsValid()) { if (!self->IsValid()) {
callback->OnComplete(NS_ERROR_FAILURE); callback->OnComplete(NS_ERROR_NOT_AVAILABLE);
return; return;
} }
mozilla::contentanalysis::ContentAnalysis:: mozilla::contentanalysis::ContentAnalysis::
@@ -1102,7 +1102,7 @@ NS_IMETHODIMP nsBaseClipboard::ClipboardDataSnapshot::GetDataSync(
} }
if (!IsValid()) { if (!IsValid()) {
return NS_ERROR_FAILURE; return NS_ERROR_NOT_AVAILABLE;
} }
MOZ_ASSERT(mClipboard); MOZ_ASSERT(mClipboard);

View File

@@ -27,6 +27,7 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "PermissionMessageUtils.h" #include "PermissionMessageUtils.h"
using mozilla::ipc::ResponseRejectReason;
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@@ -168,7 +169,7 @@ NS_IMETHODIMP ClipboardDataSnapshotProxy::GetData(
} }
if (!mActor->CanSend()) { if (!mActor->CanSend()) {
return aCallback->OnComplete(NS_ERROR_FAILURE); return aCallback->OnComplete(NS_ERROR_NOT_AVAILABLE);
} }
mActor->SendGetData(flavors)->Then( mActor->SendGetData(flavors)->Then(
@@ -196,9 +197,10 @@ NS_IMETHODIMP ClipboardDataSnapshotProxy::GetData(
callback->OnComplete(NS_OK); callback->OnComplete(NS_OK);
}, },
/* reject */ /* reject */
[callback = [callback = nsCOMPtr{aCallback}](ResponseRejectReason aReason) {
nsCOMPtr{aCallback}](mozilla::ipc::ResponseRejectReason aReason) { callback->OnComplete(ResponseRejectReason::ActorDestroyed == aReason
callback->OnComplete(NS_ERROR_FAILURE); ? NS_ERROR_NOT_AVAILABLE
: NS_ERROR_FAILURE);
}); });
return NS_OK; return NS_OK;
@@ -226,13 +228,13 @@ NS_IMETHODIMP ClipboardDataSnapshotProxy::GetDataSync(
} }
if (!mActor->CanSend()) { if (!mActor->CanSend()) {
return NS_ERROR_FAILURE; return NS_ERROR_NOT_AVAILABLE;
} }
IPCTransferableDataOrError ipcTransferableDataOrError; IPCTransferableDataOrError ipcTransferableDataOrError;
bool success = mActor->SendGetDataSync(flavors, &ipcTransferableDataOrError); bool success = mActor->SendGetDataSync(flavors, &ipcTransferableDataOrError);
if (!success) { if (!success) {
return NS_ERROR_FAILURE; return NS_ERROR_NOT_AVAILABLE;
} }
if (ipcTransferableDataOrError.type() == if (ipcTransferableDataOrError.type() ==
IPCTransferableDataOrError::Tnsresult) { IPCTransferableDataOrError::Tnsresult) {
@@ -309,8 +311,7 @@ NS_IMETHODIMP nsClipboardProxy::GetDataSnapshot(
callback->OnSuccess(result.inspect()); callback->OnSuccess(result.inspect());
}, },
/* reject */ /* reject */
[callback = nsCOMPtr{aCallback}]( [callback = nsCOMPtr{aCallback}](ResponseRejectReason aReason) {
mozilla::ipc::ResponseRejectReason aReason) {
callback->OnError(NS_ERROR_FAILURE); callback->OnError(NS_ERROR_FAILURE);
}); });
return NS_OK; return NS_OK;

View File

@@ -234,18 +234,18 @@ function asyncClipboardRequestGetData(aRequest, aFlavor, aThrows = false) {
aThrows ? "throw" : "success" aThrows ? "throw" : "success"
}` }`
); );
reject(e); reject(e.result);
} }
}); });
} }
function syncClipboardRequestGetData(aRequest, aFlavor, aThrows = false) { function syncClipboardRequestGetData(aRequest, aFlavor, aResult = Cr.NS_OK) {
var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
Ci.nsITransferable Ci.nsITransferable
); );
trans.init(null); trans.init(null);
trans.addDataFlavor(aFlavor); trans.addDataFlavor(aFlavor);
let error = undefined; let result = Cr.NS_OK;
try { try {
aRequest.getDataSync(trans); aRequest.getDataSync(trans);
try { try {
@@ -258,12 +258,13 @@ function syncClipboardRequestGetData(aRequest, aFlavor, aThrows = false) {
return ""; return "";
} }
} catch (e) { } catch (e) {
error = e; result = e.result;
return error;
} finally { } finally {
ok( is(
aThrows === (error !== undefined), result,
`nsIAsyncGetClipboardData.getData should ${aThrows ? "throw" : "success"}` aResult,
`nsIAsyncGetClipboardData.getData should ${aResult == Cr.NS_OK ? "throw" : "success"}`
); );
} }
return "";
} }

View File

@@ -65,10 +65,14 @@ clipboardTypes.forEach(function (type) {
let request = await getClipboardDataSnapshot(type); let request = await getClipboardDataSnapshot(type);
isDeeply(request.flavorList, [], "Check flavorList"); isDeeply(request.flavorList, [], "Check flavorList");
await asyncClipboardRequestGetData(request, "text/plain", true).catch( await asyncClipboardRequestGetData(request, "text/plain", true).catch(e => {
() => {} is(
); e,
syncClipboardRequestGetData(request, "text/plain", true); Cr.NS_ERROR_FAILURE,
"should be rejected with NS_ERROR_FAILURE error"
);
});
syncClipboardRequestGetData(request, "text/plain", Cr.NS_ERROR_FAILURE);
}); });
add_task(async function test_clipboard_getDataSnapshot_after_write() { add_task(async function test_clipboard_getDataSnapshot_after_write() {
@@ -90,11 +94,15 @@ clipboardTypes.forEach(function (type) {
); );
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
await asyncClipboardRequestGetData(request, "text/html", true).catch( await asyncClipboardRequestGetData(request, "text/html", true).catch(e => {
() => {} is(
); e,
Cr.NS_ERROR_FAILURE,
"should be rejected with NS_ERROR_FAILURE error"
);
});
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
syncClipboardRequestGetData(request, "text/html", true); syncClipboardRequestGetData(request, "text/html", Cr.NS_ERROR_FAILURE);
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
// Writing a new data should invalid existing get request. // Writing a new data should invalid existing get request.
@@ -103,12 +111,21 @@ clipboardTypes.forEach(function (type) {
() => { () => {
ok(false, "asyncClipboardRequestGetData should not success"); ok(false, "asyncClipboardRequestGetData should not success");
}, },
() => { e => {
is(
e,
Cr.NS_ERROR_NOT_AVAILABLE,
"should throw NS_ERROR_NOT_AVAILABLE error"
);
ok(true, "asyncClipboardRequestGetData should reject"); ok(true, "asyncClipboardRequestGetData should reject");
} }
); );
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
syncClipboardRequestGetData(request, "text/plain", true); syncClipboardRequestGetData(
request,
"text/plain",
Cr.NS_ERROR_NOT_AVAILABLE
);
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
info(`check clipboard data again`); info(`check clipboard data again`);
@@ -155,8 +172,12 @@ clipboardTypes.forEach(function (type) {
() => { () => {
ok(false, "asyncClipboardRequestGetData should not success"); ok(false, "asyncClipboardRequestGetData should not success");
}, },
() => { e => {
ok(true, "asyncClipboardRequestGetData should reject"); is(
e,
Cr.NS_ERROR_NOT_AVAILABLE,
"asyncClipboardRequestGetData should reject with NS_ERROR_NOT_AVAILABLE error"
);
} }
); );
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
@@ -187,9 +208,13 @@ add_task(async function test_html_data() {
"Check data" "Check data"
); );
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
await asyncClipboardRequestGetData(request, "text/plain", true).catch( await asyncClipboardRequestGetData(request, "text/plain", true).catch(e => {
() => {} is(
); e,
Cr.NS_ERROR_FAILURE,
"should be rejected with NS_ERROR_FAILURE error"
);
});
is( is(
syncClipboardRequestGetData(request, "text/html"), syncClipboardRequestGetData(request, "text/html"),
@@ -197,5 +222,5 @@ add_task(async function test_html_data() {
"Check data (sync)" "Check data (sync)"
); );
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
syncClipboardRequestGetData(request, "text/plain", true); syncClipboardRequestGetData(request, "text/plain", Cr.NS_ERROR_FAILURE);
}); });

View File

@@ -48,10 +48,10 @@ clipboardTypes.forEach(function (type) {
let request = getClipboardDataSnapshotSync(type); let request = getClipboardDataSnapshotSync(type);
isDeeply(request.flavorList, [], "Check flavorList"); isDeeply(request.flavorList, [], "Check flavorList");
await asyncClipboardRequestGetData(request, "text/plain", true).catch( await asyncClipboardRequestGetData(request, "text/plain", true).catch(e => {
() => {} is(e, Cr.NS_ERROR_FAILURE, "should throw NS_ERROR_FAILURE error");
); });
syncClipboardRequestGetData(request, "text/plain", true); syncClipboardRequestGetData(request, "text/plain", Cr.NS_ERROR_FAILURE);
}); });
add_task(async function test_clipboard_getDataSnapshotSync_after_write() { add_task(async function test_clipboard_getDataSnapshotSync_after_write() {
@@ -73,11 +73,11 @@ clipboardTypes.forEach(function (type) {
); );
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
await asyncClipboardRequestGetData(request, "text/html", true).catch( await asyncClipboardRequestGetData(request, "text/html", true).catch(e => {
() => {} is(e, Cr.NS_ERROR_FAILURE, "should throw NS_ERROR_FAILURE error");
); });
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
syncClipboardRequestGetData(request, "text/html", true); syncClipboardRequestGetData(request, "text/html", Cr.NS_ERROR_FAILURE);
ok(request.valid, "request should still be valid"); ok(request.valid, "request should still be valid");
// Writing a new data should invalid existing get request. // Writing a new data should invalid existing get request.
@@ -86,12 +86,20 @@ clipboardTypes.forEach(function (type) {
() => { () => {
ok(false, "asyncClipboardRequestGetData should not success"); ok(false, "asyncClipboardRequestGetData should not success");
}, },
() => { e => {
ok(true, "asyncClipboardRequestGetData should reject"); is(
e,
Cr.NS_ERROR_NOT_AVAILABLE,
"should throw NS_ERROR_NOT_AVAILABLE error"
);
} }
); );
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
syncClipboardRequestGetData(request, "text/plain", true); syncClipboardRequestGetData(
request,
"text/plain",
Cr.NS_ERROR_NOT_AVAILABLE
);
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
info(`check clipboard data again`); info(`check clipboard data again`);
@@ -132,8 +140,12 @@ clipboardTypes.forEach(function (type) {
() => { () => {
ok(false, "asyncClipboardRequestGetData should not success"); ok(false, "asyncClipboardRequestGetData should not success");
}, },
() => { e => {
ok(true, "asyncClipboardRequestGetData should reject"); is(
e,
Cr.NS_ERROR_NOT_AVAILABLE,
"should throw NS_ERROR_NOT_AVAILABLE error"
);
} }
); );
ok(!request.valid, "request should no longer be valid"); ok(!request.valid, "request should no longer be valid");
@@ -164,9 +176,9 @@ add_task(async function test_clipboard_getDataSnapshotSync_html_data() {
"Check data" "Check data"
); );
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
await asyncClipboardRequestGetData(request, "text/plain", true).catch( await asyncClipboardRequestGetData(request, "text/plain", true).catch(e => {
() => {} is(e, Cr.NS_ERROR_FAILURE, "should throw NS_ERROR_FAILURE error");
); });
is( is(
syncClipboardRequestGetData(request, "text/html"), syncClipboardRequestGetData(request, "text/html"),
@@ -174,5 +186,5 @@ add_task(async function test_clipboard_getDataSnapshotSync_html_data() {
"Check data (sync)" "Check data (sync)"
); );
// Requesting a flavor that is not in the list should throw error. // Requesting a flavor that is not in the list should throw error.
syncClipboardRequestGetData(request, "text/plain", true); syncClipboardRequestGetData(request, "text/plain", Cr.NS_ERROR_FAILURE);
}); });