Merge inbound to mozilla-central a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Mon, 04 Feb 2019 23:42:26 +0200
changeset 456661 a27965fa737496e7516e3f60becf093c548de585
parent 456646 94d34e0a4cbc4543311720cb9c761b4d8e8c9bc9 (current diff)
parent 456660 9c347507b88c80841d8069ff364061f555ece219 (diff)
child 456662 f9b86dec401e29519598cb5f035c9e0dee13cc79
child 456685 840cee0ce7b0538a82375ec5e35869505954531a
child 456718 4436a32af9fb4441d830e7f07a655dbcae60668b
push id35499
push userccoroiu@mozilla.com
push dateMon, 04 Feb 2019 21:42:59 +0000
treeherdermozilla-central@a27965fa7374 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
a27965fa7374 / 67.0a1 / 20190204214259 / files
nightly linux64
a27965fa7374 / 67.0a1 / 20190204214259 / files
nightly mac
a27965fa7374 / 67.0a1 / 20190204214259 / files
nightly win32
a27965fa7374 / 67.0a1 / 20190204214259 / files
nightly win64
a27965fa7374 / 67.0a1 / 20190204214259 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central a=merge
security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
--- a/browser/components/aboutconfig/content/aboutconfig.html
+++ b/browser/components/aboutconfig/content/aboutconfig.html
@@ -13,31 +13,33 @@
     <link rel="stylesheet" type="text/css"
           href="chrome://browser/content/aboutconfig/aboutconfig.css">
     <link rel="localization" href="browser/aboutConfig.ftl">
     <script type="application/javascript"
             src="chrome://browser/content/aboutconfig/aboutconfig.js"></script>
     <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">
         <input type="checkbox" id="showWarningNextTime" checked>
         <label for="showWarningNextTime"
                data-l10n-id="about-config-warning-checkbox"></label>
       </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>
   </body>
 </html>
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -9,16 +9,22 @@ const {Preferences} = ChromeUtils.import
 const SEARCH_TIMEOUT_MS = 500;
 
 const GETTERS_BY_PREF_TYPE = {
   [Ci.nsIPrefBranch.PREF_BOOL]: "getBoolPref",
   [Ci.nsIPrefBranch.PREF_INT]: "getIntPref",
   [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);
 
 /**
  * Maps the name of each preference in the back-end to its PrefRow object,
  * separating the preferences that actually exist. This is as an optimization to
  * avoid querying the preferences service each time the list is filtered.
  */
@@ -202,17 +208,17 @@ class PrefRow {
         for (let type of ["Boolean", "Number", "String"]) {
           let radio = document.createElement("input");
           radio.type = "radio";
           radio.name = "type";
           radio.value = type;
           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 => {
           if (event.target.name != "type") {
             return;
           }
           let type = event.target.value;
           if (this.type != type) {
--- a/browser/locales/en-US/browser/aboutConfig.ftl
+++ b/browser/locales/en-US/browser/aboutConfig.ftl
@@ -15,16 +15,21 @@ about-config-search =
 
 about-config-pref-add = Add
 about-config-pref-toggle = Toggle
 about-config-pref-edit = Edit
 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.
 ##
 ## Variables:
 ##   $value (String): The full value of the preference.
 about-config-pref-accessible-value-default =
     .aria-label = { $value } (default)
--- a/devtools/client/shared/test/unit/test_escapeCSSComment.js
+++ b/devtools/client/shared/test/unit/test_escapeCSSComment.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "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 = [
   {
     input: "simple",
     expected: "simple",
   },
   {
     input: "/* comment */",
@@ -28,12 +28,12 @@ const TEST_DATA = [
 function run_test() {
   let i = 0;
   for (const test of TEST_DATA) {
     ++i;
     info("Test #" + i);
 
     const escaped = escapeCSSComment(test.input);
     equal(escaped, test.expected);
-    const unescaped = _unescapeCSSComment(escaped);
+    const unescaped = unescapeCSSComment(escaped);
     equal(unescaped, test.input);
   }
 }
--- a/devtools/client/shared/test/unit/test_rewriteDeclarations.js
+++ b/devtools/client/shared/test/unit/test_rewriteDeclarations.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "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 = [
   {
     desc: "simple set",
     input: "p:v;",
     instruction: {type: "set", name: "p", value: "N", priority: "",
                   index: 0},
--- a/devtools/client/shared/view-source.js
+++ b/devtools/client/shared/view-source.js
@@ -47,17 +47,17 @@ exports.viewSourceInStyleEditor = async 
  * @param {string} [reason=unknown]
  *
  * @return {Promise<boolean>}
  */
 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;
   }
 
   exports.viewSource(toolbox, sourceURL, sourceLine);
   return false;
 };
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -397,17 +397,17 @@ skip-if = verify
 [browser_webconsole_shows_reqs_from_netmonitor.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
 [browser_webconsole_sidebar_object_expand_when_message_pruned.js]
 [browser_webconsole_sidebar_scroll.js]
 [browser_webconsole_sourcemap_css.js]
 [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]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
 [browser_webconsole_strict_mode_errors.js]
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -358,16 +358,22 @@ async function checkClickOnNode(hud, too
   const onSourceInDebuggerOpened = once(hud.ui, "source-in-debugger-opened");
 
   EventUtils.sendMouseEvent({ type: "click" },
     frameLinkNode.querySelector(".frame-link-filename"));
 
   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,
     "expected source url"
   );
 }
 
 /**
--- a/devtools/shared/css/parsing-utils.js
+++ b/devtools/shared/css/parsing-utils.js
@@ -2,47 +2,35 @@
 /* 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");
 
 loader.lazyRequireGetter(this, "CSS_ANGLEUNIT", "devtools/shared/css/constants", true);
 
 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
  * CSS tokens.  Comment tokens are dropped.
  *
  * @param {String} CSS source string
  * @yield {CSSToken} The next CSSToken that is lexed
  * @see CSSToken for details about the returned tokens
@@ -254,27 +242,16 @@ function cssTrim(str) {
   const match = /^[ \t\r\n\f]*(.*?)[ \t\r\n\f]*$/.exec(str);
   if (match) {
     return match[1];
   }
   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
  * that don't make sense in isolation.
  *
  * The return value and arguments are like parseDeclarations, with
  * these additional arguments.
  *
  * @param {Function} isCssPropertyKnown
@@ -514,644 +491,16 @@ function parseDeclarations(isCssProperty
  */
 function parseNamedDeclarations(isCssPropertyKnown, inputString,
                                 parseComments = false) {
   return parseDeclarations(isCssPropertyKnown, inputString, parseComments)
          .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.
  *
  * The components making up the CSS selector can be extracted into 3 different
  * types: element, attribute and pseudoclass. The object that is appended to
  * the returned array contains the value related to one of the 3 types described
  * along with the actual type.
  *
  * The following are the 3 types that can be returned in the object signature:
@@ -1291,18 +640,16 @@ function getAngleValueInDegrees(angleVal
     default:
       throw new Error("No matched angle unit.");
   }
 }
 
 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;
--- a/devtools/shared/fronts/inspector/moz.build
+++ b/devtools/shared/fronts/inspector/moz.build
@@ -1,10 +1,11 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'node-picker.js',
+    'rule-rewriter.js',
 )
 
copy from devtools/shared/css/parsing-utils.js
copy to devtools/shared/fronts/inspector/rule-rewriter.js
--- a/devtools/shared/css/parsing-utils.js
+++ b/devtools/shared/fronts/inspector/rule-rewriter.js
@@ -10,519 +10,35 @@
 // 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);
-
-const SELECTOR_ATTRIBUTE = exports.SELECTOR_ATTRIBUTE = 1;
-const SELECTOR_ELEMENT = exports.SELECTOR_ELEMENT = 2;
-const SELECTOR_PSEUDO_CLASS = exports.SELECTOR_PSEUDO_CLASS = 3;
+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|$)/;
 
-// 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 = "!";
-
-/**
- * A generator function that lexes a CSS source string, yielding the
- * CSS tokens.  Comment tokens are dropped.
- *
- * @param {String} CSS source string
- * @yield {CSSToken} The next CSSToken that is lexed
- * @see CSSToken for details about the returned tokens
- */
-function* cssTokenizer(string) {
-  const lexer = getCSSLexer(string);
-  while (true) {
-    const token = lexer.nextToken();
-    if (!token) {
-      break;
-    }
-    // None of the existing consumers want comments.
-    if (token.tokenType !== "comment") {
-      yield token;
-    }
-  }
-}
-
-/**
- * Pass |string| to the CSS lexer and return an array of all the
- * returned tokens.  Comment tokens are not included.  In addition to
- * the usual information, each token will have starting and ending
- * line and column information attached.  Specifically, each token
- * has an additional "loc" attribute.  This attribute is an object
- * of the form {line: L, column: C}.  Lines and columns are both zero
- * based.
- *
- * It's best not to add new uses of this function.  In general it is
- * simpler and better to use the CSSToken offsets, rather than line
- * and column.  Also, this function lexes the entire input string at
- * once, rather than lazily yielding a token stream.  Use
- * |cssTokenizer| or |getCSSLexer| instead.
- *
- * @param{String} string The input string.
- * @return {Array} An array of tokens (@see CSSToken) that have
- *        line and column information.
- */
-function cssTokenizerWithLineColumn(string) {
-  const lexer = getCSSLexer(string);
-  const result = [];
-  let prevToken = undefined;
-  while (true) {
-    const token = lexer.nextToken();
-    const lineNumber = lexer.lineNumber;
-    const columnNumber = lexer.columnNumber;
-
-    if (prevToken) {
-      prevToken.loc.end = {
-        line: lineNumber,
-        column: columnNumber,
-      };
-    }
-
-    if (!token) {
-      break;
-    }
-
-    if (token.tokenType === "comment") {
-      // We've already dealt with the previous token's location.
-      prevToken = undefined;
-    } else {
-      const startLoc = {
-        line: lineNumber,
-        column: columnNumber,
-      };
-      token.loc = {start: startLoc};
-
-      result.push(token);
-      prevToken = token;
-    }
-  }
-
-  return result;
-}
-
-/**
- * Escape a comment body.  Find the comment start and end strings in a
- * string and inserts backslashes so that the resulting text can
- * itself be put inside a comment.
- *
- * @param {String} inputString
- *                 input string
- * @return {String} the escaped result
- */
-function escapeCSSComment(inputString) {
-  const result = inputString.replace(/\/(\\*)\*/g, "/\\$1*");
-  return result.replace(/\*(\\*)\//g, "*\\$1/");
-}
-
-/**
- * Un-escape a comment body.  This undoes any comment escaping that
- * was done by escapeCSSComment.  That is, given input like "/\*
- * comment *\/", it will strip the backslashes.
- *
- * @param {String} inputString
- *                 input string
- * @return {String} the un-escaped result
- */
-function unescapeCSSComment(inputString) {
-  const result = inputString.replace(/\/\\(\\*)\*/g, "/$1*");
-  return result.replace(/\*\\(\\*)\//g, "*$1/");
-}
-
-/**
- * A helper function for @see parseDeclarations that handles parsing
- * of comment text.  This wraps a recursive call to parseDeclarations
- * with the processing needed to ensure that offsets in the result
- * refer back to the original, unescaped, input string.
- *
- * @param {Function} isCssPropertyKnown
- *        A function to check if the CSS property is known. This is either an
- *        internal server function or from the CssPropertiesFront.
- * @param {String} commentText The text of the comment, without the
- *                             delimiters.
- * @param {Number} startOffset The offset of the comment opener
- *                             in the original text.
- * @param {Number} endOffset The offset of the comment closer
- *                           in the original text.
- * @return {array} Array of declarations of the same form as returned
- *                 by parseDeclarations.
- */
-function parseCommentDeclarations(isCssPropertyKnown, commentText, startOffset,
-                                  endOffset) {
-  let commentOverride = false;
-  if (commentText === "") {
-    return [];
-  } else if (commentText[0] === COMMENT_PARSING_HEURISTIC_BYPASS_CHAR) {
-    // This is the special sign that the comment was written by
-    // rewriteDeclarations and so we should bypass the usual
-    // heuristic.
-    commentOverride = true;
-    commentText = commentText.substring(1);
-  }
-
-  const rewrittenText = unescapeCSSComment(commentText);
-
-  // We might have rewritten an embedded comment.  For example
-  // /\* ... *\/ would turn into /* ... */.
-  // This rewriting is necessary for proper lexing, but it means
-  // that the offsets we get back can be off.  So now we compute
-  // a map so that we can rewrite offsets later.  The map is the same
-  // length as |rewrittenText| and tells us how to map an index
-  // into |rewrittenText| to an index into |commentText|.
-  //
-  // First, we find the location of each comment starter or closer in
-  // |rewrittenText|.  At these spots we put a 1 into |rewrites|.
-  // Then we walk the array again, using the elements to compute a
-  // delta, which we use to make the final mapping.
-  //
-  // Note we allocate one extra entry because we can see an ending
-  // offset that is equal to the length.
-  const rewrites = new Array(rewrittenText.length + 1).fill(0);
-
-  const commentRe = /\/\\*\*|\*\\*\//g;
-  while (true) {
-    const matchData = commentRe.exec(rewrittenText);
-    if (!matchData) {
-      break;
-    }
-    rewrites[matchData.index] = 1;
-  }
-
-  let delta = 0;
-  for (let i = 0; i <= rewrittenText.length; ++i) {
-    delta += rewrites[i];
-    // |startOffset| to add the offset from the comment starter, |+2|
-    // for the length of the "/*", then |i| and |delta| as described
-    // above.
-    rewrites[i] = startOffset + 2 + i + delta;
-    if (commentOverride) {
-      ++rewrites[i];
-    }
-  }
-
-  // Note that we pass "false" for parseComments here.  It doesn't
-  // seem worthwhile to support declarations in comments-in-comments
-  // here, as there's no way to generate those using the tools, and
-  // users would be crazy to write such things.
-  const newDecls = parseDeclarationsInternal(isCssPropertyKnown, rewrittenText,
-                                           false, true, commentOverride);
-  for (const decl of newDecls) {
-    decl.offsets[0] = rewrites[decl.offsets[0]];
-    decl.offsets[1] = rewrites[decl.offsets[1]];
-    decl.colonOffsets[0] = rewrites[decl.colonOffsets[0]];
-    decl.colonOffsets[1] = rewrites[decl.colonOffsets[1]];
-    decl.commentOffsets = [startOffset, endOffset];
-  }
-  return newDecls;
-}
-
-/**
- * A helper function for parseDeclarationsInternal that creates a new
- * empty declaration.
- *
- * @return {object} an empty declaration of the form returned by
- *                  parseDeclarations
- */
-function getEmptyDeclaration() {
-  return {name: "", value: "", priority: "",
-          terminator: "",
-          offsets: [undefined, undefined],
-          colonOffsets: false};
-}
-
-/**
- * Like trim, but only trims CSS-allowed whitespace.
- */
-function cssTrim(str) {
-  const match = /^[ \t\r\n\f]*(.*?)[ \t\r\n\f]*$/.exec(str);
-  if (match) {
-    return match[1];
-  }
-  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
- * that don't make sense in isolation.
- *
- * The return value and arguments are like parseDeclarations, with
- * these additional arguments.
- *
- * @param {Function} isCssPropertyKnown
- *        Function to check if the CSS property is known.
- * @param {Boolean} inComment
- *        If true, assume that this call is parsing some text
- *        which came from a comment in another declaration.
- *        In this case some heuristics are used to avoid parsing
- *        text which isn't obviously a series of declarations.
- * @param {Boolean} commentOverride
- *        This only makes sense when inComment=true.
- *        When true, assume that the comment was generated by
- *        rewriteDeclarations, and skip the usual name-checking
- *        heuristic.
- */
-function parseDeclarationsInternal(isCssPropertyKnown, inputString,
-                                   parseComments, inComment, commentOverride) {
-  if (inputString === null || inputString === undefined) {
-    throw new Error("empty input string");
-  }
-
-  const lexer = getCSSLexer(inputString);
-
-  let declarations = [getEmptyDeclaration()];
-  let lastProp = declarations[0];
-
-  // This tracks the "!important" parsing state.  The states are:
-  // 0 - haven't seen anything
-  // 1 - have seen "!", looking for "important" next (possibly after
-  //     whitespace).
-  // 2 - have seen "!important"
-  let importantState = 0;
-  // This is true if we saw whitespace or comments between the "!" and
-  // the "important".
-  let importantWS = false;
-  let current = "";
-  while (true) {
-    const token = lexer.nextToken();
-    if (!token) {
-      break;
-    }
-
-    // Update the start and end offsets of the declaration, but only
-    // when we see a significant token.
-    if (token.tokenType !== "whitespace" && token.tokenType !== "comment") {
-      if (lastProp.offsets[0] === undefined) {
-        lastProp.offsets[0] = token.startOffset;
-      }
-      lastProp.offsets[1] = token.endOffset;
-    } else if (lastProp.name && !current && !importantState &&
-               !lastProp.priority && lastProp.colonOffsets[1]) {
-      // Whitespace appearing after the ":" is attributed to it.
-      lastProp.colonOffsets[1] = token.endOffset;
-    } else if (importantState === 1) {
-      importantWS = true;
-    }
-
-    if (token.tokenType === "symbol" && token.text === ":") {
-      // Either way, a "!important" we've seen is no longer valid now.
-      importantState = 0;
-      importantWS = false;
-      if (!lastProp.name) {
-        // Set the current declaration name if there's no name yet
-        lastProp.name = cssTrim(current);
-        lastProp.colonOffsets = [token.startOffset, token.endOffset];
-        current = "";
-
-        // When parsing a comment body, if the left-hand-side is not a
-        // valid property name, then drop it and stop parsing.
-        if (inComment && !commentOverride &&
-            !isCssPropertyKnown(lastProp.name)) {
-          lastProp.name = null;
-          break;
-        }
-      } else {
-        // Otherwise, just append ':' to the current value (declaration value
-        // with colons)
-        current += ":";
-      }
-    } else if (token.tokenType === "symbol" && token.text === ";") {
-      lastProp.terminator = "";
-      // When parsing a comment, if the name hasn't been set, then we
-      // have probably just seen an ordinary semicolon used in text,
-      // so drop this and stop parsing.
-      if (inComment && !lastProp.name) {
-        current = "";
-        break;
-      }
-      if (importantState === 2) {
-        lastProp.priority = "important";
-      } else if (importantState === 1) {
-        current += "!";
-        if (importantWS) {
-          current += " ";
-        }
-      }
-      lastProp.value = cssTrim(current);
-      current = "";
-      importantState = 0;
-      importantWS = false;
-      declarations.push(getEmptyDeclaration());
-      lastProp = declarations[declarations.length - 1];
-    } else if (token.tokenType === "ident") {
-      if (token.text === "important" && importantState === 1) {
-        importantState = 2;
-      } else {
-        if (importantState > 0) {
-          current += "!";
-          if (importantWS) {
-            current += " ";
-          }
-          if (importantState === 2) {
-            current += "important ";
-          }
-          importantState = 0;
-          importantWS = false;
-        }
-        // Re-escape the token to avoid dequoting problems.
-        // See bug 1287620.
-        current += CSS.escape(token.text);
-      }
-    } else if (token.tokenType === "symbol" && token.text === "!") {
-      importantState = 1;
-    } else if (token.tokenType === "whitespace") {
-      if (current !== "") {
-        current = current.trimRight() + " ";
-      }
-    } else if (token.tokenType === "comment") {
-      if (parseComments && !lastProp.name && !lastProp.value) {
-        const commentText = inputString.substring(token.startOffset + 2,
-                                                token.endOffset - 2);
-        const newDecls = parseCommentDeclarations(isCssPropertyKnown, commentText,
-                                                token.startOffset,
-                                                token.endOffset);
-
-        // Insert the new declarations just before the final element.
-        const lastDecl = declarations.pop();
-        declarations = [...declarations, ...newDecls, lastDecl];
-      } else {
-        current = current.trimRight() + " ";
-      }
-    } else {
-      if (importantState > 0) {
-        current += "!";
-        if (importantWS) {
-          current += " ";
-        }
-        if (importantState === 2) {
-          current += "important ";
-        }
-        importantState = 0;
-        importantWS = false;
-      }
-      current += inputString.substring(token.startOffset, token.endOffset);
-    }
-  }
-
-  // Handle whatever trailing properties or values might still be there
-  if (current) {
-    if (!lastProp.name) {
-      // Ignore this case in comments.
-      if (!inComment) {
-        // Trailing property found, e.g. p1:v1;p2:v2;p3
-        lastProp.name = cssTrim(current);
-      }
-    } else {
-      // Trailing value found, i.e. value without an ending ;
-      if (importantState === 2) {
-        lastProp.priority = "important";
-      } else if (importantState === 1) {
-        current += "!";
-      }
-      lastProp.value = cssTrim(current);
-      const terminator = lexer.performEOFFixup("", true);
-      lastProp.terminator = terminator + ";";
-      // If the input was unterminated, attribute the remainder to
-      // this property.  This avoids some bad behavior when rewriting
-      // an unterminated comment.
-      if (terminator) {
-        lastProp.offsets[1] = inputString.length;
-      }
-    }
-  }
-
-  // Remove declarations that have neither a name nor a value
-  declarations = declarations.filter(prop => prop.name || prop.value);
-
-  return declarations;
-}
-
-/**
- * Returns an array of CSS declarations given a string.
- * For example, parseDeclarations(isCssPropertyKnown, "width: 1px; height: 1px")
- * would return:
- * [{name:"width", value: "1px"}, {name: "height", "value": "1px"}]
- *
- * The input string is assumed to only contain declarations so { and }
- * characters will be treated as part of either the property or value,
- * depending where it's found.
- *
- * @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.
- * @param {String} inputString
- *        An input string of CSS
- * @param {Boolean} parseComments
- *        If true, try to parse the contents of comments as well.
- *        A comment will only be parsed if it occurs outside of
- *        the body of some other declaration.
- * @return {Array} an array of objects with the following signature:
- *         [{"name": string, "value": string, "priority": string,
- *           "terminator": string,
- *           "offsets": [start, end], "colonOffsets": [start, end]},
- *          ...]
- *         Here, "offsets" holds the offsets of the start and end
- *         of the declaration text, in a form suitable for use with
- *         String.substring.
- *         "terminator" is a string to use to terminate the declaration,
- *         usually "" to mean no additional termination is needed.
- *         "colonOffsets" holds the start and end locations of the
- *         ":" that separates the property name from the value.
- *         If the declaration appears in a comment, then there will
- *         be an additional {"commentOffsets": [start, end] property
- *         on the object, which will hold the offsets of the start
- *         and end of the enclosing comment.
- */
-function parseDeclarations(isCssPropertyKnown, inputString,
-                           parseComments = false) {
-  return parseDeclarationsInternal(isCssPropertyKnown, inputString,
-                                   parseComments, false, false);
-}
-
-/**
- * Like @see parseDeclarations, but removes properties that do not
- * have a name.
- */
-function parseNamedDeclarations(isCssPropertyKnown, inputString,
-                                parseComments = false) {
-  return parseDeclarations(isCssPropertyKnown, inputString, parseComments)
-         .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.
  *
@@ -1142,167 +658,19 @@ RuleRewriter.prototype = {
    *                  |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.
- *
- * The components making up the CSS selector can be extracted into 3 different
- * types: element, attribute and pseudoclass. The object that is appended to
- * the returned array contains the value related to one of the 3 types described
- * along with the actual type.
- *
- * The following are the 3 types that can be returned in the object signature:
- * (1) SELECTOR_ATTRIBUTE
- * (2) SELECTOR_ELEMENT
- * (3) SELECTOR_PSEUDO_CLASS
- *
- * @param {String} value
- *        The CSS selector text.
- * @return {Array} an array of objects with the following signature:
- *         [{ "value": string, "type": integer }, ...]
+ * Like trimRight, but only trims CSS-allowed whitespace.
  */
-function parsePseudoClassesAndAttributes(value) {
-  if (!value) {
-    throw new Error("empty input string");
+function cssTrimRight(str) {
+  const match = /^(.*?)[ \t\r\n\f]*$/.exec(str);
+  if (match) {
+    return match[1];
   }
-
-  const tokens = cssTokenizer(value);
-  const result = [];
-  let current = "";
-  let functionCount = 0;
-  let hasAttribute = false;
-  let hasColon = false;
-
-  for (const token of tokens) {
-    if (token.tokenType === "ident") {
-      current += value.substring(token.startOffset, token.endOffset);
-
-      if (hasColon && !functionCount) {
-        if (current) {
-          result.push({ value: current, type: SELECTOR_PSEUDO_CLASS });
-        }
-
-        current = "";
-        hasColon = false;
-      }
-    } else if (token.tokenType === "symbol" && token.text === ":") {
-      if (!hasColon) {
-        if (current) {
-          result.push({ value: current, type: SELECTOR_ELEMENT });
-        }
-
-        current = "";
-        hasColon = true;
-      }
-
-      current += token.text;
-    } else if (token.tokenType === "function") {
-      current += value.substring(token.startOffset, token.endOffset);
-      functionCount++;
-    } else if (token.tokenType === "symbol" && token.text === ")") {
-      current += token.text;
-
-      if (hasColon && functionCount == 1) {
-        if (current) {
-          result.push({ value: current, type: SELECTOR_PSEUDO_CLASS });
-        }
-
-        current = "";
-        functionCount--;
-        hasColon = false;
-      } else {
-        functionCount--;
-      }
-    } else if (token.tokenType === "symbol" && token.text === "[") {
-      if (!hasAttribute && !functionCount) {
-        if (current) {
-          result.push({ value: current, type: SELECTOR_ELEMENT });
-        }
-
-        current = "";
-        hasAttribute = true;
-      }
-
-      current += token.text;
-    } else if (token.tokenType === "symbol" && token.text === "]") {
-      current += token.text;
-
-      if (hasAttribute && !functionCount) {
-        if (current) {
-          result.push({ value: current, type: SELECTOR_ATTRIBUTE });
-        }
-
-        current = "";
-        hasAttribute = false;
-      }
-    } else {
-      current += value.substring(token.startOffset, token.endOffset);
-    }
-  }
-
-  if (current) {
-    result.push({ value: current, type: SELECTOR_ELEMENT });
-  }
-
-  return result;
+  return str;
 }
 
-/**
- * Expects a single CSS value to be passed as the input and parses the value
- * and priority.
- *
- * @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.
- * @param {String} value
- *        The value from the text editor.
- * @return {Object} an object with 'value' and 'priority' properties.
- */
-function parseSingleValue(isCssPropertyKnown, value) {
-  const declaration = parseDeclarations(isCssPropertyKnown,
-                                      "a: " + value + ";")[0];
-  return {
-    value: declaration ? declaration.value : "",
-    priority: declaration ? declaration.priority : "",
-  };
-}
-
-/**
- * Convert an angle value to degree.
- *
- * @param {Number} angleValue The angle value.
- * @param {CSS_ANGLEUNIT} angleUnit The angleValue's angle unit.
- * @return {Number} An angle value in degree.
- */
-function getAngleValueInDegrees(angleValue, angleUnit) {
-  switch (angleUnit) {
-    case CSS_ANGLEUNIT.deg:
-      return angleValue;
-    case CSS_ANGLEUNIT.grad:
-      return angleValue * 0.9;
-    case CSS_ANGLEUNIT.rad:
-      return angleValue * 180 / Math.PI;
-    case CSS_ANGLEUNIT.turn:
-      return angleValue * 360;
-    default:
-      throw new Error("No matched angle unit.");
-  }
-}
-
-exports.cssTokenizer = cssTokenizer;
-exports.cssTokenizerWithLineColumn = cssTokenizerWithLineColumn;
-exports.escapeCSSComment = escapeCSSComment;
-// unescapeCSSComment is exported for testing.
-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;
+module.exports = RuleRewriter;
--- a/devtools/shared/fronts/styles.js
+++ b/devtools/shared/fronts/styles.js
@@ -8,18 +8,17 @@ const {
   registerFront,
 } = require("devtools/shared/protocol");
 const {
   pageStyleSpec,
   styleRuleSpec,
 } = 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
  */
 class PageStyleFront extends FrontClassWithSpec(pageStyleSpec) {
   constructor(conn) {
     super(conn);
     this.inspector = this.parent();
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -429,18 +429,17 @@ def run_test_remote(test, device, prefix
     try:
         out = device.shell_output(cmd, env=env,
                                   cwd=options.remote_test_root,
                                   timeout=int(options.timeout))
         returncode = 0
     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()
 
     # We can't distinguish between stdout and stderr so we pass
     # the same buffer to both.
     return TestOutput(test, cmd, out, out, returncode, elapsed, False)
 
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -31,17 +31,17 @@ fuzzy-if(d2d,0-1,0-4) fuzzy-if(webrender
 fuzzy-if(webrender,0-1,0-43) HTTP == transformed-1.html?up transformed-1.html?ref
 fuzzy-if(Android,0-5,0-20000) == uncovering-1.html uncovering-1-ref.html
 fuzzy-if(Android,0-5,0-20000) == uncovering-2.html uncovering-2-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,0-149,0-4520) == less-than-scrollbar-height.html less-than-scrollbar-height-ref.html
 == huge-horizontal-overflow.html huge-horizontal-overflow-ref.html
 == 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
 == fractional-scroll-area.html?top=0.4&outerBottom=100&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
 == fractional-scroll-area.html?top=0&outerBottom=99.6&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
 == fractional-scroll-area.html?top=0&outerBottom=100.4&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
 == fractional-scroll-area.html?top=-0.4&outerBottom=99.6&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
 == fractional-scroll-area.html?top=-0.4&outerBottom=100.4&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
--- a/python/mozboot/mozboot/bootstrap.py
+++ b/python/mozboot/mozboot/bootstrap.py
@@ -436,17 +436,18 @@ class Bootstrapper(object):
 
         self.instance.install_system_packages()
 
         # Like 'install_browser_packages' or 'install_mobile_android_packages'.
         getattr(self.instance, 'install_%s_packages' % application)()
 
         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()
 
         # We need to enable the loading of hgrc in case extensions are
         # required to open the repo.
         r = current_firefox_checkout(check_output=self.instance.check_output,
                                      env=self.instance._hg_cleanenv(load_hgrc=True),
                                      hg=self.instance.which('hg'))
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_42_RTM
+d0a282507d59
--- a/security/nss/automation/abi-check/expected-report-libnsssysinit.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnsssysinit.so.txt
@@ -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
-
--- a/security/nss/automation/abi-check/previous-nss-release
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -1,1 +1,1 @@
-NSS_3_41_BRANCH
+NSS_3_42_BRANCH
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -45,17 +45,16 @@ clean=0
 rebuild_gyp=0
 rebuild_nspr=0
 target=Debug
 verbose=0
 fuzz=0
 fuzz_tls=0
 fuzz_oss=0
 no_local_nspr=0
-sslkeylogfile=1
 
 gyp_params=(--depth="$cwd" --generator-output=".")
 ninja_params=()
 
 # Assume that the target architecture is the same as the host by default.
 host_arch=$(python "$cwd"/coreconf/detect_host_arch.py)
 target_arch=$host_arch
 
@@ -99,32 +98,29 @@ while [ $# -gt 0 ]; do
         --ct-verif) gyp_params+=(-Dct_verif=1) ;;
         --nspr) nspr_clean; rebuild_nspr=1 ;;
         --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;;
         --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;;
         --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
         --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
 done
 
 # Set the target architecture and build type.
 gyp_params+=(-Dtarget_arch="$target_arch")
 if [ "$opt_build" = 1 ]; then
     target=Release
 else
     target=Debug
 fi
 
-gyp_params+=(-Denable_sslkeylogfile="$sslkeylogfile")
-
 # Do special setup.
 if [ "$fuzz" = 1 ]; then
     source "$cwd"/coreconf/fuzz.sh
 fi
 nspr_set_flags $sanitizer_flags
 if [ ! -z "$sanitizer_flags" ]; then
     gyp_params+=(-Dsanitizer_flags="$sanitizer_flags")
 fi
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/gtests/ssl_gtest/Makefile
+++ b/security/nss/gtests/ssl_gtest/Makefile
@@ -31,22 +31,16 @@ CFLAGS += -I$(CORE_DEPTH)/lib/ssl
 
 ifdef NSS_DISABLE_TLS_1_3
 NSS_DISABLE_TLS_1_3=1
 # Run parameterized tests only, for which we can easily exclude TLS 1.3
 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)                              #
 #######################################################################
 
 include $(CORE_DEPTH)/coreconf/rules.mk
 
 #######################################################################
 # (6) Execute "component" rules. (OPTIONAL)                           #
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -15,28 +15,28 @@ CPPSRCS = \
       bloomfilter_unittest.cc \
       ssl_0rtt_unittest.cc \
       ssl_agent_unittest.cc \
       ssl_auth_unittest.cc \
       ssl_cert_ext_unittest.cc \
       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 \
       ssl_ems_unittest.cc \
       ssl_exporter_unittest.cc \
       ssl_extension_unittest.cc \
       ssl_fragment_unittest.cc \
       ssl_fuzz_unittest.cc \
       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 \
       ssl_record_unittest.cc \
       ssl_recordsize_unittest.cc \
       ssl_resumption_unittest.cc \
       ssl_renegotiation_unittest.cc \
       ssl_skip_unittest.cc \
@@ -48,17 +48,16 @@ CPPSRCS = \
       selfencrypt_unittest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_protect.cc \
       tls_esni_unittest.cc \
-      $(SSLKEYLOGFILE_FILES) \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
             -I$(CORE_DEPTH)/gtests/common \
             -I$(CORE_DEPTH)/cpputil
 
 REQUIRES = nspr nss libdbm gtest cpputil
 
deleted file mode 100644
--- a/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
+++ /dev/null
@@ -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
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -16,28 +16,28 @@
         'selfencrypt_unittest.cc',
         'ssl_0rtt_unittest.cc',
         'ssl_agent_unittest.cc',
         'ssl_auth_unittest.cc',
         'ssl_cert_ext_unittest.cc',
         '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',
         'ssl_ems_unittest.cc',
         'ssl_exporter_unittest.cc',
         'ssl_extension_unittest.cc',
         'ssl_fuzz_unittest.cc',
         'ssl_fragment_unittest.cc',
         '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',
         'ssl_record_unittest.cc',
         'ssl_recordsize_unittest.cc',
         'ssl_resumption_unittest.cc',
         'ssl_renegotiation_unittest.cc',
         'ssl_skip_unittest.cc',
@@ -86,31 +86,23 @@
             '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
           ],
         }],
         [ 'disable_dbm==0', {
           'dependencies': [
             '<(DEPTH)/lib/dbm/src/src.gyp:dbm',
           ],
         }],
-        [ 'enable_sslkeylogfile==1', {
-          'sources': [
-            'ssl_keylog_unittest.cc',
-          ],
-          'defines': [
-            'NSS_ALLOW_SSLKEYLOGFILE',
-          ],
-        }],
       ],
     }
   ],
   'target_defaults': {
     'include_dirs': [
       '../../lib/ssl'
     ],
     'defines': [
-      'NSS_USE_STATIC_LIBS',
+      'NSS_USE_STATIC_LIBS'
     ],
   },
   'variables': {
     'module': 'nss',
   }
 }
--- a/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
@@ -1,76 +1,39 @@
 /* -*- 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/. */
 
+#ifdef NSS_ALLOW_SSLKEYLOGFILE
+
 #include <cstdlib>
 #include <fstream>
 #include <sstream>
 
 #include "gtest_utils.h"
 #include "tls_connect.h"
 
 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;
-}
+static const std::string keylog_file_path = "keylog.txt";
+static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;
 
-class KeyLogFileTestBase : public TlsConnectGeneric {
- private:
-  std::string env_to_set_;
-
+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);) {
       if (line[0] == '#') {
         continue;
       }
 
       std::istringstream iss(line);
@@ -97,16 +60,38 @@ class KeyLogFileTest : public KeyLogFile
       ASSERT_EQ(2U, labels["EARLY_EXPORTER_SECRET"]);
       ASSERT_EQ(4U, labels["CLIENT_HANDSHAKE_TRAFFIC_SECRET"]);
       ASSERT_EQ(4U, labels["SERVER_HANDSHAKE_TRAFFIC_SECRET"]);
       ASSERT_EQ(4U, labels["CLIENT_TRAFFIC_SECRET_0"]);
       ASSERT_EQ(4U, labels["SERVER_TRAFFIC_SECRET_0"]);
       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
 // and can process the SSLKEYLOGFILE environment variable.
 
 TEST_P(KeyLogFileTest, KeyLogFile) {
   testing::GTEST_FLAG(death_test_style) = "threadsafe";
 
@@ -123,42 +108,11 @@ INSTANTIATE_TEST_CASE_P(
                        TlsConnectTestBase::kTlsV10ToV12));
 #ifndef NSS_DISABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(
     KeyLogFileTLS13, KeyLogFileTest,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        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";
+}  // namespace nss_test
 
-  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
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -46,10 +46,8 @@ NSS build tool options:
                      --with-nspr=<include>:<lib> sets include and lib paths
     --system-nspr    attempt to use system nspr
                      shorthand for --with-nspr=/usr/include/nspr:
     --system-sqlite  use system sqlite
     --enable-fips    enable FIPS checks
     --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
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * 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
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/smime/cmscinfo.c
+++ b/security/nss/lib/smime/cmscinfo.c
@@ -46,16 +46,20 @@ nss_cmsContentInfo_private_destroy(NSSCM
 /*
  * NSS_CMSContentInfo_Destroy - destroy a CMS contentInfo and all of its sub-pieces.
  */
 void
 NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo)
 {
     SECOidTag kind;
 
+    if (cinfo == NULL) {
+        return;
+    }
+
     kind = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
     switch (kind) {
         case SEC_OID_PKCS7_ENVELOPED_DATA:
             NSS_CMSEnvelopedData_Destroy(cinfo->content.envelopedData);
             break;
         case SEC_OID_PKCS7_SIGNED_DATA:
             NSS_CMSSignedData_Destroy(cinfo->content.signedData);
             break;
@@ -81,16 +85,21 @@ NSS_CMSContentInfo_Destroy(NSSCMSContent
 
 /*
  * NSS_CMSContentInfo_GetChildContentInfo - get content's contentInfo (if it exists)
  */
 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:
             if (cinfo->content.signedData != NULL) {
                 ccinfo = &(cinfo->content.signedData->contentInfo);
             }
             break;
         case SEC_OID_PKCS7_ENVELOPED_DATA:
@@ -122,16 +131,19 @@ NSS_CMSContentInfo_GetChildContentInfo(N
     }
     return ccinfo;
 }
 
 SECStatus
 NSS_CMSContentInfo_SetDontStream(NSSCMSContentInfo *cinfo, PRBool dontStream)
 {
     SECStatus rv;
+    if (cinfo == NULL) {
+        return SECFailure;
+    }
 
     rv = NSS_CMSContentInfo_Private_Init(cinfo);
     if (rv != SECSuccess) {
         /* default is streaming, failure to get ccinfo will not effect this */
         return dontStream ? SECFailure : SECSuccess;
     }
     cinfo->privateInfo->dontStream = dontStream;
     return SECSuccess;
@@ -140,25 +152,30 @@ NSS_CMSContentInfo_SetDontStream(NSSCMSC
 /*
  * NSS_CMSContentInfo_SetContent - set content type & content
  */
 SECStatus
 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;
 
     if (NSS_CMSType_IsData(type) && ptr) {
         cinfo->rawContent = ptr;
     } else {
         /* as we always have some inner data,
      * we need to set it to something, just to fool the encoder enough to work on it
@@ -180,18 +197,19 @@ NSS_CMSContentInfo_SetContent(NSSCMSMess
 /*
  * data == NULL -> pass in data via NSS_CMSEncoder_Update
  * data != NULL -> take this data
  */
 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;
     }
 
     return SECSuccess;
 }
 
 SECStatus
@@ -225,16 +243,20 @@ NSS_CMSContentInfo_SetContent_EncryptedD
 /*
  * NSS_CMSContentInfo_GetContent - get pointer to inner content
  *
  * needs to be casted...
  */
 void *
 NSS_CMSContentInfo_GetContent(NSSCMSContentInfo *cinfo)
 {
+    if (cinfo == NULL) {
+        return NULL;
+    }
+
     SECOidTag tag = cinfo->contentTypeTag
                         ? cinfo->contentTypeTag->offset
                         : SEC_OID_UNKNOWN;
     switch (tag) {
         case SEC_OID_PKCS7_DATA:
         case SEC_OID_PKCS7_SIGNED_DATA:
         case SEC_OID_PKCS7_ENVELOPED_DATA:
         case SEC_OID_PKCS7_DIGESTED_DATA:
@@ -255,16 +277,20 @@ NSS_CMSContentInfo_GetContent(NSSCMSCont
 
 SECItem *
 NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo)
 {
     NSSCMSContentInfo *ccinfo;
     SECOidTag tag;
     SECItem *pItem = NULL;
 
+    if (cinfo == NULL) {
+        return NULL;
+    }
+
     tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
     if (NSS_CMSType_IsData(tag)) {
         pItem = cinfo->content.data;
     } else if (NSS_CMSType_IsWrapper(tag)) {
         ccinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
         if (ccinfo != NULL) {
             pItem = NSS_CMSContentInfo_GetContent(ccinfo);
         }
@@ -277,99 +303,141 @@ NSS_CMSContentInfo_GetInnerContent(NSSCM
 
 /*
  * NSS_CMSContentInfo_GetContentType{Tag,OID} - find out (saving pointer to lookup result
  * for future reference) and return the inner content type.
  */
 SECOidTag
 NSS_CMSContentInfo_GetContentTypeTag(NSSCMSContentInfo *cinfo)
 {
+    if (cinfo == NULL) {
+        return SEC_OID_UNKNOWN;
+    }
+
     if (cinfo->contentTypeTag == NULL)
         cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
 
     if (cinfo->contentTypeTag == NULL)
         return SEC_OID_UNKNOWN;
 
     return cinfo->contentTypeTag->offset;
 }
 
 SECItem *
 NSS_CMSContentInfo_GetContentTypeOID(NSSCMSContentInfo *cinfo)
 {
-    if (cinfo->contentTypeTag == NULL)
-        cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
+    if (cinfo == NULL) {
+        return NULL;
+    }
 
-    if (cinfo->contentTypeTag == NULL)
+    if (cinfo->contentTypeTag == NULL) {
+        cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
+    }
+
+    if (cinfo->contentTypeTag == NULL) {
         return NULL;
+    }
 
     return &(cinfo->contentTypeTag->oid);
 }
 
 /*
  * NSS_CMSContentInfo_GetContentEncAlgTag - find out (saving pointer to lookup result
  * for future reference) and return the content encryption algorithm tag.
  */
 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;
 }
 
 /*
  * NSS_CMSContentInfo_GetContentEncAlg - find out and return the content encryption algorithm tag.
  */
 SECAlgorithmID *
 NSS_CMSContentInfo_GetContentEncAlg(NSSCMSContentInfo *cinfo)
 {
+    if (cinfo == NULL) {
+        return NULL;
+    }
+
     return &(cinfo->contentEncAlg);
 }
 
 SECStatus
 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;
 }
 
 SECStatus
 NSS_CMSContentInfo_SetContentEncAlgID(PLArenaPool *poolp, NSSCMSContentInfo *cinfo,
                                       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);
 }
 
 int
 NSS_CMSContentInfo_GetBulkKeySize(NSSCMSContentInfo *cinfo)
 {
+    if (cinfo == NULL) {
+        return 0;
+    }
+
     return cinfo->keysize;
 }
--- a/security/nss/lib/smime/cmsdigdata.c
+++ b/security/nss/lib/smime/cmsdigdata.c
@@ -51,17 +51,19 @@ loser:
 
 /*
  * NSS_CMSDigestedData_Destroy - destroy a digestedData object
  */
 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;
 }
 
 /*
  * NSS_CMSDigestedData_GetContentInfo - return pointer to digestedData object's contentInfo
  */
 NSSCMSContentInfo *
 NSS_CMSDigestedData_GetContentInfo(NSSCMSDigestedData *digd)
--- a/security/nss/lib/smime/cmsencdata.c
+++ b/security/nss/lib/smime/cmsencdata.c
@@ -82,17 +82,19 @@ loser:
 
 /*
  * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
  */
 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;
 }
 
 /*
  * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
  */
 NSSCMSContentInfo *
 NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
--- a/security/nss/lib/smime/cmsenvdata.c
+++ b/security/nss/lib/smime/cmsenvdata.c
@@ -139,16 +139,21 @@ NSS_CMSEnvelopedData_Encode_BeforeStart(
     PLArenaPool *poolp;
     extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
     void *mark = NULL;
     int i;
 
     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);
 #if 0
     PORT_SetErrorString("Cannot find recipientinfos to encode.");
 #endif
         goto loser;
     }
--- a/security/nss/lib/smime/cmsmessage.c
+++ b/security/nss/lib/smime/cmsmessage.c
@@ -24,42 +24,45 @@ NSSCMSMessage *
 NSS_CMSMessage_Create(PLArenaPool *poolp)
 {
     void *mark = NULL;
     NSSCMSMessage *cmsg;
     PRBool poolp_is_ours = PR_FALSE;
 
     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;
     }
 
     if (!poolp_is_ours)
         mark = PORT_ArenaMark(poolp);
 
     cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSMessage));
     if (cmsg == NULL ||
         NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)) != SECSuccess) {
         if (!poolp_is_ours) {
             if (mark) {
                 PORT_ArenaRelease(poolp, mark);
             }
-        } else
+        } else {
             PORT_FreeArena(poolp, PR_FALSE);
+        }
         return NULL;
     }
 
     cmsg->poolp = poolp;
     cmsg->poolp_is_ours = poolp_is_ours;
     cmsg->refCount = 1;
 
