зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central a=merge
This commit is contained in:
Коммит
98926c4646
|
@ -18,14 +18,16 @@
|
|||
<title data-l10n-id="about-config-title"></title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="container" role="alertdialog" aria-labelledby="warningTitle"
|
||||
aria-describedby="warningDescription">
|
||||
|
||||
<div class="title">
|
||||
<h1 class="title-text" data-l10n-id="about-config-warning-title"></h1>
|
||||
<h1 id="warningTitle" class="title-text"
|
||||
data-l10n-id="about-config-warning-title"></h1>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<p data-l10n-id="about-config-warning-text"></p>
|
||||
<p id="warningDescription" data-l10n-id="about-config-warning-text"></p>
|
||||
</div>
|
||||
|
||||
<div class="toggle-container-with-text">
|
||||
|
@ -35,7 +37,7 @@
|
|||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<button class="primary" onclick="onWarningButtonClick();"
|
||||
<button autofocus class="primary" onclick="onWarningButtonClick();"
|
||||
data-l10n-id="about-config-warning-button"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,6 +14,12 @@ const GETTERS_BY_PREF_TYPE = {
|
|||
[Ci.nsIPrefBranch.PREF_STRING]: "getStringPref",
|
||||
};
|
||||
|
||||
const STRINGS_ADD_BY_TYPE = {
|
||||
Boolean: "about-config-pref-add-type-boolean",
|
||||
Number: "about-config-pref-add-type-number",
|
||||
String: "about-config-pref-add-type-string",
|
||||
};
|
||||
|
||||
let gDefaultBranch = Services.prefs.getDefaultBranch("");
|
||||
let gFilterPrefsTask = new DeferredTask(() => filterPrefs(), SEARCH_TIMEOUT_MS);
|
||||
|
||||
|
@ -207,7 +213,7 @@ class PrefRow {
|
|||
radio.checked = this.type == type;
|
||||
form.appendChild(radio);
|
||||
let radioLabel = document.createElement("span");
|
||||
radioLabel.textContent = type;
|
||||
document.l10n.setAttributes(radioLabel, STRINGS_ADD_BY_TYPE[type]);
|
||||
form.appendChild(radioLabel);
|
||||
}
|
||||
form.addEventListener("click", event => {
|
||||
|
|
|
@ -20,6 +20,11 @@ about-config-pref-save = Save
|
|||
about-config-pref-reset = Reset
|
||||
about-config-pref-delete = Delete
|
||||
|
||||
## Labels for the type selection radio buttons shown when adding preferences.
|
||||
about-config-pref-add-type-boolean = Boolean
|
||||
about-config-pref-add-type-number = Number
|
||||
about-config-pref-add-type-string = String
|
||||
|
||||
## Preferences with a non-default value are differentiated visually, and at the
|
||||
## same time the state is made accessible to screen readers using an aria-label
|
||||
## that won't be visible or copied to the clipboard.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"use strict";
|
||||
|
||||
const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const {escapeCSSComment, _unescapeCSSComment} = require("devtools/shared/css/parsing-utils");
|
||||
const {escapeCSSComment, unescapeCSSComment} = require("devtools/shared/css/parsing-utils");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ function run_test() {
|
|||
|
||||
const escaped = escapeCSSComment(test.input);
|
||||
equal(escaped, test.expected);
|
||||
const unescaped = _unescapeCSSComment(escaped);
|
||||
const unescaped = unescapeCSSComment(escaped);
|
||||
equal(unescaped, test.input);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"use strict";
|
||||
|
||||
const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const {RuleRewriter} = require("devtools/shared/css/parsing-utils");
|
||||
const RuleRewriter = require("devtools/shared/fronts/inspector/rule-rewriter");
|
||||
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
|
||||
|
||||
const TEST_DATA = [
|
||||
|
|
|
@ -52,7 +52,7 @@ exports.viewSourceInDebugger = async function(toolbox, sourceURL, sourceLine,
|
|||
reason = "unknown") {
|
||||
const dbg = await toolbox.loadTool("jsdebugger");
|
||||
const source = dbg.getSource(sourceURL);
|
||||
if (source) {
|
||||
if (source || await toolbox.sourceMapService.hasOriginalURL(sourceURL)) {
|
||||
await toolbox.selectTool("jsdebugger", reason);
|
||||
dbg.selectSource(sourceURL, sourceLine);
|
||||
return true;
|
||||
|
|
|
@ -402,7 +402,7 @@ skip-if = verify
|
|||
[browser_webconsole_sourcemap_error.js]
|
||||
[browser_webconsole_sourcemap_invalid.js]
|
||||
[browser_webconsole_sourcemap_nosource.js]
|
||||
skip-if = true # will be fixed with 1523421
|
||||
skip-if = verify
|
||||
[browser_webconsole_split.js]
|
||||
[browser_webconsole_split_close_button.js]
|
||||
[browser_webconsole_split_escape_key.js]
|
||||
|
|
|
@ -363,6 +363,12 @@ async function checkClickOnNode(hud, toolbox, frameLinkNode) {
|
|||
await onSourceInDebuggerOpened;
|
||||
|
||||
const dbg = toolbox.getPanel("jsdebugger");
|
||||
|
||||
// Wait for the source to finish loading, if it is pending.
|
||||
await waitFor(() => {
|
||||
return !!dbg._selectors.getSelectedSource(dbg._getState());
|
||||
});
|
||||
|
||||
is(
|
||||
dbg._selectors.getSelectedSource(dbg._getState()).url,
|
||||
url,
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
// This file holds various CSS parsing and rewriting utilities.
|
||||
// Some entry points of note are:
|
||||
// parseDeclarations - parse a CSS rule into declarations
|
||||
// RuleRewriter - rewrite CSS rule text
|
||||
// parsePseudoClassesAndAttributes - parse selector and extract
|
||||
// pseudo-classes
|
||||
// parseSingleValue - parse a single CSS property value
|
||||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
const {getCSSLexer} = require("devtools/shared/css/lexer");
|
||||
|
||||
loader.lazyRequireGetter(this, "CSS_ANGLEUNIT", "devtools/shared/css/constants", true);
|
||||
|
@ -23,21 +21,11 @@ const SELECTOR_ATTRIBUTE = exports.SELECTOR_ATTRIBUTE = 1;
|
|||
const SELECTOR_ELEMENT = exports.SELECTOR_ELEMENT = 2;
|
||||
const SELECTOR_PSEUDO_CLASS = exports.SELECTOR_PSEUDO_CLASS = 3;
|
||||
|
||||
// Used to test whether a newline appears anywhere in some text.
|
||||
const NEWLINE_RX = /[\r\n]/;
|
||||
// Used to test whether a bit of text starts an empty comment, either
|
||||
// an "ordinary" /* ... */ comment, or a "heuristic bypass" comment
|
||||
// like /*! ... */.
|
||||
const EMPTY_COMMENT_START_RX = /^\/\*!?[ \r\n\t\f]*$/;
|
||||
// Used to test whether a bit of text ends an empty comment.
|
||||
const EMPTY_COMMENT_END_RX = /^[ \r\n\t\f]*\*\//;
|
||||
// Used to test whether a string starts with a blank line.
|
||||
const BLANK_LINE_RX = /^[ \t]*(?:\r\n|\n|\r|\f|$)/;
|
||||
|
||||
// When commenting out a declaration, we put this character into the
|
||||
// comment opener so that future parses of the commented text know to
|
||||
// bypass the property name validity heuristic.
|
||||
const COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = "!";
|
||||
const COMMENT_PARSING_HEURISTIC_BYPASS_CHAR =
|
||||
exports.COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = "!";
|
||||
|
||||
/**
|
||||
* A generator function that lexes a CSS source string, yielding the
|
||||
|
@ -258,17 +246,6 @@ function cssTrim(str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like trimRight, but only trims CSS-allowed whitespace.
|
||||
*/
|
||||
function cssTrimRight(str) {
|
||||
const match = /^(.*?)[ \t\r\n\f]*$/.exec(str);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that does all the parsing work for
|
||||
* parseDeclarations. This is separate because it has some arguments
|
||||
|
@ -518,634 +495,6 @@ function parseNamedDeclarations(isCssPropertyKnown, inputString,
|
|||
.filter(item => !!item.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an object that can be used to rewrite declarations in some
|
||||
* source text. The source text and parsing are handled in the same
|
||||
* way as @see parseNamedDeclarations, with |parseComments| being true.
|
||||
* Rewriting is done by calling one of the modification functions like
|
||||
* setPropertyEnabled. The returned object has the same interface
|
||||
* as @see RuleModificationList.
|
||||
*
|
||||
* An example showing how to disable the 3rd property in a rule:
|
||||
*
|
||||
* let rewriter = new RuleRewriter(isCssPropertyKnown, ruleActor,
|
||||
* ruleActor.authoredText);
|
||||
* rewriter.setPropertyEnabled(3, "color", false);
|
||||
* rewriter.apply().then(() => { ... the change is made ... });
|
||||
*
|
||||
* The exported rewriting methods are |renameProperty|, |setPropertyEnabled|,
|
||||
* |createProperty|, |setProperty|, and |removeProperty|. The |apply|
|
||||
* method can be used to send the edited text to the StyleRuleActor;
|
||||
* |getDefaultIndentation| is useful for the methods requiring a
|
||||
* default indentation value; and |getResult| is useful for testing.
|
||||
*
|
||||
* Additionally, editing will set the |changedDeclarations| property
|
||||
* on this object. This property has the same form as the |changed|
|
||||
* property of the object returned by |getResult|.
|
||||
*
|
||||
* @param {Function} isCssPropertyKnown
|
||||
* A function to check if the CSS property is known. This is either an
|
||||
* internal server function or from the CssPropertiesFront.
|
||||
* that are supported by the server. Note that if Bug 1222047
|
||||
* is completed then isCssPropertyKnown will not need to be passed in.
|
||||
* The CssProperty front will be able to obtained directly from the
|
||||
* RuleRewriter.
|
||||
* @param {StyleRuleFront} rule The style rule to use. Note that this
|
||||
* is only needed by the |apply| and |getDefaultIndentation| methods;
|
||||
* and in particular for testing it can be |null|.
|
||||
* @param {String} inputString The CSS source text to parse and modify.
|
||||
* @return {Object} an object that can be used to rewrite the input text.
|
||||
*/
|
||||
function RuleRewriter(isCssPropertyKnown, rule, inputString) {
|
||||
this.rule = rule;
|
||||
this.isCssPropertyKnown = isCssPropertyKnown;
|
||||
// The RuleRewriter sends CSS rules as text to the server, but with this modifications
|
||||
// array, it also sends the list of changes so the server doesn't have to re-parse the
|
||||
// rule if it needs to track what changed.
|
||||
this.modifications = [];
|
||||
|
||||
// Keep track of which any declarations we had to rewrite while
|
||||
// performing the requested action.
|
||||
this.changedDeclarations = {};
|
||||
|
||||
// If not null, a promise that must be wait upon before |apply| can
|
||||
// do its work.
|
||||
this.editPromise = null;
|
||||
|
||||
// If the |defaultIndentation| property is set, then it is used;
|
||||
// otherwise the RuleRewriter will try to compute the default
|
||||
// indentation based on the style sheet's text. This override
|
||||
// facility is for testing.
|
||||
this.defaultIndentation = null;
|
||||
|
||||
this.startInitialization(inputString);
|
||||
}
|
||||
|
||||
RuleRewriter.prototype = {
|
||||
/**
|
||||
* An internal function to initialize the rewriter with a given
|
||||
* input string.
|
||||
*
|
||||
* @param {String} inputString the input to use
|
||||
*/
|
||||
startInitialization: function(inputString) {
|
||||
this.inputString = inputString;
|
||||
// Whether there are any newlines in the input text.
|
||||
this.hasNewLine = /[\r\n]/.test(this.inputString);
|
||||
// The declarations.
|
||||
this.declarations = parseNamedDeclarations(this.isCssPropertyKnown, this.inputString,
|
||||
true);
|
||||
this.decl = null;
|
||||
this.result = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to complete initialization and set some
|
||||
* properties for further processing.
|
||||
*
|
||||
* @param {Number} index The index of the property to modify
|
||||
*/
|
||||
completeInitialization: function(index) {
|
||||
if (index < 0) {
|
||||
throw new Error("Invalid index " + index + ". Expected positive integer");
|
||||
}
|
||||
// |decl| is the declaration to be rewritten, or null if there is no
|
||||
// declaration corresponding to |index|.
|
||||
// |result| is used to accumulate the result text.
|
||||
if (index < this.declarations.length) {
|
||||
this.decl = this.declarations[index];
|
||||
this.result = this.inputString.substring(0, this.decl.offsets[0]);
|
||||
} else {
|
||||
this.decl = null;
|
||||
this.result = this.inputString;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper function to compute the indentation of some text. This
|
||||
* examines the rule's existing text to guess the indentation to use;
|
||||
* unlike |getDefaultIndentation|, which examines the entire style
|
||||
* sheet.
|
||||
*
|
||||
* @param {String} string the input text
|
||||
* @param {Number} offset the offset at which to compute the indentation
|
||||
* @return {String} the indentation at the indicated position
|
||||
*/
|
||||
getIndentation: function(string, offset) {
|
||||
let originalOffset = offset;
|
||||
for (--offset; offset >= 0; --offset) {
|
||||
const c = string[offset];
|
||||
if (c === "\r" || c === "\n" || c === "\f") {
|
||||
return string.substring(offset + 1, originalOffset);
|
||||
}
|
||||
if (c !== " " && c !== "\t") {
|
||||
// Found some non-whitespace character before we found a newline
|
||||
// -- let's reset the starting point and keep going, as we saw
|
||||
// something on the line before the declaration.
|
||||
originalOffset = offset;
|
||||
}
|
||||
}
|
||||
// Ran off the end.
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Modify a property value to ensure it is "lexically safe" for
|
||||
* insertion into a style sheet. This function doesn't attempt to
|
||||
* ensure that the resulting text is a valid value for the given
|
||||
* property; but rather just that inserting the text into the style
|
||||
* sheet will not cause unwanted changes to other rules or
|
||||
* declarations.
|
||||
*
|
||||
* @param {String} text The input text. This should include the trailing ";".
|
||||
* @return {Array} An array of the form [anySanitized, text], where
|
||||
* |anySanitized| is a boolean that indicates
|
||||
* whether anything substantive has changed; and
|
||||
* where |text| is the text that has been rewritten
|
||||
* to be "lexically safe".
|
||||
*/
|
||||
sanitizePropertyValue: function(text) {
|
||||
// Start by stripping any trailing ";". This is done here to
|
||||
// avoid the case where the user types "url(" (which is turned
|
||||
// into "url(;" by the rule view before coming here), being turned
|
||||
// into "url(;)" by this code -- due to the way "url(...)" is
|
||||
// parsed as a single token.
|
||||
text = text.replace(/;$/, "");
|
||||
const lexer = getCSSLexer(text);
|
||||
|
||||
let result = "";
|
||||
let previousOffset = 0;
|
||||
const parenStack = [];
|
||||
let anySanitized = false;
|
||||
|
||||
// Push a closing paren on the stack.
|
||||
const pushParen = (token, closer) => {
|
||||
result = result + text.substring(previousOffset, token.startOffset) +
|
||||
text.substring(token.startOffset, token.endOffset);
|
||||
// We set the location of the paren in a funny way, to handle
|
||||
// the case where we've seen a function token, where the paren
|
||||
// appears at the end.
|
||||
parenStack.push({closer, offset: result.length - 1});
|
||||
previousOffset = token.endOffset;
|
||||
};
|
||||
|
||||
// Pop a closing paren from the stack.
|
||||
const popSomeParens = (closer) => {
|
||||
while (parenStack.length > 0) {
|
||||
const paren = parenStack.pop();
|
||||
|
||||
if (paren.closer === closer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Found a non-matching closing paren, so quote it. Note that
|
||||
// these are processed in reverse order.
|
||||
result = result.substring(0, paren.offset) + "\\" +
|
||||
result.substring(paren.offset);
|
||||
anySanitized = true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const token = lexer.nextToken();
|
||||
if (!token) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (token.tokenType === "symbol") {
|
||||
switch (token.text) {
|
||||
case ";":
|
||||
// We simply drop the ";" here. This lets us cope with
|
||||
// declarations that don't have a ";" and also other
|
||||
// termination. The caller handles adding the ";" again.
|
||||
result += text.substring(previousOffset, token.startOffset);
|
||||
previousOffset = token.endOffset;
|
||||
break;
|
||||
|
||||
case "{":
|
||||
pushParen(token, "}");
|
||||
break;
|
||||
|
||||
case "(":
|
||||
pushParen(token, ")");
|
||||
break;
|
||||
|
||||
case "[":
|
||||
pushParen(token, "]");
|
||||
break;
|
||||
|
||||
case "}":
|
||||
case ")":
|
||||
case "]":
|
||||
// Did we find an unmatched close bracket?
|
||||
if (!popSomeParens(token.text)) {
|
||||
// Copy out text from |previousOffset|.
|
||||
result += text.substring(previousOffset, token.startOffset);
|
||||
// Quote the offending symbol.
|
||||
result += "\\" + token.text;
|
||||
previousOffset = token.endOffset;
|
||||
anySanitized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (token.tokenType === "function") {
|
||||
pushParen(token, ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Fix up any unmatched parens.
|
||||
popSomeParens(null);
|
||||
|
||||
// Copy out any remaining text, then any needed terminators.
|
||||
result += text.substring(previousOffset, text.length);
|
||||
const eofFixup = lexer.performEOFFixup("", true);
|
||||
if (eofFixup) {
|
||||
anySanitized = true;
|
||||
result += eofFixup;
|
||||
}
|
||||
return [anySanitized, result];
|
||||
},
|
||||
|
||||
/**
|
||||
* Start at |index| and skip whitespace
|
||||
* backward in |string|. Return the index of the first
|
||||
* non-whitespace character, or -1 if the entire string was
|
||||
* whitespace.
|
||||
* @param {String} string the input string
|
||||
* @param {Number} index the index at which to start
|
||||
* @return {Number} index of the first non-whitespace character, or -1
|
||||
*/
|
||||
skipWhitespaceBackward: function(string, index) {
|
||||
for (--index;
|
||||
index >= 0 && (string[index] === " " || string[index] === "\t");
|
||||
--index) {
|
||||
// Nothing.
|
||||
}
|
||||
return index;
|
||||
},
|
||||
|
||||
/**
|
||||
* Terminate a given declaration, if needed.
|
||||
*
|
||||
* @param {Number} index The index of the rule to possibly
|
||||
* terminate. It might be invalid, so this
|
||||
* function must check for that.
|
||||
*/
|
||||
maybeTerminateDecl: function(index) {
|
||||
if (index < 0 || index >= this.declarations.length
|
||||
// No need to rewrite declarations in comments.
|
||||
|| ("commentOffsets" in this.declarations[index])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const termDecl = this.declarations[index];
|
||||
let endIndex = termDecl.offsets[1];
|
||||
// Due to an oddity of the lexer, we might have gotten a bit of
|
||||
// extra whitespace in a trailing bad_url token -- so be sure to
|
||||
// skip that as well.
|
||||
endIndex = this.skipWhitespaceBackward(this.result, endIndex) + 1;
|
||||
|
||||
const trailingText = this.result.substring(endIndex);
|
||||
if (termDecl.terminator) {
|
||||
// Insert the terminator just at the end of the declaration,
|
||||
// before any trailing whitespace.
|
||||
this.result = this.result.substring(0, endIndex) + termDecl.terminator +
|
||||
trailingText;
|
||||
// In a couple of cases, we may have had to add something to
|
||||
// terminate the declaration, but the termination did not
|
||||
// actually affect the property's value -- and at this spot, we
|
||||
// only care about reporting value changes. In particular, we
|
||||
// might have added a plain ";", or we might have terminated a
|
||||
// comment with "*/;". Neither of these affect the value.
|
||||
if (termDecl.terminator !== ";" && termDecl.terminator !== "*/;") {
|
||||
this.changedDeclarations[index] =
|
||||
termDecl.value + termDecl.terminator.slice(0, -1);
|
||||
}
|
||||
}
|
||||
// If the rule generally has newlines, but this particular
|
||||
// declaration doesn't have a trailing newline, insert one now.
|
||||
// Maybe this style is too weird to bother with.
|
||||
if (this.hasNewLine && !NEWLINE_RX.test(trailingText)) {
|
||||
this.result += "\n";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitize the given property value and return the sanitized form.
|
||||
* If the property is rewritten during sanitization, make a note in
|
||||
* |changedDeclarations|.
|
||||
*
|
||||
* @param {String} text The property text.
|
||||
* @param {Number} index The index of the property.
|
||||
* @return {String} The sanitized text.
|
||||
*/
|
||||
sanitizeText: function(text, index) {
|
||||
const [anySanitized, sanitizedText] = this.sanitizePropertyValue(text);
|
||||
if (anySanitized) {
|
||||
this.changedDeclarations[index] = sanitizedText;
|
||||
}
|
||||
return sanitizedText;
|
||||
},
|
||||
|
||||
/**
|
||||
* Rename a declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name current name of the property
|
||||
* @param {String} newName new name of the property
|
||||
*/
|
||||
renameProperty: function(index, name, newName) {
|
||||
this.completeInitialization(index);
|
||||
this.result += CSS.escape(newName);
|
||||
// We could conceivably compute the name offsets instead so we
|
||||
// could preserve white space and comments on the LHS of the ":".
|
||||
this.completeCopying(this.decl.colonOffsets[0]);
|
||||
this.modifications.push({ type: "set", index, name, newName });
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable or disable a declaration
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name current name of the property
|
||||
* @param {Boolean} isEnabled true if the property should be enabled;
|
||||
* false if it should be disabled
|
||||
*/
|
||||
setPropertyEnabled: function(index, name, isEnabled) {
|
||||
this.completeInitialization(index);
|
||||
const decl = this.decl;
|
||||
const priority = decl.priority;
|
||||
let copyOffset = decl.offsets[1];
|
||||
if (isEnabled) {
|
||||
// Enable it. First see if the comment start can be deleted.
|
||||
const commentStart = decl.commentOffsets[0];
|
||||
if (EMPTY_COMMENT_START_RX.test(this.result.substring(commentStart))) {
|
||||
this.result = this.result.substring(0, commentStart);
|
||||
} else {
|
||||
this.result += "*/ ";
|
||||
}
|
||||
|
||||
// Insert the name and value separately, so we can report
|
||||
// sanitization changes properly.
|
||||
const commentNamePart =
|
||||
this.inputString.substring(decl.offsets[0],
|
||||
decl.colonOffsets[1]);
|
||||
this.result += unescapeCSSComment(commentNamePart);
|
||||
|
||||
// When uncommenting, we must be sure to sanitize the text, to
|
||||
// avoid things like /* decl: }; */, which will be accepted as
|
||||
// a property but which would break the entire style sheet.
|
||||
let newText = this.inputString.substring(decl.colonOffsets[1],
|
||||
decl.offsets[1]);
|
||||
newText = cssTrimRight(unescapeCSSComment(newText));
|
||||
this.result += this.sanitizeText(newText, index) + ";";
|
||||
|
||||
// See if the comment end can be deleted.
|
||||
const trailingText = this.inputString.substring(decl.offsets[1]);
|
||||
if (EMPTY_COMMENT_END_RX.test(trailingText)) {
|
||||
copyOffset = decl.commentOffsets[1];
|
||||
} else {
|
||||
this.result += " /*";
|
||||
}
|
||||
} else {
|
||||
// Disable it. Note that we use our special comment syntax
|
||||
// here.
|
||||
const declText = this.inputString.substring(decl.offsets[0],
|
||||
decl.offsets[1]);
|
||||
this.result += "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR +
|
||||
" " + escapeCSSComment(declText) + " */";
|
||||
}
|
||||
this.completeCopying(copyOffset);
|
||||
|
||||
if (isEnabled) {
|
||||
this.modifications.push({ type: "set", index, name, value: decl.value, priority });
|
||||
} else {
|
||||
this.modifications.push({ type: "disable", index, name });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise that will be resolved to the default indentation
|
||||
* of the rule. This is a helper for internalCreateProperty.
|
||||
*
|
||||
* @return {Promise} a promise that will be resolved to a string
|
||||
* that holds the default indentation that should be used
|
||||
* for edits to the rule.
|
||||
*/
|
||||
getDefaultIndentation: function() {
|
||||
return this.rule.parentStyleSheet.guessIndentation();
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to create a new declaration. This does all
|
||||
* the work of |createProperty|.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name name of the new property
|
||||
* @param {String} value value of the new property
|
||||
* @param {String} priority priority of the new property; either
|
||||
* the empty string or "important"
|
||||
* @param {Boolean} enabled True if the new property should be
|
||||
* enabled, false if disabled
|
||||
* @return {Promise} a promise that is resolved when the edit has
|
||||
* completed
|
||||
*/
|
||||
async internalCreateProperty(index, name, value, priority, enabled) {
|
||||
this.completeInitialization(index);
|
||||
let newIndentation = "";
|
||||
if (this.hasNewLine) {
|
||||
if (this.declarations.length > 0) {
|
||||
newIndentation = this.getIndentation(this.inputString,
|
||||
this.declarations[0].offsets[0]);
|
||||
} else if (this.defaultIndentation) {
|
||||
newIndentation = this.defaultIndentation;
|
||||
} else {
|
||||
newIndentation = await this.getDefaultIndentation();
|
||||
}
|
||||
}
|
||||
|
||||
this.maybeTerminateDecl(index - 1);
|
||||
|
||||
// If we generally have newlines, and if skipping whitespace
|
||||
// backward stops at a newline, then insert our text before that
|
||||
// whitespace. This ensures the indentation we computed is what
|
||||
// is actually used.
|
||||
let savedWhitespace = "";
|
||||
if (this.hasNewLine) {
|
||||
const wsOffset = this.skipWhitespaceBackward(this.result,
|
||||
this.result.length);
|
||||
if (this.result[wsOffset] === "\r" || this.result[wsOffset] === "\n") {
|
||||
savedWhitespace = this.result.substring(wsOffset + 1);
|
||||
this.result = this.result.substring(0, wsOffset + 1);
|
||||
}
|
||||
}
|
||||
|
||||
let newText = CSS.escape(name) + ": " + this.sanitizeText(value, index);
|
||||
if (priority === "important") {
|
||||
newText += " !important";
|
||||
}
|
||||
newText += ";";
|
||||
|
||||
if (!enabled) {
|
||||
newText = "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR + " " +
|
||||
escapeCSSComment(newText) + " */";
|
||||
}
|
||||
|
||||
this.result += newIndentation + newText;
|
||||
if (this.hasNewLine) {
|
||||
this.result += "\n";
|
||||
}
|
||||
this.result += savedWhitespace;
|
||||
|
||||
if (this.decl) {
|
||||
// Still want to copy in the declaration previously at this
|
||||
// index.
|
||||
this.completeCopying(this.decl.offsets[0]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name name of the new property
|
||||
* @param {String} value value of the new property
|
||||
* @param {String} priority priority of the new property; either
|
||||
* the empty string or "important"
|
||||
* @param {Boolean} enabled True if the new property should be
|
||||
* enabled, false if disabled
|
||||
*/
|
||||
createProperty: function(index, name, value, priority, enabled) {
|
||||
this.editPromise = this.internalCreateProperty(index, name, value, priority, enabled);
|
||||
// Log the modification only if the created property is enabled.
|
||||
if (enabled) {
|
||||
this.modifications.push({ type: "set", index, name, value, priority });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a declaration's value.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* This can be -1 in the case where
|
||||
* the rule does not support setRuleText;
|
||||
* generally for setting properties
|
||||
* on an element's style.
|
||||
* @param {String} name the property's name
|
||||
* @param {String} value the property's value
|
||||
* @param {String} priority the property's priority, either the empty
|
||||
* string or "important"
|
||||
*/
|
||||
setProperty: function(index, name, value, priority) {
|
||||
this.completeInitialization(index);
|
||||
// We might see a "set" on a previously non-existent property; in
|
||||
// that case, act like "create".
|
||||
if (!this.decl) {
|
||||
this.createProperty(index, name, value, priority, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that this assumes that "set" never operates on disabled
|
||||
// properties.
|
||||
this.result += this.inputString.substring(this.decl.offsets[0],
|
||||
this.decl.colonOffsets[1]) +
|
||||
this.sanitizeText(value, index);
|
||||
|
||||
if (priority === "important") {
|
||||
this.result += " !important";
|
||||
}
|
||||
this.result += ";";
|
||||
this.completeCopying(this.decl.offsets[1]);
|
||||
this.modifications.push({ type: "set", index, name, value, priority });
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name the name of the property to remove
|
||||
*/
|
||||
removeProperty: function(index, name) {
|
||||
this.completeInitialization(index);
|
||||
|
||||
// If asked to remove a property that does not exist, bail out.
|
||||
if (!this.decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the property is disabled, then first enable it, and then
|
||||
// delete it. We take this approach because we want to remove the
|
||||
// entire comment if possible; but the logic for dealing with
|
||||
// comments is hairy and already implemented in
|
||||
// setPropertyEnabled.
|
||||
if (this.decl.commentOffsets) {
|
||||
this.setPropertyEnabled(index, name, true);
|
||||
this.startInitialization(this.result);
|
||||
this.completeInitialization(index);
|
||||
}
|
||||
|
||||
let copyOffset = this.decl.offsets[1];
|
||||
// Maybe removing this rule left us with a completely blank
|
||||
// line. In this case, we'll delete the whole thing. We only
|
||||
// bother with this if we're looking at sources that already
|
||||
// have a newline somewhere.
|
||||
if (this.hasNewLine) {
|
||||
const nlOffset = this.skipWhitespaceBackward(this.result,
|
||||
this.decl.offsets[0]);
|
||||
if (nlOffset < 0 || this.result[nlOffset] === "\r" ||
|
||||
this.result[nlOffset] === "\n") {
|
||||
const trailingText = this.inputString.substring(copyOffset);
|
||||
const match = BLANK_LINE_RX.exec(trailingText);
|
||||
if (match) {
|
||||
this.result = this.result.substring(0, nlOffset + 1);
|
||||
copyOffset += match[0].length;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.completeCopying(copyOffset);
|
||||
this.modifications.push({ type: "remove", index, name });
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to copy any trailing text to the output
|
||||
* string.
|
||||
*
|
||||
* @param {Number} copyOffset Offset into |inputString| of the
|
||||
* final text to copy to the output string.
|
||||
*/
|
||||
completeCopying: function(copyOffset) {
|
||||
// Add the trailing text.
|
||||
this.result += this.inputString.substring(copyOffset);
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply the modifications in this object to the associated rule.
|
||||
*
|
||||
* @return {Promise} A promise which will be resolved when the modifications
|
||||
* are complete.
|
||||
*/
|
||||
apply: function() {
|
||||
return promise.resolve(this.editPromise).then(() => {
|
||||
return this.rule.setRuleText(this.result, this.modifications);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the result of the rewriting. This is used for testing.
|
||||
*
|
||||
* @return {object} an object of the form {changed: object, text: string}
|
||||
* |changed| is an object where each key is
|
||||
* the index of a property whose value had to be
|
||||
* rewritten during the sanitization process, and
|
||||
* whose value is the new text of the property.
|
||||
* |text| is the rewritten text of the rule.
|
||||
*/
|
||||
getResult: function() {
|
||||
return {changed: this.changedDeclarations, text: this.result};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of the parsed CSS selector value and type given a string.
|
||||
*
|
||||
|
@ -1296,13 +645,11 @@ function getAngleValueInDegrees(angleValue, angleUnit) {
|
|||
exports.cssTokenizer = cssTokenizer;
|
||||
exports.cssTokenizerWithLineColumn = cssTokenizerWithLineColumn;
|
||||
exports.escapeCSSComment = escapeCSSComment;
|
||||
// unescapeCSSComment is exported for testing.
|
||||
exports._unescapeCSSComment = unescapeCSSComment;
|
||||
exports.unescapeCSSComment = unescapeCSSComment;
|
||||
exports.parseDeclarations = parseDeclarations;
|
||||
exports.parseNamedDeclarations = parseNamedDeclarations;
|
||||
// parseCommentDeclarations is exported for testing.
|
||||
exports._parseCommentDeclarations = parseCommentDeclarations;
|
||||
exports.RuleRewriter = RuleRewriter;
|
||||
exports.parsePseudoClassesAndAttributes = parsePseudoClassesAndAttributes;
|
||||
exports.parseSingleValue = parseSingleValue;
|
||||
exports.getAngleValueInDegrees = getAngleValueInDegrees;
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
|
||||
DevToolsModules(
|
||||
'node-picker.js',
|
||||
'rule-rewriter.js',
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,676 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
// This file holds various CSS parsing and rewriting utilities.
|
||||
// Some entry points of note are:
|
||||
// parseDeclarations - parse a CSS rule into declarations
|
||||
// RuleRewriter - rewrite CSS rule text
|
||||
// parsePseudoClassesAndAttributes - parse selector and extract
|
||||
// pseudo-classes
|
||||
// parseSingleValue - parse a single CSS property value
|
||||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
const { getCSSLexer } = require("devtools/shared/css/lexer");
|
||||
const {
|
||||
COMMENT_PARSING_HEURISTIC_BYPASS_CHAR,
|
||||
escapeCSSComment,
|
||||
parseNamedDeclarations,
|
||||
unescapeCSSComment,
|
||||
} = require("devtools/shared/css/parsing-utils");
|
||||
|
||||
// Used to test whether a newline appears anywhere in some text.
|
||||
const NEWLINE_RX = /[\r\n]/;
|
||||
// Used to test whether a bit of text starts an empty comment, either
|
||||
// an "ordinary" /* ... */ comment, or a "heuristic bypass" comment
|
||||
// like /*! ... */.
|
||||
const EMPTY_COMMENT_START_RX = /^\/\*!?[ \r\n\t\f]*$/;
|
||||
// Used to test whether a bit of text ends an empty comment.
|
||||
const EMPTY_COMMENT_END_RX = /^[ \r\n\t\f]*\*\//;
|
||||
// Used to test whether a string starts with a blank line.
|
||||
const BLANK_LINE_RX = /^[ \t]*(?:\r\n|\n|\r|\f|$)/;
|
||||
|
||||
/**
|
||||
* Return an object that can be used to rewrite declarations in some
|
||||
* source text. The source text and parsing are handled in the same
|
||||
* way as @see parseNamedDeclarations, with |parseComments| being true.
|
||||
* Rewriting is done by calling one of the modification functions like
|
||||
* setPropertyEnabled. The returned object has the same interface
|
||||
* as @see RuleModificationList.
|
||||
*
|
||||
* An example showing how to disable the 3rd property in a rule:
|
||||
*
|
||||
* let rewriter = new RuleRewriter(isCssPropertyKnown, ruleActor,
|
||||
* ruleActor.authoredText);
|
||||
* rewriter.setPropertyEnabled(3, "color", false);
|
||||
* rewriter.apply().then(() => { ... the change is made ... });
|
||||
*
|
||||
* The exported rewriting methods are |renameProperty|, |setPropertyEnabled|,
|
||||
* |createProperty|, |setProperty|, and |removeProperty|. The |apply|
|
||||
* method can be used to send the edited text to the StyleRuleActor;
|
||||
* |getDefaultIndentation| is useful for the methods requiring a
|
||||
* default indentation value; and |getResult| is useful for testing.
|
||||
*
|
||||
* Additionally, editing will set the |changedDeclarations| property
|
||||
* on this object. This property has the same form as the |changed|
|
||||
* property of the object returned by |getResult|.
|
||||
*
|
||||
* @param {Function} isCssPropertyKnown
|
||||
* A function to check if the CSS property is known. This is either an
|
||||
* internal server function or from the CssPropertiesFront.
|
||||
* that are supported by the server. Note that if Bug 1222047
|
||||
* is completed then isCssPropertyKnown will not need to be passed in.
|
||||
* The CssProperty front will be able to obtained directly from the
|
||||
* RuleRewriter.
|
||||
* @param {StyleRuleFront} rule The style rule to use. Note that this
|
||||
* is only needed by the |apply| and |getDefaultIndentation| methods;
|
||||
* and in particular for testing it can be |null|.
|
||||
* @param {String} inputString The CSS source text to parse and modify.
|
||||
* @return {Object} an object that can be used to rewrite the input text.
|
||||
*/
|
||||
function RuleRewriter(isCssPropertyKnown, rule, inputString) {
|
||||
this.rule = rule;
|
||||
this.isCssPropertyKnown = isCssPropertyKnown;
|
||||
// The RuleRewriter sends CSS rules as text to the server, but with this modifications
|
||||
// array, it also sends the list of changes so the server doesn't have to re-parse the
|
||||
// rule if it needs to track what changed.
|
||||
this.modifications = [];
|
||||
|
||||
// Keep track of which any declarations we had to rewrite while
|
||||
// performing the requested action.
|
||||
this.changedDeclarations = {};
|
||||
|
||||
// If not null, a promise that must be wait upon before |apply| can
|
||||
// do its work.
|
||||
this.editPromise = null;
|
||||
|
||||
// If the |defaultIndentation| property is set, then it is used;
|
||||
// otherwise the RuleRewriter will try to compute the default
|
||||
// indentation based on the style sheet's text. This override
|
||||
// facility is for testing.
|
||||
this.defaultIndentation = null;
|
||||
|
||||
this.startInitialization(inputString);
|
||||
}
|
||||
|
||||
RuleRewriter.prototype = {
|
||||
/**
|
||||
* An internal function to initialize the rewriter with a given
|
||||
* input string.
|
||||
*
|
||||
* @param {String} inputString the input to use
|
||||
*/
|
||||
startInitialization: function(inputString) {
|
||||
this.inputString = inputString;
|
||||
// Whether there are any newlines in the input text.
|
||||
this.hasNewLine = /[\r\n]/.test(this.inputString);
|
||||
// The declarations.
|
||||
this.declarations = parseNamedDeclarations(this.isCssPropertyKnown, this.inputString,
|
||||
true);
|
||||
this.decl = null;
|
||||
this.result = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to complete initialization and set some
|
||||
* properties for further processing.
|
||||
*
|
||||
* @param {Number} index The index of the property to modify
|
||||
*/
|
||||
completeInitialization: function(index) {
|
||||
if (index < 0) {
|
||||
throw new Error("Invalid index " + index + ". Expected positive integer");
|
||||
}
|
||||
// |decl| is the declaration to be rewritten, or null if there is no
|
||||
// declaration corresponding to |index|.
|
||||
// |result| is used to accumulate the result text.
|
||||
if (index < this.declarations.length) {
|
||||
this.decl = this.declarations[index];
|
||||
this.result = this.inputString.substring(0, this.decl.offsets[0]);
|
||||
} else {
|
||||
this.decl = null;
|
||||
this.result = this.inputString;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper function to compute the indentation of some text. This
|
||||
* examines the rule's existing text to guess the indentation to use;
|
||||
* unlike |getDefaultIndentation|, which examines the entire style
|
||||
* sheet.
|
||||
*
|
||||
* @param {String} string the input text
|
||||
* @param {Number} offset the offset at which to compute the indentation
|
||||
* @return {String} the indentation at the indicated position
|
||||
*/
|
||||
getIndentation: function(string, offset) {
|
||||
let originalOffset = offset;
|
||||
for (--offset; offset >= 0; --offset) {
|
||||
const c = string[offset];
|
||||
if (c === "\r" || c === "\n" || c === "\f") {
|
||||
return string.substring(offset + 1, originalOffset);
|
||||
}
|
||||
if (c !== " " && c !== "\t") {
|
||||
// Found some non-whitespace character before we found a newline
|
||||
// -- let's reset the starting point and keep going, as we saw
|
||||
// something on the line before the declaration.
|
||||
originalOffset = offset;
|
||||
}
|
||||
}
|
||||
// Ran off the end.
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Modify a property value to ensure it is "lexically safe" for
|
||||
* insertion into a style sheet. This function doesn't attempt to
|
||||
* ensure that the resulting text is a valid value for the given
|
||||
* property; but rather just that inserting the text into the style
|
||||
* sheet will not cause unwanted changes to other rules or
|
||||
* declarations.
|
||||
*
|
||||
* @param {String} text The input text. This should include the trailing ";".
|
||||
* @return {Array} An array of the form [anySanitized, text], where
|
||||
* |anySanitized| is a boolean that indicates
|
||||
* whether anything substantive has changed; and
|
||||
* where |text| is the text that has been rewritten
|
||||
* to be "lexically safe".
|
||||
*/
|
||||
sanitizePropertyValue: function(text) {
|
||||
// Start by stripping any trailing ";". This is done here to
|
||||
// avoid the case where the user types "url(" (which is turned
|
||||
// into "url(;" by the rule view before coming here), being turned
|
||||
// into "url(;)" by this code -- due to the way "url(...)" is
|
||||
// parsed as a single token.
|
||||
text = text.replace(/;$/, "");
|
||||
const lexer = getCSSLexer(text);
|
||||
|
||||
let result = "";
|
||||
let previousOffset = 0;
|
||||
const parenStack = [];
|
||||
let anySanitized = false;
|
||||
|
||||
// Push a closing paren on the stack.
|
||||
const pushParen = (token, closer) => {
|
||||
result = result + text.substring(previousOffset, token.startOffset) +
|
||||
text.substring(token.startOffset, token.endOffset);
|
||||
// We set the location of the paren in a funny way, to handle
|
||||
// the case where we've seen a function token, where the paren
|
||||
// appears at the end.
|
||||
parenStack.push({closer, offset: result.length - 1});
|
||||
previousOffset = token.endOffset;
|
||||
};
|
||||
|
||||
// Pop a closing paren from the stack.
|
||||
const popSomeParens = (closer) => {
|
||||
while (parenStack.length > 0) {
|
||||
const paren = parenStack.pop();
|
||||
|
||||
if (paren.closer === closer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Found a non-matching closing paren, so quote it. Note that
|
||||
// these are processed in reverse order.
|
||||
result = result.substring(0, paren.offset) + "\\" +
|
||||
result.substring(paren.offset);
|
||||
anySanitized = true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const token = lexer.nextToken();
|
||||
if (!token) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (token.tokenType === "symbol") {
|
||||
switch (token.text) {
|
||||
case ";":
|
||||
// We simply drop the ";" here. This lets us cope with
|
||||
// declarations that don't have a ";" and also other
|
||||
// termination. The caller handles adding the ";" again.
|
||||
result += text.substring(previousOffset, token.startOffset);
|
||||
previousOffset = token.endOffset;
|
||||
break;
|
||||
|
||||
case "{":
|
||||
pushParen(token, "}");
|
||||
break;
|
||||
|
||||
case "(":
|
||||
pushParen(token, ")");
|
||||
break;
|
||||
|
||||
case "[":
|
||||
pushParen(token, "]");
|
||||
break;
|
||||
|
||||
case "}":
|
||||
case ")":
|
||||
case "]":
|
||||
// Did we find an unmatched close bracket?
|
||||
if (!popSomeParens(token.text)) {
|
||||
// Copy out text from |previousOffset|.
|
||||
result += text.substring(previousOffset, token.startOffset);
|
||||
// Quote the offending symbol.
|
||||
result += "\\" + token.text;
|
||||
previousOffset = token.endOffset;
|
||||
anySanitized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (token.tokenType === "function") {
|
||||
pushParen(token, ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Fix up any unmatched parens.
|
||||
popSomeParens(null);
|
||||
|
||||
// Copy out any remaining text, then any needed terminators.
|
||||
result += text.substring(previousOffset, text.length);
|
||||
const eofFixup = lexer.performEOFFixup("", true);
|
||||
if (eofFixup) {
|
||||
anySanitized = true;
|
||||
result += eofFixup;
|
||||
}
|
||||
return [anySanitized, result];
|
||||
},
|
||||
|
||||
/**
|
||||
* Start at |index| and skip whitespace
|
||||
* backward in |string|. Return the index of the first
|
||||
* non-whitespace character, or -1 if the entire string was
|
||||
* whitespace.
|
||||
* @param {String} string the input string
|
||||
* @param {Number} index the index at which to start
|
||||
* @return {Number} index of the first non-whitespace character, or -1
|
||||
*/
|
||||
skipWhitespaceBackward: function(string, index) {
|
||||
for (--index;
|
||||
index >= 0 && (string[index] === " " || string[index] === "\t");
|
||||
--index) {
|
||||
// Nothing.
|
||||
}
|
||||
return index;
|
||||
},
|
||||
|
||||
/**
|
||||
* Terminate a given declaration, if needed.
|
||||
*
|
||||
* @param {Number} index The index of the rule to possibly
|
||||
* terminate. It might be invalid, so this
|
||||
* function must check for that.
|
||||
*/
|
||||
maybeTerminateDecl: function(index) {
|
||||
if (index < 0 || index >= this.declarations.length
|
||||
// No need to rewrite declarations in comments.
|
||||
|| ("commentOffsets" in this.declarations[index])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const termDecl = this.declarations[index];
|
||||
let endIndex = termDecl.offsets[1];
|
||||
// Due to an oddity of the lexer, we might have gotten a bit of
|
||||
// extra whitespace in a trailing bad_url token -- so be sure to
|
||||
// skip that as well.
|
||||
endIndex = this.skipWhitespaceBackward(this.result, endIndex) + 1;
|
||||
|
||||
const trailingText = this.result.substring(endIndex);
|
||||
if (termDecl.terminator) {
|
||||
// Insert the terminator just at the end of the declaration,
|
||||
// before any trailing whitespace.
|
||||
this.result = this.result.substring(0, endIndex) + termDecl.terminator +
|
||||
trailingText;
|
||||
// In a couple of cases, we may have had to add something to
|
||||
// terminate the declaration, but the termination did not
|
||||
// actually affect the property's value -- and at this spot, we
|
||||
// only care about reporting value changes. In particular, we
|
||||
// might have added a plain ";", or we might have terminated a
|
||||
// comment with "*/;". Neither of these affect the value.
|
||||
if (termDecl.terminator !== ";" && termDecl.terminator !== "*/;") {
|
||||
this.changedDeclarations[index] =
|
||||
termDecl.value + termDecl.terminator.slice(0, -1);
|
||||
}
|
||||
}
|
||||
// If the rule generally has newlines, but this particular
|
||||
// declaration doesn't have a trailing newline, insert one now.
|
||||
// Maybe this style is too weird to bother with.
|
||||
if (this.hasNewLine && !NEWLINE_RX.test(trailingText)) {
|
||||
this.result += "\n";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitize the given property value and return the sanitized form.
|
||||
* If the property is rewritten during sanitization, make a note in
|
||||
* |changedDeclarations|.
|
||||
*
|
||||
* @param {String} text The property text.
|
||||
* @param {Number} index The index of the property.
|
||||
* @return {String} The sanitized text.
|
||||
*/
|
||||
sanitizeText: function(text, index) {
|
||||
const [anySanitized, sanitizedText] = this.sanitizePropertyValue(text);
|
||||
if (anySanitized) {
|
||||
this.changedDeclarations[index] = sanitizedText;
|
||||
}
|
||||
return sanitizedText;
|
||||
},
|
||||
|
||||
/**
|
||||
* Rename a declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name current name of the property
|
||||
* @param {String} newName new name of the property
|
||||
*/
|
||||
renameProperty: function(index, name, newName) {
|
||||
this.completeInitialization(index);
|
||||
this.result += CSS.escape(newName);
|
||||
// We could conceivably compute the name offsets instead so we
|
||||
// could preserve white space and comments on the LHS of the ":".
|
||||
this.completeCopying(this.decl.colonOffsets[0]);
|
||||
this.modifications.push({ type: "set", index, name, newName });
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable or disable a declaration
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name current name of the property
|
||||
* @param {Boolean} isEnabled true if the property should be enabled;
|
||||
* false if it should be disabled
|
||||
*/
|
||||
setPropertyEnabled: function(index, name, isEnabled) {
|
||||
this.completeInitialization(index);
|
||||
const decl = this.decl;
|
||||
const priority = decl.priority;
|
||||
let copyOffset = decl.offsets[1];
|
||||
if (isEnabled) {
|
||||
// Enable it. First see if the comment start can be deleted.
|
||||
const commentStart = decl.commentOffsets[0];
|
||||
if (EMPTY_COMMENT_START_RX.test(this.result.substring(commentStart))) {
|
||||
this.result = this.result.substring(0, commentStart);
|
||||
} else {
|
||||
this.result += "*/ ";
|
||||
}
|
||||
|
||||
// Insert the name and value separately, so we can report
|
||||
// sanitization changes properly.
|
||||
const commentNamePart =
|
||||
this.inputString.substring(decl.offsets[0],
|
||||
decl.colonOffsets[1]);
|
||||
this.result += unescapeCSSComment(commentNamePart);
|
||||
|
||||
// When uncommenting, we must be sure to sanitize the text, to
|
||||
// avoid things like /* decl: }; */, which will be accepted as
|
||||
// a property but which would break the entire style sheet.
|
||||
let newText = this.inputString.substring(decl.colonOffsets[1],
|
||||
decl.offsets[1]);
|
||||
newText = cssTrimRight(unescapeCSSComment(newText));
|
||||
this.result += this.sanitizeText(newText, index) + ";";
|
||||
|
||||
// See if the comment end can be deleted.
|
||||
const trailingText = this.inputString.substring(decl.offsets[1]);
|
||||
if (EMPTY_COMMENT_END_RX.test(trailingText)) {
|
||||
copyOffset = decl.commentOffsets[1];
|
||||
} else {
|
||||
this.result += " /*";
|
||||
}
|
||||
} else {
|
||||
// Disable it. Note that we use our special comment syntax
|
||||
// here.
|
||||
const declText = this.inputString.substring(decl.offsets[0],
|
||||
decl.offsets[1]);
|
||||
this.result += "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR +
|
||||
" " + escapeCSSComment(declText) + " */";
|
||||
}
|
||||
this.completeCopying(copyOffset);
|
||||
|
||||
if (isEnabled) {
|
||||
this.modifications.push({ type: "set", index, name, value: decl.value, priority });
|
||||
} else {
|
||||
this.modifications.push({ type: "disable", index, name });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise that will be resolved to the default indentation
|
||||
* of the rule. This is a helper for internalCreateProperty.
|
||||
*
|
||||
* @return {Promise} a promise that will be resolved to a string
|
||||
* that holds the default indentation that should be used
|
||||
* for edits to the rule.
|
||||
*/
|
||||
getDefaultIndentation: function() {
|
||||
return this.rule.parentStyleSheet.guessIndentation();
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to create a new declaration. This does all
|
||||
* the work of |createProperty|.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name name of the new property
|
||||
* @param {String} value value of the new property
|
||||
* @param {String} priority priority of the new property; either
|
||||
* the empty string or "important"
|
||||
* @param {Boolean} enabled True if the new property should be
|
||||
* enabled, false if disabled
|
||||
* @return {Promise} a promise that is resolved when the edit has
|
||||
* completed
|
||||
*/
|
||||
async internalCreateProperty(index, name, value, priority, enabled) {
|
||||
this.completeInitialization(index);
|
||||
let newIndentation = "";
|
||||
if (this.hasNewLine) {
|
||||
if (this.declarations.length > 0) {
|
||||
newIndentation = this.getIndentation(this.inputString,
|
||||
this.declarations[0].offsets[0]);
|
||||
} else if (this.defaultIndentation) {
|
||||
newIndentation = this.defaultIndentation;
|
||||
} else {
|
||||
newIndentation = await this.getDefaultIndentation();
|
||||
}
|
||||
}
|
||||
|
||||
this.maybeTerminateDecl(index - 1);
|
||||
|
||||
// If we generally have newlines, and if skipping whitespace
|
||||
// backward stops at a newline, then insert our text before that
|
||||
// whitespace. This ensures the indentation we computed is what
|
||||
// is actually used.
|
||||
let savedWhitespace = "";
|
||||
if (this.hasNewLine) {
|
||||
const wsOffset = this.skipWhitespaceBackward(this.result,
|
||||
this.result.length);
|
||||
if (this.result[wsOffset] === "\r" || this.result[wsOffset] === "\n") {
|
||||
savedWhitespace = this.result.substring(wsOffset + 1);
|
||||
this.result = this.result.substring(0, wsOffset + 1);
|
||||
}
|
||||
}
|
||||
|
||||
let newText = CSS.escape(name) + ": " + this.sanitizeText(value, index);
|
||||
if (priority === "important") {
|
||||
newText += " !important";
|
||||
}
|
||||
newText += ";";
|
||||
|
||||
if (!enabled) {
|
||||
newText = "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR + " " +
|
||||
escapeCSSComment(newText) + " */";
|
||||
}
|
||||
|
||||
this.result += newIndentation + newText;
|
||||
if (this.hasNewLine) {
|
||||
this.result += "\n";
|
||||
}
|
||||
this.result += savedWhitespace;
|
||||
|
||||
if (this.decl) {
|
||||
// Still want to copy in the declaration previously at this
|
||||
// index.
|
||||
this.completeCopying(this.decl.offsets[0]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name name of the new property
|
||||
* @param {String} value value of the new property
|
||||
* @param {String} priority priority of the new property; either
|
||||
* the empty string or "important"
|
||||
* @param {Boolean} enabled True if the new property should be
|
||||
* enabled, false if disabled
|
||||
*/
|
||||
createProperty: function(index, name, value, priority, enabled) {
|
||||
this.editPromise = this.internalCreateProperty(index, name, value, priority, enabled);
|
||||
// Log the modification only if the created property is enabled.
|
||||
if (enabled) {
|
||||
this.modifications.push({ type: "set", index, name, value, priority });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a declaration's value.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* This can be -1 in the case where
|
||||
* the rule does not support setRuleText;
|
||||
* generally for setting properties
|
||||
* on an element's style.
|
||||
* @param {String} name the property's name
|
||||
* @param {String} value the property's value
|
||||
* @param {String} priority the property's priority, either the empty
|
||||
* string or "important"
|
||||
*/
|
||||
setProperty: function(index, name, value, priority) {
|
||||
this.completeInitialization(index);
|
||||
// We might see a "set" on a previously non-existent property; in
|
||||
// that case, act like "create".
|
||||
if (!this.decl) {
|
||||
this.createProperty(index, name, value, priority, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that this assumes that "set" never operates on disabled
|
||||
// properties.
|
||||
this.result += this.inputString.substring(this.decl.offsets[0],
|
||||
this.decl.colonOffsets[1]) +
|
||||
this.sanitizeText(value, index);
|
||||
|
||||
if (priority === "important") {
|
||||
this.result += " !important";
|
||||
}
|
||||
this.result += ";";
|
||||
this.completeCopying(this.decl.offsets[1]);
|
||||
this.modifications.push({ type: "set", index, name, value, priority });
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a declaration.
|
||||
*
|
||||
* @param {Number} index index of the property in the rule.
|
||||
* @param {String} name the name of the property to remove
|
||||
*/
|
||||
removeProperty: function(index, name) {
|
||||
this.completeInitialization(index);
|
||||
|
||||
// If asked to remove a property that does not exist, bail out.
|
||||
if (!this.decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the property is disabled, then first enable it, and then
|
||||
// delete it. We take this approach because we want to remove the
|
||||
// entire comment if possible; but the logic for dealing with
|
||||
// comments is hairy and already implemented in
|
||||
// setPropertyEnabled.
|
||||
if (this.decl.commentOffsets) {
|
||||
this.setPropertyEnabled(index, name, true);
|
||||
this.startInitialization(this.result);
|
||||
this.completeInitialization(index);
|
||||
}
|
||||
|
||||
let copyOffset = this.decl.offsets[1];
|
||||
// Maybe removing this rule left us with a completely blank
|
||||
// line. In this case, we'll delete the whole thing. We only
|
||||
// bother with this if we're looking at sources that already
|
||||
// have a newline somewhere.
|
||||
if (this.hasNewLine) {
|
||||
const nlOffset = this.skipWhitespaceBackward(this.result,
|
||||
this.decl.offsets[0]);
|
||||
if (nlOffset < 0 || this.result[nlOffset] === "\r" ||
|
||||
this.result[nlOffset] === "\n") {
|
||||
const trailingText = this.inputString.substring(copyOffset);
|
||||
const match = BLANK_LINE_RX.exec(trailingText);
|
||||
if (match) {
|
||||
this.result = this.result.substring(0, nlOffset + 1);
|
||||
copyOffset += match[0].length;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.completeCopying(copyOffset);
|
||||
this.modifications.push({ type: "remove", index, name });
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to copy any trailing text to the output
|
||||
* string.
|
||||
*
|
||||
* @param {Number} copyOffset Offset into |inputString| of the
|
||||
* final text to copy to the output string.
|
||||
*/
|
||||
completeCopying: function(copyOffset) {
|
||||
// Add the trailing text.
|
||||
this.result += this.inputString.substring(copyOffset);
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply the modifications in this object to the associated rule.
|
||||
*
|
||||
* @return {Promise} A promise which will be resolved when the modifications
|
||||
* are complete.
|
||||
*/
|
||||
apply: function() {
|
||||
return promise.resolve(this.editPromise).then(() => {
|
||||
return this.rule.setRuleText(this.result, this.modifications);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the result of the rewriting. This is used for testing.
|
||||
*
|
||||
* @return {object} an object of the form {changed: object, text: string}
|
||||
* |changed| is an object where each key is
|
||||
* the index of a property whose value had to be
|
||||
* rewritten during the sanitization process, and
|
||||
* whose value is the new text of the property.
|
||||
* |text| is the rewritten text of the rule.
|
||||
*/
|
||||
getResult: function() {
|
||||
return {changed: this.changedDeclarations, text: this.result};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Like trimRight, but only trims CSS-allowed whitespace.
|
||||
*/
|
||||
function cssTrimRight(str) {
|
||||
const match = /^(.*?)[ \t\r\n\f]*$/.exec(str);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
module.exports = RuleRewriter;
|
|
@ -13,8 +13,7 @@ const {
|
|||
} = require("devtools/shared/specs/styles");
|
||||
const promise = require("promise");
|
||||
|
||||
loader.lazyRequireGetter(this, "RuleRewriter",
|
||||
"devtools/shared/css/parsing-utils", true);
|
||||
loader.lazyRequireGetter(this, "RuleRewriter", "devtools/shared/fronts/inspector/rule-rewriter");
|
||||
|
||||
/**
|
||||
* PageStyleFront, the front object for the PageStyleActor
|
||||
|
|
|
@ -434,8 +434,7 @@ def run_test_remote(test, device, prefix, options):
|
|||
except ADBTimeoutError:
|
||||
raise
|
||||
except ADBProcessError as e:
|
||||
out = e.adb_process.stdout
|
||||
print("exception output: %s" % str(out))
|
||||
out = str(e.adb_process.stdout)
|
||||
returncode = e.adb_process.exitcode
|
||||
|
||||
elapsed = (datetime.now() - start).total_seconds()
|
||||
|
|
|
@ -36,7 +36,7 @@ fuzzy-if(asyncPan&&!layersGPUAccelerated,0-149,0-4520) == less-than-scrollbar-he
|
|||
== huge-vertical-overflow.html huge-vertical-overflow-ref.html
|
||||
fuzzy-if(asyncPan&&!layersGPUAccelerated,0-102,0-6818) == iframe-scrolling-attr-1.html iframe-scrolling-attr-ref.html
|
||||
fuzzy-if(asyncPan&&!layersGPUAccelerated,0-140,0-6818) == iframe-scrolling-attr-2.html iframe-scrolling-attr-ref.html
|
||||
== frame-scrolling-attr-1.html frame-scrolling-attr-ref.html
|
||||
fuzzy(0-1,0-2) == frame-scrolling-attr-1.html frame-scrolling-attr-ref.html
|
||||
fuzzy-if(asyncPan&&!layersGPUAccelerated,0-102,0-2420) == frame-scrolling-attr-2.html frame-scrolling-attr-ref.html
|
||||
== move-item.html move-item-ref.html # bug 1125750
|
||||
== fractional-scroll-area.html?top=-0.4&outerBottom=100&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
|
||||
|
|
|
@ -441,7 +441,8 @@ class Bootstrapper(object):
|
|||
|
||||
hg_installed, hg_modern = self.instance.ensure_mercurial_modern()
|
||||
self.instance.ensure_python_modern()
|
||||
self.instance.ensure_rust_modern()
|
||||
if not self.instance.artifact_mode:
|
||||
self.instance.ensure_rust_modern()
|
||||
|
||||
state_dir_available, state_dir = self.try_to_create_state_dir()
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
NSS_3_42_RTM
|
||||
d0a282507d59
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
Function symbols changes summary: 2 Removed, 0 Added function symbols not referenced by debug info
|
||||
Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info
|
||||
|
||||
2 Removed function symbols not referenced by debug info:
|
||||
|
||||
_fini
|
||||
_init
|
||||
|
|
@ -1 +1 @@
|
|||
NSS_3_41_BRANCH
|
||||
NSS_3_42_BRANCH
|
||||
|
|
|
@ -50,7 +50,6 @@ fuzz=0
|
|||
fuzz_tls=0
|
||||
fuzz_oss=0
|
||||
no_local_nspr=0
|
||||
sslkeylogfile=1
|
||||
|
||||
gyp_params=(--depth="$cwd" --generator-output=".")
|
||||
ninja_params=()
|
||||
|
@ -104,7 +103,6 @@ while [ $# -gt 0 ]; do
|
|||
--enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
|
||||
--enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;;
|
||||
--mozpkix-only) gyp_params+=(-Dmozpkix_only=1 -Ddisable_tests=1 -Dsign_libs=0) ;;
|
||||
--disable-keylog) sslkeylogfile=0 ;;
|
||||
*) show_help; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
|
@ -118,8 +116,6 @@ else
|
|||
target=Debug
|
||||
fi
|
||||
|
||||
gyp_params+=(-Denable_sslkeylogfile="$sslkeylogfile")
|
||||
|
||||
# Do special setup.
|
||||
if [ "$fuzz" = 1 ]; then
|
||||
source "$cwd"/coreconf/fuzz.sh
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -36,12 +36,6 @@ CPPSRCS := $(filter-out $(shell grep -l '^TEST_F' $(CPPSRCS)), $(CPPSRCS))
|
|||
CFLAGS += -DNSS_DISABLE_TLS_1_3
|
||||
endif
|
||||
|
||||
ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
SSLKEYLOGFILE_FILES = ssl_keylog_unittest.cc
|
||||
else
|
||||
SSLKEYLOGFILE_FILES = $(NULL)
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
|
|
@ -20,7 +20,6 @@ CPPSRCS = \
|
|||
ssl_ciphersuite_unittest.cc \
|
||||
ssl_custext_unittest.cc \
|
||||
ssl_damage_unittest.cc \
|
||||
ssl_debug_env_unittest.cc \
|
||||
ssl_dhe_unittest.cc \
|
||||
ssl_drop_unittest.cc \
|
||||
ssl_ecdh_unittest.cc \
|
||||
|
@ -32,6 +31,7 @@ CPPSRCS = \
|
|||
ssl_gather_unittest.cc \
|
||||
ssl_gtest.cc \
|
||||
ssl_hrr_unittest.cc \
|
||||
ssl_keylog_unittest.cc \
|
||||
ssl_keyupdate_unittest.cc \
|
||||
ssl_loopback_unittest.cc \
|
||||
ssl_misc_unittest.cc \
|
||||
|
@ -53,7 +53,6 @@ CPPSRCS = \
|
|||
tls_filter.cc \
|
||||
tls_protect.cc \
|
||||
tls_esni_unittest.cc \
|
||||
$(SSLKEYLOGFILE_FILES) \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
extern "C" {
|
||||
extern FILE* ssl_trace_iob;
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
extern FILE* ssl_keylog_iob;
|
||||
#endif
|
||||
}
|
||||
|
||||
// These tests ensure that when the associated environment variables are unset
|
||||
// that the lazily-initialized defaults are what they are supposed to be.
|
||||
|
||||
#ifdef DEBUG
|
||||
TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLDEBUGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
}
|
||||
|
||||
Connect();
|
||||
EXPECT_EQ(stderr, ssl_trace_iob);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
TEST_P(TlsConnectGeneric, DebugEnvKeylogFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLKEYLOGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
}
|
||||
|
||||
Connect();
|
||||
EXPECT_EQ(nullptr, ssl_keylog_iob);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
|
@ -21,7 +21,6 @@
|
|||
'ssl_ciphersuite_unittest.cc',
|
||||
'ssl_custext_unittest.cc',
|
||||
'ssl_damage_unittest.cc',
|
||||
'ssl_debug_env_unittest.cc',
|
||||
'ssl_dhe_unittest.cc',
|
||||
'ssl_drop_unittest.cc',
|
||||
'ssl_ecdh_unittest.cc',
|
||||
|
@ -33,6 +32,7 @@
|
|||
'ssl_gather_unittest.cc',
|
||||
'ssl_gtest.cc',
|
||||
'ssl_hrr_unittest.cc',
|
||||
'ssl_keylog_unittest.cc',
|
||||
'ssl_keyupdate_unittest.cc',
|
||||
'ssl_loopback_unittest.cc',
|
||||
'ssl_misc_unittest.cc',
|
||||
|
@ -91,14 +91,6 @@
|
|||
'<(DEPTH)/lib/dbm/src/src.gyp:dbm',
|
||||
],
|
||||
}],
|
||||
[ 'enable_sslkeylogfile==1', {
|
||||
'sources': [
|
||||
'ssl_keylog_unittest.cc',
|
||||
],
|
||||
'defines': [
|
||||
'NSS_ALLOW_SSLKEYLOGFILE',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
],
|
||||
|
@ -107,7 +99,7 @@
|
|||
'../../lib/ssl'
|
||||
],
|
||||
'defines': [
|
||||
'NSS_USE_STATIC_LIBS',
|
||||
'NSS_USE_STATIC_LIBS'
|
||||
],
|
||||
},
|
||||
'variables': {
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* 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/. */
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
@ -13,59 +15,20 @@
|
|||
|
||||
namespace nss_test {
|
||||
|
||||
static const std::string kKeylogFilePath = "keylog.txt";
|
||||
static const std::string kKeylogBlankEnv = "SSLKEYLOGFILE=";
|
||||
static const std::string kKeylogSetEnv = kKeylogBlankEnv + kKeylogFilePath;
|
||||
|
||||
extern "C" {
|
||||
extern FILE* ssl_keylog_iob;
|
||||
}
|
||||
|
||||
class KeyLogFileTestBase : public TlsConnectGeneric {
|
||||
private:
|
||||
std::string env_to_set_;
|
||||
static const std::string keylog_file_path = "keylog.txt";
|
||||
static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;
|
||||
|
||||
class KeyLogFileTest : public TlsConnectGeneric {
|
||||
public:
|
||||
virtual void CheckKeyLog() = 0;
|
||||
|
||||
KeyLogFileTestBase(std::string env) : env_to_set_(env) {}
|
||||
|
||||
void SetUp() override {
|
||||
TlsConnectGeneric::SetUp();
|
||||
// Remove previous results (if any).
|
||||
(void)remove(kKeylogFilePath.c_str());
|
||||
PR_SetEnv(env_to_set_.c_str());
|
||||
(void)remove(keylog_file_path.c_str());
|
||||
PR_SetEnv(keylog_env.c_str());
|
||||
}
|
||||
|
||||
void ConnectAndCheck() {
|
||||
// This is a child process, ensure that error messages immediately
|
||||
// propagate or else it will not be visible.
|
||||
::testing::GTEST_FLAG(throw_on_failure) = true;
|
||||
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
} else {
|
||||
Connect();
|
||||
}
|
||||
CheckKeyLog();
|
||||
_exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
class KeyLogFileTest : public KeyLogFileTestBase {
|
||||
public:
|
||||
KeyLogFileTest() : KeyLogFileTestBase(kKeylogSetEnv) {}
|
||||
|
||||
void CheckKeyLog() override {
|
||||
std::ifstream f(kKeylogFilePath);
|
||||
void CheckKeyLog() {
|
||||
std::ifstream f(keylog_file_path);
|
||||
std::map<std::string, size_t> labels;
|
||||
std::set<std::string> client_randoms;
|
||||
for (std::string line; std::getline(f, line);) {
|
||||
|
@ -102,6 +65,28 @@ class KeyLogFileTest : public KeyLogFileTestBase {
|
|||
ASSERT_EQ(4U, labels["EXPORTER_SECRET"]);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectAndCheck() {
|
||||
// This is a child process, ensure that error messages immediately
|
||||
// propagate or else it will not be visible.
|
||||
::testing::GTEST_FLAG(throw_on_failure) = true;
|
||||
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
} else {
|
||||
Connect();
|
||||
}
|
||||
CheckKeyLog();
|
||||
_exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Tests are run in a separate process to ensure that NSS is not initialized yet
|
||||
|
@ -128,37 +113,6 @@ INSTANTIATE_TEST_CASE_P(
|
|||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
class KeyLogFileUnsetTest : public KeyLogFileTestBase {
|
||||
public:
|
||||
KeyLogFileUnsetTest() : KeyLogFileTestBase(kKeylogBlankEnv) {}
|
||||
|
||||
void CheckKeyLog() override {
|
||||
std::ifstream f(kKeylogFilePath);
|
||||
EXPECT_FALSE(f.good());
|
||||
|
||||
EXPECT_EQ(nullptr, ssl_keylog_iob);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(KeyLogFileUnsetTest, KeyLogFile) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
|
||||
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileDTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileTLS13, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
#endif // NSS_ALLOW_SSLKEYLOGFILE
|
||||
|
|
|
@ -51,5 +51,3 @@ NSS build tool options:
|
|||
--enable-libpkix make libpkix part of the build
|
||||
--mozpkix-only build only static mozpkix and mozpkix-test libraries
|
||||
support for this build option is limited
|
||||
--disable-keylog enable support for logging key data to a file specified
|
||||
by the SSLKEYLOGFILE environment variable
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
|
||||
*/
|
||||
#define NSS_VERSION "3.42" _NSS_CUSTOMIZED
|
||||
#define NSS_VERSION "3.43" _NSS_CUSTOMIZED " Beta"
|
||||
#define NSS_VMAJOR 3
|
||||
#define NSS_VMINOR 42
|
||||
#define NSS_VMINOR 43
|
||||
#define NSS_VPATCH 0
|
||||
#define NSS_VBUILD 0
|
||||
#define NSS_BETA PR_FALSE
|
||||
#define NSS_BETA PR_TRUE
|
||||
|
||||
#ifndef RC_INVOKED
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo)
|
|||
{
|
||||
SECOidTag kind;
|
||||
|
||||
if (cinfo == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
kind = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
|
||||
switch (kind) {
|
||||
case SEC_OID_PKCS7_ENVELOPED_DATA:
|
||||
|
@ -86,6 +90,11 @@ NSSCMSContentInfo *
|
|||
NSS_CMSContentInfo_GetChildContentInfo(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
NSSCMSContentInfo *ccinfo = NULL;
|
||||
|
||||
if (cinfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SECOidTag tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
|
||||
switch (tag) {
|
||||
case SEC_OID_PKCS7_SIGNED_DATA:
|
||||
|
@ -127,6 +136,9 @@ SECStatus
|
|||
NSS_CMSContentInfo_SetDontStream(NSSCMSContentInfo *cinfo, PRBool dontStream)
|
||||
{
|
||||
SECStatus rv;
|
||||
if (cinfo == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = NSS_CMSContentInfo_Private_Init(cinfo);
|
||||
if (rv != SECSuccess) {
|
||||
|
@ -145,15 +157,20 @@ NSS_CMSContentInfo_SetContent(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo,
|
|||
SECOidTag type, void *ptr)
|
||||
{
|
||||
SECStatus rv;
|
||||
if (cinfo == NULL || cmsg == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
cinfo->contentTypeTag = SECOID_FindOIDByTag(type);
|
||||
if (cinfo->contentTypeTag == NULL)
|
||||
if (cinfo->contentTypeTag == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* do not copy the oid, just create a reference */
|
||||
rv = SECITEM_CopyItem(cmsg->poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid));
|
||||
if (rv != SECSuccess)
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
cinfo->content.pointer = ptr;
|
||||
|
||||
|
@ -185,8 +202,9 @@ SECStatus
|
|||
NSS_CMSContentInfo_SetContent_Data(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo,
|
||||
SECItem *data, PRBool detached)
|
||||
{
|
||||
if (NSS_CMSContentInfo_SetContent(cmsg, cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess)
|
||||
if (NSS_CMSContentInfo_SetContent(cmsg, cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (detached) {
|
||||
cinfo->rawContent = NULL;
|
||||
}
|
||||
|
@ -230,6 +248,10 @@ NSS_CMSContentInfo_SetContent_EncryptedData(NSSCMSMessage *cmsg, NSSCMSContentIn
|
|||
void *
|
||||
NSS_CMSContentInfo_GetContent(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SECOidTag tag = cinfo->contentTypeTag
|
||||
? cinfo->contentTypeTag->offset
|
||||
: SEC_OID_UNKNOWN;
|
||||
|
@ -260,6 +282,10 @@ NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo)
|
|||
SECOidTag tag;
|
||||
SECItem *pItem = NULL;
|
||||
|
||||
if (cinfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
|
||||
if (NSS_CMSType_IsData(tag)) {
|
||||
pItem = cinfo->content.data;
|
||||
|
@ -282,6 +308,10 @@ NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo)
|
|||
SECOidTag
|
||||
NSS_CMSContentInfo_GetContentTypeTag(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo == NULL) {
|
||||
return SEC_OID_UNKNOWN;
|
||||
}
|
||||
|
||||
if (cinfo->contentTypeTag == NULL)
|
||||
cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
|
||||
|
||||
|
@ -294,11 +324,17 @@ NSS_CMSContentInfo_GetContentTypeTag(NSSCMSContentInfo *cinfo)
|
|||
SECItem *
|
||||
NSS_CMSContentInfo_GetContentTypeOID(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo->contentTypeTag == NULL)
|
||||
cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
|
||||
|
||||
if (cinfo->contentTypeTag == NULL)
|
||||
if (cinfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cinfo->contentTypeTag == NULL) {
|
||||
cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
|
||||
}
|
||||
|
||||
if (cinfo->contentTypeTag == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &(cinfo->contentTypeTag->oid);
|
||||
}
|
||||
|
@ -310,8 +346,13 @@ NSS_CMSContentInfo_GetContentTypeOID(NSSCMSContentInfo *cinfo)
|
|||
SECOidTag
|
||||
NSS_CMSContentInfo_GetContentEncAlgTag(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN)
|
||||
if (cinfo == NULL) {
|
||||
return SEC_OID_UNKNOWN;
|
||||
}
|
||||
|
||||
if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN) {
|
||||
cinfo->contentEncAlgTag = SECOID_GetAlgorithmTag(&(cinfo->contentEncAlg));
|
||||
}
|
||||
|
||||
return cinfo->contentEncAlgTag;
|
||||
}
|
||||
|
@ -322,6 +363,10 @@ NSS_CMSContentInfo_GetContentEncAlgTag(NSSCMSContentInfo *cinfo)
|
|||
SECAlgorithmID *
|
||||
NSS_CMSContentInfo_GetContentEncAlg(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &(cinfo->contentEncAlg);
|
||||
}
|
||||
|
||||
|
@ -330,10 +375,14 @@ NSS_CMSContentInfo_SetContentEncAlg(PLArenaPool *poolp, NSSCMSContentInfo *cinfo
|
|||
SECOidTag bulkalgtag, SECItem *parameters, int keysize)
|
||||
{
|
||||
SECStatus rv;
|
||||
if (cinfo == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters);
|
||||
if (rv != SECSuccess)
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
cinfo->keysize = keysize;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
@ -343,27 +392,42 @@ NSS_CMSContentInfo_SetContentEncAlgID(PLArenaPool *poolp, NSSCMSContentInfo *cin
|
|||
SECAlgorithmID *algid, int keysize)
|
||||
{
|
||||
SECStatus rv;
|
||||
if (cinfo == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = SECOID_CopyAlgorithmID(poolp, &(cinfo->contentEncAlg), algid);
|
||||
if (rv != SECSuccess)
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
if (keysize >= 0)
|
||||
}
|
||||
if (keysize >= 0) {
|
||||
cinfo->keysize = keysize;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
void
|
||||
NSS_CMSContentInfo_SetBulkKey(NSSCMSContentInfo *cinfo, PK11SymKey *bulkkey)
|
||||
{
|
||||
cinfo->bulkkey = PK11_ReferenceSymKey(bulkkey);
|
||||
cinfo->keysize = PK11_GetKeyStrength(cinfo->bulkkey, &(cinfo->contentEncAlg));
|
||||
if (cinfo == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bulkkey == NULL) {
|
||||
cinfo->bulkkey = NULL;
|
||||
cinfo->keysize = 0;
|
||||
} else {
|
||||
cinfo->bulkkey = PK11_ReferenceSymKey(bulkkey);
|
||||
cinfo->keysize = PK11_GetKeyStrength(cinfo->bulkkey, &(cinfo->contentEncAlg));
|
||||
}
|
||||
}
|
||||
|
||||
PK11SymKey *
|
||||
NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo->bulkkey == NULL)
|
||||
if (cinfo == NULL || cinfo->bulkkey == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PK11_ReferenceSymKey(cinfo->bulkkey);
|
||||
}
|
||||
|
@ -371,5 +435,9 @@ NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo *cinfo)
|
|||
int
|
||||
NSS_CMSContentInfo_GetBulkKeySize(NSSCMSContentInfo *cinfo)
|
||||
{
|
||||
if (cinfo == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cinfo->keysize;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,9 @@ void
|
|||
NSS_CMSDigestedData_Destroy(NSSCMSDigestedData *digd)
|
||||
{
|
||||
/* everything's in a pool, so don't worry about the storage */
|
||||
NSS_CMSContentInfo_Destroy(&(digd->contentInfo));
|
||||
if (digd != NULL) {
|
||||
NSS_CMSContentInfo_Destroy(&(digd->contentInfo));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,9 @@ void
|
|||
NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
|
||||
{
|
||||
/* everything's in a pool, so don't worry about the storage */
|
||||
NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
|
||||
if (encd != NULL) {
|
||||
NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -144,6 +144,11 @@ NSS_CMSEnvelopedData_Encode_BeforeStart(NSSCMSEnvelopedData *envd)
|
|||
poolp = envd->cmsg->poolp;
|
||||
cinfo = &(envd->contentInfo);
|
||||
|
||||
if (cinfo == NULL) {
|
||||
PORT_SetError(SEC_ERROR_BAD_DATA);
|
||||
goto loser;
|
||||
}
|
||||
|
||||
recipientinfos = envd->recipientInfos;
|
||||
if (recipientinfos == NULL) {
|
||||
PORT_SetError(SEC_ERROR_BAD_DATA);
|
||||
|
|
|
@ -29,8 +29,9 @@ NSS_CMSMessage_Create(PLArenaPool *poolp)
|
|||
|
||||
if (poolp == NULL) {
|
||||
poolp = PORT_NewArena(1024); /* XXX what is right value? */
|
||||
if (poolp == NULL)
|
||||
if (poolp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
poolp_is_ours = PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -44,8 +45,9 @@ NSS_CMSMessage_Create(PLArenaPool *poolp)
|
|||
if (mark) {
|
||||
PORT_ArenaRelease(poolp, mark);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
PORT_FreeArena(poolp, PR_FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -53,8 +55,9 @@ NSS_CMSMessage_Create(PLArenaPool *poolp)
|
|||
cmsg->poolp_is_ours = poolp_is_ours;
|
||||
cmsg->refCount = 1;
|
||||
|
||||
if (mark)
|
||||
if (mark) {
|
||||
PORT_ArenaUnmark(poolp, mark);
|
||||
}
|
||||
|
||||
return cmsg;
|
||||
}
|
||||
|
@ -73,8 +76,13 @@ NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
|
|||
NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
|
||||
SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
|
||||
{
|
||||
if (pwfn)
|
||||
if (cmsg == NULL) {
|
||||
return;
|
||||
}
|
||||
if (pwfn) {
|
||||
PK11_SetPasswordFunc(pwfn);
|
||||
}
|
||||
|
||||
cmsg->pwfn_arg = pwfn_arg;
|
||||
cmsg->decrypt_key_cb = decrypt_key_cb;
|
||||
cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
|
||||
|
@ -88,19 +96,25 @@ NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
|
|||
void
|
||||
NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
|
||||
{
|
||||
PORT_Assert(cmsg->refCount > 0);
|
||||
if (cmsg->refCount <= 0) /* oops */
|
||||
if (cmsg == NULL)
|
||||
return;
|
||||
|
||||
cmsg->refCount--; /* thread safety? */
|
||||
if (cmsg->refCount > 0)
|
||||
PORT_Assert(cmsg->refCount > 0);
|
||||
if (cmsg->refCount <= 0) { /* oops */
|
||||
return;
|
||||
}
|
||||
|
||||
cmsg->refCount--; /* thread safety? */
|
||||
if (cmsg->refCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
|
||||
|
||||
/* if poolp is not NULL, cmsg is the owner of its arena */
|
||||
if (cmsg->poolp_is_ours)
|
||||
if (cmsg->poolp_is_ours) {
|
||||
PORT_FreeArena(cmsg->poolp, PR_FALSE); /* XXX clear it? */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -112,8 +126,9 @@ NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
|
|||
NSSCMSMessage *
|
||||
NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
|
||||
{
|
||||
if (cmsg == NULL)
|
||||
if (cmsg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PORT_Assert(cmsg->refCount > 0);
|
||||
|
||||
|
@ -127,6 +142,10 @@ NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
|
|||
PLArenaPool *
|
||||
NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
|
||||
{
|
||||
if (cmsg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cmsg->poolp;
|
||||
}
|
||||
|
||||
|
@ -136,6 +155,10 @@ NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
|
|||
NSSCMSContentInfo *
|
||||
NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
|
||||
{
|
||||
if (cmsg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &(cmsg->contentInfo);
|
||||
}
|
||||
|
||||
|
@ -147,6 +170,10 @@ NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
|
|||
SECItem *
|
||||
NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
|
||||
{
|
||||
if (cmsg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this is a shortcut */
|
||||
NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
|
||||
SECItem *pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
|
||||
|
@ -164,6 +191,10 @@ NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
|
|||
int count = 0;
|
||||
NSSCMSContentInfo *cinfo;
|
||||
|
||||
if (cmsg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* walk down the chain of contentinfos */
|
||||
for (cinfo = &(cmsg->contentInfo); cinfo != NULL;) {
|
||||
count++;
|
||||
|
@ -183,6 +214,10 @@ NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
|
|||
int count = 0;
|
||||
NSSCMSContentInfo *cinfo;
|
||||
|
||||
if (cmsg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* walk down the chain of contentinfos */
|
||||
for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n;
|
||||
cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
|
||||
|
@ -200,6 +235,10 @@ NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
|
|||
{
|
||||
NSSCMSContentInfo *cinfo;
|
||||
|
||||
if (cmsg == NULL) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* descend into CMS message */
|
||||
for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
|
||||
cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
|
||||
|
@ -221,6 +260,10 @@ NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
|
|||
{
|
||||
NSSCMSContentInfo *cinfo;
|
||||
|
||||
if (cmsg == NULL) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* walk down the chain of contentinfos */
|
||||
for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
|
||||
cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
|
||||
|
@ -251,13 +294,21 @@ NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
|
|||
{
|
||||
NSSCMSContentInfo *cinfo;
|
||||
|
||||
if (cmsg == NULL) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* walk down the chain of contentinfos */
|
||||
for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
|
||||
cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
|
||||
switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
|
||||
case SEC_OID_PKCS7_SIGNED_DATA:
|
||||
if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos))
|
||||
if (cinfo->content.signedData == NULL) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* callback here for generic wrappers? */
|
||||
|
@ -278,8 +329,9 @@ NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
|
|||
{
|
||||
SECItem *item = NULL;
|
||||
|
||||
if (cmsg == NULL)
|
||||
if (cmsg == NULL) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
|
|||
{
|
||||
const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
|
||||
|
||||
if (typeInfo && typeInfo->destroy) {
|
||||
if (typeInfo && (typeInfo->destroy) && (gd != NULL)) {
|
||||
(*typeInfo->destroy)(gd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
|
||||
*/
|
||||
#define SOFTOKEN_VERSION "3.42" SOFTOKEN_ECC_STRING
|
||||
#define SOFTOKEN_VERSION "3.43" SOFTOKEN_ECC_STRING " Beta"
|
||||
#define SOFTOKEN_VMAJOR 3
|
||||
#define SOFTOKEN_VMINOR 42
|
||||
#define SOFTOKEN_VMINOR 43
|
||||
#define SOFTOKEN_VPATCH 0
|
||||
#define SOFTOKEN_VBUILD 0
|
||||
#define SOFTOKEN_BETA PR_FALSE
|
||||
#define SOFTOKEN_BETA PR_TRUE
|
||||
|
||||
#endif /* _SOFTKVER_H_ */
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#define UNUSED_ERROR(x) ER3(SSL_ERROR_UNUSED_##x, (SSL_ERROR_BASE + x), \
|
||||
"Unrecognized SSL error_code.")
|
||||
|
||||
/* SSL-specific security error codes */
|
||||
/* SSL-specific security error codes */
|
||||
/* caller must include "sslerr.h" */
|
||||
|
||||
ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
|
||||
"Unable to communicate securely. Peer does not support high-grade encryption.")
|
||||
"Unable to communicate securely. Peer does not support high-grade encryption.")
|
||||
|
||||
ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
|
||||
"Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
|
||||
"Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
|
||||
|
||||
ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
|
||||
"Cannot communicate securely with peer: no common encryption algorithm(s).")
|
||||
|
@ -197,7 +197,7 @@ ER3(SSL_ERROR_RX_UNKNOWN_ALERT, (SSL_ERROR_BASE + 57),
|
|||
"SSL received an alert record with an unknown alert description.")
|
||||
|
||||
/*
|
||||
* Received an alert reporting what we did wrong. (more alerts above)
|
||||
* Received an alert reporting what we did wrong. (more alerts above)
|
||||
*/
|
||||
ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT, (SSL_ERROR_BASE + 58),
|
||||
"SSL peer has closed this connection.")
|
||||
|
|
|
@ -73,11 +73,6 @@
|
|||
'-std=gnu99',
|
||||
],
|
||||
}],
|
||||
[ 'enable_sslkeylogfile==1', {
|
||||
'defines': [
|
||||
'NSS_ALLOW_SSLKEYLOGFILE',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
|
@ -97,6 +92,11 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
'target_defaults': {
|
||||
'defines': [
|
||||
'NSS_ALLOW_SSLKEYLOGFILE=1'
|
||||
]
|
||||
},
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
* of pkcs11 modules common to all applications.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OS Specific function to get where the NSS user database should reside.
|
||||
*/
|
||||
#ifndef LINUX
|
||||
#error __FILE__ only builds on Linux.
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -150,44 +149,6 @@ userCanModifySystemDB()
|
|||
return (access(NSS_DEFAULT_SYSTEM, W_OK) == 0);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef XP_WIN
|
||||
static char *
|
||||
getUserDB(void)
|
||||
{
|
||||
/* use the registry to find the user's NSS_DIR. if no entry exists, create
|
||||
* one in the users Appdir location */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
getSystemDB(void)
|
||||
{
|
||||
/* use the registry to find the system's NSS_DIR. if no entry exists, create
|
||||
* one based on the windows system data area */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
userIsRoot()
|
||||
{
|
||||
/* use the registry to find if the user is the system administrator. */
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
userCanModifySystemDB()
|
||||
{
|
||||
/* use the registry to find if the user has administrative privilege
|
||||
* to modify the system's nss database. */
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Need to write getUserDB, SystemDB, userIsRoot, and userCanModifySystemDB functions"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static PRBool
|
||||
getFIPSEnv(void)
|
||||
{
|
||||
|
@ -203,7 +164,6 @@ getFIPSEnv(void)
|
|||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#ifdef XP_LINUX
|
||||
|
||||
static PRBool
|
||||
getFIPSMode(void)
|
||||
|
@ -228,14 +188,6 @@ getFIPSMode(void)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
static PRBool
|
||||
getFIPSMode(void)
|
||||
{
|
||||
return getFIPSEnv();
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NSS_DEFAULT_FLAGS "flags=readonly"
|
||||
|
||||
/* configuration flags according to
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
/* General security error codes */
|
||||
/* General security error codes */
|
||||
/* Caller must #include "secerr.h" */
|
||||
|
||||
ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
|
||||
|
@ -54,7 +54,7 @@ ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
|
|||
"The security password entered is incorrect.")
|
||||
|
||||
ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
|
||||
"New password entered incorrectly. Please try again.")
|
||||
"New password entered incorrectly. Please try again.")
|
||||
|
||||
ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
|
||||
"security library: no nodelock.")
|
||||
|
@ -96,10 +96,10 @@ ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
|
|||
"Cert Library: No Response")
|
||||
|
||||
ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
|
||||
"The certificate issuer's certificate has expired. Check your system date and time.")
|
||||
"The certificate issuer's certificate has expired. Check your system date and time.")
|
||||
|
||||
ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
|
||||
"The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
|
||||
"The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
|
||||
|
||||
ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
|
||||
"The CRL for the certificate's issuer has an invalid signature.")
|
||||
|
@ -159,7 +159,7 @@ ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
|
|||
|
||||
/* Fortezza Alerts */
|
||||
ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
|
||||
"Fortezza card has not been properly initialized. \
|
||||
"Fortezza card has not been properly initialized. \
|
||||
Please remove it and return it to your issuer.")
|
||||
|
||||
ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
|
||||
|
@ -245,31 +245,31 @@ ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
|
|||
"Error attempting to import certificates.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
|
||||
"Unable to import. Decoding error. File not valid.")
|
||||
"Unable to import. Decoding error. File not valid.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
|
||||
"Unable to import. Invalid MAC. Incorrect password or corrupt file.")
|
||||
"Unable to import. Invalid MAC. Incorrect password or corrupt file.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
|
||||
"Unable to import. MAC algorithm not supported.")
|
||||
"Unable to import. MAC algorithm not supported.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, (SEC_ERROR_BASE + 81),
|
||||
"Unable to import. Only password integrity and privacy modes supported.")
|
||||
"Unable to import. Only password integrity and privacy modes supported.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
|
||||
"Unable to import. File structure is corrupt.")
|
||||
"Unable to import. File structure is corrupt.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
|
||||
"Unable to import. Encryption algorithm not supported.")
|
||||
"Unable to import. Encryption algorithm not supported.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
|
||||
"Unable to import. File version not supported.")
|
||||
"Unable to import. File version not supported.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, (SEC_ERROR_BASE + 85),
|
||||
"Unable to import. Incorrect privacy password.")
|
||||
"Unable to import. Incorrect privacy password.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
|
||||
"Unable to import. Same nickname already exists in database.")
|
||||
"Unable to import. Same nickname already exists in database.")
|
||||
|
||||
ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
|
||||
"The user pressed cancel.")
|
||||
|
@ -290,34 +290,34 @@ ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
|
|||
"Address in signing certificate does not match address in message headers.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
|
||||
"Unable to import. Error attempting to import private key.")
|
||||
"Unable to import. Error attempting to import private key.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
|
||||
"Unable to import. Error attempting to import certificate chain.")
|
||||
"Unable to import. Error attempting to import certificate chain.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
|
||||
"Unable to export. Unable to locate certificate or key by nickname.")
|
||||
"Unable to export. Unable to locate certificate or key by nickname.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
|
||||
"Unable to export. Private Key could not be located and exported.")
|
||||
"Unable to export. Private Key could not be located and exported.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
|
||||
"Unable to export. Unable to write the export file.")
|
||||
"Unable to export. Unable to write the export file.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
|
||||
"Unable to import. Unable to read the import file.")
|
||||
"Unable to import. Unable to read the import file.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
|
||||
"Unable to export. Key database corrupt or deleted.")
|
||||
"Unable to export. Key database corrupt or deleted.")
|
||||
|
||||
ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
|
||||
"Unable to generate public/private key pair.")
|
||||
|
||||
ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
|
||||
"Password entered is invalid. Please pick a different one.")
|
||||
"Password entered is invalid. Please pick a different one.")
|
||||
|
||||
ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
|
||||
"Old password entered incorrectly. Please try again.")
|
||||
"Old password entered incorrectly. Please try again.")
|
||||
|
||||
ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
|
||||
"Certificate nickname already in use.")
|
||||
|
@ -344,7 +344,7 @@ ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110),
|
|||
"New KRL is not later than the current one.")
|
||||
|
||||
ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111),
|
||||
"New CKL has different issuer than current CKL. Delete current CKL.")
|
||||
"New CKL has different issuer than current CKL. Delete current CKL.")
|
||||
|
||||
ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
|
||||
"The Certifying Authority for this certificate is not permitted to issue a \
|
||||
|
@ -518,7 +518,7 @@ ER3(SEC_ERROR_PKCS11_GENERAL_ERROR, (SEC_ERROR_BASE + 167),
|
|||
"A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS11_FUNCTION_FAILED, (SEC_ERROR_BASE + 168),
|
||||
"A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
|
||||
"A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
|
||||
|
||||
ER3(SEC_ERROR_PKCS11_DEVICE_ERROR, (SEC_ERROR_BASE + 169),
|
||||
"A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
|
||||
*/
|
||||
#define NSSUTIL_VERSION "3.42"
|
||||
#define NSSUTIL_VERSION "3.43 Beta"
|
||||
#define NSSUTIL_VMAJOR 3
|
||||
#define NSSUTIL_VMINOR 42
|
||||
#define NSSUTIL_VMINOR 43
|
||||
#define NSSUTIL_VPATCH 0
|
||||
#define NSSUTIL_VBUILD 0
|
||||
#define NSSUTIL_BETA PR_FALSE
|
||||
#define NSSUTIL_BETA PR_TRUE
|
||||
|
||||
SEC_BEGIN_PROTOS
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
[ 'OS=="linux"', {
|
||||
'dependencies': [
|
||||
'lib/freebl/freebl.gyp:freeblpriv3',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" and mozilla_client==0', {
|
||||
'dependencies': [
|
||||
'lib/sysinit/sysinit.gyp:nsssysinit',
|
||||
],
|
||||
}],
|
||||
|
@ -68,7 +72,7 @@
|
|||
'lib/util/util.gyp:nssutil',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'OS=="linux"', {
|
||||
[ 'OS=="linux" and mozilla_client==0', {
|
||||
'dependencies': [
|
||||
'lib/sysinit/sysinit.gyp:nsssysinit_static',
|
||||
],
|
||||
|
@ -199,6 +203,10 @@
|
|||
[ 'OS=="linux"', {
|
||||
'dependencies': [
|
||||
'cmd/lowhashtest/lowhashtest.gyp:lowhashtest',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" and mozilla_client==0', {
|
||||
'dependencies': [
|
||||
'gtests/sysinit_gtest/sysinit_gtest.gyp:sysinit_gtest',
|
||||
],
|
||||
}],
|
||||
|
|
|
@ -364,13 +364,31 @@ if mozinfo.isWin:
|
|||
pid)
|
||||
if not pHandle:
|
||||
return False
|
||||
pExitCode = ctypes.wintypes.DWORD()
|
||||
ctypes.windll.kernel32.GetExitCodeProcess(
|
||||
pHandle,
|
||||
ctypes.byref(pExitCode))
|
||||
ctypes.windll.kernel32.CloseHandle(pHandle)
|
||||
return pExitCode.value == STILL_ACTIVE
|
||||
|
||||
try:
|
||||
pExitCode = ctypes.wintypes.DWORD()
|
||||
ctypes.windll.kernel32.GetExitCodeProcess(
|
||||
pHandle,
|
||||
ctypes.byref(pExitCode))
|
||||
|
||||
if pExitCode.value != STILL_ACTIVE:
|
||||
return False
|
||||
|
||||
# We have a live process handle. But Windows aggressively
|
||||
# re-uses pids, so let's attempt to verify that this is
|
||||
# actually Firefox.
|
||||
namesize = 1024
|
||||
pName = ctypes.create_string_buffer(namesize)
|
||||
namelen = ctypes.windll.kernel32.GetProcessImageFileNameA(pHandle,
|
||||
pName,
|
||||
namesize)
|
||||
if namelen == 0:
|
||||
# Still an active process, so conservatively assume it's Firefox.
|
||||
return True
|
||||
|
||||
return pName.value.endswith(('firefox.exe', 'plugin-container.exe'))
|
||||
finally:
|
||||
ctypes.windll.kernel32.CloseHandle(pHandle)
|
||||
else:
|
||||
import errno
|
||||
|
||||
|
|
|
@ -478,10 +478,11 @@ if mozinfo.isWin:
|
|||
:param pid: PID of the process to terminate.
|
||||
"""
|
||||
PROCESS_TERMINATE = 0x0001
|
||||
SYNCHRONIZE = 0x00100000
|
||||
WAIT_OBJECT_0 = 0x0
|
||||
WAIT_FAILED = -1
|
||||
logger = get_logger()
|
||||
handle = OpenProcess(PROCESS_TERMINATE, 0, pid)
|
||||
handle = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, 0, pid)
|
||||
if handle:
|
||||
if kernel32.TerminateProcess(handle, 1):
|
||||
# TerminateProcess is async; wait up to 30 seconds for process to
|
||||
|
|
Загрузка…
Ссылка в новой задаче