mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-27 10:57:34 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
93601ea999
17 changed files with 336 additions and 308 deletions
|
|
@ -23,10 +23,6 @@ const childProcessMessageManager =
|
||||||
Cc["@mozilla.org/childprocessmessagemanager;1"]
|
Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||||
.getService(Ci.nsISyncMessageSender);
|
.getService(Ci.nsISyncMessageSender);
|
||||||
|
|
||||||
// Amount of space that will be allocated for the stream's backing-store.
|
|
||||||
// Must be power of 2. Used to copy the data stream in onStopRequest.
|
|
||||||
const SEGMENT_SIZE = Math.pow(2, 17);
|
|
||||||
|
|
||||||
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
|
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
|
||||||
const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" +
|
const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" +
|
||||||
JSON_VIEW_MIME_TYPE + "&to=*/*";
|
JSON_VIEW_MIME_TYPE + "&to=*/*";
|
||||||
|
|
@ -61,9 +57,8 @@ let Converter = Class({
|
||||||
* 1. asyncConvertData captures the listener
|
* 1. asyncConvertData captures the listener
|
||||||
* 2. onStartRequest fires, initializes stuff, modifies the listener
|
* 2. onStartRequest fires, initializes stuff, modifies the listener
|
||||||
* to match our output type
|
* to match our output type
|
||||||
* 3. onDataAvailable transcodes the data into a UTF-8 string
|
* 3. onDataAvailable spits it back to the listener
|
||||||
* 4. onStopRequest gets the collected data and converts it,
|
* 4. onStopRequest spits it back to the listener
|
||||||
* spits it to the listener
|
|
||||||
* 5. convert does nothing, it's just the synchronous version
|
* 5. convert does nothing, it's just the synchronous version
|
||||||
* of asyncConvertData
|
* of asyncConvertData
|
||||||
*/
|
*/
|
||||||
|
|
@ -76,60 +71,80 @@ let Converter = Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
onDataAvailable: function (request, context, inputStream, offset, count) {
|
onDataAvailable: function (request, context, inputStream, offset, count) {
|
||||||
// From https://developer.mozilla.org/en/Reading_textual_data
|
this.listener.onDataAvailable(...arguments);
|
||||||
let is = Cc["@mozilla.org/intl/converter-input-stream;1"]
|
|
||||||
.createInstance(Ci.nsIConverterInputStream);
|
|
||||||
is.init(inputStream, this.charset, -1,
|
|
||||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
|
||||||
|
|
||||||
// Seed it with something positive
|
|
||||||
while (count) {
|
|
||||||
let str = {};
|
|
||||||
let bytesRead = is.readString(count, str);
|
|
||||||
if (!bytesRead) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
count -= bytesRead;
|
|
||||||
this.data += str.value;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onStartRequest: function (request, context) {
|
onStartRequest: function (request, context) {
|
||||||
this.data = "";
|
// Set the content type to HTML in order to parse the doctype, styles
|
||||||
this.uri = request.QueryInterface(Ci.nsIChannel).URI.spec;
|
// and scripts, but later a <plaintext> element will switch the tokenizer
|
||||||
|
// to the plaintext state in order to parse the JSON.
|
||||||
|
request.QueryInterface(Ci.nsIChannel);
|
||||||
|
request.contentType = "text/html";
|
||||||
|
|
||||||
// Sets the charset if it is available. (For documents loaded from the
|
// JSON enforces UTF-8 charset (see bug 741776).
|
||||||
// filesystem, this is not set.)
|
request.contentCharset = "UTF-8";
|
||||||
this.charset =
|
|
||||||
request.QueryInterface(Ci.nsIChannel).contentCharset || "UTF-8";
|
// Changing the content type breaks saving functionality. Fix it.
|
||||||
|
fixSave(request);
|
||||||
|
|
||||||
this.channel = request;
|
|
||||||
this.channel.contentType = "text/html";
|
|
||||||
this.channel.contentCharset = "UTF-8";
|
|
||||||
// Because content might still have a reference to this window,
|
// Because content might still have a reference to this window,
|
||||||
// force setting it to a null principal to avoid it being same-
|
// force setting it to a null principal to avoid it being same-
|
||||||
// origin with (other) content.
|
// origin with (other) content.
|
||||||
this.channel.loadInfo.resetPrincipalsToNullPrincipal();
|
request.loadInfo.resetPrincipalsToNullPrincipal();
|
||||||
|
|
||||||
this.listener.onStartRequest(this.channel, context);
|
// Start the request.
|
||||||
|
this.listener.onStartRequest(request, context);
|
||||||
|
|
||||||
|
// Initialize stuff.
|
||||||
|
let win = NetworkHelper.getWindowForRequest(request);
|
||||||
|
exportData(win, request);
|
||||||
|
win.addEventListener("DOMContentLoaded", event => {
|
||||||
|
win.addEventListener("contentMessage", onContentMessage, false, true);
|
||||||
|
}, {once: true});
|
||||||
|
|
||||||
|
// Insert the initial HTML code.
|
||||||
|
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||||
|
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||||
|
converter.charset = "UTF-8";
|
||||||
|
let stream = converter.convertToInputStream(initialHTML(win.document));
|
||||||
|
this.listener.onDataAvailable(request, context, stream, 0, stream.available());
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* This should go something like this:
|
|
||||||
* 1. Make sure we have a unicode string.
|
|
||||||
* 2. Convert it to a Javascript object.
|
|
||||||
* 2.1 Removes the callback
|
|
||||||
* 3. Convert that to HTML? Or XUL?
|
|
||||||
* 4. Spit it back out at the listener
|
|
||||||
*/
|
|
||||||
onStopRequest: function (request, context, statusCode) {
|
onStopRequest: function (request, context, statusCode) {
|
||||||
let headers = {
|
this.listener.onStopRequest(request, context, statusCode);
|
||||||
response: [],
|
this.listener = null;
|
||||||
request: []
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
let win = NetworkHelper.getWindowForRequest(request);
|
// Lets "save as" save the original JSON, not the viewer.
|
||||||
|
// To save with the proper extension we need the original content type,
|
||||||
|
// which has been replaced by application/vnd.mozilla.json.view
|
||||||
|
function fixSave(request) {
|
||||||
|
let originalType;
|
||||||
|
if (request instanceof Ci.nsIHttpChannel) {
|
||||||
|
try {
|
||||||
|
let header = request.getResponseHeader("Content-Type");
|
||||||
|
originalType = header.split(";")[0];
|
||||||
|
} catch (err) {
|
||||||
|
// Handled below
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let uri = request.QueryInterface(Ci.nsIChannel).URI.spec;
|
||||||
|
let match = uri.match(/^data:(.*?)[,;]/);
|
||||||
|
if (match) {
|
||||||
|
originalType = match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const JSON_TYPES = ["application/json", "application/manifest+json"];
|
||||||
|
if (!JSON_TYPES.includes(originalType)) {
|
||||||
|
originalType = JSON_TYPES[0];
|
||||||
|
}
|
||||||
|
request.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||||
|
request.setProperty("contentType", originalType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports variables that will be accessed by the non-privileged scripts.
|
||||||
|
function exportData(win, request) {
|
||||||
let Locale = {
|
let Locale = {
|
||||||
$STR: key => {
|
$STR: key => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -140,14 +155,12 @@ let Converter = Class({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
JsonViewUtils.exportIntoContentScope(win, Locale, "Locale");
|
JsonViewUtils.exportIntoContentScope(win, Locale, "Locale");
|
||||||
|
|
||||||
Events.once(win, "DOMContentLoaded", event => {
|
let headers = {
|
||||||
win.addEventListener("contentMessage",
|
response: [],
|
||||||
this.onContentMessage.bind(this), false, true);
|
request: []
|
||||||
});
|
};
|
||||||
|
|
||||||
// The request doesn't have to be always nsIHttpChannel
|
// The request doesn't have to be always nsIHttpChannel
|
||||||
// (e.g. in case of data: URLs)
|
// (e.g. in case of data: URLs)
|
||||||
if (request instanceof Ci.nsIHttpChannel) {
|
if (request instanceof Ci.nsIHttpChannel) {
|
||||||
|
|
@ -156,66 +169,32 @@ let Converter = Class({
|
||||||
headers.response.push({name: name, value: value});
|
headers.response.push({name: name, value: value});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
request.visitRequestHeaders({
|
request.visitRequestHeaders({
|
||||||
visitHeader: function (name, value) {
|
visitHeader: function (name, value) {
|
||||||
headers.request.push({name: name, value: value});
|
headers.request.push({name: name, value: value});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
JsonViewUtils.exportIntoContentScope(win, headers, "headers");
|
||||||
|
}
|
||||||
|
|
||||||
let outputDoc = "";
|
// Serializes a qualifiedName and an optional set of attributes into an HTML
|
||||||
|
// start tag. Be aware qualifiedName and attribute names are not validated.
|
||||||
try {
|
// Attribute values are escaped with escapingString algorithm in attribute mode
|
||||||
headers = JSON.stringify(headers);
|
// (https://html.spec.whatwg.org/multipage/syntax.html#escapingString).
|
||||||
outputDoc = this.toHTML(this.data, headers, this.uri);
|
function startTag(qualifiedName, attributes = {}) {
|
||||||
} catch (e) {
|
return Object.entries(attributes).reduce(function (prev, [attr, value]) {
|
||||||
console.error("JSON Viewer ERROR " + e);
|
return prev + " " + attr + "=\"" +
|
||||||
outputDoc = this.toErrorPage(e, this.data, this.uri);
|
value.replace(/&/g, "&")
|
||||||
}
|
.replace(/\u00a0/g, " ")
|
||||||
|
.replace(/"/g, """) +
|
||||||
let storage = Cc["@mozilla.org/storagestream;1"]
|
"\"";
|
||||||
.createInstance(Ci.nsIStorageStream);
|
}, "<" + qualifiedName) + ">";
|
||||||
|
}
|
||||||
storage.init(SEGMENT_SIZE, 0xffffffff, null);
|
|
||||||
let out = storage.getOutputStream(0);
|
|
||||||
|
|
||||||
let binout = Cc["@mozilla.org/binaryoutputstream;1"]
|
|
||||||
.createInstance(Ci.nsIBinaryOutputStream);
|
|
||||||
|
|
||||||
binout.setOutputStream(out);
|
|
||||||
binout.writeUtf8Z(outputDoc);
|
|
||||||
binout.close();
|
|
||||||
|
|
||||||
// We need to trim 4 bytes off the front (this could be underlying bug).
|
|
||||||
let trunc = 4;
|
|
||||||
let instream = storage.newInputStream(trunc);
|
|
||||||
|
|
||||||
// Pass the data to the main content listener
|
|
||||||
this.listener.onDataAvailable(this.channel, context, instream, 0,
|
|
||||||
instream.available());
|
|
||||||
|
|
||||||
this.listener.onStopRequest(this.channel, context, statusCode);
|
|
||||||
|
|
||||||
this.listener = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
htmlEncode: function (t) {
|
|
||||||
return t !== null ? t.toString()
|
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/"/g, """)
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">") : "";
|
|
||||||
},
|
|
||||||
|
|
||||||
toHTML: function (json, headers, title) {
|
|
||||||
let themeClassName = "theme-" + JsonViewUtils.getCurrentTheme();
|
|
||||||
let clientBaseUrl = "resource://devtools/client/";
|
|
||||||
let baseUrl = clientBaseUrl + "jsonview/";
|
|
||||||
let themeVarsUrl = clientBaseUrl + "themes/variables.css";
|
|
||||||
let commonUrl = clientBaseUrl + "themes/common.css";
|
|
||||||
let toolbarsUrl = clientBaseUrl + "themes/toolbars.css";
|
|
||||||
|
|
||||||
|
// Builds an HTML string that will be used to load stylesheets and scripts,
|
||||||
|
// and switch the parser to plaintext state.
|
||||||
|
function initialHTML(doc) {
|
||||||
let os;
|
let os;
|
||||||
let platform = Services.appinfo.OS;
|
let platform = Services.appinfo.OS;
|
||||||
if (platform.startsWith("WINNT")) {
|
if (platform.startsWith("WINNT")) {
|
||||||
|
|
@ -226,52 +205,38 @@ let Converter = Class({
|
||||||
os = "linux";
|
os = "linux";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<!DOCTYPE html>\n" +
|
let base = doc.createElement("base");
|
||||||
"<html platform=\"" + os + "\" class=\"" + themeClassName + "\">" +
|
base.href = "resource://devtools/client/jsonview/";
|
||||||
"<head><title>" + this.htmlEncode(title) + "</title>" +
|
|
||||||
"<base href=\"" + this.htmlEncode(baseUrl) + "\">" +
|
|
||||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
|
|
||||||
themeVarsUrl + "\">" +
|
|
||||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
|
|
||||||
commonUrl + "\">" +
|
|
||||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
|
|
||||||
toolbarsUrl + "\">" +
|
|
||||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\">" +
|
|
||||||
"<script data-main=\"viewer-config\" src=\"lib/require.js\"></script>" +
|
|
||||||
"</head><body>" +
|
|
||||||
"<div id=\"content\"></div>" +
|
|
||||||
"<div id=\"json\">" + this.htmlEncode(json) + "</div>" +
|
|
||||||
"<div id=\"headers\">" + this.htmlEncode(headers) + "</div>" +
|
|
||||||
"</body></html>";
|
|
||||||
},
|
|
||||||
|
|
||||||
toErrorPage: function (error, data, uri) {
|
let style = doc.createElement("link");
|
||||||
// Escape unicode nulls
|
style.rel = "stylesheet";
|
||||||
data = data.replace("\u0000", "\uFFFD");
|
style.type = "text/css";
|
||||||
|
style.href = "css/main.css";
|
||||||
|
|
||||||
let errorInfo = error + "";
|
let script = doc.createElement("script");
|
||||||
|
script.src = "lib/require.js";
|
||||||
|
script.dataset.main = "viewer-config";
|
||||||
|
script.defer = true;
|
||||||
|
|
||||||
let output = "<div id=\"error\">" + "error parsing";
|
let head = doc.createElement("head");
|
||||||
if (errorInfo.message) {
|
head.append(base, style, script);
|
||||||
output += "<div class=\"errormessage\">" + errorInfo.message + "</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "</div><div id=\"json\">" + this.highlightError(data,
|
|
||||||
errorInfo.line, errorInfo.column) + "</div>";
|
|
||||||
|
|
||||||
return "<!DOCTYPE html>\n" +
|
return "<!DOCTYPE html>\n" +
|
||||||
"<html><head><title>" + this.htmlEncode(uri + " - Error") + "</title>" +
|
startTag("html", {
|
||||||
"<base href=\"" + this.htmlEncode(this.data.url()) + "\">" +
|
"platform": os,
|
||||||
"</head><body>" +
|
"class": "theme-" + JsonViewUtils.getCurrentTheme(),
|
||||||
output +
|
"dir": Services.locale.isAppLocaleRTL ? "rtl" : "ltr"
|
||||||
"</body></html>";
|
}) +
|
||||||
},
|
head.outerHTML +
|
||||||
|
startTag("body") +
|
||||||
|
startTag("div", {"id": "content"}) +
|
||||||
|
startTag("plaintext", {"id": "json"});
|
||||||
|
}
|
||||||
|
|
||||||
// Chrome <-> Content communication
|
// Chrome <-> Content communication
|
||||||
|
function onContentMessage(e) {
|
||||||
onContentMessage: function (e) {
|
|
||||||
// Do not handle events from different documents.
|
// Do not handle events from different documents.
|
||||||
let win = NetworkHelper.getWindowForRequest(this.channel);
|
let win = this;
|
||||||
if (win != e.target) {
|
if (win != e.target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -279,20 +244,20 @@ let Converter = Class({
|
||||||
let value = e.detail.value;
|
let value = e.detail.value;
|
||||||
switch (e.detail.type) {
|
switch (e.detail.type) {
|
||||||
case "copy":
|
case "copy":
|
||||||
Clipboard.set(value, "text");
|
copyString(win, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "copy-headers":
|
case "copy-headers":
|
||||||
this.copyHeaders(value);
|
copyHeaders(win, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "save":
|
case "save":
|
||||||
childProcessMessageManager.sendAsyncMessage(
|
childProcessMessageManager.sendAsyncMessage(
|
||||||
"devtools:jsonview:save", value);
|
"devtools:jsonview:save", value);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
copyHeaders: function (headers) {
|
function copyHeaders(win, headers) {
|
||||||
let value = "";
|
let value = "";
|
||||||
let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n";
|
let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n";
|
||||||
|
|
||||||
|
|
@ -310,9 +275,17 @@ let Converter = Class({
|
||||||
value += header.name + ": " + header.value + eol;
|
value += header.name + ": " + header.value + eol;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clipboard.set(value, "text");
|
copyString(win, value);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
function copyString(win, string) {
|
||||||
|
win.document.addEventListener("copy", event => {
|
||||||
|
event.clipboardData.setData("text/plain", string);
|
||||||
|
event.preventDefault();
|
||||||
|
}, {once: true});
|
||||||
|
|
||||||
|
win.document.execCommand("copy", false, null);
|
||||||
|
}
|
||||||
|
|
||||||
// Stream converter component definition
|
// Stream converter component definition
|
||||||
let service = xpcom.Service({
|
let service = xpcom.Service({
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ pre {
|
||||||
font-family: var(--monospace-font-family);
|
font-family: var(--monospace-font-family);
|
||||||
}
|
}
|
||||||
|
|
||||||
#json,
|
#json {
|
||||||
#headers {
|
|
||||||
display: none;
|
display: none;
|
||||||
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
@import "resource://devtools/client/shared/components/reps/reps.css";
|
@import "resource://devtools/client/themes/variables.css";
|
||||||
|
@import "resource://devtools/client/themes/common.css";
|
||||||
|
@import "resource://devtools/client/themes/toolbars.css";
|
||||||
@import "resource://devtools/client/shared/components/tree/tree-view.css";
|
@import "resource://devtools/client/shared/components/tree/tree-view.css";
|
||||||
@import "resource://devtools/client/shared/components/tabs/tabs.css";
|
@import "resource://devtools/client/shared/components/tabs/tabs.css";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,28 @@ define(function (require, exports, module) {
|
||||||
const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area"));
|
const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area"));
|
||||||
|
|
||||||
const json = document.getElementById("json");
|
const json = document.getElementById("json");
|
||||||
const headers = document.getElementById("headers");
|
|
||||||
|
|
||||||
let jsonData;
|
|
||||||
|
|
||||||
try {
|
|
||||||
jsonData = JSON.parse(json.textContent);
|
|
||||||
} catch (err) {
|
|
||||||
jsonData = err + "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application state object.
|
// Application state object.
|
||||||
let input = {
|
let input = {
|
||||||
jsonText: json.textContent,
|
jsonText: json.textContent,
|
||||||
jsonPretty: null,
|
jsonPretty: null,
|
||||||
json: jsonData,
|
headers: window.headers,
|
||||||
headers: JSON.parse(headers.textContent),
|
|
||||||
tabActive: 0,
|
tabActive: 0,
|
||||||
prettified: false
|
prettified: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remove BOM, if present.
|
||||||
|
if (input.jsonText.startsWith("\ufeff")) {
|
||||||
|
input.jsonText = input.jsonText.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
input.json = JSON.parse(input.jsonText);
|
||||||
|
} catch (err) {
|
||||||
|
input.json = err;
|
||||||
|
}
|
||||||
|
|
||||||
json.remove();
|
json.remove();
|
||||||
headers.remove();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application actions/commands. This list implements all commands
|
* Application actions/commands. This list implements all commands
|
||||||
|
|
@ -61,7 +61,7 @@ define(function (require, exports, module) {
|
||||||
theApp.setState({jsonText: input.jsonText});
|
theApp.setState({jsonText: input.jsonText});
|
||||||
} else {
|
} else {
|
||||||
if (!input.jsonPretty) {
|
if (!input.jsonPretty) {
|
||||||
input.jsonPretty = JSON.stringify(jsonData, null, " ");
|
input.jsonPretty = JSON.stringify(input.json, null, " ");
|
||||||
}
|
}
|
||||||
theApp.setState({jsonText: input.jsonPretty});
|
theApp.setState({jsonText: input.jsonPretty});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@ exports.exportIntoContentScope = function (win, obj, defineAs) {
|
||||||
Cu.exportFunction(propValue, clone, {
|
Cu.exportFunction(propValue, clone, {
|
||||||
defineAs: propName
|
defineAs: propName
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
clone[propName] = Cu.cloneInto(propValue, win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include "nsIDOMWindow.h"
|
#include "nsIDOMWindow.h"
|
||||||
#include "nsITabChild.h"
|
#include "nsITabChild.h"
|
||||||
#include "nsIContent.h"
|
#include "nsIContent.h"
|
||||||
|
#include "nsIImageLoadingContent.h"
|
||||||
#include "nsILoadContext.h"
|
#include "nsILoadContext.h"
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
|
@ -145,6 +146,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||||
decision);
|
decision);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
|
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
|
||||||
|
// If we are blocking an image, we have to let the
|
||||||
|
// ImageLoadingContent know that we blocked the load.
|
||||||
|
if (externalType == nsIContentPolicy::TYPE_IMAGE ||
|
||||||
|
externalType == nsIContentPolicy::TYPE_IMAGESET) {
|
||||||
|
nsCOMPtr<nsIImageLoadingContent> img =
|
||||||
|
do_QueryInterface(requestingContext);
|
||||||
|
if (img) {
|
||||||
|
img->SetBlockedRequest(*decision);
|
||||||
|
}
|
||||||
|
}
|
||||||
/* policy says no, no point continuing to check */
|
/* policy says no, no point continuing to check */
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +204,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||||
decision);
|
decision);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
|
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
|
||||||
|
// If we are blocking an image, we have to let the
|
||||||
|
// ImageLoadingContent know that we blocked the load.
|
||||||
|
if (externalType == nsIContentPolicy::TYPE_IMAGE ||
|
||||||
|
externalType == nsIContentPolicy::TYPE_IMAGESET) {
|
||||||
|
nsCOMPtr<nsIImageLoadingContent> img =
|
||||||
|
do_QueryInterface(requestingContext);
|
||||||
|
if (img) {
|
||||||
|
img->SetBlockedRequest(*decision);
|
||||||
|
}
|
||||||
|
}
|
||||||
/* policy says no, no point continuing to check */
|
/* policy says no, no point continuing to check */
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8478,12 +8478,9 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType
|
||||||
bool
|
bool
|
||||||
nsContentUtils::IsPreloadType(nsContentPolicyType aType)
|
nsContentUtils::IsPreloadType(nsContentPolicyType aType)
|
||||||
{
|
{
|
||||||
if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
|
return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
|
||||||
aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
|
aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
|
||||||
aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) {
|
aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
|
||||||
|
|
@ -9222,19 +9222,23 @@ already_AddRefed<nsIURI>
|
||||||
nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
|
nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
|
||||||
const nsAString& aSrcAttr,
|
const nsAString& aSrcAttr,
|
||||||
const nsAString& aSrcsetAttr,
|
const nsAString& aSrcsetAttr,
|
||||||
const nsAString& aSizesAttr)
|
const nsAString& aSizesAttr,
|
||||||
|
bool *aIsImgSet)
|
||||||
{
|
{
|
||||||
nsString sourceURL;
|
nsString sourceURL;
|
||||||
|
bool isImgSet;
|
||||||
if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) {
|
if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) {
|
||||||
// We're in a <picture> element and found a URI from a source previous to
|
// We're in a <picture> element and found a URI from a source previous to
|
||||||
// this image, use it.
|
// this image, use it.
|
||||||
sourceURL = mPreloadPictureFoundSource;
|
sourceURL = mPreloadPictureFoundSource;
|
||||||
|
isImgSet = true;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise try to use this <img> as a source
|
// Otherwise try to use this <img> as a source
|
||||||
HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr,
|
HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr,
|
||||||
aSrcsetAttr, aSizesAttr,
|
aSrcsetAttr, aSizesAttr,
|
||||||
NullString(), NullString(),
|
NullString(), NullString(),
|
||||||
sourceURL);
|
sourceURL);
|
||||||
|
isImgSet = !aSrcsetAttr.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty sources are not loaded by <img> (i.e. not resolved to the baseURI)
|
// Empty sources are not loaded by <img> (i.e. not resolved to the baseURI)
|
||||||
|
|
@ -9252,6 +9256,8 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*aIsImgSet = isImgSet;
|
||||||
|
|
||||||
// We don't clear mPreloadPictureFoundSource because subsequent <img> tags in
|
// We don't clear mPreloadPictureFoundSource because subsequent <img> tags in
|
||||||
// this this <picture> share the same <sources> (though this is not valid per
|
// this this <picture> share the same <sources> (though this is not valid per
|
||||||
// spec)
|
// spec)
|
||||||
|
|
@ -9260,16 +9266,12 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
|
nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
|
||||||
ReferrerPolicy aReferrerPolicy)
|
ReferrerPolicy aReferrerPolicy, bool aIsImgSet)
|
||||||
{
|
{
|
||||||
// Early exit if the img is already present in the img-cache
|
// Early exit if the img is already present in the img-cache
|
||||||
// which indicates that the "real" load has already started and
|
// which indicates that the "real" load has already started and
|
||||||
// that we shouldn't preload it.
|
// that we shouldn't preload it.
|
||||||
int16_t blockingStatus;
|
if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this))) {
|
||||||
if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) ||
|
|
||||||
!nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
|
|
||||||
this, NodePrincipal(), &blockingStatus,
|
|
||||||
nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9288,6 +9290,10 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
|
||||||
MOZ_CRASH("Unknown CORS mode!");
|
MOZ_CRASH("Unknown CORS mode!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsContentPolicyType policyType =
|
||||||
|
aIsImgSet ? nsIContentPolicy::TYPE_IMAGESET :
|
||||||
|
nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD;
|
||||||
|
|
||||||
// Image not in cache - trigger preload
|
// Image not in cache - trigger preload
|
||||||
RefPtr<imgRequestProxy> request;
|
RefPtr<imgRequestProxy> request;
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
|
|
@ -9301,7 +9307,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
|
||||||
loadFlags,
|
loadFlags,
|
||||||
NS_LITERAL_STRING("img"),
|
NS_LITERAL_STRING("img"),
|
||||||
getter_AddRefs(request),
|
getter_AddRefs(request),
|
||||||
nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD);
|
policyType);
|
||||||
|
|
||||||
// Pin image-reference to avoid evicting it from the img-cache before
|
// Pin image-reference to avoid evicting it from the img-cache before
|
||||||
// the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
|
// the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
|
||||||
|
|
|
||||||
|
|
@ -948,11 +948,13 @@ public:
|
||||||
ResolvePreloadImage(nsIURI *aBaseURI,
|
ResolvePreloadImage(nsIURI *aBaseURI,
|
||||||
const nsAString& aSrcAttr,
|
const nsAString& aSrcAttr,
|
||||||
const nsAString& aSrcsetAttr,
|
const nsAString& aSrcsetAttr,
|
||||||
const nsAString& aSizesAttr) override;
|
const nsAString& aSizesAttr,
|
||||||
|
bool *aIsImgSet) override;
|
||||||
|
|
||||||
virtual void MaybePreLoadImage(nsIURI* uri,
|
virtual void MaybePreLoadImage(nsIURI* uri,
|
||||||
const nsAString &aCrossOriginAttr,
|
const nsAString &aCrossOriginAttr,
|
||||||
ReferrerPolicy aReferrerPolicy) override;
|
ReferrerPolicy aReferrerPolicy,
|
||||||
|
bool aIsImgSet) override;
|
||||||
virtual void ForgetImagePreload(nsIURI* aURI) override;
|
virtual void ForgetImagePreload(nsIURI* aURI) override;
|
||||||
|
|
||||||
virtual void MaybePreconnect(nsIURI* uri,
|
virtual void MaybePreconnect(nsIURI* uri,
|
||||||
|
|
|
||||||
|
|
@ -2260,21 +2260,27 @@ public:
|
||||||
* nesting and possible sources, which are used to inform URL selection
|
* nesting and possible sources, which are used to inform URL selection
|
||||||
* responsive <picture> or <img srcset> images. Unset attributes are expected
|
* responsive <picture> or <img srcset> images. Unset attributes are expected
|
||||||
* to be marked void.
|
* to be marked void.
|
||||||
|
* If this image is for <picture> or <img srcset>, aIsImgSet will be set to
|
||||||
|
* true, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual already_AddRefed<nsIURI>
|
virtual already_AddRefed<nsIURI>
|
||||||
ResolvePreloadImage(nsIURI *aBaseURI,
|
ResolvePreloadImage(nsIURI *aBaseURI,
|
||||||
const nsAString& aSrcAttr,
|
const nsAString& aSrcAttr,
|
||||||
const nsAString& aSrcsetAttr,
|
const nsAString& aSrcsetAttr,
|
||||||
const nsAString& aSizesAttr) = 0;
|
const nsAString& aSizesAttr,
|
||||||
|
bool *aIsImgSet) = 0;
|
||||||
/**
|
/**
|
||||||
* Called by nsParser to preload images. Can be removed and code moved
|
* Called by nsParser to preload images. Can be removed and code moved
|
||||||
* to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the
|
* to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the
|
||||||
* parser-module is linked with gklayout-module. aCrossOriginAttr should
|
* parser-module is linked with gklayout-module. aCrossOriginAttr should
|
||||||
* be a void string if the attr is not present.
|
* be a void string if the attr is not present.
|
||||||
|
* aIsImgSet is the value got from calling ResolvePreloadImage, it is true
|
||||||
|
* when this image is for loading <picture> or <img srcset> images.
|
||||||
*/
|
*/
|
||||||
virtual void MaybePreLoadImage(nsIURI* uri,
|
virtual void MaybePreLoadImage(nsIURI* uri,
|
||||||
const nsAString& aCrossOriginAttr,
|
const nsAString& aCrossOriginAttr,
|
||||||
ReferrerPolicyEnum aReferrerPolicy) = 0;
|
ReferrerPolicyEnum aReferrerPolicy,
|
||||||
|
bool aIsImgSet) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by images to forget an image preload when they start doing
|
* Called by images to forget an image preload when they start doing
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,15 @@ interface nsIImageLoadingContent : imgINotificationObserver
|
||||||
*/
|
*/
|
||||||
imgIRequest getRequest(in long aRequestType);
|
imgIRequest getRequest(in long aRequestType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function when the request was blocked by any of the
|
||||||
|
* security policies enforced.
|
||||||
|
*
|
||||||
|
* @param aContentDecision the decision returned from nsIContentPolicy
|
||||||
|
* (any of the types REJECT_*)
|
||||||
|
*/
|
||||||
|
void setBlockedRequest(in int16_t aContentDecision);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the current request's size is available.
|
* @return true if the current request's size is available.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#include "mozAutoDocUpdate.h"
|
#include "mozAutoDocUpdate.h"
|
||||||
#include "mozilla/AsyncEventDispatcher.h"
|
#include "mozilla/AsyncEventDispatcher.h"
|
||||||
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/EventStates.h"
|
#include "mozilla/EventStates.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
#include "mozilla/dom/ImageTracker.h"
|
#include "mozilla/dom/ImageTracker.h"
|
||||||
|
|
@ -94,7 +95,8 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||||
mNewRequestsWillNeedAnimationReset(false),
|
mNewRequestsWillNeedAnimationReset(false),
|
||||||
mStateChangerDepth(0),
|
mStateChangerDepth(0),
|
||||||
mCurrentRequestRegistered(false),
|
mCurrentRequestRegistered(false),
|
||||||
mPendingRequestRegistered(false)
|
mPendingRequestRegistered(false),
|
||||||
|
mIsStartingImageLoad(false)
|
||||||
{
|
{
|
||||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
||||||
mLoadingEnabled = false;
|
mLoadingEnabled = false;
|
||||||
|
|
@ -785,6 +787,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
nsIDocument* aDocument,
|
nsIDocument* aDocument,
|
||||||
nsLoadFlags aLoadFlags)
|
nsLoadFlags aLoadFlags)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage.");
|
||||||
|
if (mIsStartingImageLoad) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Pending load/error events need to be canceled in some situations. This
|
// Pending load/error events need to be canceled in some situations. This
|
||||||
// is not documented in the spec, but can cause site compat problems if not
|
// is not documented in the spec, but can cause site compat problems if not
|
||||||
// done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
|
// done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
|
||||||
|
|
@ -814,6 +821,21 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoRestore<bool> guard(mIsStartingImageLoad);
|
||||||
|
mIsStartingImageLoad = true;
|
||||||
|
|
||||||
|
// Data documents, or documents from DOMParser shouldn't perform image loading.
|
||||||
|
if (aDocument->IsLoadedAsData()) {
|
||||||
|
// This is the only codepath on which we can reach SetBlockedRequest while
|
||||||
|
// our pending request exists. Just clear it out here if we do have one.
|
||||||
|
ClearPendingRequest(NS_BINDING_ABORTED,
|
||||||
|
Some(OnNonvisible::DISCARD_IMAGES));
|
||||||
|
SetBlockedRequest(nsIContentPolicy::REJECT_REQUEST);
|
||||||
|
FireEvent(NS_LITERAL_STRING("error"));
|
||||||
|
FireEvent(NS_LITERAL_STRING("loadend"));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// URI equality check.
|
// URI equality check.
|
||||||
//
|
//
|
||||||
// We skip the equality check if our current image was blocked, since in that
|
// We skip the equality check if our current image was blocked, since in that
|
||||||
|
|
@ -844,23 +866,8 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
"Principal mismatch?");
|
"Principal mismatch?");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Are we blocked?
|
|
||||||
int16_t cpDecision = nsIContentPolicy::REJECT_REQUEST;
|
|
||||||
nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType);
|
nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType);
|
||||||
|
|
||||||
nsContentUtils::CanLoadImage(aNewURI,
|
|
||||||
static_cast<nsIImageLoadingContent*>(this),
|
|
||||||
aDocument,
|
|
||||||
aDocument->NodePrincipal(),
|
|
||||||
&cpDecision,
|
|
||||||
policyType);
|
|
||||||
if (!NS_CP_ACCEPTED(cpDecision)) {
|
|
||||||
FireEvent(NS_LITERAL_STRING("error"));
|
|
||||||
FireEvent(NS_LITERAL_STRING("loadend"));
|
|
||||||
SetBlockedRequest(aNewURI, cpDecision);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsLoadFlags loadFlags = aLoadFlags;
|
nsLoadFlags loadFlags = aLoadFlags;
|
||||||
int32_t corsmode = GetCORSMode();
|
int32_t corsmode = GetCORSMode();
|
||||||
if (corsmode == CORS_ANONYMOUS) {
|
if (corsmode == CORS_ANONYMOUS) {
|
||||||
|
|
@ -878,7 +885,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
referrerPolicy = imgReferrerPolicy;
|
referrerPolicy = imgReferrerPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not blocked. Do the load.
|
|
||||||
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
|
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
|
||||||
nsCOMPtr<nsIContent> content =
|
nsCOMPtr<nsIContent> content =
|
||||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||||
|
|
@ -932,7 +938,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||||
|
|
||||||
FireEvent(NS_LITERAL_STRING("error"));
|
FireEvent(NS_LITERAL_STRING("error"));
|
||||||
FireEvent(NS_LITERAL_STRING("loadend"));
|
FireEvent(NS_LITERAL_STRING("loadend"));
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -1212,46 +1217,42 @@ nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
|
||||||
mMostRecentRequestChange = now;
|
mMostRecentRequestChange = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have a usable current request, get rid of any half-baked
|
|
||||||
// request that might be sitting there and make this one current.
|
|
||||||
if (!HaveSize(mCurrentRequest))
|
|
||||||
return PrepareCurrentRequest(aImageLoadType);
|
|
||||||
|
|
||||||
// Otherwise, make it pending.
|
// We only want to cancel the existing current request if size is not
|
||||||
return PreparePendingRequest(aImageLoadType);
|
// available. bz says the web depends on this behavior.
|
||||||
|
// Otherwise, we get rid of any half-baked request that might be sitting there
|
||||||
|
// and make this one current.
|
||||||
|
// TODO: Bug 583491
|
||||||
|
// Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp
|
||||||
|
return HaveSize(mCurrentRequest) ?
|
||||||
|
PreparePendingRequest(aImageLoadType) :
|
||||||
|
PrepareCurrentRequest(aImageLoadType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
nsresult
|
||||||
nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
|
nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision)
|
||||||
{
|
{
|
||||||
|
// If this is not calling from LoadImage, for example, from ServiceWorker,
|
||||||
|
// bail out.
|
||||||
|
if (!mIsStartingImageLoad) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
|
MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
|
||||||
|
|
||||||
// We do some slightly illogical stuff here to maintain consistency with
|
// We should never have a pending request after we got blocked.
|
||||||
// old behavior that people probably depend on. Even in the case where the
|
MOZ_ASSERT(!mPendingRequest, "mPendingRequest should be null.");
|
||||||
// new image is blocked, the old one should really be canceled with the
|
|
||||||
// reason "image source changed". However, apparently there's some abuse
|
|
||||||
// over in nsImageFrame where the displaying of the "broken" icon for the
|
|
||||||
// next image depends on the cancel reason of the previous image. ugh.
|
|
||||||
// XXX(seth): So shouldn't we fix nsImageFrame?!
|
|
||||||
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED,
|
|
||||||
Some(OnNonvisible::DISCARD_IMAGES));
|
|
||||||
|
|
||||||
// For the blocked case, we only want to cancel the existing current request
|
|
||||||
// if size is not available. bz says the web depends on this behavior.
|
|
||||||
if (!HaveSize(mCurrentRequest)) {
|
|
||||||
|
|
||||||
|
if (HaveSize(mCurrentRequest)) {
|
||||||
|
// PreparePendingRequest set mPendingRequestFlags, now since we've decided
|
||||||
|
// to block it, we reset it back to 0.
|
||||||
|
mPendingRequestFlags = 0;
|
||||||
|
} else {
|
||||||
mImageBlockingStatus = aContentDecision;
|
mImageBlockingStatus = aContentDecision;
|
||||||
uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET;
|
|
||||||
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED,
|
|
||||||
Some(OnNonvisible::DISCARD_IMAGES));
|
|
||||||
|
|
||||||
// We still want to remember what URI we were and if it was an imageset,
|
|
||||||
// despite not having an actual request. These are both cleared as part of
|
|
||||||
// ClearCurrentRequest() before a new request is started.
|
|
||||||
mCurrentURI = aURI;
|
|
||||||
mCurrentRequestFlags = keepFlags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<imgRequestProxy>&
|
RefPtr<imgRequestProxy>&
|
||||||
|
|
@ -1262,7 +1263,7 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType)
|
||||||
mImageBlockingStatus = nsIContentPolicy::ACCEPT;
|
mImageBlockingStatus = nsIContentPolicy::ACCEPT;
|
||||||
|
|
||||||
// Get rid of anything that was there previously.
|
// Get rid of anything that was there previously.
|
||||||
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED,
|
ClearCurrentRequest(NS_BINDING_ABORTED,
|
||||||
Some(OnNonvisible::DISCARD_IMAGES));
|
Some(OnNonvisible::DISCARD_IMAGES));
|
||||||
|
|
||||||
if (mNewRequestsWillNeedAnimationReset) {
|
if (mNewRequestsWillNeedAnimationReset) {
|
||||||
|
|
@ -1281,7 +1282,7 @@ RefPtr<imgRequestProxy>&
|
||||||
nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
|
nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
|
||||||
{
|
{
|
||||||
// Get rid of anything that was there previously.
|
// Get rid of anything that was there previously.
|
||||||
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED,
|
ClearPendingRequest(NS_BINDING_ABORTED,
|
||||||
Some(OnNonvisible::DISCARD_IMAGES));
|
Some(OnNonvisible::DISCARD_IMAGES));
|
||||||
|
|
||||||
if (mNewRequestsWillNeedAnimationReset) {
|
if (mNewRequestsWillNeedAnimationReset) {
|
||||||
|
|
|
||||||
|
|
@ -302,18 +302,11 @@ protected:
|
||||||
*/
|
*/
|
||||||
RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType);
|
RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType);
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when we would normally call PrepareNextRequest(), but the request was
|
|
||||||
* blocked.
|
|
||||||
*/
|
|
||||||
void SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a COMPtr reference to the current/pending image requests, cleaning
|
* Returns a COMPtr reference to the current/pending image requests, cleaning
|
||||||
* up and canceling anything that was there before. Note that if you just want
|
* up and canceling anything that was there before. Note that if you just want
|
||||||
* to get rid of one of the requests, you should call
|
* to get rid of one of the requests, you should call
|
||||||
* Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate
|
* Clear*Request(NS_BINDING_ABORTED) instead.
|
||||||
* aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED).
|
|
||||||
*
|
*
|
||||||
* @param aImageLoadType The ImageLoadType for this request
|
* @param aImageLoadType The ImageLoadType for this request
|
||||||
*/
|
*/
|
||||||
|
|
@ -459,6 +452,14 @@ private:
|
||||||
// registered with the refresh driver.
|
// registered with the refresh driver.
|
||||||
bool mCurrentRequestRegistered;
|
bool mCurrentRequestRegistered;
|
||||||
bool mPendingRequestRegistered;
|
bool mPendingRequestRegistered;
|
||||||
|
|
||||||
|
// This member is used in SetBlockedRequest, if it's true, then this call is
|
||||||
|
// triggered from LoadImage.
|
||||||
|
// If this is false, it means this call is from other places like
|
||||||
|
// ServiceWorker, then we will ignore call to SetBlockedRequest for now.
|
||||||
|
//
|
||||||
|
// Also we use this variable to check if some evil code is reentering LoadImage.
|
||||||
|
bool mIsStartingImageLoad;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsImageLoadingContent_h__
|
#endif // nsImageLoadingContent_h__
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "nsIStreamListener.h"
|
#include "nsIStreamListener.h"
|
||||||
#include "nsCDefaultURIFixup.h"
|
#include "nsCDefaultURIFixup.h"
|
||||||
#include "nsIURIFixup.h"
|
#include "nsIURIFixup.h"
|
||||||
|
#include "nsIImageLoadingContent.h"
|
||||||
|
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
#include "mozilla/dom/TabChild.h"
|
#include "mozilla/dom/TabChild.h"
|
||||||
|
|
@ -801,6 +802,8 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel)
|
||||||
// within nsCorsListenerProxy
|
// within nsCorsListenerProxy
|
||||||
rv = DoCheckLoadURIChecks(uri, loadInfo);
|
rv = DoCheckLoadURIChecks(uri, loadInfo);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
// TODO: Bug 1371237
|
||||||
|
// consider calling SetBlockedRequest in nsContentSecurityManager::CheckChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -1684,6 +1684,7 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
|
||||||
|
|
||||||
rv = newChannel->AsyncOpen2(listener);
|
rv = newChannel->AsyncOpen2(listener);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
req->CancelAndForgetObserver(rv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -907,6 +907,9 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Bug 1353683
|
||||||
|
// consider calling SetBlockedRequest in nsCORSListenerProxy::UpdateChannel
|
||||||
|
//
|
||||||
// Check that the uri is ok to load
|
// Check that the uri is ok to load
|
||||||
rv = nsContentUtils::GetSecurityManager()->
|
rv = nsContentUtils::GetSecurityManager()->
|
||||||
CheckLoadURIWithPrincipal(mRequestingPrincipal, uri,
|
CheckLoadURIWithPrincipal(mRequestingPrincipal, uri,
|
||||||
|
|
|
||||||
|
|
@ -954,8 +954,9 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
|
||||||
const nsAString& aImageReferrerPolicy)
|
const nsAString& aImageReferrerPolicy)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
|
nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
|
||||||
|
bool isImgSet = false;
|
||||||
nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset,
|
nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset,
|
||||||
aSizes);
|
aSizes, &isImgSet);
|
||||||
if (uri && ShouldPreloadURI(uri)) {
|
if (uri && ShouldPreloadURI(uri)) {
|
||||||
// use document wide referrer policy
|
// use document wide referrer policy
|
||||||
mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy;
|
mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy;
|
||||||
|
|
@ -969,7 +970,7 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy);
|
mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy, isImgSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue