bug 1272890 - implement match_about_blank for content scripts r=kmag

MozReview-Commit-ID: 3iZLpUw5LF4

--HG--
extra : rebase_source : d520a13211584af096f68cd0a2cfec022a72e413
This commit is contained in:
Tomislav Jovanovic 2016-10-12 05:48:04 +02:00
Родитель 0a5faee022
Коммит 47aa3f8372
4 изменённых файлов: 159 добавлений и 7 удалений

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

@ -101,6 +101,7 @@ function Script(extension, options, deferred = PromiseUtils.defer()) {
this.js = this.options.js || [];
this.css = this.options.css || [];
this.remove_css = this.options.remove_css;
this.match_about_blank = this.options.match_about_blank;
this.deferred = deferred;
@ -140,6 +141,12 @@ Script.prototype = {
return false;
}
if (this.match_about_blank && ["about:blank", "about:srcdoc"].includes(uri.spec)) {
// When matching about:blank/srcdoc documents, the checks below
// need to be performed against the "owner" document's URI.
uri = window.document.nodePrincipal.URI;
}
if (!(this.matches_.matches(uri) || this.matches_host_.matchesIgnoringPath(uri))) {
return false;
}
@ -166,8 +173,6 @@ Script.prototype = {
return false;
}
// TODO: match_about_blank.
return true;
},
@ -426,11 +431,13 @@ DocumentManager = {
extensionPageWindows: new Map(),
init() {
Services.obs.addObserver(this, "content-document-global-created", false);
Services.obs.addObserver(this, "document-element-inserted", false);
Services.obs.addObserver(this, "inner-window-destroyed", false);
},
uninit() {
Services.obs.removeObserver(this, "content-document-global-created");
Services.obs.removeObserver(this, "document-element-inserted");
Services.obs.removeObserver(this, "inner-window-destroyed");
},
@ -447,13 +454,27 @@ DocumentManager = {
},
observe: function(subject, topic, data) {
if (topic == "document-element-inserted") {
// For some types of documents (about:blank), we only see the first
// notification, for others (data: URIs) we only observe the second.
if (topic == "content-document-global-created" || topic == "document-element-inserted") {
let document = subject;
let window = document && document.defaultView;
if (topic == "content-document-global-created") {
window = subject;
document = window && window.document;
}
if (!document || !document.location || !window) {
return;
}
// Make sure we always load exactly once (notice != used as logical XOR),
// usually on document-element-inserted, except for about:blank documents.
if ((topic == "content-document-global-created") != (window.location.href == "about:blank")) {
return;
}
// Make sure we only load into frames that ExtensionContent.init
// was called on (i.e., not frames for social or sidebars).
let mm = getWindowMessageManager(window);
@ -482,7 +503,8 @@ DocumentManager = {
}
}
this.trigger("document_start", window);
this.trigger(window);
/* eslint-disable mozilla/balanced-listeners */
window.addEventListener("DOMContentLoaded", this, true);
window.addEventListener("load", this, true);
@ -526,9 +548,9 @@ DocumentManager = {
// Need to check if we're still on the right page? Greasemonkey does this.
if (event.type == "DOMContentLoaded") {
this.trigger("document_end", window);
this.trigger(window);
} else if (event.type == "load") {
this.trigger("document_idle", window);
this.trigger(window);
}
},
@ -666,7 +688,7 @@ DocumentManager = {
}
},
trigger(when, window) {
trigger(window) {
let state = this.getWindowState(window);
if (state == "document_start") {

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

@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<iframe id="a_b" src="about:blank"></iframe>
<iframe srcdoc="galactica actual" src="adama"></iframe>
</body>
</html>

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

@ -18,6 +18,7 @@ support-files =
file_WebNavigation_page1.html
file_WebNavigation_page2.html
file_WebNavigation_page3.html
file_with_about_blank.html
file_image_good.png
file_image_bad.png
file_image_redirect.png
@ -50,6 +51,8 @@ skip-if = os == 'android' # Android does not currently support windows.
[test_ext_contentscript_devtools_metadata.html]
[test_ext_contentscript_exporthelpers.html]
[test_ext_contentscript_css.html]
[test_ext_contentscript_about_blank.html]
skip-if = (os == 'android') # bug 1312357
[test_ext_contentscript_teardown.html]
skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
[test_ext_exclude_include_globs.html]

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

@ -0,0 +1,117 @@
<!doctype html>
<html>
<head>
<title>Test content script match_about_blank option</title>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
add_task(function* test_contentscript_about_blank() {
const manifest = {
content_scripts: [
{
match_about_blank: true,
matches: ["http://mochi.test/*/file_with_about_blank.html", "http://example.com/*"],
all_frames: true,
css: ["all.css"],
js: ["all.js"],
}, {
matches: ["http://mochi.test/*/file_with_about_blank.html"],
css: ["mochi_without.css"],
js: ["mochi_without.js"],
all_frames: true,
}, {
match_about_blank: true,
matches: ["http://mochi.test/*/file_with_about_blank.html"],
css: ["mochi_with.css"],
js: ["mochi_with.js"],
all_frames: true,
},
],
};
const files = {
"all.js": function() {
browser.runtime.sendMessage("all");
},
"all.css": `
body { color: red; }
`,
"mochi_without.js": function() {
browser.runtime.sendMessage("mochi_without");
},
"mochi_without.css": `
body { background: yellow; }
`,
"mochi_with.js": function() {
browser.runtime.sendMessage("mochi_with");
},
"mochi_with.css": `
body { text-align: right; }
`,
};
function background() {
browser.runtime.onMessage.addListener((script, {url}) => {
const kind = url.startsWith("about:") ? url : "top";
browser.test.sendMessage("script", [script, kind, url]);
browser.test.sendMessage(`${script}:${kind}`);
});
}
const PATH = "tests/toolkit/components/extensions/test/mochitest/file_with_about_blank.html";
const extension = ExtensionTestUtils.loadExtension({manifest, files, background});
yield extension.startup();
let count = 0;
extension.onMessage("script", script => {
info(`script ran: ${script}`);
count++;
});
let win = window.open("http://example.com/" + PATH);
yield Promise.all([
extension.awaitMessage("all:top"),
extension.awaitMessage("all:about:blank"),
extension.awaitMessage("all:about:srcdoc"),
]);
is(count, 3, "exactly 3 scripts ran");
win.close();
win = window.open("http://mochi.test:8888/" + PATH);
yield Promise.all([
extension.awaitMessage("all:top"),
extension.awaitMessage("all:about:blank"),
extension.awaitMessage("all:about:srcdoc"),
extension.awaitMessage("mochi_without:top"),
extension.awaitMessage("mochi_with:top"),
extension.awaitMessage("mochi_with:about:blank"),
extension.awaitMessage("mochi_with:about:srcdoc"),
]);
let style = win.getComputedStyle(win.document.body);
is(style.color, "rgb(255, 0, 0)", "top window text color is red");
is(style.backgroundColor, "rgb(255, 255, 0)", "top window background is yellow");
is(style.textAlign, "right", "top window text is right-aligned");
let a_b = win.document.getElementById("a_b");
style = a_b.contentWindow.getComputedStyle(a_b.contentDocument.body);
is(style.color, "rgb(255, 0, 0)", "about:blank iframe text color is red");
is(style.backgroundColor, "transparent", "about:blank iframe background is transparent");
is(style.textAlign, "right", "about:blank text is right-aligned");
is(count, 10, "exactly 7 more scripts ran");
win.close();
yield extension.unload();
});
</script>
</body>
</html>