-    if (mark)
+    if (mark) {
         PORT_ArenaUnmark(poolp, mark);
+    }
 
     return cmsg;
 }
 
 /*
  * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
  *
  * "cmsg" - message object
@@ -68,90 +71,114 @@ NSS_CMSMessage_Create(PLArenaPool *poolp
  * "detached_digestalgs", "detached_digests" - digests from detached content
  */
 void
 NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
                                  PK11PasswordFunc pwfn, void *pwfn_arg,
                                  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;
     cmsg->detached_digestalgs = detached_digestalgs;
     cmsg->detached_digests = detached_digests;
 }
 
 /*
  * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
  */
 void
 NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
 {
-    PORT_Assert(cmsg->refCount > 0);
-    if (cmsg->refCount <= 0) /* oops */
+    if (cmsg == NULL)
         return;
 
+    PORT_Assert(cmsg->refCount > 0);
+    if (cmsg->refCount <= 0) { /* oops */
+        return;
+    }
+
     cmsg->refCount--; /* thread safety? */
-    if (cmsg->refCount > 0)
+    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? */
+    }
 }
 
 /*
  * NSS_CMSMessage_Copy - return a copy of the given message.
  *
  * The copy may be virtual or may be real -- either way, the result needs
  * to be passed to NSS_CMSMessage_Destroy later (as does the original).
  */
 NSSCMSMessage *
 NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
 {
-    if (cmsg == NULL)
+    if (cmsg == NULL) {
         return NULL;
+    }
 
     PORT_Assert(cmsg->refCount > 0);
 
     cmsg->refCount++; /* XXX chrisk thread safety? */
     return cmsg;
 }
 
 /*
  * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
  */
 PLArenaPool *
 NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
 {
+    if (cmsg == NULL) {
+        return NULL;
+    }
+
     return cmsg->poolp;
 }
 
 /*
  * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
  */
 NSSCMSContentInfo *
 NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
 {
+    if (cmsg == NULL) {
+        return NULL;
+    }
+
     return &(cmsg->contentInfo);
 }
 
 /*
  * Return a pointer to the actual content.
  * In the case of those types which are encrypted, this returns the *plain* content.
  * In case of nested contentInfos, this descends and retrieves the innermost content.
  */
 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);
     return pItem;
 }
 
 /*
  * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
@@ -159,16 +186,20 @@ NSS_CMSMessage_GetContent(NSSCMSMessage 
  * CMS data content objects do not count.
  */
 int
 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++;
         cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
     }
     return count;
 }
 
