mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge m-c to m-i
MozReview-Commit-ID: B5Nf2oiDcqG
This commit is contained in:
commit
fe9d9c45d7
@ -87,11 +87,12 @@ function testToggleToolboxButtons() {
|
||||
let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
|
||||
let toggleableTools = toolbox.toolboxButtons;
|
||||
|
||||
// The noautohide button is only displayed in the browser toolbox
|
||||
// The noautohide button is only displayed in the browser toolbox, and the element
|
||||
// picker button is not toggleable.
|
||||
toggleableTools = toggleableTools.filter(
|
||||
tool => tool.id != "command-button-noautohide");
|
||||
tool => tool.id != "command-button-noautohide" && tool.id != "command-button-pick");
|
||||
toolboxButtonNodes = toolboxButtonNodes.filter(
|
||||
btn => btn.id != "command-button-noautohide");
|
||||
btn => btn.id != "command-button-noautohide" && btn.id != "command-button-pick");
|
||||
|
||||
is(checkNodes.length, toggleableTools.length,
|
||||
"All of the buttons are toggleable.");
|
||||
|
@ -71,10 +71,6 @@ loader.lazyGetter(this, "registerHarOverlay", () => {
|
||||
// addons that have manually inserted toolbarbuttons into DOM.
|
||||
// (By default, supported target is only local tab)
|
||||
const ToolboxButtons = exports.ToolboxButtons = [
|
||||
{ id: "command-button-pick",
|
||||
isTargetSupported: target =>
|
||||
target.getTrait("highlightable")
|
||||
},
|
||||
{ id: "command-button-frames",
|
||||
isTargetSupported: target => {
|
||||
return target.activeTab && target.activeTab.traits.frames;
|
||||
@ -958,7 +954,7 @@ Toolbox.prototype = {
|
||||
* Add buttons to the UI as specified in the devtools.toolbox.toolbarSpec pref
|
||||
*/
|
||||
_buildButtons: function () {
|
||||
if (!this.target.isAddon || this.target.isWebExtension) {
|
||||
if (this.target.getTrait("highlightable")) {
|
||||
this._buildPickerButton();
|
||||
}
|
||||
|
||||
@ -1003,7 +999,6 @@ Toolbox.prototype = {
|
||||
this._pickerButton.className =
|
||||
"command-button command-button-invertable devtools-button";
|
||||
this._pickerButton.setAttribute("title", L10N.getStr("pickButton.tooltip"));
|
||||
this._pickerButton.setAttribute("hidden", "true");
|
||||
|
||||
let container = this.doc.querySelector("#toolbox-picker-container");
|
||||
container.appendChild(this._pickerButton);
|
||||
|
@ -42,7 +42,6 @@ const TOOLBOX_L10N = new LocalizationHelper("devtools/locale/toolbox.properties"
|
||||
|
||||
// Sidebar dimensions
|
||||
const INITIAL_SIDEBAR_SIZE = 350;
|
||||
const MIN_SIDEBAR_SIZE = 50;
|
||||
|
||||
// If the toolbox width is smaller than given amount of pixels,
|
||||
// the sidebar automatically switches from 'landscape' to 'portrait' mode.
|
||||
@ -457,7 +456,6 @@ Inspector.prototype = {
|
||||
className: "inspector-sidebar-splitter",
|
||||
initialWidth: INITIAL_SIDEBAR_SIZE,
|
||||
initialHeight: INITIAL_SIDEBAR_SIZE,
|
||||
minSize: MIN_SIDEBAR_SIZE,
|
||||
splitterSize: 1,
|
||||
endPanelControl: true,
|
||||
startPanel: this.InspectorTabPanel({
|
||||
|
@ -14,7 +14,6 @@ devtools.jar:
|
||||
content/projecteditor/chrome/content/projecteditor-test.xul (projecteditor/chrome/content/projecteditor-test.xul)
|
||||
content/projecteditor/chrome/content/projecteditor-loader.js (projecteditor/chrome/content/projecteditor-loader.js)
|
||||
content/netmonitor/netmonitor.xul (netmonitor/netmonitor.xul)
|
||||
content/netmonitor/netmonitor.css (netmonitor/netmonitor.css)
|
||||
content/netmonitor/netmonitor-controller.js (netmonitor/netmonitor-controller.js)
|
||||
content/netmonitor/netmonitor-view.js (netmonitor/netmonitor-view.js)
|
||||
content/webconsole/webconsole.xul (webconsole/webconsole.xul)
|
||||
|
129
devtools/client/netmonitor/filter-predicates.js
Normal file
129
devtools/client/netmonitor/filter-predicates.js
Normal file
@ -0,0 +1,129 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Predicates used when filtering items.
|
||||
*
|
||||
* @param object item
|
||||
* The filtered item.
|
||||
* @return boolean
|
||||
* True if the item should be visible, false otherwise.
|
||||
*/
|
||||
function all() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isHtml({ mimeType }) {
|
||||
return mimeType && mimeType.includes("/html");
|
||||
}
|
||||
|
||||
function isCss({ mimeType }) {
|
||||
return mimeType && mimeType.includes("/css");
|
||||
}
|
||||
|
||||
function isJs({ mimeType }) {
|
||||
return mimeType && (
|
||||
mimeType.includes("/ecmascript") ||
|
||||
mimeType.includes("/javascript") ||
|
||||
mimeType.includes("/x-javascript"));
|
||||
}
|
||||
|
||||
function isXHR(item) {
|
||||
// Show the request it is XHR, except if the request is a WS upgrade
|
||||
return item.isXHR && !isWS(item);
|
||||
}
|
||||
|
||||
function isFont({ url, mimeType }) {
|
||||
// Fonts are a mess.
|
||||
return (mimeType && (
|
||||
mimeType.includes("font/") ||
|
||||
mimeType.includes("/font"))) ||
|
||||
url.includes(".eot") ||
|
||||
url.includes(".ttf") ||
|
||||
url.includes(".otf") ||
|
||||
url.includes(".woff");
|
||||
}
|
||||
|
||||
function isImage({ mimeType }) {
|
||||
return mimeType && mimeType.includes("image/");
|
||||
}
|
||||
|
||||
function isMedia({ mimeType }) {
|
||||
// Not including images.
|
||||
return mimeType && (
|
||||
mimeType.includes("audio/") ||
|
||||
mimeType.includes("video/") ||
|
||||
mimeType.includes("model/"));
|
||||
}
|
||||
|
||||
function isFlash({ url, mimeType }) {
|
||||
// Flash is a mess.
|
||||
return (mimeType && (
|
||||
mimeType.includes("/x-flv") ||
|
||||
mimeType.includes("/x-shockwave-flash"))) ||
|
||||
url.includes(".swf") ||
|
||||
url.includes(".flv");
|
||||
}
|
||||
|
||||
function isWS({ requestHeaders, responseHeaders }) {
|
||||
// Detect a websocket upgrade if request has an Upgrade header with value 'websocket'
|
||||
if (!requestHeaders || !Array.isArray(requestHeaders.headers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the 'upgrade' header.
|
||||
let upgradeHeader = requestHeaders.headers.find(header => {
|
||||
return (header.name == "Upgrade");
|
||||
});
|
||||
|
||||
// If no header found on request, check response - mainly to get
|
||||
// something we can unit test, as it is impossible to set
|
||||
// the Upgrade header on outgoing XHR as per the spec.
|
||||
if (!upgradeHeader && responseHeaders &&
|
||||
Array.isArray(responseHeaders.headers)) {
|
||||
upgradeHeader = responseHeaders.headers.find(header => {
|
||||
return (header.name == "Upgrade");
|
||||
});
|
||||
}
|
||||
|
||||
// Return false if there is no such header or if its value isn't 'websocket'.
|
||||
if (!upgradeHeader || upgradeHeader.value != "websocket") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isOther(item) {
|
||||
let tests = [isHtml, isCss, isJs, isXHR, isFont, isImage, isMedia, isFlash, isWS];
|
||||
return tests.every(is => !is(item));
|
||||
}
|
||||
|
||||
function isFreetextMatch({ url }, text) {
|
||||
let lowerCaseUrl = url.toLowerCase();
|
||||
let lowerCaseText = text.toLowerCase();
|
||||
let textLength = text.length;
|
||||
// Support negative filtering
|
||||
if (text.startsWith("-") && textLength > 1) {
|
||||
lowerCaseText = lowerCaseText.substring(1, textLength);
|
||||
return !lowerCaseUrl.includes(lowerCaseText);
|
||||
}
|
||||
|
||||
// no text is a positive match
|
||||
return !text || lowerCaseUrl.includes(lowerCaseText);
|
||||
}
|
||||
|
||||
exports.Filters = {
|
||||
all: all,
|
||||
html: isHtml,
|
||||
css: isCss,
|
||||
js: isJs,
|
||||
xhr: isXHR,
|
||||
fonts: isFont,
|
||||
images: isImage,
|
||||
media: isMedia,
|
||||
flash: isFlash,
|
||||
ws: isWS,
|
||||
other: isOther,
|
||||
};
|
||||
|
||||
exports.isFreetextMatch = isFreetextMatch;
|
@ -7,7 +7,6 @@ const { Ci } = require("chrome");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
const { resolve } = require("promise");
|
||||
const Services = require("Services");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
loader.lazyRequireGetter(this, "HarCollector", "devtools/client/netmonitor/har/har-collector", true);
|
||||
loader.lazyRequireGetter(this, "HarExporter", "devtools/client/netmonitor/har/har-exporter", true);
|
||||
@ -200,51 +199,6 @@ var HarAutomation = Class({
|
||||
getString: function (stringGrip) {
|
||||
return this.webConsoleClient.getString(stringGrip);
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
*
|
||||
* @param object headers
|
||||
* The "requestHeaders".
|
||||
* @param object uploadHeaders
|
||||
* The "requestHeadersFromUploadStream".
|
||||
* @param object postData
|
||||
* The "requestPostData".
|
||||
* @return array
|
||||
* A promise that is resolved with the extracted form data.
|
||||
*/
|
||||
_getFormDataSections: Task.async(function* (headers, uploadHeaders,
|
||||
postData) {
|
||||
let formDataSections = [];
|
||||
|
||||
let { headers: requestHeaders } = headers;
|
||||
let { headers: payloadHeaders } = uploadHeaders;
|
||||
let allHeaders = [...payloadHeaders, ...requestHeaders];
|
||||
|
||||
let contentTypeHeader = allHeaders.find(e => {
|
||||
return e.name.toLowerCase() == "content-type";
|
||||
});
|
||||
|
||||
let contentTypeLongString = contentTypeHeader ?
|
||||
contentTypeHeader.value : "";
|
||||
let contentType = yield this.getString(contentTypeLongString);
|
||||
|
||||
if (contentType.includes("x-www-form-urlencoded")) {
|
||||
let postDataLongString = postData.postData.text;
|
||||
let data = yield this.getString(postDataLongString);
|
||||
|
||||
for (let section of data.split(/\r\n|\r|\n/)) {
|
||||
// Before displaying it, make sure this section of the POST data
|
||||
// isn't a line containing upload stream headers.
|
||||
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
|
||||
formDataSections.push(section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formDataSections;
|
||||
}),
|
||||
});
|
||||
|
||||
// Helpers
|
||||
|
@ -8,6 +8,7 @@ const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const Services = require("Services");
|
||||
const appInfo = Services.appinfo;
|
||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||
const { getFormDataSections } = require("devtools/client/netmonitor/request-utils");
|
||||
|
||||
loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
|
||||
|
||||
@ -272,16 +273,19 @@ HarBuilder.prototype = {
|
||||
postData.mimeType = "application/x-www-form-urlencoded";
|
||||
|
||||
// Extract form parameters and produce nice HAR array.
|
||||
this._options.view._getFormDataSections(file.requestHeaders,
|
||||
getFormDataSections(
|
||||
file.requestHeaders,
|
||||
file.requestHeadersFromUploadStream,
|
||||
file.requestPostData).then(formDataSections => {
|
||||
formDataSections.forEach(section => {
|
||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
||||
if (paramsArray) {
|
||||
postData.params = [...postData.params, ...paramsArray];
|
||||
}
|
||||
});
|
||||
file.requestPostData,
|
||||
this._options.getString
|
||||
).then(formDataSections => {
|
||||
formDataSections.forEach(section => {
|
||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
||||
if (paramsArray) {
|
||||
postData.params = [...postData.params, ...paramsArray];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -8,7 +8,9 @@ DIRS += [
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
'panel.js'
|
||||
'filter-predicates.js',
|
||||
'panel.js',
|
||||
'request-utils.js',
|
||||
)
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
@ -32,7 +32,8 @@ const {ViewHelpers, Heritage, WidgetMethods, setNamedTimeout} =
|
||||
require("devtools/client/shared/widgets/view-helpers");
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {Curl, CurlUtils} = require("devtools/client/shared/curl");
|
||||
|
||||
const {Filters, isFreetextMatch} = require("devtools/client/netmonitor/filter-predicates");
|
||||
const {getFormDataSections} = require("devtools/client/netmonitor/request-utils");
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
*/
|
||||
@ -759,65 +760,19 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
clipboardHelper.copyString(string);
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
*
|
||||
* @param object headers
|
||||
* The "requestHeaders".
|
||||
* @param object uploadHeaders
|
||||
* The "requestHeadersFromUploadStream".
|
||||
* @param object postData
|
||||
* The "requestPostData".
|
||||
* @return array
|
||||
* A promise that is resolved with the extracted form data.
|
||||
*/
|
||||
_getFormDataSections: Task.async(function* (headers, uploadHeaders,
|
||||
postData) {
|
||||
let formDataSections = [];
|
||||
|
||||
let { headers: requestHeaders } = headers;
|
||||
let { headers: payloadHeaders } = uploadHeaders;
|
||||
let allHeaders = [...payloadHeaders, ...requestHeaders];
|
||||
|
||||
let contentTypeHeader = allHeaders.find(e => {
|
||||
return e.name.toLowerCase() == "content-type";
|
||||
});
|
||||
|
||||
let contentTypeLongString = contentTypeHeader ?
|
||||
contentTypeHeader.value : "";
|
||||
|
||||
let contentType = yield gNetwork.getString(contentTypeLongString);
|
||||
|
||||
if (contentType.includes("x-www-form-urlencoded")) {
|
||||
let postDataLongString = postData.postData.text;
|
||||
let text = yield gNetwork.getString(postDataLongString);
|
||||
|
||||
for (let section of text.split(/\r\n|\r|\n/)) {
|
||||
// Before displaying it, make sure this section of the POST data
|
||||
// isn't a line containing upload stream headers.
|
||||
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
|
||||
formDataSections.push(section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formDataSections;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Copy the request form data parameters (or raw payload) from
|
||||
* the currently selected item.
|
||||
*/
|
||||
copyPostData: Task.async(function* () {
|
||||
let selected = this.selectedItem.attachment;
|
||||
let view = this;
|
||||
|
||||
// Try to extract any form data parameters.
|
||||
let formDataSections = yield view._getFormDataSections(
|
||||
let formDataSections = yield getFormDataSections(
|
||||
selected.requestHeaders,
|
||||
selected.requestHeadersFromUploadStream,
|
||||
selected.requestPostData);
|
||||
selected.requestPostData,
|
||||
gNetwork.getString.bind(gNetwork));
|
||||
|
||||
let params = [];
|
||||
formDataSections.forEach(section => {
|
||||
@ -1130,7 +1085,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
*/
|
||||
_enableFilter: function (type) {
|
||||
// Make sure this is a valid filter type.
|
||||
if (Object.keys(this._allFilterPredicates).indexOf(type) == -1) {
|
||||
if (!Object.keys(Filters).includes(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1152,35 +1107,12 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
* the active filters.
|
||||
*/
|
||||
get _filterPredicate() {
|
||||
let filterPredicates = this._allFilterPredicates;
|
||||
let currentFreetextFilter = this._currentFreetextFilter;
|
||||
|
||||
return requestItem => {
|
||||
return this._activeFilters.some(filterName => {
|
||||
return filterPredicates[filterName].call(this, requestItem) &&
|
||||
filterPredicates.freetext.call(this, requestItem,
|
||||
currentFreetextFilter);
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an object with all the filter predicates as [key: function] pairs.
|
||||
*/
|
||||
get _allFilterPredicates() {
|
||||
return {
|
||||
all: () => true,
|
||||
html: this.isHtml,
|
||||
css: this.isCss,
|
||||
js: this.isJs,
|
||||
xhr: this.isXHR,
|
||||
fonts: this.isFont,
|
||||
images: this.isImage,
|
||||
media: this.isMedia,
|
||||
flash: this.isFlash,
|
||||
ws: this.isWS,
|
||||
other: this.isOther,
|
||||
freetext: this.isFreetextMatch
|
||||
const { attachment } = requestItem;
|
||||
return this._activeFilters.some(filterName => Filters[filterName](attachment)) &&
|
||||
isFreetextMatch(attachment, currentFreetextFilter);
|
||||
};
|
||||
},
|
||||
|
||||
@ -1303,125 +1235,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
this.refreshSummary();
|
||||
},
|
||||
|
||||
/**
|
||||
* Predicates used when filtering items.
|
||||
*
|
||||
* @param object item
|
||||
* The filtered item.
|
||||
* @return boolean
|
||||
* True if the item should be visible, false otherwise.
|
||||
*/
|
||||
isHtml: function ({ attachment: { mimeType } }) {
|
||||
return mimeType && mimeType.includes("/html");
|
||||
},
|
||||
|
||||
isCss: function ({ attachment: { mimeType } }) {
|
||||
return mimeType && mimeType.includes("/css");
|
||||
},
|
||||
|
||||
isJs: function ({ attachment: { mimeType } }) {
|
||||
return mimeType && (
|
||||
mimeType.includes("/ecmascript") ||
|
||||
mimeType.includes("/javascript") ||
|
||||
mimeType.includes("/x-javascript"));
|
||||
},
|
||||
|
||||
isXHR: function (item) {
|
||||
// Show the request it is XHR, except
|
||||
// if the request is a WS upgrade
|
||||
return item.attachment.isXHR && !this.isWS(item);
|
||||
},
|
||||
|
||||
isFont: function ({ attachment: { url, mimeType } }) {
|
||||
// Fonts are a mess.
|
||||
return (mimeType && (
|
||||
mimeType.includes("font/") ||
|
||||
mimeType.includes("/font"))) ||
|
||||
url.includes(".eot") ||
|
||||
url.includes(".ttf") ||
|
||||
url.includes(".otf") ||
|
||||
url.includes(".woff");
|
||||
},
|
||||
|
||||
isImage: function ({ attachment: { mimeType } }) {
|
||||
return mimeType && mimeType.includes("image/");
|
||||
},
|
||||
|
||||
isMedia: function ({ attachment: { mimeType } }) {
|
||||
// Not including images.
|
||||
return mimeType && (
|
||||
mimeType.includes("audio/") ||
|
||||
mimeType.includes("video/") ||
|
||||
mimeType.includes("model/"));
|
||||
},
|
||||
|
||||
isFlash: function ({ attachment: { url, mimeType } }) {
|
||||
// Flash is a mess.
|
||||
return (mimeType && (
|
||||
mimeType.includes("/x-flv") ||
|
||||
mimeType.includes("/x-shockwave-flash"))) ||
|
||||
url.includes(".swf") ||
|
||||
url.includes(".flv");
|
||||
},
|
||||
|
||||
isWS: function ({ attachment: { requestHeaders, responseHeaders } }) {
|
||||
// Detect a websocket upgrade if request has an Upgrade header
|
||||
// with value 'websocket'
|
||||
|
||||
if (!requestHeaders || !Array.isArray(requestHeaders.headers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the 'upgrade' header.
|
||||
let upgradeHeader = requestHeaders.headers.find(header => {
|
||||
return (header.name == "Upgrade");
|
||||
});
|
||||
|
||||
// If no header found on request, check response - mainly to get
|
||||
// something we can unit test, as it is impossible to set
|
||||
// the Upgrade header on outgoing XHR as per the spec.
|
||||
if (!upgradeHeader && responseHeaders &&
|
||||
Array.isArray(responseHeaders.headers)) {
|
||||
upgradeHeader = responseHeaders.headers.find(header => {
|
||||
return (header.name == "Upgrade");
|
||||
});
|
||||
}
|
||||
|
||||
// Return false if there is no such header or if its value isn't
|
||||
// 'websocket'.
|
||||
if (!upgradeHeader || upgradeHeader.value != "websocket") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
isOther: function (e) {
|
||||
return !this.isHtml(e) &&
|
||||
!this.isCss(e) &&
|
||||
!this.isJs(e) &&
|
||||
!this.isXHR(e) &&
|
||||
!this.isFont(e) &&
|
||||
!this.isImage(e) &&
|
||||
!this.isMedia(e) &&
|
||||
!this.isFlash(e) &&
|
||||
!this.isWS(e);
|
||||
},
|
||||
|
||||
isFreetextMatch: function ({ attachment: { url } }, text) {
|
||||
let lowerCaseUrl = url.toLowerCase();
|
||||
let lowerCaseText = text.toLowerCase();
|
||||
let textLength = text.length;
|
||||
// Support negative filtering
|
||||
if (text.startsWith("-") && textLength > 1) {
|
||||
lowerCaseText = lowerCaseText.substring(1, textLength);
|
||||
return !lowerCaseUrl.includes(lowerCaseText);
|
||||
}
|
||||
|
||||
// no text is a positive match
|
||||
return !text || lowerCaseUrl.includes(lowerCaseText);
|
||||
},
|
||||
|
||||
/**
|
||||
* Predicates used when sorting items.
|
||||
*
|
||||
@ -2947,7 +2760,7 @@ NetworkDetailsView.prototype = {
|
||||
$("#raw-headers").hidden = true;
|
||||
$("#response-content-image-box").hidden = true;
|
||||
|
||||
let isHtml = RequestsMenuView.prototype.isHtml({ attachment: data });
|
||||
let isHtml = Filters.html(data);
|
||||
|
||||
// Show the "Preview" tabpanel only for plain HTML responses.
|
||||
this.sidebar.toggleTab(isHtml, "preview-tab");
|
||||
@ -3293,8 +3106,11 @@ NetworkDetailsView.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let formDataSections = yield RequestsMenuView.prototype
|
||||
._getFormDataSections(headers, uploadHeaders, postData);
|
||||
let formDataSections = yield getFormDataSections(
|
||||
headers,
|
||||
uploadHeaders,
|
||||
postData,
|
||||
gNetwork.getString.bind(gNetwork));
|
||||
|
||||
this._params.onlyEnumVisible = false;
|
||||
|
||||
@ -3838,8 +3654,7 @@ PerformanceStatisticsView.prototype = {
|
||||
*/
|
||||
_sanitizeChartDataSource: function (items, emptyCache) {
|
||||
let data = [
|
||||
"html", "css", "js", "xhr", "fonts", "images", "media", "flash", "ws",
|
||||
"other"
|
||||
"html", "css", "js", "xhr", "fonts", "images", "media", "flash", "ws", "other"
|
||||
].map(e => ({
|
||||
cached: 0,
|
||||
count: 0,
|
||||
@ -3852,31 +3667,31 @@ PerformanceStatisticsView.prototype = {
|
||||
let details = requestItem.attachment;
|
||||
let type;
|
||||
|
||||
if (RequestsMenuView.prototype.isHtml(requestItem)) {
|
||||
if (Filters.html(details)) {
|
||||
// "html"
|
||||
type = 0;
|
||||
} else if (RequestsMenuView.prototype.isCss(requestItem)) {
|
||||
} else if (Filters.css(details)) {
|
||||
// "css"
|
||||
type = 1;
|
||||
} else if (RequestsMenuView.prototype.isJs(requestItem)) {
|
||||
} else if (Filters.js(details)) {
|
||||
// "js"
|
||||
type = 2;
|
||||
} else if (RequestsMenuView.prototype.isFont(requestItem)) {
|
||||
} else if (Filters.fonts(details)) {
|
||||
// "fonts"
|
||||
type = 4;
|
||||
} else if (RequestsMenuView.prototype.isImage(requestItem)) {
|
||||
} else if (Filters.images(details)) {
|
||||
// "images"
|
||||
type = 5;
|
||||
} else if (RequestsMenuView.prototype.isMedia(requestItem)) {
|
||||
} else if (Filters.media(details)) {
|
||||
// "media"
|
||||
type = 6;
|
||||
} else if (RequestsMenuView.prototype.isFlash(requestItem)) {
|
||||
} else if (Filters.flash(details)) {
|
||||
// "flash"
|
||||
type = 7;
|
||||
} else if (RequestsMenuView.prototype.isWS(requestItem)) {
|
||||
} else if (Filters.ws(details)) {
|
||||
// "ws"
|
||||
type = 8;
|
||||
} else if (RequestsMenuView.prototype.isXHR(requestItem)) {
|
||||
} else if (Filters.xhr(details)) {
|
||||
// Verify XHR last, to categorize other mime types in their own blobs.
|
||||
// "xhr"
|
||||
type = 3;
|
||||
|
@ -1,47 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#toolbar-labels {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsed details pane needs to be truly hidden to prevent both accessibility
|
||||
* tools and keyboard from accessing its contents.
|
||||
*/
|
||||
#details-pane.pane-collapsed {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#details-pane-toggle[disabled] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#custom-pane {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#response-content-image-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#network-statistics-charts {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cropped-textbox .textbox-input {
|
||||
/* workaround for textbox not supporting the @crop attribute */
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#toolbar-spacer,
|
||||
#details-pane-toggle,
|
||||
.requests-menu-waterfall,
|
||||
#requests-menu-network-summary-button > .toolbarbutton-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/content/netmonitor/netmonitor.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/netmonitor.css" type="text/css"?>
|
||||
<!DOCTYPE window [
|
||||
|
50
devtools/client/netmonitor/request-utils.js
Normal file
50
devtools/client/netmonitor/request-utils.js
Normal file
@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
*
|
||||
* @param object headers
|
||||
* The "requestHeaders".
|
||||
* @param object uploadHeaders
|
||||
* The "requestHeadersFromUploadStream".
|
||||
* @param object postData
|
||||
* The "requestPostData".
|
||||
* @param object getString
|
||||
Callback to retrieve a string from a LongStringGrip.
|
||||
* @return array
|
||||
* A promise that is resolved with the extracted form data.
|
||||
*/
|
||||
exports.getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
|
||||
getString) {
|
||||
let formDataSections = [];
|
||||
|
||||
let { headers: requestHeaders } = headers;
|
||||
let { headers: payloadHeaders } = uploadHeaders;
|
||||
let allHeaders = [...payloadHeaders, ...requestHeaders];
|
||||
|
||||
let contentTypeHeader = allHeaders.find(e => {
|
||||
return e.name.toLowerCase() == "content-type";
|
||||
});
|
||||
|
||||
let contentTypeLongString = contentTypeHeader ? contentTypeHeader.value : "";
|
||||
|
||||
let contentType = yield getString(contentTypeLongString);
|
||||
|
||||
if (contentType.includes("x-www-form-urlencoded")) {
|
||||
let postDataLongString = postData.postData.text;
|
||||
let text = yield getString(postDataLongString);
|
||||
|
||||
for (let section of text.split(/\r\n|\r|\n/)) {
|
||||
// Before displaying it, make sure this section of the POST data
|
||||
// isn't a line containing upload stream headers.
|
||||
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
|
||||
formDataSections.push(section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formDataSections;
|
||||
});
|
@ -37,7 +37,6 @@ pref("devtools.toolbox.splitconsoleEnabled", false);
|
||||
pref("devtools.toolbox.splitconsoleHeight", 100);
|
||||
|
||||
// Toolbox Button preferences
|
||||
pref("devtools.command-button-pick.enabled", true);
|
||||
pref("devtools.command-button-frames.enabled", true);
|
||||
pref("devtools.command-button-splitconsole.enabled", true);
|
||||
pref("devtools.command-button-paintflashing.enabled", false);
|
||||
|
@ -59,7 +59,7 @@ define(function (require, exports, module) {
|
||||
);
|
||||
});
|
||||
|
||||
let ownProperties = object.preview ? object.preview.ownProperties : [];
|
||||
let ownProperties = object.preview ? object.preview.ownProperties : {};
|
||||
let indexes = this.getPropIndexes(ownProperties, max, isInterestingProp);
|
||||
if (indexes.length < max && indexes.length < object.ownPropertyLength) {
|
||||
// There are not enough props yet. Then add uninteresting props to display them.
|
||||
@ -70,24 +70,17 @@ define(function (require, exports, module) {
|
||||
);
|
||||
}
|
||||
|
||||
let props = this.getProps(ownProperties, indexes);
|
||||
if (props.length < object.ownPropertyLength) {
|
||||
const truncate = Object.keys(ownProperties).length > max;
|
||||
let props = this.getProps(ownProperties, indexes, truncate);
|
||||
if (truncate) {
|
||||
// There are some undisplayed props. Then display "more...".
|
||||
let objectLink = this.props.objectLink || span;
|
||||
|
||||
props.push(Caption({
|
||||
object: objectLink({
|
||||
object: object
|
||||
}, ((object ? object.ownPropertyLength : 0) - max) + " more…")
|
||||
}, `${object.ownPropertyLength - max} more…`)
|
||||
}));
|
||||
} else if (props.length > 0) {
|
||||
// Remove the last comma.
|
||||
// NOTE: do not change comp._store.props directly to update a property,
|
||||
// it should be re-rendered or cloned with changed props
|
||||
let last = props.length - 1;
|
||||
props[last] = React.cloneElement(props[last], {
|
||||
delim: ""
|
||||
});
|
||||
}
|
||||
|
||||
return props;
|
||||
@ -98,9 +91,10 @@ define(function (require, exports, module) {
|
||||
*
|
||||
* @param {Object} ownProperties Props object.
|
||||
* @param {Array} indexes Indexes of props.
|
||||
* @param {Boolean} truncate true if the grip will be truncated.
|
||||
* @return {Array} Props.
|
||||
*/
|
||||
getProps: function (ownProperties, indexes) {
|
||||
getProps: function (ownProperties, indexes, truncate) {
|
||||
let props = [];
|
||||
|
||||
// Make indexes ordered by ascending.
|
||||
@ -117,7 +111,7 @@ define(function (require, exports, module) {
|
||||
name: name,
|
||||
object: value,
|
||||
equal: ": ",
|
||||
delim: ", ",
|
||||
delim: i !== indexes.length - 1 || truncate ? ", " : "",
|
||||
defaultRep: Grip
|
||||
})));
|
||||
});
|
||||
@ -169,7 +163,7 @@ define(function (require, exports, module) {
|
||||
(this.props.mode == "long") ? 100 : 3);
|
||||
|
||||
let objectLink = this.props.objectLink || span;
|
||||
if (this.props.mode == "tiny" || !props.length) {
|
||||
if (this.props.mode == "tiny") {
|
||||
return (
|
||||
span({className: "objectBox objectBox-object"},
|
||||
this.getTitle(object),
|
||||
|
@ -27,6 +27,7 @@ window.onload = Task.async(function* () {
|
||||
yield testMaxProps();
|
||||
yield testMoreThanMaxProps();
|
||||
yield testUninterestingProps();
|
||||
yield testNonEnumerableProps();
|
||||
|
||||
// Test that properties are rendered as expected by PropRep
|
||||
yield testNestedObject();
|
||||
@ -50,7 +51,7 @@ window.onload = Task.async(function* () {
|
||||
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
|
||||
|
||||
// Test rendering
|
||||
const defaultOutput = `Object`;
|
||||
const defaultOutput = `Object { }`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
@ -59,7 +60,7 @@ window.onload = Task.async(function* () {
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: defaultOutput,
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
@ -146,6 +147,40 @@ window.onload = Task.async(function* () {
|
||||
const expectedOutput = `Object { a: undefined, b: undefined, c: "c", 1 more… }`;
|
||||
}
|
||||
|
||||
function testNonEnumerableProps() {
|
||||
// Test object: `Object.defineProperty({}, "foo", {enumerable : false});`
|
||||
const testName = "testNonEnumerableProps";
|
||||
|
||||
// Test that correct rep is chosen
|
||||
const gripStub = getGripStub("testNonEnumerableProps");
|
||||
const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
|
||||
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
|
||||
|
||||
// Test rendering
|
||||
const defaultOutput = `Object { }`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
|
||||
}
|
||||
|
||||
function testNestedObject() {
|
||||
// Test object: `{objProp: {id: 1}, strProp: "test string"}`
|
||||
const testName = "testNestedObject";
|
||||
@ -362,7 +397,22 @@ window.onload = Task.async(function* () {
|
||||
"safeGetterValues": {}
|
||||
}
|
||||
};
|
||||
|
||||
case "testNonEnumerableProps":
|
||||
return {
|
||||
"type": "object",
|
||||
"actor": "server1.conn1.child1/obj30",
|
||||
"class": "Object",
|
||||
"extensible": true,
|
||||
"frozen": false,
|
||||
"sealed": false,
|
||||
"ownPropertyLength": 1,
|
||||
"preview": {
|
||||
"kind": "Object",
|
||||
"ownProperties": {},
|
||||
"ownPropertiesLength": 1,
|
||||
"safeGetterValues": {}
|
||||
}
|
||||
};
|
||||
case "testNestedObject":
|
||||
return {
|
||||
"type": "object",
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#font-showall {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#font-showall:hover {
|
||||
|
@ -31,11 +31,14 @@ window {
|
||||
|
||||
/* The main panel layout. This area consists of a toolbar, markup view
|
||||
and breadcrumbs bar. */
|
||||
.devtools-main-content {
|
||||
#inspector-main-content {
|
||||
/* Subtract 1 pixel from the panel height. It's puzzling why this
|
||||
is needed, but if not presented the entire Inspector panel
|
||||
content jumps 1 pixel up when the Toolbox is opened. */
|
||||
height: calc(100% - 1px);
|
||||
/* This min-width avoids a visual glitch when moving the splitter quickly to the left.
|
||||
See bug 1307408 comment #12. */
|
||||
min-width: 125px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
@ -49,10 +52,19 @@ window {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* Minimum width for the Inspector main (uncontrolled) area. */
|
||||
#inspector-splitter-box .uncontrolled {
|
||||
/* Minimum dimensions for the Inspector splitter areas. */
|
||||
#inspector-splitter-box .uncontrolled,
|
||||
#inspector-splitter-box .controlled {
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Set a minimum width of 200px for tab content to avoid breaking the layout when resizing
|
||||
the sidebar tab to small width. If a specific panel supports smaller width, this should
|
||||
be overridden on a panel-by-panel basis */
|
||||
.inspector-tabpanel {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
#inspector-splitter-box .controlled.pane-collapsed {
|
||||
@ -171,12 +183,8 @@ window {
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
/* Set the minimum width for the side bar so, all tabs are
|
||||
properly visible. The value can be decreased when bug 1281789
|
||||
is fixed and the all-tabs-menu is available again. */
|
||||
#inspector-sidebar-container {
|
||||
overflow: hidden;
|
||||
min-width: 50px;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -3,6 +3,49 @@
|
||||
* 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/. */
|
||||
|
||||
#toolbar-labels {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsed details pane needs to be truly hidden to prevent both accessibility
|
||||
* tools and keyboard from accessing its contents.
|
||||
*/
|
||||
#details-pane.pane-collapsed {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#details-pane-toggle[disabled] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#custom-pane {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#response-content-image-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#network-statistics-charts {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cropped-textbox .textbox-input {
|
||||
/* workaround for textbox not supporting the @crop attribute */
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#toolbar-spacer,
|
||||
#details-pane-toggle,
|
||||
.requests-menu-waterfall,
|
||||
#requests-menu-network-summary-button > .toolbarbutton-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
--table-splitter-color: rgba(255,255,255,0.15);
|
||||
--table-zebra-background: rgba(255,255,255,0.05);
|
||||
|
@ -30,6 +30,9 @@
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* Override the min-width from .inspector-tabpanel, as the rule panel can support small
|
||||
widths */
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
/* Rule View Toolbar */
|
||||
|
@ -29,6 +29,10 @@ def resolve_path(start, relativePath):
|
||||
"""Helper to resolve a path from a start, and a relative path"""
|
||||
return os.path.normpath(os.path.join(start, relativePath))
|
||||
|
||||
def stringify(obj):
|
||||
"""Helper to stringify to JSON"""
|
||||
return json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '))
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
@ -42,9 +46,9 @@ class MachCommands(MachCommandBase):
|
||||
db = self.get_properties_db_from_xpcshell()
|
||||
|
||||
self.output_template({
|
||||
'preferences': json.dumps(preferences),
|
||||
'cssProperties': json.dumps(db['cssProperties']),
|
||||
'pseudoElements': json.dumps(db['pseudoElements'])})
|
||||
'preferences': stringify(preferences),
|
||||
'cssProperties': stringify(db['cssProperties']),
|
||||
'pseudoElements': stringify(db['pseudoElements'])})
|
||||
|
||||
def get_preferences(self):
|
||||
"""Get all of the preferences associated with enabling and disabling a property."""
|
||||
|
File diff suppressed because one or more lines are too long
@ -9,8 +9,6 @@
|
||||
* to generate these files can be found at devtools/shared/css/generate-properties-db.js.
|
||||
*/
|
||||
|
||||
/* eslint-disable max-len */
|
||||
|
||||
/**
|
||||
* A list of CSS Properties and their various characteristics.
|
||||
*/
|
||||
@ -26,5 +24,3 @@ exports.PSEUDO_ELEMENTS = ${pseudoElements};
|
||||
* exposed for testing purposes.
|
||||
*/
|
||||
exports.PREFERENCES = ${preferences};
|
||||
|
||||
/* eslint-enable max-len */
|
||||
|
@ -268,28 +268,22 @@ function normalizeCssData(db) {
|
||||
// Fill in any missing DB information from the static database.
|
||||
db = Object.assign({}, CSS_PROPERTIES_DB, db);
|
||||
|
||||
// Add "supports" information to the css properties if it's missing.
|
||||
if (!db.properties.color.supports) {
|
||||
for (let name in db.properties) {
|
||||
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
|
||||
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
|
||||
}
|
||||
for (let name in db.properties) {
|
||||
// Skip the current property if we can't find it in CSS_PROPERTIES_DB.
|
||||
if (typeof CSS_PROPERTIES_DB.properties[name] !== "object") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add "values" information to the css properties if it's missing.
|
||||
if (!db.properties.color.values) {
|
||||
for (let name in db.properties) {
|
||||
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
|
||||
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
|
||||
}
|
||||
// Add "supports" information to the css properties if it's missing.
|
||||
if (!db.properties.color.supports) {
|
||||
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
|
||||
}
|
||||
}
|
||||
|
||||
// Add "subproperties" information to the css properties if it's
|
||||
// missing.
|
||||
if (!db.properties.background.subproperties) {
|
||||
for (let name in db.properties) {
|
||||
// Add "values" information to the css properties if it's missing.
|
||||
if (!db.properties.color.values) {
|
||||
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
|
||||
}
|
||||
// Add "subproperties" information to the css properties if it's missing.
|
||||
if (!db.properties.background.subproperties) {
|
||||
db.properties[name].subproperties =
|
||||
CSS_PROPERTIES_DB.properties[name].subproperties;
|
||||
}
|
||||
@ -311,7 +305,8 @@ function reattachCssColorValues(db) {
|
||||
|
||||
for (let name in db.properties) {
|
||||
const property = db.properties[name];
|
||||
if (property.values[0] === "COLOR") {
|
||||
// "values" can be undefined if {name} was not found in CSS_PROPERTIES_DB.
|
||||
if (property.values && property.values[0] === "COLOR") {
|
||||
property.values.shift();
|
||||
property.values = property.values.concat(colors).sort();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
/**
|
||||
* Test that the devtool's client-side CSS properties database is in sync with the values
|
||||
* on the platform. If they are not, then `mach generate-css-db` needs to be run to
|
||||
* on the platform. If they are not, then `mach devtools-css-db` needs to be run to
|
||||
* make everything up to date. Nightly, aurora, beta, and release may have different
|
||||
* preferences for what CSS values are enabled. The static CSS properties database can
|
||||
* be slightly different from the target platform as long as there is a preference that
|
||||
@ -23,7 +23,7 @@ function run_test() {
|
||||
const propertiesErrorMessage = "If this assertion fails, then the client side CSS " +
|
||||
"properties list in devtools is out of sync with the " +
|
||||
"CSS properties on the platform. To fix this " +
|
||||
"assertion run `mach generate-css-db` to re-generate " +
|
||||
"assertion run `mach devtools-css-db` to re-generate " +
|
||||
"the client side properties.";
|
||||
|
||||
// Check that the platform and client match for pseudo elements.
|
||||
|
@ -672,10 +672,6 @@ nsXMLContentSerializer::SerializeAttr(const nsAString& aPrefix,
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if both have been found we don't need to search further
|
||||
if (bIncludesDouble && bIncludesSingle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delimiter and escaping is according to the following table
|
||||
|
@ -165,12 +165,14 @@ ReportOnCallerUTF8(JSContext* callerContext,
|
||||
|
||||
char* buf = JS_vsmprintf(format, ap);
|
||||
if (!buf) {
|
||||
va_end(ap);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
JS_ReportErrorUTF8(callerContext, "%s", buf);
|
||||
JS_smprintf_free(buf);
|
||||
|
||||
va_end(ap);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -183,11 +185,12 @@ ReportOnCallerUTF8(JSCLContextHelper& helper,
|
||||
|
||||
char* buf = JS_vsmprintf(format, ap);
|
||||
if (!buf) {
|
||||
va_end(ap);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
helper.reportErrorAfterPop(buf);
|
||||
|
||||
va_end(ap);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7659,7 +7659,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
frame = nullptr;
|
||||
}
|
||||
// Implicit pointer capture for touch
|
||||
if (sPointerEventImplicitCapture &&
|
||||
if (frame && sPointerEventImplicitCapture &&
|
||||
pointerEvent->mMessage == ePointerDown &&
|
||||
pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
|
||||
nsCOMPtr<nsIContent> targetContent;
|
||||
|
@ -245,10 +245,10 @@ fuzzy-if(skiaContent,1,5) pref(svg.marker-improvements.enabled,true) == marker-o
|
||||
# fuzzy because of the differences between clipPath and mask clipping
|
||||
== mask-and-clipPath.html mask-and-clipPath.html
|
||||
== mask-and-clipPath-2.svg mask-and-clipPath-2.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-01.svg mask-type-01.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-02.svg mask-type-02.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-03.svg mask-type-03.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-04.svg mask-type-04.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-01.svg mask-type-01.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-02.svg mask-type-02.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-03.svg mask-type-03.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-04.svg mask-type-04.svg
|
||||
== nested-viewBox-01.svg nested-viewBox-01.svg
|
||||
fuzzy-if(skiaContent,3,448000) == nesting-invalid-01.svg nesting-invalid-01.svg
|
||||
fuzzy-if(d2d&&/^Windows\x20NT\x20(6\.1|10\.0)/.test(http.oscpu),63,168) fuzzy-if(cocoaWidget,1,122) fuzzy-if(skiaContent,2,1000) == non-scaling-stroke-01.svg non-scaling-stroke-01.svg
|
||||
|
@ -220,10 +220,10 @@ fuzzy-if(skiaContent,1,10000) == mask-basic-02.svg mask-basic-02-ref.svg
|
||||
# fuzzy because of the differences between clipPath and mask clipping
|
||||
fuzzy(27,28) == mask-and-clipPath.html mask-and-clipPath-ref.html
|
||||
== mask-and-clipPath-2.svg pass.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-01.svg mask-type-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-02.svg mask-type-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-03.svg mask-type-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d||skiaContent,1,6400) == mask-type-04.svg mask-type-01-ref.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-01.svg mask-type-01-ref.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-02.svg mask-type-01-ref.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-03.svg mask-type-01-ref.svg
|
||||
fuzzy-if(d2d||skiaContent,1,6400) == mask-type-04.svg mask-type-01-ref.svg
|
||||
== nested-viewBox-01.svg pass.svg
|
||||
fuzzy-if(skiaContent,3,448000) == nesting-invalid-01.svg nesting-invalid-01-ref.svg
|
||||
fuzzy-if(d2d&&/^Windows\x20NT\x20(6\.1|10\.0)/.test(http.oscpu),63,168) fuzzy-if(cocoaWidget,1,122) fuzzy-if(skiaContent,2,1000) == non-scaling-stroke-01.svg non-scaling-stroke-01-ref.svg # bug 1074161 for Win7 and OSX 10.8
|
||||
|
@ -2792,7 +2792,7 @@ CSS_PROP_SVGRESET(
|
||||
mask_type,
|
||||
MaskType,
|
||||
CSS_PROPERTY_PARSE_VALUE,
|
||||
"layout.css.masking.enabled",
|
||||
"",
|
||||
VARIANT_HK,
|
||||
kMaskTypeKTable,
|
||||
CSS_PROP_NO_OFFSET,
|
||||
|
@ -1801,6 +1801,14 @@ var gCSSProperties = {
|
||||
],
|
||||
invalid_values: [ "5", "..25px", ".+5px", ".px", "-.px", "++5px", "-+4px", "+-3px", "--7px", "+-.6px", "-+.5px", "++.7px", "--.4px" ],
|
||||
},
|
||||
"mask-type": {
|
||||
domProp: "maskType",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "luminance" ],
|
||||
other_values: [ "alpha" ],
|
||||
invalid_values: [],
|
||||
},
|
||||
"-moz-outline-radius": {
|
||||
domProp: "MozOutlineRadius",
|
||||
inherited: false,
|
||||
@ -5561,17 +5569,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.text-combine-upright.enabled")) {
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCSSPropertyPrefEnabled("layout.css.masking.enabled")) {
|
||||
gCSSProperties["mask-type"] = {
|
||||
domProp: "maskType",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "luminance" ],
|
||||
other_values: [ "alpha" ],
|
||||
invalid_values: []
|
||||
};
|
||||
}
|
||||
|
||||
if (IsCSSPropertyPrefEnabled("svg.paint-order.enabled")) {
|
||||
gCSSProperties["paint-order"] = {
|
||||
domProp: "paintOrder",
|
||||
|
@ -72,7 +72,6 @@ var gProps = {
|
||||
"layout.css.image-orientation.enabled": ["image-orientation"],
|
||||
"layout.css.mix-blend-mode.enabled": ["mix-blend-mode"],
|
||||
"layout.css.isolation.enabled": [ "isolation"],
|
||||
"layout.css.masking.enabled": ["mask-type"],
|
||||
"layout.css.touch_action.enabled": ["touch-action"],
|
||||
"svg.transform-box.enabled": ["transform-box"]
|
||||
};
|
||||
|
@ -67,7 +67,9 @@ public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnC
|
||||
mStatusText = (TextView) content.findViewById(R.id.find_status);
|
||||
|
||||
mInflated = true;
|
||||
GeckoApp.getEventDispatcher().registerGeckoThreadListener(this, "TextSelection:Data");
|
||||
GeckoApp.getEventDispatcher().registerGeckoThreadListener(this,
|
||||
"FindInPage:MatchesCountResult",
|
||||
"TextSelection:Data");
|
||||
}
|
||||
|
||||
public void show() {
|
||||
@ -110,7 +112,34 @@ public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnC
|
||||
if (!mInflated) {
|
||||
return;
|
||||
}
|
||||
GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this, "TextSelection:Data");
|
||||
GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this,
|
||||
"FindInPage:MatchesCountResult",
|
||||
"TextSelection:Data");
|
||||
}
|
||||
|
||||
private void onMatchesCountResult(final int total, final int current, final int limit, final String searchString) {
|
||||
if (total == -1) {
|
||||
updateResult(Integer.toString(limit) + "+");
|
||||
} else if (total > 0) {
|
||||
updateResult(Integer.toString(current) + "/" + Integer.toString(total));
|
||||
} else if (TextUtils.isEmpty(searchString)) {
|
||||
updateResult("");
|
||||
} else {
|
||||
// We display 0/0, when there were no
|
||||
// matches found, or if matching has been turned off by setting
|
||||
// pref accessibility.typeaheadfind.matchesCountLimit to 0.
|
||||
updateResult("0/0");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateResult(final String statusText) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mStatusText.setVisibility(statusText.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
mStatusText.setText(statusText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TextWatcher implementation
|
||||
@ -160,6 +189,14 @@ public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnC
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
if (event.equals("FindInPage:MatchesCountResult")) {
|
||||
onMatchesCountResult(message.optInt("total", 0),
|
||||
message.optInt("current", 0),
|
||||
message.optInt("limit", 0),
|
||||
message.optString("searchString"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.equals("TextSelection:Data") || !REQUEST_ID.equals(message.optString("requestId"))) {
|
||||
return;
|
||||
}
|
||||
@ -203,21 +240,8 @@ public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnC
|
||||
GeckoAppShell.sendRequestToGecko(new GeckoRequest(request, searchString) {
|
||||
@Override
|
||||
public void onResponse(NativeJSObject nativeJSObject) {
|
||||
final int total = nativeJSObject.optInt("total", 0);
|
||||
if (total == -1) {
|
||||
final int limit = nativeJSObject.optInt("limit", 0);
|
||||
updateResult(Integer.toString(limit) + "+");
|
||||
} else if (total > 0) {
|
||||
final int current = nativeJSObject.optInt("current", 0);
|
||||
updateResult(Integer.toString(current) + "/" + Integer.toString(total));
|
||||
} else if (TextUtils.isEmpty(searchString)) {
|
||||
updateResult("");
|
||||
} else {
|
||||
// We display 0/0, when there were no
|
||||
// matches found, or if matching has been turned off by setting
|
||||
// pref accessibility.typeaheadfind.matchesCountLimit to 0.
|
||||
updateResult("0/0");
|
||||
}
|
||||
// We don't care about the return value, because `onMatchesCountResult`
|
||||
// does the heavy lifting.
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -227,16 +251,6 @@ public class FindInPageBar extends LinearLayout implements TextWatcher, View.OnC
|
||||
searchString + "]");
|
||||
updateResult("");
|
||||
}
|
||||
|
||||
private void updateResult(final String statusText) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mStatusText.setVisibility(statusText.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
mStatusText.setText(statusText);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ var FindHelper = {
|
||||
_initialViewport: null,
|
||||
_viewportChanged: false,
|
||||
_result: null,
|
||||
_limit: 0,
|
||||
|
||||
// Start of nsIObserver implementation.
|
||||
|
||||
observe: function(aMessage, aTopic, aData) {
|
||||
switch(aTopic) {
|
||||
@ -31,34 +32,25 @@ var FindHelper = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When the FindInPageBar opens/ becomes visible, it's time to:
|
||||
* 1. Add listeners for other message types sent from the FindInPageBar
|
||||
* 2. initialize the Finder instance, if necessary.
|
||||
*/
|
||||
_findOpened: function() {
|
||||
try {
|
||||
this._limit = Services.prefs.getIntPref("accessibility.typeaheadfind.matchesCountLimit");
|
||||
} catch (e) {
|
||||
// Pref not available, assume 0, no match counting.
|
||||
this._limit = 0;
|
||||
}
|
||||
|
||||
Messaging.addListener((data) => {
|
||||
this.doFind(data);
|
||||
return this._getMatchesCountResult(data);
|
||||
}, "FindInPage:Find");
|
||||
|
||||
Messaging.addListener((data) => {
|
||||
this.findAgain(data, false);
|
||||
return this._getMatchesCountResult(data);
|
||||
}, "FindInPage:Next");
|
||||
|
||||
Messaging.addListener((data) => {
|
||||
this.findAgain(data, true);
|
||||
return this._getMatchesCountResult(data);
|
||||
}, "FindInPage:Prev");
|
||||
Messaging.addListener(data => this.doFind(data), "FindInPage:Find");
|
||||
Messaging.addListener(data => this.findAgain(data, false), "FindInPage:Next");
|
||||
Messaging.addListener(data => this.findAgain(data, true), "FindInPage:Prev");
|
||||
|
||||
// Initialize the finder component for the current page by performing a fake find.
|
||||
this._init();
|
||||
this._finder.requestMatchesCount("", 1);
|
||||
this._finder.requestMatchesCount("");
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the Finder instance from the active tabs' browser and start tracking
|
||||
* the active viewport.
|
||||
*/
|
||||
_init: function() {
|
||||
// If there's no find in progress, start one.
|
||||
if (this._finder) {
|
||||
@ -78,6 +70,10 @@ var FindHelper = {
|
||||
this._viewportChanged = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Detach from the Finder instance (so stop listening for messages) and stop
|
||||
* tracking the active viewport.
|
||||
*/
|
||||
_uninit: function() {
|
||||
// If there's no find in progress, there's nothing to clean up.
|
||||
if (!this._finder) {
|
||||
@ -92,6 +88,9 @@ var FindHelper = {
|
||||
this._viewportChanged = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* When the FindInPageBar closes, it's time to stop listening for its messages.
|
||||
*/
|
||||
_findClosed: function() {
|
||||
Messaging.removeListener("FindInPage:Find");
|
||||
Messaging.removeListener("FindInPage:Next");
|
||||
@ -99,47 +98,86 @@ var FindHelper = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Request, wait for, and return the current matchesCount results for a string.
|
||||
* Start an asynchronous find-in-page operation, using the current Finder
|
||||
* instance and request to count the amount of matches.
|
||||
* If no Finder instance is currently active, we'll lazily initialize it here.
|
||||
*
|
||||
* @param {String} searchString Word to search for in the current document
|
||||
* @return {Object} Echo of the current find action
|
||||
*/
|
||||
_getMatchesCountResult: function(findString) {
|
||||
// Count matches up to any provided limit.
|
||||
if (this._limit <= 0) {
|
||||
return { total: 0, current: 0, limit: 0 };
|
||||
}
|
||||
|
||||
// Sync call to Finder, results available immediately.
|
||||
this._finder.requestMatchesCount(findString, this._limit);
|
||||
return this._result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pass along the count results to FindInPageBar for display.
|
||||
*/
|
||||
onMatchesCountResult: function(result) {
|
||||
this._result = result;
|
||||
this._result.limit = this._limit;
|
||||
},
|
||||
|
||||
doFind: function(searchString) {
|
||||
if (!this._finder) {
|
||||
this._init();
|
||||
}
|
||||
|
||||
this._finder.fastFind(searchString, false);
|
||||
return { searchString, findBackwards: false };
|
||||
},
|
||||
|
||||
/**
|
||||
* Restart the same find-in-page operation as before via `doFind()`. If we
|
||||
* haven't called `doFind()`, we simply kick off a regular find.
|
||||
*
|
||||
* @param {String} searchString Word to search for in the current document
|
||||
* @param {Boolean} findBackwards Direction to search in
|
||||
* @return {Object} Echo of the current find action
|
||||
*/
|
||||
findAgain: function(searchString, findBackwards) {
|
||||
// This always happens if the user taps next/previous after re-opening the
|
||||
// search bar, and not only forces _init() but also an initial fastFind(STRING)
|
||||
// before any findAgain(DIRECTION).
|
||||
if (!this._finder) {
|
||||
this.doFind(searchString);
|
||||
return;
|
||||
return this.doFind(searchString);
|
||||
}
|
||||
|
||||
this._finder.findAgain(findBackwards, false, false);
|
||||
return { searchString, findBackwards };
|
||||
},
|
||||
|
||||
// Start of Finder.jsm listener implementation.
|
||||
|
||||
/**
|
||||
* Pass along the count results to FindInPageBar for display. The result that
|
||||
* is sent to the FindInPageBar is augmented with the current find-in-page count
|
||||
* limit.
|
||||
*
|
||||
* @param {Object} result Result coming from the Finder instance that contains
|
||||
* the following properties:
|
||||
* - {Number} total The total amount of matches found
|
||||
* - {Number} current The index of current found range
|
||||
* in the document
|
||||
*/
|
||||
onMatchesCountResult: function(result) {
|
||||
this._result = result;
|
||||
|
||||
Messaging.sendRequest(Object.assign({
|
||||
type: "FindInPage:MatchesCountResult"
|
||||
}, this._result));
|
||||
},
|
||||
|
||||
/**
|
||||
* When a find-in-page action finishes, this method is invoked. This is mainly
|
||||
* used at the moment to detect if the current viewport has changed, which might
|
||||
* be indicated by not finding a string in the current page.
|
||||
*
|
||||
* @param {Object} aData A dictionary, representing the find result, which
|
||||
* contains the following properties:
|
||||
* - {String} searchString Word that was searched for
|
||||
* in the current document
|
||||
* - {Number} result One of the following
|
||||
* Ci.nsITypeAheadFind.* result
|
||||
* indicators: FIND_FOUND,
|
||||
* FIND_NOTFOUND, FIND_WRAPPED,
|
||||
* FIND_PENDING
|
||||
* - {Boolean} findBackwards Whether the search direction
|
||||
* was backwards
|
||||
* - {Boolean} findAgain Whether the previous search
|
||||
* was repeated
|
||||
* - {Boolean} drawOutline Whether we may (re-)draw the
|
||||
* outline of a hyperlink
|
||||
* - {Boolean} linksOnly Whether links-only mode was
|
||||
* active
|
||||
*/
|
||||
onFindResult: function(aData) {
|
||||
if (aData.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
|
||||
if (this._viewportChanged) {
|
||||
|
@ -2468,9 +2468,6 @@ pref("layout.css.devPixelsPerPx", "-1.0");
|
||||
// Is support for CSS initial-letter property enabled?
|
||||
pref("layout.css.initial-letter.enabled", false);
|
||||
|
||||
// Is support for CSS Masking features enabled?
|
||||
pref("layout.css.masking.enabled", true);
|
||||
|
||||
// Is support for mix-blend-mode enabled?
|
||||
pref("layout.css.mix-blend-mode.enabled", true);
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "BRNameMatchingPolicy.h"
|
||||
#include "CTKnownLogs.h"
|
||||
#include "ExtendedValidation.h"
|
||||
#include "MultiLogCTVerifier.h"
|
||||
@ -322,7 +321,7 @@ CertVerifier::SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode)
|
||||
static const unsigned int MIN_RSA_BITS = 2048;
|
||||
static const unsigned int MIN_RSA_BITS_WEAK = 1024;
|
||||
|
||||
SECStatus
|
||||
Result
|
||||
CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
Time time, void* pinArg, const char* hostname,
|
||||
/*out*/ UniqueCERTCertList& builtChain,
|
||||
@ -348,41 +347,34 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
}
|
||||
if (ocspStaplingStatus) {
|
||||
if (usage != certificateUsageSSLServer) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
*ocspStaplingStatus = OCSP_STAPLING_NEVER_CHECKED;
|
||||
}
|
||||
|
||||
if (keySizeStatus) {
|
||||
if (usage != certificateUsageSSLServer) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
*keySizeStatus = KeySizeStatus::NeverChecked;
|
||||
}
|
||||
|
||||
if (sha1ModeResult) {
|
||||
if (usage != certificateUsageSSLServer) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
*sha1ModeResult = SHA1ModeResult::NeverChecked;
|
||||
}
|
||||
|
||||
if (!cert ||
|
||||
(usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
Result rv;
|
||||
|
||||
Input certDER;
|
||||
rv = certDER.Init(cert->derCert.data, cert->derCert.len);
|
||||
Result rv = certDER.Init(cert->derCert.data, cert->derCert.len);
|
||||
if (rv != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(rv), 0);
|
||||
return SECFailure;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We configure the OCSP fetching modes separately for EV and non-EV
|
||||
@ -404,8 +396,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
stapledOCSPResponseSECItem->len);
|
||||
if (rv != Success) {
|
||||
// The stapled OCSP response was too big.
|
||||
PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0);
|
||||
return SECFailure;
|
||||
return Result::ERROR_OCSP_MALFORMED_RESPONSE;
|
||||
}
|
||||
stapledOCSPResponse = &stapledOCSPResponseInput;
|
||||
}
|
||||
@ -797,14 +788,13 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
}
|
||||
|
||||
if (rv != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(rv), 0);
|
||||
return SECFailure;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
return Success;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
Result
|
||||
CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* sctsFromTLS,
|
||||
@ -831,84 +821,74 @@ CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
|
||||
}
|
||||
|
||||
if (!hostname || !hostname[0]) {
|
||||
PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
|
||||
return SECFailure;
|
||||
return Result::ERROR_BAD_CERT_DOMAIN;
|
||||
}
|
||||
|
||||
// CreateCertErrorRunnable assumes that CheckCertHostname is only called
|
||||
// if VerifyCert succeeded.
|
||||
SECStatus rv = VerifyCert(peerCert.get(), certificateUsageSSLServer, time,
|
||||
pinarg, hostname, builtChain, flags,
|
||||
stapledOCSPResponse, sctsFromTLS,
|
||||
evOidPolicy, ocspStaplingStatus, keySizeStatus,
|
||||
sha1ModeResult, pinningTelemetryInfo,
|
||||
ctInfo);
|
||||
if (rv != SECSuccess) {
|
||||
Result rv = VerifyCert(peerCert.get(), certificateUsageSSLServer, time,
|
||||
pinarg, hostname, builtChain, flags,
|
||||
stapledOCSPResponse, sctsFromTLS, evOidPolicy,
|
||||
ocspStaplingStatus, keySizeStatus, sha1ModeResult,
|
||||
pinningTelemetryInfo, ctInfo);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Input peerCertInput;
|
||||
Result result = peerCertInput.Init(peerCert->derCert.data,
|
||||
peerCert->derCert.len);
|
||||
if (result != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(result), 0);
|
||||
return SECFailure;
|
||||
rv = peerCertInput.Init(peerCert->derCert.data, peerCert->derCert.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Input stapledOCSPResponseInput;
|
||||
Input* responseInputPtr = nullptr;
|
||||
if (stapledOCSPResponse) {
|
||||
result = stapledOCSPResponseInput.Init(stapledOCSPResponse->data,
|
||||
stapledOCSPResponse->len);
|
||||
if (result != Success) {
|
||||
rv = stapledOCSPResponseInput.Init(stapledOCSPResponse->data,
|
||||
stapledOCSPResponse->len);
|
||||
if (rv != Success) {
|
||||
// The stapled OCSP response was too big.
|
||||
PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0);
|
||||
return SECFailure;
|
||||
return Result::ERROR_OCSP_MALFORMED_RESPONSE;
|
||||
}
|
||||
responseInputPtr = &stapledOCSPResponseInput;
|
||||
}
|
||||
|
||||
if (!(flags & FLAG_TLS_IGNORE_STATUS_REQUEST)) {
|
||||
result = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr);
|
||||
|
||||
if (result != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(result), 0);
|
||||
return SECFailure;
|
||||
rv = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
Input hostnameInput;
|
||||
result = hostnameInput.Init(BitwiseCast<const uint8_t*, const char*>(hostname),
|
||||
strlen(hostname));
|
||||
if (result != Success) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
rv = hostnameInput.Init(BitwiseCast<const uint8_t*, const char*>(hostname),
|
||||
strlen(hostname));
|
||||
if (rv != Success) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
bool isBuiltInRoot;
|
||||
result = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
|
||||
if (result != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(result), 0);
|
||||
return SECFailure;
|
||||
rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
BRNameMatchingPolicy nameMatchingPolicy(
|
||||
isBuiltInRoot ? mNameMatchingMode
|
||||
: BRNameMatchingPolicy::Mode::DoNotEnforce);
|
||||
result = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
|
||||
if (result != Success) {
|
||||
rv = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
|
||||
if (rv != Success) {
|
||||
// Treat malformed name information as a domain mismatch.
|
||||
if (result == Result::ERROR_BAD_DER) {
|
||||
PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
|
||||
} else {
|
||||
PR_SetError(MapResultToPRErrorCode(result), 0);
|
||||
if (rv == Result::ERROR_BAD_DER) {
|
||||
return Result::ERROR_BAD_CERT_DOMAIN;
|
||||
}
|
||||
return SECFailure;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (saveIntermediatesInPermanentDatabase) {
|
||||
SaveIntermediateCerts(builtChain);
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
return Success;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
@ -97,23 +97,24 @@ public:
|
||||
|
||||
// *evOidPolicy == SEC_OID_UNKNOWN means the cert is NOT EV
|
||||
// Only one usage per verification is supported.
|
||||
SECStatus VerifyCert(CERTCertificate* cert,
|
||||
SECCertificateUsage usage,
|
||||
mozilla::pkix::Time time,
|
||||
void* pinArg,
|
||||
const char* hostname,
|
||||
/*out*/ UniqueCERTCertList& builtChain,
|
||||
Flags flags = 0,
|
||||
/*optional in*/ const SECItem* stapledOCSPResponse = nullptr,
|
||||
/*optional in*/ const SECItem* sctsFromTLS = nullptr,
|
||||
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
|
||||
/*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
||||
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr);
|
||||
mozilla::pkix::Result VerifyCert(
|
||||
CERTCertificate* cert,
|
||||
SECCertificateUsage usage,
|
||||
mozilla::pkix::Time time,
|
||||
void* pinArg,
|
||||
const char* hostname,
|
||||
/*out*/ UniqueCERTCertList& builtChain,
|
||||
Flags flags = 0,
|
||||
/*optional in*/ const SECItem* stapledOCSPResponse = nullptr,
|
||||
/*optional in*/ const SECItem* sctsFromTLS = nullptr,
|
||||
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
|
||||
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
|
||||
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
|
||||
/*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
|
||||
/*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
|
||||
/*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr);
|
||||
|
||||
SECStatus VerifySSLServerCert(
|
||||
mozilla::pkix::Result VerifySSLServerCert(
|
||||
const UniqueCERTCertificate& peerCert,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* sctsFromTLS,
|
||||
|
@ -1309,8 +1309,6 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
MOZ_ASSERT(infoObject);
|
||||
MOZ_ASSERT(cert);
|
||||
|
||||
SECStatus rv;
|
||||
|
||||
// We want to avoid storing any intermediate cert information when browsing
|
||||
// in private, transient contexts.
|
||||
bool saveIntermediates =
|
||||
@ -1331,20 +1329,18 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
flags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
|
||||
}
|
||||
|
||||
rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
|
||||
sctsFromTLSExtension, time, infoObject,
|
||||
infoObject->GetHostNameRaw(),
|
||||
certList, saveIntermediates, flags,
|
||||
&evOidPolicy, &ocspStaplingStatus,
|
||||
&keySizeStatus, &sha1ModeResult,
|
||||
&pinningTelemetryInfo,
|
||||
&certificateTransparencyInfo);
|
||||
PRErrorCode savedErrorCode;
|
||||
if (rv != SECSuccess) {
|
||||
savedErrorCode = PR_GetError();
|
||||
}
|
||||
Result rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
|
||||
sctsFromTLSExtension, time,
|
||||
infoObject,
|
||||
infoObject->GetHostNameRaw(),
|
||||
certList, saveIntermediates,
|
||||
flags, &evOidPolicy,
|
||||
&ocspStaplingStatus,
|
||||
&keySizeStatus, &sha1ModeResult,
|
||||
&pinningTelemetryInfo,
|
||||
&certificateTransparencyInfo);
|
||||
|
||||
uint32_t evStatus = (rv != SECSuccess) ? 0 // 0 = Failure
|
||||
uint32_t evStatus = (rv != Success) ? 0 // 0 = Failure
|
||||
: (evOidPolicy == SEC_OID_UNKNOWN) ? 1 // 1 = DV
|
||||
: 2; // 2 = EV
|
||||
Telemetry::Accumulate(Telemetry::CERT_EV_STATUS, evStatus);
|
||||
@ -1379,15 +1375,14 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
RefPtr<nsNSSCertificate> nsc;
|
||||
|
||||
if (!status || !status->HasServerCert()) {
|
||||
if( rv == SECSuccess ){
|
||||
if (rv == Success) {
|
||||
nsc = nsNSSCertificate::Create(cert.get(), &evOidPolicy);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nsc = nsNSSCertificate::Create(cert.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
if (rv == Success) {
|
||||
GatherSuccessfulValidationTelemetry(certList);
|
||||
GatherCertificateTransparencyTelemetry(certList,
|
||||
certificateTransparencyInfo);
|
||||
@ -1400,13 +1395,13 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
infoObject->SetSSLStatus(status);
|
||||
}
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
if (rv == Success) {
|
||||
// Certificate verification succeeded delete any potential record
|
||||
// of certificate error bits.
|
||||
RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject,
|
||||
nullptr, rv);
|
||||
}
|
||||
else {
|
||||
nullptr,
|
||||
SECSuccess);
|
||||
} else {
|
||||
// Certificate verification failed, update the status' bits.
|
||||
RememberCertErrorsTable::GetInstance().LookupCertErrorBits(
|
||||
infoObject, status);
|
||||
@ -1414,7 +1409,7 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
|
||||
if (status && !status->HasServerCert()) {
|
||||
nsNSSCertificate::EVStatus evStatus;
|
||||
if (evOidPolicy == SEC_OID_UNKNOWN || rv != SECSuccess) {
|
||||
if (evOidPolicy == SEC_OID_UNKNOWN || rv != Success) {
|
||||
evStatus = nsNSSCertificate::ev_status_invalid;
|
||||
} else {
|
||||
evStatus = nsNSSCertificate::ev_status_valid;
|
||||
@ -1426,14 +1421,14 @@ AuthCertificate(CertVerifier& certVerifier,
|
||||
}
|
||||
}
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
if (rv != Success) {
|
||||
// Certificate validation failed; store the peer certificate chain on
|
||||
// infoObject so it can be used for error reporting.
|
||||
infoObject->SetFailedCertChain(Move(peerCertChain));
|
||||
PR_SetError(savedErrorCode, 0);
|
||||
PR_SetError(MapResultToPRErrorCode(rv), 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
return rv == Success ? SECSuccess : SECFailure;
|
||||
}
|
||||
|
||||
/*static*/ SECStatus
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nssb64.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "secerr.h"
|
||||
@ -256,11 +257,16 @@ VerifyCertificate(CERTCertificate* cert, void* voidContext, void* pinArg)
|
||||
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
|
||||
NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return MapSECStatus(certVerifier->VerifyCert(cert,
|
||||
certificateUsageObjectSigner,
|
||||
Now(), pinArg,
|
||||
nullptr, // hostname
|
||||
context->builtChain));
|
||||
Result result = certVerifier->VerifyCert(cert,
|
||||
certificateUsageObjectSigner,
|
||||
Now(), pinArg,
|
||||
nullptr, // hostname
|
||||
context->builtChain);
|
||||
if (result != Success) {
|
||||
return GetXPCOMFromNSSError(MapResultToPRErrorCode(result));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -681,7 +681,8 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain)
|
||||
nullptr, /*XXX fixme*/
|
||||
nullptr, /* hostname */
|
||||
nssChain,
|
||||
CertVerifier::FLAG_LOCAL_ONLY) != SECSuccess) {
|
||||
CertVerifier::FLAG_LOCAL_ONLY)
|
||||
!= mozilla::pkix::Success) {
|
||||
nssChain = nullptr;
|
||||
// keep going
|
||||
}
|
||||
@ -707,7 +708,8 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain)
|
||||
nullptr, /*XXX fixme*/
|
||||
nullptr, /*hostname*/
|
||||
nssChain,
|
||||
CertVerifier::FLAG_LOCAL_ONLY) != SECSuccess) {
|
||||
CertVerifier::FLAG_LOCAL_ONLY)
|
||||
!= mozilla::pkix::Success) {
|
||||
nssChain = nullptr;
|
||||
// keep going
|
||||
}
|
||||
@ -1153,7 +1155,7 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
|
||||
uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY |
|
||||
mozilla::psm::CertVerifier::FLAG_MUST_BE_EV;
|
||||
UniqueCERTCertList unusedBuiltChain;
|
||||
SECStatus rv = certVerifier->VerifyCert(mCert.get(),
|
||||
mozilla::pkix::Result result = certVerifier->VerifyCert(mCert.get(),
|
||||
certificateUsageSSLServer, mozilla::pkix::Now(),
|
||||
nullptr /* XXX pinarg */,
|
||||
nullptr /* hostname */,
|
||||
@ -1163,7 +1165,7 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
|
||||
nullptr /* sctsFromTLSExtension */,
|
||||
&resultOidTag);
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
if (result != mozilla::pkix::Success) {
|
||||
resultOidTag = SEC_OID_UNKNOWN;
|
||||
}
|
||||
if (resultOidTag != SEC_OID_UNKNOWN) {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nspr.h"
|
||||
#include "pkix/Time.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "secasn1.h"
|
||||
#include "secder.h"
|
||||
@ -613,17 +614,17 @@ nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
|
||||
}
|
||||
|
||||
UniqueCERTCertList certChain;
|
||||
SECStatus srv = certVerifier->VerifyCert(node->cert,
|
||||
certificateUsageEmailRecipient,
|
||||
mozilla::pkix::Now(), ctx,
|
||||
nullptr, certChain);
|
||||
if (srv != SECSuccess) {
|
||||
mozilla::pkix::Result result =
|
||||
certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
|
||||
mozilla::pkix::Now(), ctx, nullptr, certChain);
|
||||
if (result != mozilla::pkix::Success) {
|
||||
nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
|
||||
DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
|
||||
continue;
|
||||
}
|
||||
srv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient,
|
||||
false);
|
||||
SECStatus srv = ImportCertsIntoPermanentStorage(certChain,
|
||||
certUsageEmailRecipient,
|
||||
false);
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -669,18 +670,18 @@ nsNSSCertificateDB::ImportValidCACertsInList(const UniqueCERTCertList& filteredC
|
||||
!CERT_LIST_END(node, filteredCerts.get());
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
UniqueCERTCertList certChain;
|
||||
SECStatus rv = certVerifier->VerifyCert(node->cert,
|
||||
certificateUsageVerifyCA,
|
||||
mozilla::pkix::Now(), ctx,
|
||||
nullptr, certChain);
|
||||
if (rv != SECSuccess) {
|
||||
mozilla::pkix::Result result =
|
||||
certVerifier->VerifyCert(node->cert, certificateUsageVerifyCA,
|
||||
mozilla::pkix::Now(), ctx, nullptr, certChain);
|
||||
if (result != mozilla::pkix::Success) {
|
||||
nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
|
||||
DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock);
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
|
||||
if (rv != SECSuccess) {
|
||||
SECStatus srv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA,
|
||||
true);
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -1140,13 +1141,13 @@ nsNSSCertificateDB::FindCertByEmailAddress(const char* aEmailAddress,
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
|
||||
UniqueCERTCertList unusedCertChain;
|
||||
SECStatus srv = certVerifier->VerifyCert(node->cert,
|
||||
certificateUsageEmailRecipient,
|
||||
mozilla::pkix::Now(),
|
||||
nullptr /*XXX pinarg*/,
|
||||
nullptr /*hostname*/,
|
||||
unusedCertChain);
|
||||
if (srv == SECSuccess) {
|
||||
mozilla::pkix::Result result =
|
||||
certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
|
||||
mozilla::pkix::Now(),
|
||||
nullptr /*XXX pinarg*/,
|
||||
nullptr /*hostname*/,
|
||||
unusedCertChain);
|
||||
if (result == mozilla::pkix::Success) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1488,45 +1489,38 @@ VerifyCertAtTime(nsIX509Cert* aCert,
|
||||
|
||||
UniqueCERTCertList resultChain;
|
||||
SECOidTag evOidPolicy;
|
||||
SECStatus srv;
|
||||
mozilla::pkix::Result result;
|
||||
|
||||
if (aHostname && aUsage == certificateUsageSSLServer) {
|
||||
srv = certVerifier->VerifySSLServerCert(nssCert,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
aTime,
|
||||
nullptr, // Assume no context
|
||||
aHostname,
|
||||
resultChain,
|
||||
false, // don't save intermediates
|
||||
aFlags,
|
||||
&evOidPolicy);
|
||||
result = certVerifier->VerifySSLServerCert(nssCert,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
aTime,
|
||||
nullptr, // Assume no context
|
||||
aHostname,
|
||||
resultChain,
|
||||
false, // don't save intermediates
|
||||
aFlags,
|
||||
&evOidPolicy);
|
||||
} else {
|
||||
srv = certVerifier->VerifyCert(nssCert.get(), aUsage, aTime,
|
||||
nullptr, // Assume no context
|
||||
aHostname,
|
||||
resultChain,
|
||||
aFlags,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
&evOidPolicy);
|
||||
result = certVerifier->VerifyCert(nssCert.get(), aUsage, aTime,
|
||||
nullptr, // Assume no context
|
||||
aHostname,
|
||||
resultChain,
|
||||
aFlags,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
&evOidPolicy);
|
||||
}
|
||||
|
||||
PRErrorCode error = PR_GetError();
|
||||
|
||||
nsCOMPtr<nsIX509CertList> nssCertList;
|
||||
// This adopts the list
|
||||
nssCertList = new nsNSSCertList(Move(resultChain), locker);
|
||||
NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
|
||||
|
||||
if (srv == SECSuccess) {
|
||||
if (evOidPolicy != SEC_OID_UNKNOWN) {
|
||||
*aHasEVPolicy = true;
|
||||
}
|
||||
*_retval = 0;
|
||||
} else {
|
||||
NS_ENSURE_TRUE(error != 0, NS_ERROR_FAILURE);
|
||||
*_retval = error;
|
||||
*_retval = mozilla::pkix::MapResultToPRErrorCode(result);
|
||||
if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) {
|
||||
*aHasEVPolicy = true;
|
||||
}
|
||||
nssCertList.forget(aVerifiedChain);
|
||||
|
||||
|
@ -379,6 +379,10 @@ nsNSSSocketInfo::DriveHandshake()
|
||||
NS_IMETHODIMP
|
||||
nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
|
||||
{
|
||||
NS_ENSURE_ARG(_retval);
|
||||
|
||||
*_retval = false;
|
||||
|
||||
// If this is the same hostname then the certicate status does not
|
||||
// need to be considered. They are joinable.
|
||||
if (hostname.Equals(GetHostName())) {
|
||||
@ -444,16 +448,17 @@ nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
|
||||
nsAutoCString hostnameFlat(PromiseFlatCString(hostname));
|
||||
CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY;
|
||||
UniqueCERTCertList unusedBuiltChain;
|
||||
SECStatus rv = certVerifier->VerifySSLServerCert(nssCert,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
mozilla::pkix::Now(),
|
||||
nullptr, // pinarg
|
||||
hostnameFlat.get(),
|
||||
unusedBuiltChain,
|
||||
false, // save intermediates
|
||||
flags);
|
||||
if (rv != SECSuccess) {
|
||||
mozilla::pkix::Result result =
|
||||
certVerifier->VerifySSLServerCert(nssCert,
|
||||
nullptr, // stapledOCSPResponse
|
||||
nullptr, // sctsFromTLSExtension
|
||||
mozilla::pkix::Now(),
|
||||
nullptr, // pinarg
|
||||
hostnameFlat.get(),
|
||||
unusedBuiltChain,
|
||||
false, // save intermediates
|
||||
flags);
|
||||
if (result != mozilla::pkix::Success) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -745,7 +745,7 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
|
||||
certList,
|
||||
false, // don't store intermediates
|
||||
flags)
|
||||
!= SECSuccess) {
|
||||
!= mozilla::pkix::Success) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,9 @@ SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
|
||||
if (NS_FAILED(rv)) {
|
||||
policy->AddDir(rdwrcr, "/tmp");
|
||||
}
|
||||
|
||||
// Bug 1308851: NVIDIA proprietary driver when using WebGL
|
||||
policy->AddPrefix(rdwr, "/dev", "nvidia");
|
||||
mCommonContentPolicy.reset(policy);
|
||||
#endif
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
[
|
||||
{
|
||||
"size": 1379434,
|
||||
"size": 1455774,
|
||||
"visibility": "public",
|
||||
"digest": "cafa23466e283bccb6f89db9606da281877a87e3f22439c25655767fedc118df6961d9c34fc52eb4e747d48a66acd8c15d7c8c07b8f36e2e7db4ad8826742bfd",
|
||||
"digest": "0f552a18276ff98985b236cd5e2f8baa5e4edcbbee1d8c21e3e5a5f61f2a674e5fb355f8be3b1bfb2a1f34465721d7ded12f432a50877c78c4b039ce0fcf6b8d",
|
||||
"algorithm": "sha512",
|
||||
"filename": "geckodriver-v0.10.0-linux64.tar.gz"
|
||||
"filename": "geckodriver-v0.11.1-linux64.tar.gz"
|
||||
}
|
||||
]
|
||||
|
@ -606,7 +606,7 @@ Tester.prototype = {
|
||||
// Run the GC and CC a few times to make sure that as much
|
||||
// as possible is freed.
|
||||
let numCycles = 3;
|
||||
for (i = 0; i < numCycles; i++) {
|
||||
for (let i = 0; i < numCycles; i++) {
|
||||
Cu.forceGC();
|
||||
Cu.forceCC();
|
||||
}
|
||||
|
@ -205,8 +205,8 @@ var PrintUtils = {
|
||||
// collapse the browser here -- it will be shown in
|
||||
// enterPrintPreview; this forces a reflow which fixes display
|
||||
// issues in bug 267422.
|
||||
this._sourceBrowser = this._listener.getPrintPreviewBrowser();
|
||||
this._sourceBrowser.collapsed = true;
|
||||
let ppBrowser = this._listener.getPrintPreviewBrowser();
|
||||
ppBrowser.collapsed = true;
|
||||
}
|
||||
|
||||
this._webProgressPP = {};
|
||||
@ -531,15 +531,15 @@ var PrintUtils = {
|
||||
// the original page. After we have parsed it, content will tell parent
|
||||
// that the document is ready for print previewing.
|
||||
spMM.sendAsyncMessage("Printing:Preview:ParseDocument", {
|
||||
URL: this._listener.getSourceBrowser().currentURI.spec,
|
||||
windowID: this._listener.getSourceBrowser().outerWindowID,
|
||||
URL: this._sourceBrowser.currentURI.spec,
|
||||
windowID: this._sourceBrowser.outerWindowID,
|
||||
});
|
||||
|
||||
// Here we log telemetry data for when the user enters simplify mode.
|
||||
this.logTelemetry("PRINT_PREVIEW_SIMPLIFY_PAGE_OPENED_COUNT");
|
||||
}
|
||||
} else {
|
||||
sendEnterPreviewMessage(this._listener.getSourceBrowser(), false);
|
||||
sendEnterPreviewMessage(this._sourceBrowser, false);
|
||||
}
|
||||
|
||||
if (this._webProgressPP.value) {
|
||||
|
@ -128,7 +128,7 @@ public:
|
||||
|
||||
template<typename T>
|
||||
static T* Cast(LookupCache* aThat) {
|
||||
return (T::VER == aThat->Ver() ? reinterpret_cast<T*>(aThat) : nullptr);
|
||||
return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat) : nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -374,8 +374,6 @@
|
||||
prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
|
||||
this._flashFindBar =
|
||||
prefsvc.getIntPref("accessibility.typeaheadfind.flashBar");
|
||||
this._matchesCountLimit =
|
||||
prefsvc.getIntPref("accessibility.typeaheadfind.matchesCountLimit");
|
||||
this._useModalHighlight = prefsvc.getBoolPref("findbar.modalHighlight");
|
||||
|
||||
prefsvc.addObserver("accessibility.typeaheadfind",
|
||||
@ -1309,9 +1307,9 @@
|
||||
if (aResult.total !== 0) {
|
||||
if (aResult.total == -1) {
|
||||
this._foundMatches.value = this.pluralForm.get(
|
||||
this._matchesCountLimit,
|
||||
aResult.limit,
|
||||
this.strBundle.GetStringFromName("FoundMatchesCountLimit")
|
||||
).replace("#1", this._matchesCountLimit);
|
||||
).replace("#1", aResult.limit);
|
||||
} else {
|
||||
this._foundMatches.value = this.pluralForm.get(
|
||||
aResult.total,
|
||||
|
@ -394,7 +394,8 @@ Finder.prototype = {
|
||||
_notifyMatchesCount: function(result = this._currentMatchesCountResult) {
|
||||
// The `_currentFound` property is only used for internal bookkeeping.
|
||||
delete result._currentFound;
|
||||
if (result.total == this.matchesCountLimit)
|
||||
result.limit = this.matchesCountLimit;
|
||||
if (result.total == result.limit)
|
||||
result.total = -1;
|
||||
|
||||
for (let l of this._listeners) {
|
||||
|
@ -37,17 +37,24 @@ const kRGBRE = /^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/i;
|
||||
// hard to clash with IDs content authors come up with.
|
||||
const kModalIdPrefix = "cedee4d0-74c5-4f2d-ab43-4d37c0f9d463";
|
||||
const kModalOutlineId = kModalIdPrefix + "-findbar-modalHighlight-outline";
|
||||
const kOutlineBoxColor = "255,197,53";
|
||||
const kModalStyles = {
|
||||
outlineNode: [
|
||||
["position", "absolute"],
|
||||
["background", "#ffc535"],
|
||||
["background-color", `rgb(${kOutlineBoxColor})`],
|
||||
["background-clip", "padding-box"],
|
||||
["border", "2px solid"],
|
||||
["-moz-border-top-colors", `rgba(${kOutlineBoxColor},.1) rgba(${kOutlineBoxColor},.4) rgba(${kOutlineBoxColor},.7)`],
|
||||
["-moz-border-right-colors", `rgba(${kOutlineBoxColor},.1) rgba(${kOutlineBoxColor},.4) rgba(${kOutlineBoxColor},.7)`],
|
||||
["-moz-border-bottom-colors", `rgba(${kOutlineBoxColor},.1) rgba(${kOutlineBoxColor},.4) rgba(${kOutlineBoxColor},.7)`],
|
||||
["-moz-border-left-colors", `rgba(${kOutlineBoxColor},.1) rgba(${kOutlineBoxColor},.4) rgba(${kOutlineBoxColor},.7)`],
|
||||
["border-radius", "3px"],
|
||||
["box-shadow", "0 2px 0 0 rgba(0,0,0,.1)"],
|
||||
["color", "#000"],
|
||||
["display", "-moz-box"],
|
||||
["margin", "-2px 0 0 -2px !important"],
|
||||
["padding", "2px !important"],
|
||||
["overflow", "hidden"],
|
||||
["pointer-events", "none"],
|
||||
["position", "absolute"],
|
||||
["white-space", "nowrap"],
|
||||
["will-change", "transform"],
|
||||
["z-index", 2]
|
||||
|
@ -2331,6 +2331,19 @@ var AddonManagerInternal = {
|
||||
.installTemporaryAddon(aFile);
|
||||
},
|
||||
|
||||
installAddonFromSources: function(aFile) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!(aFile instanceof Ci.nsIFile))
|
||||
throw Components.Exception("aFile must be a nsIFile",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
return AddonManagerInternal._getProviderByName("XPIProvider")
|
||||
.installAddonFromSources(aFile);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an Addon corresponding to an instance ID.
|
||||
* @param aInstanceID
|
||||
@ -3507,6 +3520,10 @@ this.AddonManager = {
|
||||
return AddonManagerInternal.installTemporaryAddon(aDirectory);
|
||||
},
|
||||
|
||||
installAddonFromSources: function(aDirectory) {
|
||||
return AddonManagerInternal.installAddonFromSources(aDirectory);
|
||||
},
|
||||
|
||||
getAddonByInstanceID: function(aInstanceID) {
|
||||
return AddonManagerInternal.getAddonByInstanceID(aInstanceID);
|
||||
},
|
||||
|
@ -412,6 +412,33 @@ function setFilePermissions(aFile, aPermissions) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a given string to a file
|
||||
*
|
||||
* @param file
|
||||
* The nsIFile instance to write into
|
||||
* @param string
|
||||
* The string to write
|
||||
*/
|
||||
function writeStringToFile(file, string) {
|
||||
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
let converter = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
|
||||
try {
|
||||
stream.init(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
|
||||
FileUtils.MODE_TRUNCATE, FileUtils.PERMS_FILE,
|
||||
0);
|
||||
converter.init(stream, "UTF-8", 0, 0x0000);
|
||||
converter.writeString(string);
|
||||
}
|
||||
finally {
|
||||
converter.close();
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A safe way to install a file or the contents of a directory to a new
|
||||
* directory. The file or directory is moved or copied recursively and if
|
||||
@ -3529,8 +3556,11 @@ this.XPIProvider = {
|
||||
}
|
||||
|
||||
try {
|
||||
addon._sourceBundle = location.installAddon(id, stageDirEntry,
|
||||
existingAddonID);
|
||||
addon._sourceBundle = location.installAddon({
|
||||
id,
|
||||
source: stageDirEntry,
|
||||
existingAddonID
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
logger.error("Failed to install staged add-on " + id + " in " + location.name,
|
||||
@ -3671,7 +3701,7 @@ this.XPIProvider = {
|
||||
|
||||
// Install the add-on
|
||||
try {
|
||||
addon._sourceBundle = profileLocation.installAddon(id, entry, null, true);
|
||||
addon._sourceBundle = profileLocation.installAddon({ id, source: entry, action: "copy" });
|
||||
logger.debug("Installed distribution add-on " + id);
|
||||
|
||||
Services.prefs.setBoolPref(PREF_BRANCH_INSTALLED_ADDON + id, true)
|
||||
@ -4027,15 +4057,48 @@ this.XPIProvider = {
|
||||
* @param aFile
|
||||
* An nsIFile for the unpacked add-on directory or XPI file.
|
||||
*
|
||||
* @return See installAddonFromLocation return value.
|
||||
*/
|
||||
installTemporaryAddon: function(aFile) {
|
||||
return this.installAddonFromLocation(aFile, TemporaryInstallLocation);
|
||||
},
|
||||
|
||||
/**
|
||||
* Permanently installs add-on from a local XPI file or directory.
|
||||
* The signature is checked but the add-on persist on application restart.
|
||||
*
|
||||
* @param aFile
|
||||
* An nsIFile for the unpacked add-on directory or XPI file.
|
||||
*
|
||||
* @return See installAddonFromLocation return value.
|
||||
*/
|
||||
installAddonFromSources: Task.async(function*(aFile) {
|
||||
let location = XPIProvider.installLocationsByName[KEY_APP_PROFILE];
|
||||
return this.installAddonFromLocation(aFile, location, "proxy");
|
||||
}),
|
||||
|
||||
/**
|
||||
* Installs add-on from a local XPI file or directory.
|
||||
*
|
||||
* @param aFile
|
||||
* An nsIFile for the unpacked add-on directory or XPI file.
|
||||
* @param aInstallLocation
|
||||
* Define a custom install location object to use for the install.
|
||||
* @param aInstallAction
|
||||
* Optional action mode to use when installing the addon
|
||||
* (see MutableDirectoryInstallLocation.installAddon)
|
||||
*
|
||||
* @return a Promise that resolves to an Addon object on success, or rejects
|
||||
* if the add-on is not a valid restartless add-on or if the
|
||||
* same ID is already temporarily installed
|
||||
* same ID is already installed.
|
||||
*/
|
||||
installTemporaryAddon: Task.async(function*(aFile) {
|
||||
installAddonFromLocation: Task.async(function*(aFile, aInstallLocation, aInstallAction) {
|
||||
if (aFile.exists() && aFile.isFile()) {
|
||||
flushJarCache(aFile);
|
||||
}
|
||||
let addon = yield loadManifestFromFile(aFile, TemporaryInstallLocation);
|
||||
let addon = yield loadManifestFromFile(aFile, aInstallLocation);
|
||||
|
||||
aInstallLocation.installAddon({ id: addon.id, source: aFile, action: aInstallAction });
|
||||
|
||||
if (addon.appDisabled) {
|
||||
let message = `Add-on ${addon.id} is not compatible with application version.`;
|
||||
@ -4054,7 +4117,7 @@ this.XPIProvider = {
|
||||
|
||||
if (!addon.bootstrap) {
|
||||
throw new Error("Only restartless (bootstrap) add-ons"
|
||||
+ " can be temporarily installed:", addon.id);
|
||||
+ " can be installed from sources:", addon.id);
|
||||
}
|
||||
let installReason = BOOTSTRAP_REASONS.ADDON_INSTALL;
|
||||
let oldAddon = yield new Promise(
|
||||
@ -4109,6 +4172,7 @@ this.XPIProvider = {
|
||||
|
||||
XPIStates.addAddon(addon);
|
||||
XPIDatabase.saveChanges();
|
||||
XPIStates.save();
|
||||
|
||||
AddonManagerPrivate.callAddonListeners("onInstalling", addon.wrapper,
|
||||
false);
|
||||
@ -6407,8 +6471,11 @@ AddonInstall.prototype = {
|
||||
|
||||
// Install the new add-on into its final location
|
||||
let existingAddonID = this.existingAddon ? this.existingAddon.id : null;
|
||||
let file = this.installLocation.installAddon(this.addon.id, stagedAddon,
|
||||
existingAddonID);
|
||||
let file = this.installLocation.installAddon({
|
||||
id: this.addon.id,
|
||||
source: stagedAddon,
|
||||
existingAddonID
|
||||
});
|
||||
|
||||
// Update the metadata in the database
|
||||
this.addon._sourceBundle = file;
|
||||
@ -6514,22 +6581,7 @@ AddonInstall.prototype = {
|
||||
this.addon._sourceBundle = stagedAddon;
|
||||
|
||||
// Cache the AddonInternal as it may have updated compatibility info
|
||||
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
let converter = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
|
||||
try {
|
||||
stream.init(stagedJSON, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
|
||||
FileUtils.MODE_TRUNCATE, FileUtils.PERMS_FILE,
|
||||
0);
|
||||
converter.init(stream, "UTF-8", 0, 0x0000);
|
||||
converter.writeString(JSON.stringify(this.addon));
|
||||
}
|
||||
finally {
|
||||
converter.close();
|
||||
stream.close();
|
||||
}
|
||||
writeStringToFile(stagedJSON, JSON.stringify(this.addon));
|
||||
|
||||
logger.debug("Staged install of " + this.addon.id + " from " + this.sourceURI.spec + " ready; waiting for restart.");
|
||||
if (isUpgrade) {
|
||||
@ -8321,18 +8373,24 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
||||
/**
|
||||
* Installs an add-on into the install location.
|
||||
*
|
||||
* @param aId
|
||||
* @param id
|
||||
* The ID of the add-on to install
|
||||
* @param aSource
|
||||
* @param source
|
||||
* The source nsIFile to install from
|
||||
* @param aExistingAddonID
|
||||
* @param existingAddonID
|
||||
* The ID of an existing add-on to uninstall at the same time
|
||||
* @param aCopy
|
||||
* If false the source files will be moved to the new location,
|
||||
* otherwise they will only be copied
|
||||
* @param action
|
||||
* What to we do with the given source file:
|
||||
* "move"
|
||||
* Default action, the source files will be moved to the new
|
||||
* location,
|
||||
* "copy"
|
||||
* The source files will be copied,
|
||||
* "proxy"
|
||||
* A "proxy file" is going to refer to the source file path
|
||||
* @return an nsIFile indicating where the add-on was installed to
|
||||
*/
|
||||
installAddon: function(aId, aSource, aExistingAddonID, aCopy) {
|
||||
installAddon: function({ id, source, existingAddonID, action = "move" }) {
|
||||
let trashDir = this.getTrashDir();
|
||||
|
||||
let transaction = new SafeInstallOperation();
|
||||
@ -8355,9 +8413,9 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
||||
// If any of these operations fails the finally block will clean up the
|
||||
// temporary directory
|
||||
try {
|
||||
moveOldAddon(aId);
|
||||
if (aExistingAddonID && aExistingAddonID != aId) {
|
||||
moveOldAddon(aExistingAddonID);
|
||||
moveOldAddon(id);
|
||||
if (existingAddonID && existingAddonID != id) {
|
||||
moveOldAddon(existingAddonID);
|
||||
|
||||
{
|
||||
// Move the data directories.
|
||||
@ -8366,12 +8424,12 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
||||
* for porting to OS.File.
|
||||
*/
|
||||
let oldDataDir = FileUtils.getDir(
|
||||
KEY_PROFILEDIR, ["extension-data", aExistingAddonID], false, true
|
||||
KEY_PROFILEDIR, ["extension-data", existingAddonID], false, true
|
||||
);
|
||||
|
||||
if (oldDataDir.exists()) {
|
||||
let newDataDir = FileUtils.getDir(
|
||||
KEY_PROFILEDIR, ["extension-data", aId], false, true
|
||||
KEY_PROFILEDIR, ["extension-data", id], false, true
|
||||
);
|
||||
if (newDataDir.exists()) {
|
||||
let trashData = trashDir.clone();
|
||||
@ -8384,15 +8442,16 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
if (aCopy) {
|
||||
transaction.copy(aSource, this._directory);
|
||||
if (action == "copy") {
|
||||
transaction.copy(source, this._directory);
|
||||
}
|
||||
else {
|
||||
if (aSource.isFile())
|
||||
flushJarCache(aSource);
|
||||
else if (action == "move") {
|
||||
if (source.isFile())
|
||||
flushJarCache(source);
|
||||
|
||||
transaction.moveUnder(aSource, this._directory);
|
||||
transaction.moveUnder(source, this._directory);
|
||||
}
|
||||
// Do nothing for the proxy file as we sideload an addon permanently
|
||||
}
|
||||
finally {
|
||||
// It isn't ideal if this cleanup fails but it isn't worth rolling back
|
||||
@ -8401,23 +8460,33 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
||||
recursiveRemove(trashDir);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Failed to remove trash directory when installing " + aId, e);
|
||||
logger.warn("Failed to remove trash directory when installing " + id, e);
|
||||
}
|
||||
}
|
||||
|
||||
let newFile = this._directory.clone();
|
||||
newFile.append(aSource.leafName);
|
||||
|
||||
if (action == "proxy") {
|
||||
// When permanently installing sideloaded addon, we just put a proxy file
|
||||
// refering to the addon sources
|
||||
newFile.append(id);
|
||||
|
||||
writeStringToFile(newFile, source.path);
|
||||
} else {
|
||||
newFile.append(source.leafName);
|
||||
}
|
||||
|
||||
try {
|
||||
newFile.lastModifiedTime = Date.now();
|
||||
} catch (e) {
|
||||
logger.warn("failed to set lastModifiedTime on " + newFile.path, e);
|
||||
}
|
||||
this._IDToFileMap[aId] = newFile;
|
||||
XPIProvider._addURIMapping(aId, newFile);
|
||||
this._IDToFileMap[id] = newFile;
|
||||
XPIProvider._addURIMapping(id, newFile);
|
||||
|
||||
if (aExistingAddonID && aExistingAddonID != aId &&
|
||||
aExistingAddonID in this._IDToFileMap) {
|
||||
delete this._IDToFileMap[aExistingAddonID];
|
||||
if (existingAddonID && existingAddonID != id &&
|
||||
existingAddonID in this._IDToFileMap) {
|
||||
delete this._IDToFileMap[existingAddonID];
|
||||
}
|
||||
|
||||
return newFile;
|
||||
@ -8824,9 +8893,7 @@ WinRegInstallLocation.prototype = {
|
||||
for (let i = 0; i < count; ++i) {
|
||||
let id = aKey.getValueName(i);
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsIFile);
|
||||
file.initWithPath(aKey.readStringValue(id));
|
||||
let file = new nsIFile(aKey.readStringValue(id));
|
||||
|
||||
if (!file.exists()) {
|
||||
logger.warn("Ignoring missing add-on in " + file.path);
|
||||
|
1
toolkit/mozapps/extensions/test/xpcshell/data/from_sources/bootstrap.js
vendored
Normal file
1
toolkit/mozapps/extensions/test/xpcshell/data/from_sources/bootstrap.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
Components.utils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>bootstrap1@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test Bootstrap 1</em:name>
|
||||
<em:description>Test Description</em:description>
|
||||
|
||||
<em:iconURL>chrome://foo/skin/icon.png</em:iconURL>
|
||||
<em:aboutURL>chrome://foo/content/about.xul</em:aboutURL>
|
||||
<em:optionsURL>chrome://foo/content/options.xul</em:optionsURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
@ -0,0 +1,80 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const ID = "bootstrap1@tests.mozilla.org";
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
|
||||
startupManager();
|
||||
|
||||
BootstrapMonitor.init();
|
||||
|
||||
// Partial list of bootstrap reasons from XPIProvider.jsm
|
||||
const BOOTSTRAP_REASONS = {
|
||||
ADDON_INSTALL: 5,
|
||||
ADDON_UPGRADE: 7,
|
||||
ADDON_DOWNGRADE: 8,
|
||||
};
|
||||
|
||||
// Install an unsigned add-on with no existing add-on present.
|
||||
// Restart and make sure it is still around.
|
||||
add_task(function*() {
|
||||
let extInstallCalled = false;
|
||||
AddonManager.addInstallListener({
|
||||
onExternalInstall: (aInstall) => {
|
||||
do_check_eq(aInstall.id, ID);
|
||||
do_check_eq(aInstall.version, "1.0");
|
||||
extInstallCalled = true;
|
||||
},
|
||||
});
|
||||
|
||||
let installingCalled = false;
|
||||
let installedCalled = false;
|
||||
AddonManager.addAddonListener({
|
||||
onInstalling: (aInstall) => {
|
||||
do_check_eq(aInstall.id, ID);
|
||||
do_check_eq(aInstall.version, "1.0");
|
||||
installingCalled = true;
|
||||
},
|
||||
onInstalled: (aInstall) => {
|
||||
do_check_eq(aInstall.id, ID);
|
||||
do_check_eq(aInstall.version, "1.0");
|
||||
installedCalled = true;
|
||||
},
|
||||
onInstallStarted: (aInstall) => {
|
||||
do_throw("onInstallStarted called unexpectedly");
|
||||
}
|
||||
});
|
||||
|
||||
yield AddonManager.installAddonFromSources(do_get_file("data/from_sources/"));
|
||||
|
||||
do_check_true(extInstallCalled);
|
||||
do_check_true(installingCalled);
|
||||
do_check_true(installedCalled);
|
||||
|
||||
let install = BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
equal(install.reason, BOOTSTRAP_REASONS.ADDON_INSTALL);
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
|
||||
do_check_neq(addon, null);
|
||||
do_check_eq(addon.version, "1.0");
|
||||
do_check_eq(addon.name, "Test Bootstrap 1");
|
||||
do_check_true(addon.isCompatible);
|
||||
do_check_false(addon.appDisabled);
|
||||
do_check_true(addon.isActive);
|
||||
do_check_eq(addon.type, "extension");
|
||||
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
install = BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
equal(install.reason, BOOTSTRAP_REASONS.ADDON_INSTALL);
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
@ -34,6 +34,7 @@ skip-if = appname != "firefox"
|
||||
[test_XPIStates.js]
|
||||
[test_temporary.js]
|
||||
tags = webextensions
|
||||
[test_install_from_sources.js]
|
||||
[test_proxies.js]
|
||||
[test_proxy.js]
|
||||
[test_pass_symbol.js]
|
||||
|
Loading…
Reference in New Issue
Block a user