Skip to content

Commit

Permalink
Bug 1408708 - Fetch stylesheet content via stylesheet window instead …
Browse files Browse the repository at this point in the history
…of top level content window. r=pbro

MozReview-Commit-ID: AKXQLNAwy8t
  • Loading branch information
ochameau committed Dec 7, 2017
1 parent c25dc80 commit 02e1065
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 7 deletions.
4 changes: 4 additions & 0 deletions devtools/client/styleeditor/test/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ subsuite = devtools
support-files =
autocomplete.html
browser_styleeditor_cmd_edit.html
bug_1405342_serviceworker_iframes.html
four.html
head.js
iframe_with_service_worker.html
iframe_service_worker.js
import.css
import.html
import2.css
Expand Down Expand Up @@ -70,6 +73,7 @@ support-files =
[browser_styleeditor_bug_740541_iframes.js]
[browser_styleeditor_bug_851132_middle_click.js]
[browser_styleeditor_bug_870339.js]
[browser_styleeditor_bug_1405342_serviceworker_iframes.js]
[browser_styleeditor_cmd_edit.js]
[browser_styleeditor_enabled.js]
[browser_styleeditor_fetch-from-cache.js]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";

// Test that sheets inside cross origin iframes, served from a service worker
// are correctly fetched via the service worker in the stylesheet editor.

add_task(async function () {
const TEST_URL = "https://test1.example.com/browser/devtools/client/styleeditor/test/bug_1405342_serviceworker_iframes.html";
let { ui } = await openStyleEditorForURL(TEST_URL);

if (ui.editors.length != 1) {
info("Stylesheet isn't available immediately, waiting for it");
await ui.once("editor-added");
}
is(ui.editors.length, 1, "Got the iframe stylesheet");

await ui.selectStyleSheet(ui.editors[0].styleSheet);
let editor = await ui.editors[0].getSourceEditor();
let text = editor.sourceEditor.getText();
is(text, "* { color: green; }",
"stylesheet content is the one served by the service worker");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 1405342</title>
</head>
<body>
<iframe src="https://test2.example.com/browser/devtools/client/styleeditor/test/iframe_with_service_worker.html"><iframe>
</body>
</html>
12 changes: 12 additions & 0 deletions devtools/client/styleeditor/test/iframe_service_worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";

self.onfetch = function (event) {
if (event.request.url.includes("sheet.css")) {
return event.respondWith(new Response("* { color: green; }"));
}
return null;
};

self.onactivate = function (event) {
event.waitUntil(self.clients.claim());
};
33 changes: 33 additions & 0 deletions devtools/client/styleeditor/test/iframe_with_service_worker.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<meta charset="utf-8">

Iframe loading a stylesheet via a service worker
<script>
"use strict";

function waitForActive(swr) {
let sw = swr.installing || swr.waiting || swr.active;
return new Promise(resolve => {
if (sw.state === "activated") {
resolve(swr);
return;
}
sw.addEventListener("statechange", function onStateChange(evt) {
if (sw.state === "activated") {
sw.removeEventListener("statechange", onStateChange);
resolve(swr);
}
});
});
}

navigator.serviceWorker.register("iframe_service_worker.js", {scope: "."})
.then(registration => waitForActive(registration))
.then(() => {
let link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "sheet.css");
document.documentElement.appendChild(link);
});
</script>
33 changes: 27 additions & 6 deletions devtools/server/actors/stylesheets.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
* Window of target
*/
get window() {
return this._window || this.parentActor.window;
return this.parentActor.window;
},

/**
Expand All @@ -150,6 +150,14 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
return this.window.document;
},

/**
* StyleSheet's window.
*/
get ownerWindow() {
// eslint-disable-next-line mozilla/use-ownerGlobal
return this.ownerDocument.defaultView;
},

get ownerNode() {
return this.rawSheet.ownerNode;
},
Expand Down Expand Up @@ -202,18 +210,31 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
}
},

initialize: function (styleSheet, parentActor, window) {
initialize: function (styleSheet, parentActor) {
protocol.Actor.prototype.initialize.call(this, null);

this.rawSheet = styleSheet;
this.parentActor = parentActor;
this.conn = this.parentActor.conn;

this._window = window;

// text and index are unknown until source load
this.text = null;
this._styleSheetIndex = -1;

// When the style is imported, `styleSheet.ownerNode` is null,
// so retrieve the topmost parent style sheet which has an ownerNode
let parentStyleSheet = styleSheet;
while (parentStyleSheet.parentStyleSheet) {
parentStyleSheet = parentStyleSheet.parentStyleSheet;
}
// When the style is injected via nsIDOMWindowUtils.loadSheet, even
// the parent style sheet has no owner, so default back to tab actor
// document
if (parentStyleSheet.ownerNode) {
this.ownerDocument = parentStyleSheet.ownerNode.ownerDocument;
} else {
this.ownerDocument = parentActor.window;
}
},

/**
Expand Down Expand Up @@ -417,8 +438,8 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
if (!excludedProtocolsRe.test(this.href)) {
// Stylesheets using other protocols should use the content principal.
options.window = this.window;
options.principal = this.document.nodePrincipal;
options.window = this.ownerWindow;
options.principal = this.ownerDocument.nodePrincipal;
}

let result;
Expand Down
13 changes: 12 additions & 1 deletion devtools/shared/DevToolsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,18 @@ function mainThreadFetch(urlIn, aOptions = { loadFromCache: true,
// the input unmodified. Essentially we try to decode the data as UTF-8
// and if that fails, we use the locale specific default encoding. This is
// the best we can do if the source does not provide charset info.
let charset = bomCharset || channel.contentCharset || aOptions.charset || "UTF-8";
let charset = bomCharset;
if (!charset) {
try {
charset = channel.contentCharset;
} catch (e) {
// Accessing `contentCharset` on content served by a service worker in
// non-e10s may throw.
}
}
if (!charset) {
charset = aOptions.charset || "UTF-8";
}
let unicodeSource = NetworkHelper.convertToUnicode(source, charset);

deferred.resolve({
Expand Down

0 comments on commit 02e1065

Please sign in to comment.