@@ -178,16 +209,20 @@ NSS_CMSMessage_ContentLevelCount(NSSCMSM
  * CMS data content objects do not count.
  */
 NSSCMSContentInfo *
 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)) {
         count++;
     }
 
     return cinfo;
 }
@@ -195,16 +230,20 @@ NSS_CMSMessage_ContentLevel(NSSCMSMessag
 /*
  * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
  */
 PRBool
 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)) {
         if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo)))
             continue; /* next level */
 
         if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
             return PR_TRUE;
@@ -216,16 +255,20 @@ NSS_CMSMessage_ContainsCertsOrCrls(NSSCM
 /*
  * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
  */
 PRBool
 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)) {
         switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
             case SEC_OID_PKCS7_ENVELOPED_DATA:
             case SEC_OID_PKCS7_ENCRYPTED_DATA:
                 return PR_TRUE;
             default:
@@ -246,23 +289,31 @@ NSS_CMSMessage_IsEncrypted(NSSCMSMessage
  * Note that the content itself can be empty (detached content was sent
  * another way); it is the presence of the signature that matters.
  */
 PRBool
 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? */
                 break;
         }
     }
     return PR_FALSE;
 }
@@ -273,18 +324,19 @@ NSS_CMSMessage_IsSigned(NSSCMSMessage *c
  * returns PR_TRUE is innermost content length is < minLen
  * XXX need the encrypted content length (why?)
  */
 PRBool
 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));
 
     if (!item) {
         return PR_TRUE;
     } else if (item->len <= minLen) {
         return PR_TRUE;
     }
