Bug 1689886 - Add a test-only clipboard.read implementation with ClipboardItem. r=nika

Differential Revision: https://phabricator.services.mozilla.com/D103588
This commit is contained in:
Tom Schuster 2021-02-10 20:50:56 +00:00
Родитель c1b72d4f7a
Коммит be7f4c6ca9
6 изменённых файлов: 73 добавлений и 40 удалений

Просмотреть файл

@ -65,27 +65,78 @@ already_AddRefed<Promise> Clipboard::ReadHelper(
RefPtr<DataTransfer> dataTransfer = new DataTransfer(
this, ePaste, /* is external */ true, nsIClipboard::kGlobalClipboard);
RefPtr<nsPIDOMWindowInner> owner = GetOwner();
// Create a new runnable
RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
"Clipboard::Read",
[p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() {
"Clipboard::Read", [p, dataTransfer, aClipboardReadType, owner,
principal = RefPtr{&aSubjectPrincipal}]() {
IgnoredErrorResult ier;
switch (aClipboardReadType) {
case eRead:
case eRead: {
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
("Clipboard, ReadHelper, read case\n"));
dataTransfer->FillAllExternalData();
// If there are items on the clipboard, data transfer will contain
// those, else, data transfer will be empty and we will be resolving
// with an empty data transfer
p->MaybeResolve(dataTransfer);
// Convert the DataTransferItems to ClipboardItems.
// FIXME(bug 1691825): This is only suitable for testing!
// A real implementation would only read from the clipboard
// in ClipboardItem::getType instead of doing it here.
nsTArray<ClipboardItem::ItemEntry> entries;
DataTransferItemList* items = dataTransfer->Items();
for (size_t i = 0; i < items->Length(); i++) {
bool found = false;
DataTransferItem* item = items->IndexedGetter(i, found);
// Only allow strings and files.
if (!found || item->Kind() == DataTransferItem::KIND_OTHER) {
continue;
}
nsAutoString type;
item->GetType(type);
if (item->Kind() == DataTransferItem::KIND_STRING) {
// We just ignore items that we can't access.
IgnoredErrorResult ignored;
nsCOMPtr<nsIVariant> data = item->Data(principal, ignored);
if (NS_WARN_IF(!data || ignored.Failed())) {
continue;
}
nsAutoString string;
if (NS_WARN_IF(NS_FAILED(data->GetAsAString(string)))) {
continue;
}
ClipboardItem::ItemEntry* entry = entries.AppendElement();
entry->mType = type;
entry->mData.SetAsString() = string;
} else {
IgnoredErrorResult ignored;
RefPtr<File> file = item->GetAsFile(*principal, ignored);
if (NS_WARN_IF(!file || ignored.Failed())) {
continue;
}
ClipboardItem::ItemEntry* entry = entries.AppendElement();
entry->mType = type;
entry->mData.SetAsBlob() = file;
}
}
nsTArray<RefPtr<ClipboardItem>> sequence;
sequence.AppendElement(MakeRefPtr<ClipboardItem>(
owner, PresentationStyle::Unspecified, std::move(entries)));
p->MaybeResolve(sequence);
break;
}
case eReadText:
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
("Clipboard, ReadHelper, read text case\n"));
nsAutoString str;
dataTransfer->GetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime),
str, aSubjectPrincipal, ier);
str, *principal, ier);
// Either resolve with a string extracted from data transfer item
// or resolve with an empty string if nothing was found
p->MaybeResolve(str);

Просмотреть файл

@ -14,8 +14,8 @@ typedef sequence<ClipboardItem> ClipboardItems;
[SecureContext, Exposed=Window, Pref="dom.events.asyncClipboard"]
interface Clipboard : EventTarget {
[Pref="dom.events.asyncClipboard.dataTransfer", Throws, NeedsSubjectPrincipal]
Promise<DataTransfer> read();
[Pref="dom.events.asyncClipboard.clipboardItem", Throws, NeedsSubjectPrincipal]
Promise<ClipboardItems> read();
[Func="Clipboard::ReadTextEnabled", Throws, NeedsSubjectPrincipal]
Promise<DOMString> readText();

Просмотреть файл

@ -1805,13 +1805,7 @@
value: true
mirror: always
# Disable clipboard read() by default
- name: dom.events.asyncClipboard.dataTransfer
type: bool
value: false
mirror: always
# Disable ClipboardItem and clipboard.write by default
# Disable ClipboardItem and clipboard.read/write by default
- name: dom.events.asyncClipboard.clipboardItem
type: bool
value: false

Просмотреть файл

@ -1 +1,2 @@
prefs: [dom.events.asyncClipboard:true, dom.events.asyncClipboard.dataTransfer:true, dom.events.asyncClipboard.clipboardItem: true, dom.events.testing.asyncClipboard:true]
prefs: [dom.events.asyncClipboard:true, dom.events.asyncClipboard.clipboardItem: true,
dom.events.testing.asyncClipboard:true]

Просмотреть файл

@ -1,4 +0,0 @@
[async-navigator-clipboard-basics.https.html]
[navigator.clipboard.read() succeeds]
expected: FAIL

Просмотреть файл

@ -59,7 +59,6 @@ function clearClipboard() {
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({"set": [
["dom.events.asyncClipboard", true],
["dom.events.asyncClipboard.dataTransfer", true],
["dom.events.asyncClipboard.clipboardItem", true],
]});
});
@ -241,8 +240,9 @@ add_task(async function test_contentscript_clipboard_permission_write() {
// Test that with enough permissions, we are allowed to use read in content script
add_task(async function test_contentscript_clipboard_permission_read() {
function contentScript() {
clipboardRead().then(function(dt) {
let s = dt.getData("text/plain");
clipboardRead().then(async function(items) {
let blob = await items[0].getType("text/plain");
let s = await blob.text();
if (s == "HELLO") {
browser.test.succeed("Read promise successfully read the right thing");
} else {
@ -323,24 +323,15 @@ add_task(async function test_contentscript_clipboard_nocontents_readtext() {
await extension.unload();
});
// Test that performing read(...) when the clipboard is empty returns an empty data transfer
// Test that performing read(...) when the clipboard is empty returns an empty ClipboardItem
add_task(async function test_contentscript_clipboard_nocontents_read() {
function contentScript() {
clipboardRead().then(function(dataT) {
// On macOS if we clear the clipboard and read from it, there will be
// no items in the data transfer object.
// On linux with e10s enabled clearing of the clipboard does not happen in
// the same way as it does on other platforms. So when we clear the clipboard
// and read from it, the data transfer object contains an item of type
// text/plain and kind string, but we can't call getAsString on it to verify
// that at least it is an empty string because the callback never gets invoked.
if (!dataT.items.length ||
(dataT.items.length == 1 && dataT.items[0].type == "text/plain" &&
dataT.items[0].kind == "string")) {
browser.test.succeed("Read promise successfully resolved");
} else {
clipboardRead().then(function(items) {
if (items[0].types.length) {
browser.test.fail("Read read the wrong thing from clipboard, " +
"data transfer has this many items:" + dataT.items.length);
"ClipboardItem has this many entries: " + items[0].types.length);
} else {
browser.test.succeed("Read promise successfully resolved");
}
browser.test.sendMessage("ready");
}, function(err) {