зеркало из https://github.com/mozilla/gecko-dev.git
146 строки
5.2 KiB
JavaScript
146 строки
5.2 KiB
JavaScript
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set sts=2 sw=2 et tw=80: */
|
|
"use strict";
|
|
|
|
const { AppConstants } = ChromeUtils.import(
|
|
"resource://gre/modules/AppConstants.jsm"
|
|
);
|
|
|
|
// Note: widget/tests/test_bug1123480.xhtml checks whether nsTransferable behaves
|
|
// as expected with regards to private browsing mode and the clipboard cache,
|
|
// i.e. that the clipboard is not cached to the disk when private browsing mode
|
|
// is enabled.
|
|
//
|
|
// This test tests that the clipboard is not cached to the disk by IPC,
|
|
// as a regression test for bug 1396224.
|
|
// It indirectly uses nsTransferable, via the async navigator.clipboard API.
|
|
|
|
// Create over 1 MB of sample garbage text. JavaScript strings are represented
|
|
// by UTF16 strings, so the size is twice as much as the actual string length.
|
|
// This value is chosen such that the size of the memory for the string exceeds
|
|
// the kLargeDatasetSize threshold in nsTransferable.h.
|
|
// It is also not a round number to reduce the odds of having an accidental
|
|
// collisions with another file (since the test below looks at the file size
|
|
// to identify the file).
|
|
var Ipsum = "0123456789".repeat(1234321);
|
|
var IpsumByteLength = Ipsum.length * 2;
|
|
var SHORT_STRING_NO_CACHE = "short string that will not be cached to the disk";
|
|
|
|
// Get a list of open file descriptors that refer to a file with the same size
|
|
// as the expected data (and assume that any mutations in file descriptor counts
|
|
// are caused by our test).
|
|
// TODO: This logic only counts file descriptors that are still open (e.g. when
|
|
// data persists after a copy). It does not detect cache files that exist only
|
|
// temporarily (e.g. after a paste).
|
|
function getClipboardCacheFDCount() {
|
|
let dir;
|
|
if (AppConstants.platform === "win") {
|
|
// On Windows, nsAnonymousTemporaryFile does not immediately delete a file.
|
|
// Instead, the Windows-specific FILE_FLAG_DELETE_ON_CLOSE flag is used,
|
|
// which means that the file is deleted when the last handle is closed.
|
|
// Apparently, this flag is unreliable (e.g. when the application crashes),
|
|
// so nsAnonymousTemporaryFile stores the temporary files in a subdirectory,
|
|
// which is cleaned up some time after start-up.
|
|
|
|
// This is just a test, and during the test we deterministically close the
|
|
// handles, so if FILE_FLAG_DELETE_ON_CLOSE does the thing it promises, the
|
|
// file is actually removed when the handle is closed.
|
|
|
|
let { FileUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/FileUtils.jsm"
|
|
);
|
|
// Path from nsAnonymousTemporaryFile.cpp, GetTempDir.
|
|
dir = FileUtils.getFile("TmpD", ["mozilla-temp-files"]);
|
|
} else {
|
|
dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
|
dir.initWithPath("/dev/fd");
|
|
}
|
|
let count = 0;
|
|
for (let fdFile of dir.directoryEntries) {
|
|
let fileSize;
|
|
try {
|
|
fileSize = fdFile.fileSize;
|
|
} catch (e) {
|
|
// This can happen on macOS.
|
|
continue;
|
|
}
|
|
if (fileSize === IpsumByteLength) {
|
|
// Assume that the file was created by us if the size matches.
|
|
++count;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
async function testCopyPaste(isPrivate) {
|
|
let win = await BrowserTestUtils.openNewBrowserWindow({ private: isPrivate });
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(win);
|
|
let browser = tab.linkedBrowser;
|
|
|
|
// Sanitize environment
|
|
await ContentTask.spawn(browser, SHORT_STRING_NO_CACHE, async shortStr => {
|
|
await content.navigator.clipboard.writeText(shortStr);
|
|
});
|
|
|
|
let initialFdCount = getClipboardCacheFDCount();
|
|
|
|
await SpecialPowers.spawn(browser, [Ipsum], async largeString => {
|
|
await content.navigator.clipboard.writeText(largeString);
|
|
});
|
|
|
|
let fdCountAfterCopy = getClipboardCacheFDCount();
|
|
if (isPrivate) {
|
|
is(fdCountAfterCopy, initialFdCount, "Private write");
|
|
} else {
|
|
is(fdCountAfterCopy, initialFdCount + 1, "Cached write");
|
|
}
|
|
|
|
let readStr = await SpecialPowers.spawn(browser, [], async () => {
|
|
let { document } = content;
|
|
document.body.contentEditable = true;
|
|
document.body.focus();
|
|
let pastePromise = new Promise(resolve => {
|
|
document.addEventListener(
|
|
"paste",
|
|
e => {
|
|
resolve(e.clipboardData.getData("text/plain"));
|
|
},
|
|
{ once: true }
|
|
);
|
|
});
|
|
document.execCommand("paste");
|
|
return pastePromise;
|
|
});
|
|
ok(readStr === Ipsum, "Read what we pasted");
|
|
|
|
if (isPrivate) {
|
|
is(getClipboardCacheFDCount(), fdCountAfterCopy, "Private read");
|
|
} else {
|
|
// Upon reading from the clipboard, a temporary nsTransferable is used, for
|
|
// which the cache is disabled. The content process does not cache clipboard
|
|
// data either. So the file descriptor count should be identical.
|
|
is(getClipboardCacheFDCount(), fdCountAfterCopy, "Read not cached");
|
|
}
|
|
|
|
// Cleanup.
|
|
await SpecialPowers.spawn(
|
|
browser,
|
|
[SHORT_STRING_NO_CACHE],
|
|
async shortStr => {
|
|
await content.navigator.clipboard.writeText(shortStr);
|
|
}
|
|
);
|
|
is(getClipboardCacheFDCount(), initialFdCount, "Drop clipboard cache if any");
|
|
|
|
BrowserTestUtils.removeTab(tab);
|
|
await BrowserTestUtils.closeWindow(win);
|
|
}
|
|
|
|
add_task(async function test_private() {
|
|
await testCopyPaste(true);
|
|
});
|
|
|
|
add_task(async function test_non_private() {
|
|
await testCopyPaste(false);
|
|
});
|