--- a/security/nss/lib/smime/cmsudf.c
+++ b/security/nss/lib/smime/cmsudf.c
@@ -234,17 +234,17 @@ NSS_CMSType_GetContentSize(SECOidTag typ
     return sizeof(SECItem *);
 }
 
 void
 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);
     }
 }
 
 SECStatus
 NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
                                             NSSCMSGenericWrapperData *gd)
 {
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * 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_ */
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -1,23 +1,23 @@
 /* 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/. */
 
 #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).")
 
 ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3,
     "Unable to find the certificate or key necessary for authentication.")
 
 ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4,
@@ -192,17 +192,17 @@ ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, (S
 
 ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE, (SSL_ERROR_BASE + 56),
     "SSL received a handshake message with an unknown message type.")
 
 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.")
 
 ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, (SSL_ERROR_BASE + 59),
     "SSL peer was not expecting a handshake message it received.")
 
 ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT, (SSL_ERROR_BASE + 60),
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -68,21 +68,16 @@
             'UNSAFE_FUZZER_MODE',
           ],
         }],
         [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd" or OS=="linux"', {
           'cflags': [
             '-std=gnu99',
           ],
         }],
-        [ 'enable_sslkeylogfile==1', {
-          'defines': [
-            'NSS_ALLOW_SSLKEYLOGFILE',
-          ],
-        }],
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
       ],
     },
     {
       'target_name': 'ssl3',
       'type': 'shared_library',
@@ -92,12 +87,17 @@
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
       ],
       'variables': {
         'mapfile': 'ssl.def'
       }
     }
   ],
+  'target_defaults': {
+    'defines': [
+      'NSS_ALLOW_SSLKEYLOGFILE=1'
+    ]
+  },
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/lib/sysinit/nsssysinit.c
+++ b/security/nss/lib/sysinit/nsssysinit.c
@@ -10,21 +10,20 @@
 /*
  * The following provides a default example for operating systems to set up
  * and manage applications loading NSS on their OS globally.
  *
  * This code hooks in to the system pkcs11.txt, which controls all the loading
  * 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>
 
 static int
 testdir(char *dir)
 {
     struct stat buf;
@@ -145,70 +144,31 @@ userIsRoot()
 }
 
 static PRBool
 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)
 {
     char *fipsEnv = PR_GetEnvSecure("NSS_FIPS");
     if (!fipsEnv) {
         return PR_FALSE;
     }
     if ((strcasecmp(fipsEnv, "fips") == 0) ||
         (strcasecmp(fipsEnv, "true") == 0) ||
         (strcasecmp(fipsEnv, "on") == 0) ||
         (strcasecmp(fipsEnv, "1") == 0)) {
         return PR_TRUE;
     }
     return PR_FALSE;
 }
-#ifdef XP_LINUX
 
 static PRBool
 getFIPSMode(void)
 {
     FILE *f;
     char d;
     size_t size;
 
@@ -223,24 +183,16 @@ getFIPSMode(void)
     fclose(f);
     if (size != 1)
         return PR_FALSE;
     if (d != '1')
         return PR_FALSE;
     return PR_TRUE;
 }
 
-#else
-static PRBool
-getFIPSMode(void)
-{
-    return getFIPSEnv();
-}
-#endif
-
 #define NSS_DEFAULT_FLAGS "flags=readonly"
 
 /* configuration flags according to
  * https://developer.mozilla.org/en/PKCS11_Module_Specs
  * As stated there the slotParams start with a slot name which is a slotID
  * Slots 1 through 3 are reserved for the nss internal modules as follows:
  * 1 for crypto operations slot non-fips,
  * 2 for the key slot, and
--- a/security/nss/lib/util/SECerrs.h
+++ b/security/nss/lib/util/SECerrs.h
@@ -1,13 +1,13 @@
 /* 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/. */
 
-/* General security error codes  */
+/* General security error codes */
 /* Caller must #include "secerr.h" */
 
 ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
     "An I/O error occurred during security authorization.")
 
 ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1,
     "security library failure.")
 
@@ -49,17 +49,17 @@ ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_
 
 ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14,
     "Peer's public key is invalid.")
 
 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.")
 
 ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18,
     "security library: bad database.")
 
 ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19,
@@ -91,20 +91,20 @@ ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BAS
 
 ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28),
     "This certificate is not valid.")
 
 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.")
 
 ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33),
     "New CRL has an invalid format.")
 
 ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34),
@@ -154,17 +154,17 @@ or improper or corrupted data.")
 ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48),
     "Unsupported or unknown key algorithm.")
 
 ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
     "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
 
 /* 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),
     "No Fortezza cards Found")
 
 ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52),
     "No Fortezza card selected")
 
@@ -240,41 +240,41 @@ ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC
 
 ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76),
     "Error attempting to export certificates.")
 
 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.")
 
 ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88),
     "Not imported, already in database.")
 
 ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89),
@@ -285,44 +285,44 @@ ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC
 
 ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91),
     "Certificate type not approved for application.")
 
 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.")
 
 ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104),
     "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
 
 ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105),
@@ -339,17 +339,17 @@ ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_E
 
 ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109),
     "Unable to delete module")
 
 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 \
 certificate with this name.")
 
 ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113),
     "The key revocation list for this certificate is not yet valid.")
 
@@ -513,17 +513,17 @@ ER3(SEC_ERROR_BAD_INFO_ACCESS_LOCATION, 
 
 ER3(SEC_ERROR_LIBPKIX_INTERNAL, (SEC_ERROR_BASE + 166),
     "Libpkix internal error occurred during cert validation.")
 
 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.")
 
 ER3(SEC_ERROR_BAD_INFO_ACCESS_METHOD, (SEC_ERROR_BASE + 170),
     "Unknown information access method in certificate extension.")
 
 ER3(SEC_ERROR_CRL_IMPORT_FAILED, (SEC_ERROR_BASE + 171),
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,22 +14,22 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * 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
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
 
--- a/security/nss/nss.gyp
+++ b/security/nss/nss.gyp
@@ -24,16 +24,20 @@
                 'lib/sqlite/sqlite.gyp:sqlite3',
                 'lib/ssl/ssl.gyp:ssl3',
                 'lib/util/util.gyp:nssutil3',
               ],
             }],
             [ 'OS=="linux"', {
               'dependencies': [
                 'lib/freebl/freebl.gyp:freeblpriv3',
+              ],
+            }],
+            [ 'OS=="linux" and mozilla_client==0', {
+              'dependencies': [
                 'lib/sysinit/sysinit.gyp:nsssysinit',
               ],
             }],
             [ 'disable_dbm==0', {
               'dependencies': [
                 'lib/softoken/legacydb/legacydb.gyp:nssdbm3',
               ],
             }],
@@ -63,17 +67,17 @@
             'lib/pkcs7/pkcs7.gyp:pkcs7',
             'lib/pki/pki.gyp:nsspki',
             'lib/smime/smime.gyp:smime',
             'lib/softoken/softoken.gyp:softokn',
             'lib/ssl/ssl.gyp:ssl',
             'lib/util/util.gyp:nssutil',
           ],
           'conditions': [
-            [ 'OS=="linux"', {
+            [ 'OS=="linux" and mozilla_client==0', {
               'dependencies': [
                 'lib/sysinit/sysinit.gyp:nsssysinit_static',
               ],
             }],
             [ 'disable_dbm==0', {
               'dependencies': [
                 'lib/dbm/src/src.gyp:dbm',
                 'lib/softoken/legacydb/legacydb.gyp:nssdbm',
@@ -194,16 +198,20 @@
             'gtests/softoken_gtest/softoken_gtest.gyp:softoken_gtest',
             'gtests/ssl_gtest/ssl_gtest.gyp:ssl_gtest',
             'gtests/util_gtest/util_gtest.gyp:util_gtest',
           ],
           'conditions': [
             [ 'OS=="linux"', {
               'dependencies': [
                 'cmd/lowhashtest/lowhashtest.gyp:lowhashtest',
+              ],
+            }],
+            [ 'OS=="linux" and mozilla_client==0', {
+              'dependencies': [
                 'gtests/sysinit_gtest/sysinit_gtest.gyp:sysinit_gtest',
               ],
             }],
             [ 'disable_libpkix==0', {
               'dependencies': [
                 'cmd/pkix-errcodes/pkix-errcodes.gyp:pkix-errcodes',
               ],
             }],
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -359,23 +359,41 @@ if mozinfo.isWin:
         STILL_ACTIVE = 259
         PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
         pHandle = ctypes.windll.kernel32.OpenProcess(
             PROCESS_QUERY_LIMITED_INFORMATION,
             0,
             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
 
     def isPidAlive(pid):
         try:
             # kill(pid, 0) checks for a valid PID without actually sending a signal
             # The method throws OSError if the PID is invalid, which we catch
             # below.
--- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -473,20 +473,21 @@ if mozinfo.isWin:
 
     def kill_pid(pid):
         """
         Terminate a process with extreme prejudice.
 
         :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
                 # actually terminate, then give up so that clients are not kept
                 # waiting indefinitely for hung processes.
                 status = kernel32.WaitForSingleObject(handle, 30000)
                 if status == WAIT_FAILED:
                     err = kernel32.GetLastError()