merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-07-21 16:56:44 +02:00
commit b76ca95f3f
126 changed files with 4787 additions and 1127 deletions

View File

@ -191,6 +191,82 @@ let OutputGenerator = {
});
},
/**
* Adds math roles to the output, for a MathML accessible.
* @param {Array} aOutput Output array.
* @param {nsIAccessible} aAccessible current accessible object.
* @param {String} aRoleStr aAccessible's role string.
*/
_addMathRoles: function _addMathRoles(aOutput, aAccessible, aRoleStr) {
// First, determine the actual role to use (e.g. mathmlfraction).
let roleStr = aRoleStr;
switch(aAccessible.role) {
case Roles.MATHML_CELL:
case Roles.MATHML_ENCLOSED:
case Roles.MATHML_LABELED_ROW:
case Roles.MATHML_ROOT:
case Roles.MATHML_SQUARE_ROOT:
case Roles.MATHML_TABLE:
case Roles.MATHML_TABLE_ROW:
// Use the default role string.
break;
case Roles.MATHML_MULTISCRIPTS:
case Roles.MATHML_OVER:
case Roles.MATHML_SUB:
case Roles.MATHML_SUB_SUP:
case Roles.MATHML_SUP:
case Roles.MATHML_UNDER:
case Roles.MATHML_UNDER_OVER:
// For scripted accessibles, use the string 'mathmlscripted'.
roleStr = 'mathmlscripted';
break;
case Roles.MATHML_FRACTION:
// From a semantic point of view, the only important point is to
// distinguish between fractions that have a bar and those that do not.
// Per the MathML 3 spec, the latter happens iff the linethickness
// attribute is of the form [zero-float][optional-unit]. In that case,
// we use the string 'mathmlfractionwithoutbar'.
let linethickness = Utils.getAttributes(aAccessible).linethickness;
if (linethickness) {
let numberMatch = linethickness.match(/^(?:\d|\.)+/);
if (numberMatch && !parseFloat(numberMatch[0])) {
roleStr += 'withoutbar';
}
}
break;
default:
// Otherwise, do not output the actual role.
roleStr = null;
break;
}
// Get the math role based on the position in the parent accessible
// (e.g. numerator for the first child of a mathmlfraction).
let mathRole = Utils.getMathRole(aAccessible);
if (mathRole) {
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift']
({string: this._getOutputName(mathRole)});
}
if (roleStr) {
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift']
({string: this._getOutputName(roleStr)});
}
},
/**
* Adds MathML menclose notations to the output.
* @param {Array} aOutput Output array.
* @param {nsIAccessible} aAccessible current accessible object.
*/
_addMencloseNotations: function _addMencloseNotations(aOutput, aAccessible) {
let notations = Utils.getAttributes(aAccessible).notation || 'longdiv';
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift'].apply(
aOutput, [for (notation of notations.split(' '))
{string: this._getOutputName('notation-' + notation)}
]
);
},
/**
* Adds an entry type attribute to the description if available.
* @param {Array} aOutput Output array.
@ -212,7 +288,7 @@ let OutputGenerator = {
_addState: function _addState(aOutput, aState, aRoleStr) {}, // jshint ignore:line
_addRole: function _addRole(aOutput, aRoleStr) {}, // jshint ignore:line
_addRole: function _addRole(aOutput, aAccessible, aRoleStr) {}, // jshint ignore:line
get outputOrder() {
if (!this._utteranceOrder) {
@ -301,7 +377,67 @@ let OutputGenerator = {
'dialog': INCLUDE_DESC | INCLUDE_NAME,
'chrome window': IGNORE_EXPLICIT_NAME,
'app root': IGNORE_EXPLICIT_NAME,
'statusbar': NAME_FROM_SUBTREE_RULE },
'statusbar': NAME_FROM_SUBTREE_RULE,
'mathml table': INCLUDE_DESC | INCLUDE_NAME,
'mathml labeled row': NAME_FROM_SUBTREE_RULE,
'mathml table row': NAME_FROM_SUBTREE_RULE,
'mathml cell': INCLUDE_DESC | INCLUDE_NAME,
'mathml fraction': INCLUDE_DESC,
'mathml square root': INCLUDE_DESC,
'mathml root': INCLUDE_DESC,
'mathml enclosed': INCLUDE_DESC,
'mathml sub': INCLUDE_DESC,
'mathml sup': INCLUDE_DESC,
'mathml sub sup': INCLUDE_DESC,
'mathml under': INCLUDE_DESC,
'mathml over': INCLUDE_DESC,
'mathml under over': INCLUDE_DESC,
'mathml multiscripts': INCLUDE_DESC,
'mathml identifier': INCLUDE_DESC,
'mathml number': INCLUDE_DESC,
'mathml operator': INCLUDE_DESC,
'mathml text': INCLUDE_DESC,
'mathml string literal': INCLUDE_DESC,
'mathml row': INCLUDE_DESC,
'mathml style': INCLUDE_DESC,
'mathml error': INCLUDE_DESC },
mathmlRolesSet: new Set([
Roles.MATHML_MATH,
Roles.MATHML_IDENTIFIER,
Roles.MATHML_NUMBER,
Roles.MATHML_OPERATOR,
Roles.MATHML_TEXT,
Roles.MATHML_STRING_LITERAL,
Roles.MATHML_GLYPH,
Roles.MATHML_ROW,
Roles.MATHML_FRACTION,
Roles.MATHML_SQUARE_ROOT,
Roles.MATHML_ROOT,
Roles.MATHML_FENCED,
Roles.MATHML_ENCLOSED,
Roles.MATHML_STYLE,
Roles.MATHML_SUB,
Roles.MATHML_SUP,
Roles.MATHML_SUB_SUP,
Roles.MATHML_UNDER,
Roles.MATHML_OVER,
Roles.MATHML_UNDER_OVER,
Roles.MATHML_MULTISCRIPTS,
Roles.MATHML_TABLE,
Roles.LABELED_ROW,
Roles.MATHML_TABLE_ROW,
Roles.MATHML_CELL,
Roles.MATHML_ACTION,
Roles.MATHML_ERROR,
Roles.MATHML_STACK,
Roles.MATHML_LONG_DIVISION,
Roles.MATHML_STACK_GROUP,
Roles.MATHML_STACK_ROW,
Roles.MATHML_STACK_CARRIES,
Roles.MATHML_STACK_CARRY,
Roles.MATHML_STACK_LINE
]),
objectOutputFunctions: {
_generateBaseOutput:
@ -311,7 +447,7 @@ let OutputGenerator = {
if (aFlags & INCLUDE_DESC) {
this._addState(output, aState, aRoleStr);
this._addType(output, aAccessible, aRoleStr);
this._addRole(output, aRoleStr);
this._addRole(output, aAccessible, aRoleStr);
}
if (aFlags & INCLUDE_VALUE && aAccessible.value.trim()) {
@ -348,7 +484,7 @@ let OutputGenerator = {
aAccessible.groupPosition({}, itemof, itemno);
let output = [];
this._addState(output, aState);
this._addRole(output, aRoleStr);
this._addRole(output, aAccessible, aRoleStr);
output.push({
string: 'objItemOfN',
args: [itemno.value, itemof.value]
@ -374,7 +510,7 @@ let OutputGenerator = {
if (table.isProbablyForLayout()) {
return output;
}
this._addRole(output, aRoleStr);
this._addRole(output, aAccessible, aRoleStr);
output.push.call(output, {
string: this._getOutputName('tblColumnInfo'),
count: table.columnCount
@ -394,6 +530,23 @@ let OutputGenerator = {
this._addName(output, aAccessible, aFlags);
this._addLandmark(output, aAccessible);
return output;
},
// Use the table output functions for MathML tabular elements.
mathmltable: function mathmltable() {
return this.objectOutputFunctions.table.apply(this, arguments);
},
mathmlcell: function mathmlcell() {
return this.objectOutputFunctions.cell.apply(this, arguments);
},
mathmlenclosed: function mathmlenclosed(aAccessible, aRoleStr, aState,
aFlags, aContext) {
let output = this.objectOutputFunctions.defaultFunc.
apply(this, [aAccessible, aRoleStr, aState, aFlags, aContext]);
this._addMencloseNotations(output, aAccessible);
return output;
}
}
};
@ -597,8 +750,12 @@ this.UtteranceGenerator = { // jshint ignore:line
return aContext.newAncestry;
},
_addRole: function _addRole(aOutput, aRoleStr) {
aOutput.push({string: this._getOutputName(aRoleStr)});
_addRole: function _addRole(aOutput, aAccessible, aRoleStr) {
if (this.mathmlRolesSet.has(aAccessible.role)) {
this._addMathRoles(aOutput, aAccessible, aRoleStr);
} else {
aOutput.push({string: this._getOutputName(aRoleStr)});
}
},
_addState: function _addState(aOutput, aState, aRoleStr) {
@ -657,7 +814,7 @@ this.UtteranceGenerator = { // jshint ignore:line
_getListUtterance:
function _getListUtterance(aAccessible, aRoleStr, aFlags, aItemCount) {
let utterance = [];
this._addRole(utterance, aRoleStr);
this._addRole(utterance, aAccessible, aRoleStr);
utterance.push({
string: this._getOutputName('listItemsCount'),
count: aItemCount
@ -805,8 +962,12 @@ this.BrailleGenerator = { // jshint ignore:line
return OutputGenerator._getOutputName(aName) + 'Abbr';
},
_addRole: function _addRole(aBraille, aRoleStr) {
aBraille.push({string: this._getOutputName(aRoleStr)});
_addRole: function _addRole(aBraille, aAccessible, aRoleStr) {
if (this.mathmlRolesSet.has(aAccessible.role)) {
this._addMathRoles(aBraille, aAccessible, aRoleStr);
} else {
aBraille.push({string: this._getOutputName(aRoleStr)});
}
},
_addState: function _addState(aBraille, aState, aRoleStr) {

View File

@ -102,7 +102,8 @@ var gSimpleTraversalRoles =
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.STATUSBAR,
Roles.SWITCH];
Roles.SWITCH,
Roles.MATHML_MATH];
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
// An object is simple, if it either has a single child lineage,

View File

@ -415,21 +415,41 @@ this.Utils = { // jshint ignore:line
},
getLandmarkName: function getLandmarkName(aAccessible) {
const landmarks = [
return this.matchRoles(aAccessible, [
'banner',
'complementary',
'contentinfo',
'main',
'navigation',
'search'
];
]);
},
getMathRole: function getMathRole(aAccessible) {
return this.matchRoles(aAccessible, [
'base',
'close-fence',
'denominator',
'numerator',
'open-fence',
'overscript',
'presubscript',
'presuperscript',
'root-index',
'subscript',
'superscript',
'underscript'
]);
},
matchRoles: function matchRoles(aAccessible, aRoles) {
let roles = this.getAttributes(aAccessible)['xml-roles'];
if (!roles) {
return;
}
// Looking up a role that would match a landmark.
return this.matchAttributeValue(roles, landmarks);
// Looking up a role that would match any in the provided roles.
return this.matchAttributeValue(roles, aRoles);
},
getEmbeddedControl: function getEmbeddedControl(aLabel) {
@ -884,8 +904,12 @@ PivotContext.prototype = {
if (!aAccessible) {
return null;
}
if ([Roles.CELL, Roles.COLUMNHEADER, Roles.ROWHEADER].indexOf(
aAccessible.role) < 0) {
if ([
Roles.CELL,
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.MATHML_CELL
].indexOf(aAccessible.role) < 0) {
return null;
}
try {
@ -950,7 +974,9 @@ PivotContext.prototype = {
cellInfo.current.columnHeaderCells))];
}
cellInfo.rowHeaders = [];
if (cellInfo.rowChanged && cellInfo.current.role === Roles.CELL) {
if (cellInfo.rowChanged &&
(cellInfo.current.role === Roles.CELL ||
cellInfo.current.role === Roles.MATHML_CELL)) {
cellInfo.rowHeaders = [headers for (headers of getHeaders( // jshint ignore:line
cellInfo.current.rowHeaderCells))];
}

View File

@ -18,6 +18,7 @@ skip-if = buildapp == 'mulet'
[test_hints.html]
[test_landmarks.html]
[test_live_regions.html]
[test_output_mathml.html]
[test_output.html]
[test_quicknav_modes.html]
[test_tables.html]

View File

@ -145,5 +145,11 @@
<div aria-label="Last sync: 30min ago" id="statusbar-2" role="status"></div>
<span id="switch-1" role="switch" aria-checked="false" aria-label="Light switch"></span>
<p>This is a MathML formula <math id="math-1" display="block">
<mfrac>
<mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>
<msqrt><mn>3</mn><mo>/</mo><mn>4</mn></msqrt>
</mfrac>
</math> with some text after.</p>
</body>
</html>

View File

@ -0,0 +1,305 @@
<html>
<head>
<title>[AccessFu] MathML Accessibility Support</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="output.js"></script>
<script type="application/javascript">
function doTest() {
// Test the following accOrElmOrID.
var tests = [{
accOrElmOrID: "math-1",
expectedUtterance: [
[{"string":"open-fence"},"(","x",",","y",{"string":"close-fence"},")"],
["(",{"string":"open-fence"},"x",",","y",")",{"string":"close-fence"}]
],
expectedBraille: [
[{"string":"open-fenceAbbr"},"(","x",",","y",{"string":"close-fenceAbbr"},")"],
["(",{"string":"open-fenceAbbr"},"x",",","y",")",{"string":"close-fenceAbbr"}]
]
}, {
accOrElmOrID: "mfrac-1",
expectedUtterance: [
[{"string":"mathmlfraction"},{"string":"numerator"},"a",{"string":"denominator"},"b"],
["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfraction"}]
],
expectedBraille: [
[{"string":"mathmlfractionAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"],
["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionAbbr"}]
]
}, {
accOrElmOrID: "mfrac-2",
expectedUtterance: [
[{"string":"mathmlfractionwithoutbar"},{"string":"numerator"},"a",{"string":"denominator"},"b"],
["a",{"string":"numerator"},"b",{"string":"denominator"},{"string":"mathmlfractionwithoutbar"}]
],
expectedBraille: [
[{"string":"mathmlfractionwithoutbarAbbr"},{"string":"numeratorAbbr"},"a",{"string":"denominatorAbbr"},"b"],
["a",{"string":"numeratorAbbr"},"b",{"string":"denominatorAbbr"},{"string":"mathmlfractionwithoutbarAbbr"}]
]
}, {
accOrElmOrID: "msub-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b"],
["a",{"string":"base"},"b",{"string":"subscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b"],
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "msup-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"superscript"},"b"],
["a",{"string":"base"},"b",{"string":"superscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"superscriptAbbr"},"b"],
["a",{"string":"baseAbbr"},"b",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "msubsup-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c"],
["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c"],
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "mmultiscripts-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"subscript"},"b",{"string":"superscript"},"c",{"string":"superscript"},"d",{"string":"presubscript"},"e",{"string":"presubscript"},"f",{"string":"presuperscript"},"g"],
["a",{"string":"base"},"b",{"string":"subscript"},"c",{"string":"superscript"},"d",{"string":"superscript"},"e",{"string":"presubscript"},"f",{"string":"presubscript"},"g",{"string":"presuperscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"subscriptAbbr"},"b",{"string":"superscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"presubscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presuperscriptAbbr"},"g"],
["a",{"string":"baseAbbr"},"b",{"string":"subscriptAbbr"},"c",{"string":"superscriptAbbr"},"d",{"string":"superscriptAbbr"},"e",{"string":"presubscriptAbbr"},"f",{"string":"presubscriptAbbr"},"g",{"string":"presuperscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "munder-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b"],
["a",{"string":"base"},"b",{"string":"underscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b"],
["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "mover-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"overscript"},"b"],
["a",{"string":"base"},"b",{"string":"overscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"overscriptAbbr"},"b"],
["a",{"string":"baseAbbr"},"b",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "munderover-1",
expectedUtterance: [
[{"string":"mathmlscripted"},{"string":"base"},"a",{"string":"underscript"},"b",{"string":"overscript"},"c"],
["a",{"string":"base"},"b",{"string":"underscript"},"c",{"string":"overscript"},{"string":"mathmlscripted"}]
],
expectedBraille: [
[{"string":"mathmlscriptedAbbr"},{"string":"baseAbbr"},"a",{"string":"underscriptAbbr"},"b",{"string":"overscriptAbbr"},"c"],
["a",{"string":"baseAbbr"},"b",{"string":"underscriptAbbr"},"c",{"string":"overscriptAbbr"},{"string":"mathmlscriptedAbbr"}]
]
}, {
accOrElmOrID: "mroot-1",
expectedUtterance: [
[{"string":"mathmlroot"},{"string":"base"},"a",{"string":"root-index"},"b"],
["a",{"string":"base"},"b",{"string":"root-index"},{"string":"mathmlroot"}]
],
expectedBraille: [
[{"string":"mathmlrootAbbr"},{"string":"baseAbbr"},"a",{"string":"root-indexAbbr"},"b"],
["a",{"string":"baseAbbr"},"b",{"string":"root-indexAbbr"},{"string":"mathmlrootAbbr"}]
]
}, {
accOrElmOrID: "mtable-1",
expectedUtterance: [
[{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2},{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"a",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"d",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},"f"],
["a",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[1]},"b",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[1]},"c",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[1]},"d",{"string":"columnInfo","args":[1]},{"string":"rowInfo","args":[2]},"e",{"string":"columnInfo","args":[2]},{"string":"rowInfo","args":[2]},"f",{"string":"columnInfo","args":[3]},{"string":"rowInfo","args":[2]},{"string":"mathmltable"},{"string":"tblColumnInfo","count":3},{"string":"tblRowInfo","count":2}]
],
expectedBraille: [
[{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2},{"string":"cellInfoAbbr","args":[1,1]},"a",{"string":"cellInfoAbbr","args":[2,1]},"b",{"string":"cellInfoAbbr","args":[3,1]},"c",{"string":"cellInfoAbbr","args":[1,2]},"d",{"string":"cellInfoAbbr","args":[2,2]},"e",{"string":"cellInfoAbbr","args":[3,2]},"f"],
["a",{"string":"cellInfoAbbr","args":[1,1]},"b",{"string":"cellInfoAbbr","args":[2,1]},"c",{"string":"cellInfoAbbr","args":[3,1]},"d",{"string":"cellInfoAbbr","args":[1,2]},"e",{"string":"cellInfoAbbr","args":[2,2]},"f",{"string":"cellInfoAbbr","args":[3,2]},{"string":"mathmltableAbbr"},{"string":"tblColumnInfoAbbr","count":3},{"string":"tblRowInfoAbbr","count":2}]
]
}, {
accOrElmOrID: "menclose-1",
expectedUtterance: [
[{"string":"mathmlenclosed"},{"string":"notation-longdiv"},"a"],
["a",{"string":"notation-longdiv"},{"string":"mathmlenclosed"}]
],
expectedBraille: [
[{"string":"mathmlenclosedAbbr"},{"string":"notation-longdivAbbr"},"a"],
["a",{"string":"notation-longdivAbbr"},{"string":"mathmlenclosedAbbr"}]
]
}, {
accOrElmOrID: "menclose-2",
expectedUtterance: [
[{"string":"mathmlenclosed"},{"string":"notation-circle"},"a"],
["a",{"string":"notation-circle"},{"string":"mathmlenclosed"}]
],
expectedBraille: [
[{"string":"mathmlenclosedAbbr"},{"string":"notation-circleAbbr"},"a"],
["a",{"string":"notation-circleAbbr"},{"string":"mathmlenclosedAbbr"}]
]
}, {
accOrElmOrID: "menclose-3",
expectedUtterance: [
[{"string":"mathmlenclosed"},{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},"a"],
["a",{"string":"notation-left"},{"string":"notation-top"},{"string":"notation-bottom"},{"string":"mathmlenclosed"}]
],
expectedBraille: [
[{"string":"mathmlenclosedAbbr"},{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},"a"],
["a",{"string":"notation-leftAbbr"},{"string":"notation-topAbbr"},{"string":"notation-bottomAbbr"},{"string":"mathmlenclosedAbbr"}]
]
}];
// Test all possible utterance order preference values.
tests.forEach(function run(test) {
var outputOrderValues = [0, 1];
outputOrderValues.forEach(function testOutputOrder(outputOrder) {
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, outputOrder);
testOutput(test.expectedUtterance[outputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 1);
testOutput(test.expectedBraille[outputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 0);
});
});
// If there was an original utterance order preference, revert to it.
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<div id="root">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1163374"
title="[AccessFu] MathML Accessibility Support">
Mozilla Bug 1163374
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<math id="math-1"><mo>(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>)</mo></math>
<math>
<mfrac id="mfrac-1">
<mi>a</mi>
<mi>b</mi>
</mfrac>
</math>
<math>
<mfrac id="mfrac-2" linethickness="0px">
<mi>a</mi>
<mi>b</mi>
</mfrac>
</math>
<math>
<msub id="msub-1">
<mi>a</mi>
<mi>b</mi>
</msub>
</math>
<math>
<msup id="msup-1">
<mi>a</mi>
<mi>b</mi>
</msup>
</math>
<math>
<msubsup id="msubsup-1">
<mi>a</mi>
<mi>b</mi>
<mi>c</mi>
</msubsup>
</math>
<math>
<mmultiscripts id="mmultiscripts-1">
<mi>a</mi>
<mi>b</mi>
<mi>c</mi>
<none/>
<mi>d</mi>
<mprescripts/>
<mi>e</mi>
<none/>
<mi>f</mi>
<mi>g</mi>
</mmultiscripts>
</math>
<math>
<munder id="munder-1">
<mi>a</mi>
<mi>b</mi>
</munder>
</math>
<math>
<mover id="mover-1">
<mi>a</mi>
<mi>b</mi>
</mover>
</math>
<math>
<munderover id="munderover-1">
<mi>a</mi>
<mi>b</mi>
<mi>c</mi>
</munderover>
</math>
<math>
<mroot id="mroot-1">
<mi>a</mi>
<mi>b</mi>
</mroot>
</math>
<math>
<mtable id="mtable-1">
<mtr>
<mtd><mi>a</mi></mtd>
<mtd><mi>b</mi></mtd>
<mtd><mi>c</mi></mtd>
</mtr>
<mtr>
<mtd><mi>d</mi></mtd>
<mtd><mi>e</mi></mtd>
<mtd><mi>f</mi></mtd>
</mtr>
</mtable>
</math>
<math>
<menclose id="menclose-1"><mi>a</mi></menclose>
</math>
<math>
<menclose id="menclose-2" notation="circle"><mi>a</mi></menclose>
</math>
<math>
<menclose id="menclose-3" notation="left top bottom"><mi>a</mi></menclose>
</math>
</div>
</body>
</html>

View File

@ -124,7 +124,8 @@
'5 8', 'gridcell4', 'Just an innocuous separator',
'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
'Dirt', 'Messy Stuff', 'statusbar-1', 'statusbar-2',
'switch-1']);
'switch-1', 'This is a MathML formula ', 'math-1',
'with some text after.']);
gQueue.invoke();
}

View File

@ -5610,11 +5610,24 @@ function handleLinkClick(event, href, linkNode) {
catch (e) { }
}
// first get document wide referrer policy, then
// get referrer attribute from clicked link and parse it and
// allow per element referrer to overrule the document wide referrer if enabled
let referrerPolicy = doc.referrerPolicy;
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
linkNode) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
getAttribute("referrer"));
if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
urlSecurityCheck(href, doc.nodePrincipal);
let params = { charset: doc.characterSet,
allowMixedContent: persistAllowMixedContentInChildTab,
referrerURI: referrerURI,
referrerPolicy: doc.referrerPolicy,
referrerPolicy: referrerPolicy,
noReferrer: BrowserUtils.linkHasNoReferrer(linkNode) };
openLinkIn(href, where, params);
event.preventDefault();

View File

@ -105,6 +105,17 @@ let handleContentContextMenu = function (event) {
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
getAttribute("referrer"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
let disableSetDesktopBg = null;
// Media related cache info parent needs for saving
let contentType = null;
@ -351,10 +362,23 @@ let ClickEventHandler = {
let [href, node] = this._hrefAndLinkNodeForClickEvent(event);
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
let referrerPolicy = ownerDoc.referrerPolicy;
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
node) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
getAttribute("referrer"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
let json = { button: event.button, shiftKey: event.shiftKey,
ctrlKey: event.ctrlKey, metaKey: event.metaKey,
altKey: event.altKey, href: null, title: null,
bookmark: false, referrerPolicy: ownerDoc.referrerPolicy };
bookmark: false, referrerPolicy: referrerPolicy };
if (href) {
try {

View File

@ -180,6 +180,11 @@ bool isIgnoredPathForImplicitCtor(const Decl *decl) {
begin->compare_lower(StringRef("graphite2")) == 0) {
return true;
}
if (begin->compare_lower(StringRef("chromium")) == 0) {
// Ignore security/sandbox/chromium but not ipc/chromium.
++begin;
return begin != end && begin->compare_lower(StringRef("sandbox")) == 0;
}
}
return false;
}

View File

@ -77,6 +77,7 @@
#include "IHistory.h"
#include "nsViewSourceHandler.h"
#include "nsWhitespaceTokenizer.h"
#include "nsICookieService.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -207,10 +208,6 @@
#endif
#include "mozIThirdPartyUtil.h"
// Values for the network.cookie.cookieBehavior pref are documented in
// nsCookieService.cpp
#define COOKIE_BEHAVIOR_ACCEPT 0 // Allow all cookies.
#define COOKIE_BEHAVIOR_REJECT_FOREIGN 1 // Reject all third-party cookies.
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
@ -13509,6 +13506,16 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
if (IsElementAnchor(aContent)) {
net::ReferrerPolicy refPolEnum = aContent->AsElement()->GetReferrerPolicy();
if (refPolEnum != net::RP_Unset) {
refererPolicy = refPolEnum;
}
}
// referer could be null here in some odd cases, but that's ok,
// we'll just load the link w/o sending a referer in those cases.
@ -14068,8 +14075,8 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate,
NS_ENSURE_SUCCESS(result, result);
if (isThirdPartyURI &&
(Preferences::GetInt("network.cookie.cookieBehavior",
COOKIE_BEHAVIOR_ACCEPT) ==
COOKIE_BEHAVIOR_REJECT_FOREIGN)) {
nsICookieService::BEHAVIOR_ACCEPT) ==
nsICookieService::BEHAVIOR_REJECT_FOREIGN)) {
return NS_OK;
}
}

View File

@ -20,46 +20,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationTimeline)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
namespace {
struct AddAnimationParams {
AnimationTimeline::AnimationSequence& mSequence;
#ifdef DEBUG
// This is only used for a pointer-equality assertion
AnimationTimeline* mTimeline;
#endif
};
} // namespace
static PLDHashOperator
AppendAnimationToSequence(nsRefPtrHashKey<dom::Animation>* aKey,
void* aParams)
{
Animation* animation = aKey->GetKey();
AddAnimationParams* params = static_cast<AddAnimationParams*>(aParams);
MOZ_ASSERT(animation->IsRelevant(),
"Animations registered with a timeline should be relevant");
MOZ_ASSERT(animation->GetTimeline() == params->mTimeline,
"Animation should refer to this timeline");
// Bug 1174575: Until we implement a suitable PseudoElement interface we
// don't have anything to return for the |target| attribute of
// KeyframeEffect(ReadOnly) objects that refer to pseudo-elements.
// Rather than return some half-baked version of these objects (e.g.
// we a null effect attribute) we simply don't provide access to animations
// whose effect refers to a pseudo-element until we can support them properly.
Element* target;
nsCSSPseudoElements::Type pseudoType;
animation->GetEffect()->GetTarget(target, pseudoType);
if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) {
return PL_DHASH_NEXT;
}
params->mSequence.AppendElement(animation);
return PL_DHASH_NEXT;
}
void
AnimationTimeline::GetAnimations(AnimationSequence& aAnimations)
{
@ -71,12 +31,28 @@ AnimationTimeline::GetAnimations(AnimationSequence& aAnimations)
}
}
#ifdef DEBUG
AddAnimationParams params{ aAnimations, this };
#else
AddAnimationParams params{ aAnimations };
#endif
mAnimations.EnumerateEntries(AppendAnimationToSequence, &params);
for (auto iter = mAnimations.Iter(); !iter.Done(); iter.Next()) {
Animation* animation = iter.Get()->GetKey();
MOZ_ASSERT(animation->IsRelevant(),
"Animations registered with a timeline should be relevant");
MOZ_ASSERT(animation->GetTimeline() == this,
"Animation should refer to this timeline");
// Bug 1174575: Until we implement a suitable PseudoElement interface we
// don't have anything to return for the |target| attribute of
// KeyframeEffect(ReadOnly) objects that refer to pseudo-elements.
// Rather than return some half-baked version of these objects (e.g.
// we a null effect attribute) we simply don't provide access to animations
// whose effect refers to a pseudo-element until we can support them
// properly.
Element* target;
nsCSSPseudoElements::Type pseudoType;
animation->GetEffect()->GetTarget(target, pseudoType);
if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
aAnimations.AppendElement(animation);
}
}
// Sort animations by priority
aAnimations.Sort(AnimationPtrComparator<nsRefPtr<Animation>>());

View File

@ -48,60 +48,56 @@ PendingAnimationTracker::IsWaiting(const dom::Animation& aAnimation,
return aSet.Contains(const_cast<dom::Animation*>(&aAnimation));
}
PLDHashOperator
TriggerAnimationAtTime(nsRefPtrHashKey<dom::Animation>* aKey,
void* aReadyTime)
{
dom::Animation* animation = aKey->GetKey();
dom::AnimationTimeline* timeline = animation->GetTimeline();
// If the animation does not have a timeline, just drop it from the map.
// The animation will detect that it is not being tracked and will trigger
// itself on the next tick where it has a timeline.
if (!timeline) {
return PL_DHASH_REMOVE;
}
// When the timeline's refresh driver is under test control, its values
// have no correspondance to wallclock times so we shouldn't try to convert
// aReadyTime (which is a wallclock time) to a timeline value. Instead, the
// animation will be started/paused when the refresh driver is next
// advanced since this will trigger a call to TriggerPendingAnimationsNow.
if (!timeline->TracksWallclockTime()) {
return PL_DHASH_NEXT;
}
Nullable<TimeDuration> readyTime =
timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime));
animation->TriggerOnNextTick(readyTime);
return PL_DHASH_REMOVE;
}
void
PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp&
aReadyTime)
{
mPlayPendingSet.EnumerateEntries(TriggerAnimationAtTime,
const_cast<TimeStamp*>(&aReadyTime));
mPausePendingSet.EnumerateEntries(TriggerAnimationAtTime,
const_cast<TimeStamp*>(&aReadyTime));
}
auto triggerAnimationsAtReadyTime = [aReadyTime](AnimationSet& aAnimationSet)
{
for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
dom::Animation* animation = iter.Get()->GetKey();
dom::AnimationTimeline* timeline = animation->GetTimeline();
PLDHashOperator
TriggerAnimationNow(nsRefPtrHashKey<dom::Animation>* aKey, void*)
{
aKey->GetKey()->TriggerNow();
return PL_DHASH_NEXT;
// If the animation does not have a timeline, just drop it from the map.
// The animation will detect that it is not being tracked and will trigger
// itself on the next tick where it has a timeline.
if (!timeline) {
iter.Remove();
}
// When the timeline's refresh driver is under test control, its values
// have no correspondance to wallclock times so we shouldn't try to
// convert aReadyTime (which is a wallclock time) to a timeline value.
// Instead, the animation will be started/paused when the refresh driver
// is next advanced since this will trigger a call to
// TriggerPendingAnimationsNow.
if (!timeline->TracksWallclockTime()) {
continue;
}
Nullable<TimeDuration> readyTime = timeline->ToTimelineTime(aReadyTime);
animation->TriggerOnNextTick(readyTime);
iter.Remove();
}
};
triggerAnimationsAtReadyTime(mPlayPendingSet);
triggerAnimationsAtReadyTime(mPausePendingSet);
}
void
PendingAnimationTracker::TriggerPendingAnimationsNow()
{
mPlayPendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
mPlayPendingSet.Clear();
mPausePendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
mPausePendingSet.Clear();
auto triggerAndClearAnimations = [](AnimationSet& aAnimationSet) {
for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
iter.Get()->GetKey()->TriggerNow();
}
aAnimationSet.Clear();
};
triggerAndClearAnimations(mPlayPendingSet);
triggerAndClearAnimations(mPausePendingSet);
}
void

View File

@ -62,3 +62,4 @@ support-files = document-timeline/file_document-timeline.html
skip-if = buildapp == 'mulet'
[mozilla/test_deferred_start.html]
support-files = mozilla/file_deferred_start.html
skip-if = (toolkit == 'gonk' && debug)

View File

@ -140,6 +140,7 @@
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/VRDevice.h"
#include "nsComputedDOMStyle.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -3485,3 +3486,16 @@ Element::FontSizeInflation()
return 1.0;
}
net::ReferrerPolicy
Element::GetReferrerPolicy()
{
if (Preferences::GetBool("network.http.enablePerElementReferrer", false) &&
IsHTMLElement()) {
const nsAttrValue* referrerValue = GetParsedAttr(nsGkAtoms::referrer);
if (referrerValue && referrerValue->Type() == nsAttrValue::eEnum) {
return net::ReferrerPolicy(referrerValue->GetEnumValue());
}
}
return net::RP_Unset;
}

View File

@ -1060,6 +1060,8 @@ public:
*/
float FontSizeInflation();
net::ReferrerPolicy GetReferrerPolicy();
protected:
/*
* Named-bools for use with SetAttrAndNotify to make call sites easier to

View File

@ -937,30 +937,26 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
}
// get document wide referrer policy
mozilla::net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", false);
// if referrer attributes are enabled in preferences, load img referrer attribute
nsresult rv;
if (referrerAttributeEnabled) {
mozilla::net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
// if the image does not provide a referrer attribute, ignore this
if (imgReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = imgReferrerPolicy;
}
// if the image does not provide a referrer attribute, ignore this
net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
if (imgReferrerPolicy != net::RP_Unset) {
referrerPolicy = imgReferrerPolicy;
}
// Not blocked. Do the load.
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
aDocument->NodePrincipal(),
aDocument->GetDocumentURI(),
referrerPolicy,
this, loadFlags,
content->LocalName(),
getter_AddRefs(req),
policyType);
nsresult rv = nsContentUtils::LoadImage(aNewURI, aDocument,
aDocument->NodePrincipal(),
aDocument->GetDocumentURI(),
referrerPolicy,
this, loadFlags,
content->LocalName(),
getter_AddRefs(req),
policyType);
// Tell the document to forget about the image preload, if any, for
// this URI, now that we might have another imgRequestProxy for it.

View File

@ -240,6 +240,8 @@ support-files =
file_audioLoop.html
file_webaudioLoop.html
file_webaudioLoop2.html
referrer_helper.js
referrer_testserver.sjs
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -672,6 +674,8 @@ support-files = referrerHelper.js
[test_bug1165501.html]
support-files = referrerHelper.js
[test_img_referrer.html]
[test_anchor_area_referrer.html]
[test_anchor_area_referrer_changing.html]
[test_caretPositionFromPoint.html]
[test_classList.html]
# This test fails on the Mac for some reason

View File

@ -0,0 +1,98 @@
/*
* common functionality for iframe, anchor, and area referrer attribute tests
*/
const GET_RESULT = sjs + 'action=get-test-results';
const RESET_STATE = sjs + 'action=resetState';
SimpleTest.waitForExplicitFinish();
var advance = function() { tests.next(); };
/**
* Listen for notifications from the child.
* These are sent in case of error, or when the loads we await have completed.
*/
window.addEventListener("message", function(event) {
if (event.data == "childLoadComplete") {
// all loads happen, continue the test.
advance();
}
});
/**
* helper to perform an XHR
* to do checkIndividualResults and resetState
*/
function doXHR(aUrl, onSuccess, onFail) {
var xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.onload = function () {
onSuccess(xhr);
};
xhr.onerror = function () {
onFail(xhr);
};
xhr.open('GET', aUrl, true);
xhr.send(null);
}
/**
* Grabs the results via XHR and passes to checker.
*/
function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
var onload = xhr => {
var results = xhr.response;
info(JSON.stringify(xhr.response));
ok(aName in results, aName + " tests have to be performed.");
is(results[aName].policy, aExpectedReferrer, aTestname + ' --- ' + results[aName].policy + ' (' + results[aName].referrer + ')');
advance();
};
var onerror = xhr => {
ok(false, "Can't get results from the counter server.");
SimpleTest.finish();
};
doXHR(GET_RESULT, onload, onerror);
}
function resetState() {
doXHR(RESET_STATE,
advance,
function(xhr) {
ok(false, "error in reset state");
SimpleTest.finish();
});
}
/**
* testing if anchor and area referrer attributes are honoured (1174913)
*/
var tests = (function() {
// enable referrer attribute
yield SpecialPowers.pushPrefEnv({"set": [['network.http.enablePerElementReferrer', true]]}, advance);
var iframe = document.getElementById("testframe");
for (var j = 0; j < testCases.length; j++) {
var actions = testCases[j].ACTION;
var tests = testCases[j].TESTS;
for (var k = 0; k < actions.length; k++) {
var actionString = actions[k];
for (var i = 0; i < tests.length; i++) {
yield resetState();
var searchParams = new URLSearchParams();
searchParams.append(ACTION, actionString);
searchParams.append(NAME, tests[i].NAME);
for (var l of PARAMS) {
if (tests[i][l]) {
searchParams.append(window[l], tests[i][l]);
}
}
yield iframe.src = sjs + searchParams.toString();
yield checkIndividualResults(tests[i].DESC, tests[i].RESULT, tests[i].NAME);
};
};
};
// complete. Be sure to yield so we don't call this twice.
yield SimpleTest.finish();
})();

View File

@ -0,0 +1,180 @@
/*
* Test server for iframe, anchor, and area referrer attributes.
* https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
*/
Components.utils.importGlobalProperties(["URLSearchParams"]);
const BASE_URL = 'example.com/tests/dom/base/test/referrer_testserver.sjs';
const SHARED_KEY = 'referrer_testserver.sjs';
const ATTRIBUTE_POLICY = 'attributePolicy';
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
const NAME = 'name';
const META_POLICY = 'metaPolicy';
const REL = 'rel';
function createTestUrl(aPolicy, aAction, aName, aType) {
return 'http://' + BASE_URL + '?' +
'action=' + aAction + '&' +
'policy=' + aPolicy + '&' +
'name=' + aName + '&' +
'type=' + aType;
}
function buildAnchorString(aMetaPolicy, aReferrerPolicy, aName, aRelString){
if (aReferrerPolicy) {
return `<a href="${createTestUrl(aReferrerPolicy, 'test', aName, 'link')}" referrer="${aReferrerPolicy}" id="link" ${aRelString}>${aReferrerPolicy}</a>`;
}
return `<a href="${createTestUrl(aMetaPolicy, 'test', aName, 'link')}" id="link" ${aRelString}>link</a>`;
}
function buildAreaString(aMetaPolicy, aReferrerPolicy, aName, aRelString){
var result = `<img src="file_mozfiledataurl_img.jpg" alt="image" usemap="#imageMap">`;
result += `<map name="imageMap">`;
if (aReferrerPolicy) {
result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(aReferrerPolicy, 'test', aName, 'link')}" alt="theArea" referrer="${aReferrerPolicy}" id="link" ${aRelString}>`;
} else {
result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(aMetaPolicy, 'test', aName, 'link')}" alt="theArea" id="link" ${aRelString}>`;
}
result += `</map>`;
return result;
}
// test page using anchor or area referrer attribute
function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aRel, aStringBuilder, aChangingMethod) {
var metaString = '';
if (aMetaPolicy) {
metaString = '<head><meta name="referrer" content="' + aMetaPolicy + '"></head>';
}
var changeString = '';
if (aChangingMethod === 'setAttribute') {
changeString = `document.getElementById("link").setAttribute("referrer", "${aNewAttributePolicy}")`;
} else if (aChangingMethod === 'property') {
changeString = `document.getElementById("link").referrer = "${aNewAttributePolicy}"`;
}
var relString = '';
if (aRel) {
relString = `rel="noreferrer"`;
}
var elementString = aStringBuilder(aMetaPolicy, aAttributePolicy, aName, relString);
return `<!DOCTYPE HTML>
<html>
${metaString}
<body>
${elementString}
<script>
window.addEventListener("load", function() {
${changeString}
document.getElementById("link").click();
}.bind(window), false);
</script>
</body>
</html>`;
}
function handleRequest(request, response) {
var params = new URLSearchParams(request.queryString);
var action = params.get('action');
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/html; charset=utf-8', false);
if (action === 'resetState') {
setSharedState(SHARED_KEY, "{}");
response.write("");
return;
}
if (action === 'get-test-results') {
// ?action=get-result
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/plain', false);
response.write(getSharedState(SHARED_KEY));
return;
}
if (action === 'redirect') {
response.write('<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>');
return;
}
if (action === 'test') {
// ?action=test&policy=origin&name=name
var policy = params.get('policy');
var name = params.get('name');
var type = params.get('type');
var result = getSharedState(SHARED_KEY);
result = result ? JSON.parse(result) : {};
var referrerLevel = "none";
var test = {}
if (request.hasHeader('Referer')) {
var referrer = request.getHeader("Referer");
if (referrer.indexOf("referrer_testserver") > 0) {
referrerLevel = "full";
} else if (referrer.indexOf("http://mochi.test:8888") == 0) {
referrerLevel = "origin";
} else {
// this is never supposed to happen
referrerLevel = "other-origin";
}
test.referrer = referrer;
} else {
test.referrer = '';
}
test.policy = referrerLevel;
test.expected = policy;
result[name] = test;
setSharedState(SHARED_KEY, JSON.stringify(result));
if (type === "link") {
// forward link click to redirect URL to finish test
var loc = "http://" + BASE_URL + "?action=redirect";
response.setStatusLine('1.1', 302, 'Found');
response.setHeader('Location', loc, false);
}
return;
}
// parse test arguments and start test
var attributePolicy = params.get(ATTRIBUTE_POLICY) || '';
var newAttributePolicy = params.get(NEW_ATTRIBUTE_POLICY) || '';
var metaPolicy = params.get(META_POLICY) || '';
var rel = params.get(REL) || '';
var name = params.get(NAME);
// anchor & area
var _getPage = createAETestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name, rel);
var _getAnchorPage = _getPage.bind(null, buildAnchorString);
var _getAreaPage = _getPage.bind(null, buildAreaString);
// aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder
if (action === 'generate-anchor-policy-test') {
response.write(_getAnchorPage());
return;
}
if (action === 'generate-anchor-changing-policy-test-set-attribute') {
response.write(_getAnchorPage('setAttribute'));
return;
}
if (action === 'generate-anchor-changing-policy-test-property') {
response.write(_getAnchorPage('property'));
return;
}
if (action === 'generate-area-policy-test') {
response.write(_getAreaPage());
return;
}
if (action === 'generate-area-changing-policy-test-set-attribute') {
response.write(_getAreaPage('setAttribute'));
return;
}
if (action === 'generate-area-changing-policy-test-property') {
response.write(_getAreaPage('property'));
return;
}
response.write("I don't know action " + action);
return;
}

View File

@ -0,0 +1,116 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test anchor and area policy attribute for Bug 1174913</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<!--
Testing that anchor and area referrer attributes are honoured correctly
* anchor tag with referrer attribute (generate-anchor-policy-test)
* regression tests that meta referrer is still working even if attribute referrers are enabled (generate-anchor-policy-test)
https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
-->
<script type="application/javascript;version=1.8">
const sjs = "/tests/dom/base/test/referrer_testserver.sjs?";
const ATTRIBUTE_POLICY = 'attributePolicy';
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
const NAME = 'name';
const META_POLICY = 'metaPolicy';
const DESC = 'description';
const RESULT = 'result';
const ACTION = 'action';
const TESTS = 'tests';
const REL = 'rel';
const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
const testCases = [
{ACTION: ["generate-anchor-policy-test", "generate-area-policy-test"],
TESTS: [
{ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-with-origin-in-meta',
META_POLICY: 'origin',
DESC: "unsafe-url (anchor) with origin in meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'origin',
NAME: 'origin-with-unsafe-url-in-meta',
META_POLICY: 'unsafe-url',
DESC: "origin (anchor) with unsafe-url in meta",
RESULT: 'origin'},
{ATTRIBUTE_POLICY: 'no-referrer',
NAME: 'no-referrer-with-origin-in-meta',
META_POLICY: 'origin',
DESC: "no-referrer (anchor) with origin in meta",
RESULT: 'none'},
{NAME: 'no-referrer-in-meta',
META_POLICY: 'no-referrer',
DESC: "no-referrer in meta",
RESULT: 'none'},
{ATTRIBUTE_POLICY: 'origin',
NAME: 'origin-with-no-meta',
META_POLICY: '',
DESC: "origin (anchor) with no meta",
RESULT: 'origin'},
// setting rel=noreferrer -> we expect no referrer
{ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-with-origin-in-meta-rel',
META_POLICY: 'origin',
DESC: "unsafe-url (anchor) with origin in meta and rel=noreferrer",
RESULT: 'none',
REL: 'noreferrer'},
{ATTRIBUTE_POLICY: 'origin',
NAME: 'origin-with-unsafe-url-in-meta-rel',
META_POLICY: 'unsafe-url',
DESC: "origin (anchor) with unsafe-url in meta and rel=noreferrer",
RESULT: 'none',
REL: 'noreferrer'},
{ATTRIBUTE_POLICY: 'origin',
NAME: 'origin-with-no-meta-rel',
META_POLICY: '',
DESC: "origin (anchor) with no meta and rel=noreferrer",
RESULT: 'none',
REL: 'noreferrer'},
// setting invalid refer values -> we expect either full referrer (default)
// or whatever is specified in the meta referrer policy
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
NAME: 'origin-when-cross-origin-with-no-meta',
META_POLICY: '',
DESC: "origin-when-cross-origin (anchor) with no meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'default',
NAME: 'default-with-no-meta',
META_POLICY: '',
DESC: "default (anchor) with no meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'something',
NAME: 'something-with-no-meta',
META_POLICY: '',
DESC: "something (anchor) with no meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
NAME: 'origin-when-cross-origin-with-no-referrer-in-meta',
META_POLICY: 'no-referrer',
DESC: "origin-when-cross-origin (anchor) with no-referrer in meta",
RESULT: 'none'},
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
NAME: 'origin-when-cross-origin-with-unsafe-url-in-meta',
META_POLICY: 'unsafe-url',
DESC: "origin-when-cross-origin (anchor) with unsafe-url in meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'origin-when-cross-origin',
NAME: 'origin-when-cross-origin-with-origin-in-meta',
META_POLICY: 'origin',
DESC: "origin-when-cross-origin (anchor) with origin in meta",
RESULT: 'origin'}]}
];
</script>
<script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
</head>
<body onload="tests.next();">
<iframe id="testframe"></iframe>
</body>
</html>

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test anchor and area policy attribute for Bug 1174913</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<!--
Testing that anchor and area referrer attributes are honoured correctly
This test is split due to errors on b2g
* testing setAttribute and .referrer (generate-anchor-changing-test)
https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
-->
<script type="application/javascript;version=1.8">
const sjs = "/tests/dom/base/test/referrer_testserver.sjs?";
const ATTRIBUTE_POLICY = 'attributePolicy';
const NEW_ATTRIBUTE_POLICY = 'newAttributePolicy';
const NAME = 'name';
const META_POLICY = 'metaPolicy';
const DESC = 'description';
const RESULT = 'result';
const ACTION = 'action';
const TESTS = 'tests';
const REL = 'rel';
const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
const testCases = [
{ACTION: ["generate-anchor-changing-policy-test-set-attribute", "generate-area-changing-policy-test-set-attribute"],
TESTS: [
{ATTRIBUTE_POLICY: 'unsafe-url',
NEW_ATTRIBUTE_POLICY: 'no-referrer',
NAME: 'no-referrer-unsafe-url-with-origin-in-meta',
META_POLICY: 'origin',
DESC: "no-referrer (anchor, orginally unsafe-url) with origin in meta",
RESULT: 'none'},
{ATTRIBUTE_POLICY: 'origin',
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-origin-with-no-referrer-in-meta',
META_POLICY: 'no-referrer',
DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'origin',
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-origin-with-no-referrer-in-meta-rel',
META_POLICY: 'no-referrer',
DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta and rel=noreferrer",
RESULT: 'none',
REL: 'noreferrer'}]},
{ACTION: ["generate-anchor-changing-policy-test-property", "generate-area-changing-policy-test-property"],
TESTS: [
{ATTRIBUTE_POLICY: 'no-referrer',
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-no-referrer-with-origin-in-meta',
META_POLICY: 'origin',
DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta",
RESULT: 'full'},
{ATTRIBUTE_POLICY: 'no-referrer',
NEW_ATTRIBUTE_POLICY: 'unsafe-url',
NAME: 'unsafe-url-no-referrer-with-origin-in-meta-rel',
META_POLICY: 'origin',
DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta and rel=noreferrer",
RESULT: 'none',
REL: 'noreferrer'}]}
];
</script>
<script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
</head>
<body onload="tests.next();">
<iframe id="testframe"></iframe>
</body>
</html>

View File

@ -123,6 +123,14 @@ public:
{
SetHTMLAttr(nsGkAtoms::rel, aValue, rv);
}
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
{
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
}
void GetReferrer(nsAString& aReferrer)
{
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
}
nsDOMTokenList* RelList();
void GetHreflang(DOMString& aValue)
{

View File

@ -128,6 +128,15 @@ public:
}
nsDOMTokenList* RelList();
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
{
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
}
void GetReferrer(nsAString& aReferrer)
{
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
}
// The Link::GetOrigin is OK for us
using Link::GetProtocol;

View File

@ -195,10 +195,10 @@ public:
}
void GetReferrer(nsAString& aReferrer)
{
GetEnumAttr(nsGkAtoms::referrer, nullptr, aReferrer);
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
}
mozilla::net::ReferrerPolicy
net::ReferrerPolicy
GetImageReferrerPolicy() override
{
return GetReferrerPolicy();

View File

@ -105,8 +105,6 @@
#include "mozilla/dom/HTMLBodyElement.h"
#include "imgIContainer.h"
#include "mozilla/net/ReferrerPolicy.h"
using namespace mozilla;
using namespace mozilla::dom;

View File

@ -233,17 +233,6 @@ public:
mScrollgrab = aValue;
}
mozilla::net::ReferrerPolicy
GetReferrerPolicy()
{
nsAutoString aPolicyString;
GetEnumAttr(nsGkAtoms::referrer, nullptr, aPolicyString);
if (aPolicyString.IsEmpty()) {
return mozilla::net::RP_Unset;
}
return mozilla::net::ReferrerPolicyFromString(aPolicyString);
}
/**
* Determine whether an attribute is an event (onclick, etc.)
* @param aName the attribute

View File

@ -9616,27 +9616,16 @@ UpdateRefcountFunction::WillCommit()
"DatabaseConnection::UpdateRefcountFunction::WillCommit",
js::ProfileEntry::Category::STORAGE);
struct Helper final
{
static PLDHashOperator
Update(const uint64_t& aKey, FileInfoEntry* aValue, void* aUserArg)
{
MOZ_ASSERT(aValue);
auto* function = static_cast<DatabaseUpdateFunction*>(aUserArg);
MOZ_ASSERT(function);
if (aValue->mDelta && !function->Update(aKey, aValue->mDelta)) {
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
DatabaseUpdateFunction function(this);
for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
auto key = iter.Key();
FileInfoEntry* value = iter.Data();
MOZ_ASSERT(value);
mFileInfoEntries.EnumerateRead(Helper::Update, &function);
if (value->mDelta && !function.Update(key, value->mDelta)) {
break;
}
}
nsresult rv = function.ErrorCode();
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -9662,22 +9651,15 @@ UpdateRefcountFunction::DidCommit()
"DatabaseConnection::UpdateRefcountFunction::DidCommit",
js::ProfileEntry::Category::STORAGE);
struct Helper final
{
static PLDHashOperator
Update(const uint64_t& aKey, FileInfoEntry* aValue, void* /* aUserArg */)
{
MOZ_ASSERT(aValue);
for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
auto value = iter.Data();
if (aValue->mDelta) {
aValue->mFileInfo->UpdateDBRefs(aValue->mDelta);
}
MOZ_ASSERT(value);
return PL_DHASH_NEXT;
if (value->mDelta) {
value->mFileInfo->UpdateDBRefs(value->mDelta);
}
};
mFileInfoEntries.EnumerateRead(Helper::Update, nullptr);
}
if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterCommit))) {
NS_WARNING("RemoveJournals failed!");
@ -9733,20 +9715,11 @@ UpdateRefcountFunction::RollbackSavepoint()
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(mInSavepoint);
struct Helper
{
static PLDHashOperator
Rollback(const uint64_t& aKey, FileInfoEntry* aValue, void* /* aUserArg */)
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aValue);
aValue->mDelta -= aValue->mSavepointDelta;
return PL_DHASH_NEXT;
}
};
mSavepointEntriesIndex.EnumerateRead(Helper::Rollback, nullptr);
for (auto iter = mSavepointEntriesIndex.ConstIter();
!iter.Done(); iter.Next()) {
auto value = iter.Data();
value->mDelta -= value->mSavepointDelta;
}
mInSavepoint = false;
mSavepointEntriesIndex.Clear();
@ -10815,31 +10788,6 @@ ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
{
AssertIsOnOwningThread();
struct Helper
{
static PLDHashOperator
MaybeScheduleTransaction(nsPtrHashKey<TransactionInfo>* aKey,
void* aClosure)
{
AssertIsOnBackgroundThread();
TransactionInfo* transactionInfo = aKey->GetKey();
MOZ_ASSERT(transactionInfo);
TransactionInfo* finishedInfo = static_cast<TransactionInfo*>(aClosure);
MOZ_ASSERT(finishedInfo);
MOZ_ASSERT(transactionInfo->mBlockedOn.Contains(finishedInfo));
transactionInfo->mBlockedOn.RemoveEntry(finishedInfo);
if (!transactionInfo->mBlockedOn.Count()) {
transactionInfo->Schedule();
}
return PL_DHASH_NEXT;
}
};
PROFILER_LABEL("IndexedDB",
"ConnectionPool::NoteFinishedTransaction",
js::ProfileEntry::Category::STORAGE);
@ -10894,8 +10842,18 @@ ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
blockInfo->mLastBlockingWrites.RemoveElement(transactionInfo);
}
transactionInfo->mBlocking.EnumerateEntries(Helper::MaybeScheduleTransaction,
transactionInfo);
for (auto iter = transactionInfo->mBlocking.Iter();
!iter.Done();
iter.Next()) {
TransactionInfo* blockedInfo = iter.Get()->GetKey();
MOZ_ASSERT(blockedInfo);
MOZ_ASSERT(blockedInfo->mBlockedOn.Contains(transactionInfo));
blockedInfo->mBlockedOn.RemoveEntry(transactionInfo);
if (!blockedInfo->mBlockedOn.Count()) {
blockedInfo->Schedule();
}
}
if (transactionInfo->mIsWriteTransaction) {
MOZ_ASSERT(dbInfo->mWriteTransactionCount);
@ -11731,38 +11689,13 @@ FullObjectStoreMetadata::HasLiveIndexes() const
{
AssertIsOnBackgroundThread();
class MOZ_STACK_CLASS Helper final
{
public:
static bool
HasLiveIndexes(const FullObjectStoreMetadata* aMetadata)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aMetadata);
bool hasLiveIndexes = false;
aMetadata->mIndexes.EnumerateRead(&Enumerate, &hasLiveIndexes);
return hasLiveIndexes;
for (auto iter = mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
if (!iter.Data()->mDeleted) {
return true;
}
}
private:
static PLDHashOperator
Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
{
auto* result = static_cast<bool*>(aClosure);
MOZ_ASSERT(result);
if (!aValue->mDeleted) {
*result = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
return Helper::HasLiveIndexes(this);
return false;
}
already_AddRefed<FullDatabaseMetadata>
@ -11770,79 +11703,6 @@ FullDatabaseMetadata::Duplicate() const
{
AssertIsOnBackgroundThread();
class MOZ_STACK_CLASS IndexClosure final
{
FullObjectStoreMetadata& mNew;
public:
explicit IndexClosure(FullObjectStoreMetadata& aNew)
: mNew(aNew)
{ }
static PLDHashOperator
Copy(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
{
MOZ_ASSERT(aKey);
MOZ_ASSERT(aValue);
MOZ_ASSERT(aClosure);
auto* closure = static_cast<IndexClosure*>(aClosure);
nsRefPtr<FullIndexMetadata> newMetadata = new FullIndexMetadata();
newMetadata->mCommonMetadata = aValue->mCommonMetadata;
if (NS_WARN_IF(!closure->mNew.mIndexes.Put(aKey, newMetadata,
fallible))) {
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
class MOZ_STACK_CLASS ObjectStoreClosure final
{
FullDatabaseMetadata& mNew;
public:
explicit ObjectStoreClosure(FullDatabaseMetadata& aNew)
: mNew(aNew)
{ }
static PLDHashOperator
Copy(const uint64_t& aKey, FullObjectStoreMetadata* aValue, void* aClosure)
{
MOZ_ASSERT(aKey);
MOZ_ASSERT(aValue);
MOZ_ASSERT(aClosure);
auto* objClosure = static_cast<ObjectStoreClosure*>(aClosure);
nsRefPtr<FullObjectStoreMetadata> newMetadata =
new FullObjectStoreMetadata();
newMetadata->mCommonMetadata = aValue->mCommonMetadata;
newMetadata->mNextAutoIncrementId = aValue->mNextAutoIncrementId;
newMetadata->mComittedAutoIncrementId = aValue->mComittedAutoIncrementId;
IndexClosure idxClosure(*newMetadata);
aValue->mIndexes.EnumerateRead(IndexClosure::Copy, &idxClosure);
if (NS_WARN_IF(aValue->mIndexes.Count() !=
newMetadata->mIndexes.Count())) {
return PL_DHASH_STOP;
}
if (NS_WARN_IF(!objClosure->mNew.mObjectStores.Put(aKey, newMetadata,
fallible))) {
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
// FullDatabaseMetadata contains two hash tables of pointers that we need to
// duplicate so we can't just use the copy constructor.
nsRefPtr<FullDatabaseMetadata> newMetadata =
@ -11853,14 +11713,41 @@ FullDatabaseMetadata::Duplicate() const
newMetadata->mNextObjectStoreId = mNextObjectStoreId;
newMetadata->mNextIndexId = mNextIndexId;
ObjectStoreClosure closure(*newMetadata);
mObjectStores.EnumerateRead(ObjectStoreClosure::Copy, &closure);
for (auto iter = mObjectStores.ConstIter(); !iter.Done(); iter.Next()) {
auto key = iter.Key();
auto value = iter.Data();
if (NS_WARN_IF(mObjectStores.Count() !=
newMetadata->mObjectStores.Count())) {
return nullptr;
nsRefPtr<FullObjectStoreMetadata> newOSMetadata =
new FullObjectStoreMetadata();
newOSMetadata->mCommonMetadata = value->mCommonMetadata;
newOSMetadata->mNextAutoIncrementId = value->mNextAutoIncrementId;
newOSMetadata->mComittedAutoIncrementId = value->mComittedAutoIncrementId;
for (auto iter = value->mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
auto key = iter.Key();
auto value = iter.Data();
nsRefPtr<FullIndexMetadata> newIndexMetadata = new FullIndexMetadata();
newIndexMetadata->mCommonMetadata = value->mCommonMetadata;
if (NS_WARN_IF(!newOSMetadata->mIndexes.Put(key, newIndexMetadata,
fallible))) {
return nullptr;
}
}
MOZ_ASSERT(value->mIndexes.Count() == newOSMetadata->mIndexes.Count());
if (NS_WARN_IF(!newMetadata->mObjectStores.Put(key, newOSMetadata,
fallible))) {
return nullptr;
}
}
MOZ_ASSERT(mObjectStores.Count() == newMetadata->mObjectStores.Count());
return newMetadata.forget();
}
@ -12357,10 +12244,11 @@ Database::Invalidate()
return false;
}
aTable.EnumerateEntries(Collect, &transactions);
if (NS_WARN_IF(transactions.Length() != count)) {
return false;
for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
if (NS_WARN_IF(!transactions.AppendElement(iter.Get()->GetKey(),
fallible))) {
return false;
}
}
if (count) {
@ -12376,23 +12264,6 @@ Database::Invalidate()
return true;
}
private:
static PLDHashOperator
Collect(nsPtrHashKey<TransactionBase>* aEntry, void* aUserData)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aUserData);
auto* array =
static_cast<FallibleTArray<nsRefPtr<TransactionBase>>*>(aUserData);
if (NS_WARN_IF(!array->AppendElement(aEntry->GetKey(), fallible))) {
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
if (mInvalidated) {
@ -12629,39 +12500,6 @@ Database::AllocPBackgroundIDBTransactionParent(
{
AssertIsOnBackgroundThread();
class MOZ_STACK_CLASS Closure final
{
const nsString& mName;
FallibleTArray<nsRefPtr<FullObjectStoreMetadata>>& mObjectStores;
public:
Closure(const nsString& aName,
FallibleTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores)
: mName(aName)
, mObjectStores(aObjectStores)
{ }
static PLDHashOperator
Find(const uint64_t& aKey,
FullObjectStoreMetadata* aValue,
void* aClosure)
{
MOZ_ASSERT(aKey);
MOZ_ASSERT(aValue);
MOZ_ASSERT(aClosure);
auto* closure = static_cast<Closure*>(aClosure);
if (closure->mName == aValue->mCommonMetadata.name() &&
!aValue->mDeleted) {
MOZ_ALWAYS_TRUE(closure->mObjectStores.AppendElement(aValue, fallible));
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
};
// Once a database is closed it must not try to open new transactions.
if (NS_WARN_IF(mClosed)) {
if (!mInvalidated) {
@ -12715,13 +12553,16 @@ Database::AllocPBackgroundIDBTransactionParent(
}
}
const uint32_t oldLength = fallibleObjectStores.Length();
for (auto iter = objectStores.ConstIter(); !iter.Done(); iter.Next()) {
auto value = iter.Data();
MOZ_ASSERT(iter.Key());
Closure closure(name, fallibleObjectStores);
objectStores.EnumerateRead(Closure::Find, &closure);
if (NS_WARN_IF((oldLength + 1) != fallibleObjectStores.Length())) {
return nullptr;
if (name == value->mCommonMetadata.name() && !value->mDeleted) {
if (NS_WARN_IF(!fallibleObjectStores.AppendElement(value, fallible))) {
return nullptr;
}
break;
}
}
}

View File

@ -432,27 +432,12 @@ IDBDatabase::RefreshSpec(bool aMayDelete)
{
AssertIsOnOwningThread();
class MOZ_STACK_CLASS Helper final
{
public:
static PLDHashOperator
RefreshTransactionsSpec(nsPtrHashKey<IDBTransaction>* aTransaction,
void* aClosure)
{
MOZ_ASSERT(aTransaction);
aTransaction->GetKey()->AssertIsOnOwningThread();
MOZ_ASSERT(aClosure);
bool mayDelete = *static_cast<bool*>(aClosure);
nsRefPtr<IDBTransaction> transaction = aTransaction->GetKey();
transaction->RefreshSpec(mayDelete);
return PL_DHASH_NEXT;
}
};
mTransactions.EnumerateEntries(Helper::RefreshTransactionsSpec, &aMayDelete);
for (auto iter = mTransactions.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<IDBTransaction> transaction = iter.Get()->GetKey();
MOZ_ASSERT(transaction);
transaction->AssertIsOnOwningThread();
transaction->RefreshSpec(aMayDelete);
}
}
nsPIDOMWindow*
@ -916,7 +901,19 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
StrongTransactionArray transactionsToAbort;
transactionsToAbort.SetCapacity(transactionTable.Count());
transactionTable.EnumerateEntries(Collect, &transactionsToAbort);
for (auto iter = transactionTable.Iter(); !iter.Done(); iter.Next()) {
IDBTransaction* transaction = iter.Get()->GetKey();
MOZ_ASSERT(transaction);
transaction->AssertIsOnOwningThread();
// Transactions that are already done can simply be ignored. Otherwise
// there is a race here and it's possible that the transaction has not
// been successfully committed yet so we will warn the user.
if (!transaction->IsDone()) {
transactionsToAbort.AppendElement(transaction);
}
}
MOZ_ASSERT(transactionsToAbort.Length() <= transactionTable.Count());
if (transactionsToAbort.IsEmpty()) {
@ -968,29 +965,6 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
aDatabase->LogWarning(kWarningMessage, filename, lineNo);
}
}
private:
static PLDHashOperator
Collect(nsPtrHashKey<IDBTransaction>* aTransactionKey, void* aClosure)
{
MOZ_ASSERT(aTransactionKey);
MOZ_ASSERT(aClosure);
IDBTransaction* transaction = aTransactionKey->GetKey();
MOZ_ASSERT(transaction);
transaction->AssertIsOnOwningThread();
// Transactions that are already done can simply be ignored. Otherwise
// there is a race here and it's possible that the transaction has not
// been successfully committed yet so we will warn the user.
if (!transaction->IsDone()) {
auto* array = static_cast<StrongTransactionArray*>(aClosure);
array->AppendElement(transaction);
}
return PL_DHASH_NEXT;
}
};
Helper::AbortTransactions(this, aShouldWarn);
@ -1254,27 +1228,6 @@ IDBDatabase::ExpireFileActors(bool aExpireAll)
return PL_DHASH_NEXT;
}
static PLDHashOperator
MaybeExpireReceivedBlobs(nsISupportsHashKey* aKey,
void* aClosure)
{
MOZ_ASSERT(aKey);
MOZ_ASSERT(!aClosure);
nsISupports* key = aKey->GetKey();
MOZ_ASSERT(key);
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(key);
MOZ_ASSERT(weakRef);
nsCOMPtr<nsISupports> referent = do_QueryReferent(weakRef);
if (!referent) {
return PL_DHASH_REMOVE;
}
return PL_DHASH_NEXT;
}
};
if (mBackgroundActor && mFileActors.Count()) {
@ -1290,8 +1243,18 @@ IDBDatabase::ExpireFileActors(bool aExpireAll)
if (aExpireAll) {
mReceivedBlobs.Clear();
} else {
mReceivedBlobs.EnumerateEntries(&Helper::MaybeExpireReceivedBlobs,
nullptr);
for (auto iter = mReceivedBlobs.Iter(); !iter.Done(); iter.Next()) {
nsISupports* key = iter.Get()->GetKey();
MOZ_ASSERT(key);
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(key);
MOZ_ASSERT(weakRef);
nsCOMPtr<nsISupports> referent = do_QueryReferent(weakRef);
if (!referent) {
iter.Remove();
}
}
}
}
}

View File

@ -753,24 +753,13 @@ IndexedDatabaseManager::InvalidateAllFileManagers()
{
AssertIsOnIOThread();
class MOZ_STACK_CLASS Helper final
{
public:
static PLDHashOperator
Enumerate(const nsACString& aKey,
FileManagerInfo* aValue,
void* aUserArg)
{
AssertIsOnIOThread();
MOZ_ASSERT(!aKey.IsEmpty());
MOZ_ASSERT(aValue);
for (auto iter = mFileManagerInfos.ConstIter(); !iter.Done(); iter.Next()) {
auto value = iter.Data();
MOZ_ASSERT(value);
aValue->InvalidateAllFileManagers();
return PL_DHASH_NEXT;
}
};
value->InvalidateAllFileManagers();
}
mFileManagerInfos.EnumerateRead(Helper::Enumerate, nullptr);
mFileManagerInfos.Clear();
}
@ -1003,29 +992,19 @@ IndexedDatabaseManager::Notify(nsITimer* aTimer)
MOZ_ASSERT(IsMainProcess());
MOZ_ASSERT(NS_IsMainThread());
class MOZ_STACK_CLASS Helper final
{
public:
static PLDHashOperator
CreateAndDispatchRunnables(FileManager* aFileManager,
nsTArray<int64_t>* aValue,
void* aClosure)
{
MOZ_ASSERT(!aValue->IsEmpty());
for (auto iter = mPendingDeleteInfos.ConstIter(); !iter.Done(); iter.Next()) {
auto key = iter.Key();
auto value = iter.Data();
MOZ_ASSERT(!value->IsEmpty());
nsRefPtr<DeleteFilesRunnable> runnable =
new DeleteFilesRunnable(aFileManager, *aValue);
nsRefPtr<DeleteFilesRunnable> runnable =
new DeleteFilesRunnable(key, *value);
MOZ_ASSERT(aValue->IsEmpty());
MOZ_ASSERT(value->IsEmpty());
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
}
return PL_DHASH_NEXT;
}
};
mPendingDeleteInfos.EnumerateRead(Helper::CreateAndDispatchRunnables,
nullptr);
mPendingDeleteInfos.Clear();
return NS_OK;

View File

@ -75,9 +75,31 @@ definitionlist = definition list
term = term
definition = definition
mathmltable = math table
mathmlcell = cell
mathmlenclosed = enclosed
mathmlfraction = fraction
mathmlfractionwithoutbar = fraction without bar
mathmlroot = root
mathmlscripted = scripted
mathmlsquareroot = square root
# More sophisticated roles which are not actual numeric roles
textarea = text area
base = base
close-fence = closing fence
denominator = denominator
numerator = numerator
open-fence = opening fence
overscript = overscript
presubscript = presubscript
presuperscript = presuperscript
root-index = root index
subscript = subscript
superscript = superscript
underscript = underscript
# Text input types
textInputType_date = date
textInputType_email = e-mail
@ -191,6 +213,26 @@ quicknav_Separator = Separators
quicknav_Table = Tables
quicknav_Checkbox = Check boxes
# MathML menclose notations.
# See developer.mozilla.org/docs/Web/MathML/Element/menclose#attr-notation
notation-longdiv = long division
notation-actuarial = actuarial
notation-phasorangle = phasor angle
notation-radical = radical
notation-box = box
notation-roundedbox = rounded box
notation-circle = circle
notation-left = left
notation-right = right
notation-top = top
notation-bottom = bottom
notation-updiagonalstrike = up diagonal strike
notation-downdiagonalstrike = down diagonal strike
notation-verticalstrike = vertical strike
notation-horizontalstrike = horizontal strike
notation-updiagonalarrow = up diagonal arrow
notation-madruwb = madruwb
# Shortened role names for braille
menubarAbbr = menu bar
scrollbarAbbr = scroll bar
@ -274,3 +316,43 @@ stateCheckedAbbr = (x)
stateUncheckedAbbr = ( )
statePressedAbbr = (x)
stateUnpressedAbbr = ( )
mathmlenclosedAbbr = enclosed
mathmltableAbbr = tbl
mathmlcellAbbr = cell
mathmlfractionAbbr = frac
mathmlfractionwithoutbarAbbr = frac no bar
mathmlrootAbbr = root
mathmlscriptedAbbr = scripted
mathmlsquarerootAbbr = sqrt
baseAbbr = base
close-fenceAbbr = close
denominatorAbbr = den
numeratorAbbr = num
open-fenceAbbr = open
overscriptAbbr = over
presubscriptAbbr = presub
presuperscriptAbbr = presup
root-indexAbbr = index
subscriptAbbr = sub
superscriptAbbr = sup
underscriptAbbr = under
notation-longdivAbbr = longdiv
notation-actuarialAbbr = act
notation-phasorangleAbbr = phasang
notation-radicalAbbr = rad
notation-boxAbbr = box
notation-roundedboxAbbr = rndbox
notation-circleAbbr = circ
notation-leftAbbr = lft
notation-rightAbbr = rght
notation-topAbbr = top
notation-bottomAbbr = bot
notation-updiagonalstrikeAbbr = updiagstrike
notation-downdiagonalstrikeAbbr = dwndiagstrike
notation-verticalstrikeAbbr = vstrike
notation-horizontalstrikeAbbr = hstrike
notation-updiagonalarrowAbbr = updiagarrow
notation-madruwbAbbr = madruwb

View File

@ -1663,16 +1663,38 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
return NS_OK;
}
RequestAudioData();
return NS_OK;
}
void
MediaDecoderStateMachine::RequestAudioData()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
return NS_OK;
if (mSentFirstFrameLoadedEvent) {
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
} else {
mAudioDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<AudioData>)
->CompletionPromise()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded)
);
}
}
nsresult
@ -1713,26 +1735,52 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
return NS_OK;
}
bool skipToNextKeyFrame = NeedToSkipToNextKeyframe();
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
bool forceDecodeAhead = static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
RequestVideoData();
return NS_OK;
}
void
MediaDecoderStateMachine::RequestVideoData()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
// Time the video decode, so that if it's slow, we can increase our low
// audio threshold to reduce the chance of an audio underrun while we're
// waiting for a video decode to complete.
mVideoDecodeStartTime = TimeStamp::Now();
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
NeedToSkipToNextKeyframe();
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
bool forceDecodeAhead = mSentFirstFrameLoadedEvent &&
static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
currentTime);
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
return NS_OK;
if (mSentFirstFrameLoadedEvent) {
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
} else {
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
->CompletionPromise()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
}
}
nsresult
@ -2028,30 +2076,10 @@ MediaDecoderStateMachine::DecodeFirstFrame()
NS_ENSURE_SUCCESS(res, res);
} else {
if (HasAudio()) {
mAudioDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<AudioData>)
->CompletionPromise()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded)
);
RequestAudioData();
}
if (HasVideo()) {
mVideoDecodeStartTime = TimeStamp::Now();
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData, false, int64_t(0), false)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
->CompletionPromise()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
RequestVideoData();
}
}

View File

@ -567,20 +567,26 @@ protected:
nsresult DispatchAudioDecodeTaskIfNeeded();
// Ensures a to decode audio has been dispatched to the decode task queue.
// Ensures a task to decode audio has been dispatched to the decode task queue.
// If a task to decode has already been dispatched, this does nothing,
// otherwise this dispatches a task to do the decode.
// This is called on the state machine or decode threads.
// The decoder monitor must be held.
nsresult EnsureAudioDecodeTaskQueued();
// Start a task to decode audio.
// The decoder monitor must be held.
void RequestAudioData();
nsresult DispatchVideoDecodeTaskIfNeeded();
// Ensures a to decode video has been dispatched to the decode task queue.
// Ensures a task to decode video has been dispatched to the decode task queue.
// If a task to decode has already been dispatched, this does nothing,
// otherwise this dispatches a task to do the decode.
// The decoder monitor must be held.
nsresult EnsureVideoDecodeTaskQueued();
// Start a task to decode video.
// The decoder monitor must be held.
void RequestVideoData();
// Re-evaluates the state and determines whether we need to dispatch
// events to run the decode, or if not whether we should set the reader

View File

@ -628,6 +628,7 @@ RTCPeerConnection.prototype = {
},
createOffer: function(optionsOrOnSuccess, onError, options) {
// This entry-point handles both new and legacy call sig. Decipher which one
let onSuccess;
if (typeof optionsOrOnSuccess == "function") {
onSuccess = optionsOrOnSuccess;
@ -694,7 +695,14 @@ RTCPeerConnection.prototype = {
});
},
createAnswer: function(onSuccess, onError) {
createAnswer: function(optionsOrOnSuccess, onError) {
// This entry-point handles both new and legacy call sig. Decipher which one
let onSuccess, options;
if (typeof optionsOrOnSuccess == "function") {
onSuccess = optionsOrOnSuccess;
} else {
options = optionsOrOnSuccess;
}
return this._legacyCatch(onSuccess, onError, () => {
let origin = Cu.getWebIDLCallerPrincipal().origin;
return this._chain(() => {

View File

@ -34,7 +34,8 @@ typedef android::MediaCodecProxy MediaCodecProxy;
namespace mozilla {
GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
: mAudioChannels(aConfig.mChannels)
: mLastDecodedTime(0)
, mAudioChannels(aConfig.mChannels)
, mAudioRate(aConfig.mRate)
, mAudioProfile(aConfig.mProfile)
, mAudioBuffer(nullptr)
@ -164,6 +165,14 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
return NS_ERROR_NOT_AVAILABLE;
}
if (mLastDecodedTime > timeUs) {
ReleaseAudioBuffer();
GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
MOZ_ASSERT(false);
return NS_ERROR_NOT_AVAILABLE;
}
mLastDecodedTime = timeUs;
const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
size_t dataOffset = mAudioBuffer->range_offset();
size_t size = mAudioBuffer->range_length();
@ -196,6 +205,8 @@ GonkAudioDecoderManager::Flush()
mQueueSample.Clear();
}
mLastDecodedTime = 0;
if (mDecoder->flush() != OK) {
return NS_ERROR_FAILURE;
}

View File

@ -43,6 +43,8 @@ private:
void ReleaseAudioBuffer();
int64_t mLastDecodedTime;
uint32_t mAudioChannels;
uint32_t mAudioRate;
const uint32_t mAudioProfile;

View File

@ -23,7 +23,6 @@
namespace mozilla {
static bool sIsWMFEnabled = false;
static bool sDXVAEnabled = false;
static int sNumDecoderThreads = -1;
static bool sIsIntelDecoderEnabled = false;
@ -72,7 +71,6 @@ void
WMFDecoderModule::Init()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
sIsWMFEnabled = Preferences::GetBool("media.windows-media-foundation.enabled", false);
sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false);
SetNumOfDecoderThreads();
@ -88,9 +86,7 @@ WMFDecoderModule::GetNumDecoderThreads()
nsresult
WMFDecoderModule::Startup()
{
if (sIsWMFEnabled) {
mWMFInitialized = SUCCEEDED(wmf::MFStartup());
}
mWMFInitialized = SUCCEEDED(wmf::MFStartup());
return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
}

View File

@ -40,12 +40,12 @@ function check_mp4(v, enabled) {
// H.264 Constrained Baseline Profile Level 3.0, mp3
check("video/mp4; codecs=\"avc1.42E01E, mp3\"", "probably");
check("video/mp4; codecs=\"avc1.42001E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.58A01E, mp4a.40.2\"", "probably");
const ProbablyIfNotLinux = !IsLinuxGStreamer() ? "probably" : "";
// H.264 Main Profile Level 3.0, AAC-LC
check("video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"", "probably");
// H.264 Main Profile Level 3.1, AAC-LC
@ -74,7 +74,7 @@ function check_mp4(v, enabled) {
check("audio/mp4; codecs=mp4a.40.5", ProbablyIfNotLinux);
check("audio/x-m4a; codecs=\"mp4a.40.5\"", ProbablyIfNotLinux);
check("audio/x-m4a; codecs=mp4a.40.5", ProbablyIfNotLinux);
}
function check_mp3(v, enabled) {
@ -134,12 +134,12 @@ function IsMP4ReaderAvailable() {
return prefs && (IsWindowsVistaOrLater() || IsMacOSSnowLeopardOrLater() || IsJellyBeanOrLater());
}
var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
getPref("media.omx.enabled") ||
getPref("media.gstreamer.enabled") ||
IsMP4ReaderAvailable();
var haveMp4 = IsWindowsVistaOrLater() ||
getPref("media.omx.enabled") ||
getPref("media.gstreamer.enabled") ||
IsMP4ReaderAvailable();
// TODO: Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
check_mp4(document.getElementById('v'), haveMp4);
var haveMp3 = getPref("media.directshow.enabled") ||

View File

@ -38,10 +38,10 @@
navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true })
.then(stream => pc1.addStream(v1.mozSrcObject = stream))
.then(() => pc1.createOffer())
.then(() => pc1.createOffer({})) // check that createOffer accepts arg.
.then(offer => pc1.setLocalDescription(offer))
.then(() => pc2.setRemoteDescription(pc1.localDescription))
.then(() => pc2.createAnswer())
.then(() => pc2.createAnswer({})) // check that createAnswer accepts arg.
.then(answer => pc2.setLocalDescription(answer))
.then(() => pc1.setRemoteDescription(pc2.localDescription))
.then(() => delivered)

View File

@ -750,8 +750,16 @@ nsresult WebMReader::SeekInternal(int64_t aTarget)
uint64_t target = aTarget * NS_PER_USEC;
if (mSeekPreroll) {
target = std::max(uint64_t(StartTime() * NS_PER_USEC),
target - mSeekPreroll);
uint64_t startTime = uint64_t(StartTime()) * NS_PER_USEC;
if (target < mSeekPreroll || target - mSeekPreroll < startTime) {
target = startTime;
} else {
target -= mSeekPreroll;
}
LOG(LogLevel::Debug,
("Reader [%p] SeekPreroll: %f StartTime: %f AdjustedTarget: %f",
this, double(mSeekPreroll) / NS_PER_S,
double(startTime) / NS_PER_S, double(target) / NS_PER_S));
}
int r = nestegg_track_seek(mContext, trackToSeek, target);
if (r != 0) {

View File

@ -668,7 +668,7 @@ MessagePort::MessagesReceived(nsTArray<MessagePortMessage>& aMessages)
RemoveDocFromBFCache();
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> data;
if (!NS_WARN_IF(SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
data))) {
// OOM, We cannot continue.
return;

View File

@ -13,6 +13,7 @@
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsICookiePermission.h"
#include "nsICookieService.h"
#include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h"
@ -228,10 +229,6 @@ DOMStorage::BroadcastChangeNotification(const nsSubstring& aKey,
NS_DispatchToMainThread(r);
}
static const uint32_t ASK_BEFORE_ACCEPT = 1;
static const uint32_t ACCEPT_SESSION = 2;
static const uint32_t BEHAVIOR_REJECT = 2;
static const char kPermissionType[] = "cookie";
static const char kStorageEnabled[] = "dom.storage.enabled";
static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
@ -282,11 +279,12 @@ DOMStorage::CanUseStorage(DOMStorage* aStorage)
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
// Treat "ask every time" as "reject always".
if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT)) {
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
lifetimePolicy == nsICookieService::ASK_BEFORE_ACCEPT) {
return false;
}
if (lifetimePolicy == ACCEPT_SESSION && aStorage) {
if (lifetimePolicy == nsICookieService::ACCEPT_SESSION && aStorage) {
aStorage->mIsSessionOnly = true;
}
}

View File

@ -67,7 +67,7 @@ using namespace mozilla::dom::bluetooth;
static void BinderDeadCallback(status_t aErr);
static void InternalSetAudioRoutes(SwitchState aState);
// Refer AudioService.java from Android
static uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
5, // voice call
15, // system
15, // ring
@ -94,7 +94,7 @@ static bool sA2dpSwitchDone = true;
namespace mozilla {
namespace dom {
namespace gonk {
static VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = {
static const VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = {
{"audio.volume.content", VOLUME_MEDIA},
{"audio.volume.notification", VOLUME_NOTIFICATION},
{"audio.volume.alarm", VOLUME_ALARM},
@ -763,7 +763,7 @@ nsresult
AudioManager::ValidateVolumeIndex(uint32_t aCategory, uint32_t aIndex) const
{
uint32_t maxIndex = GetMaxVolumeByCategory(aCategory);
if (aIndex < 0 || aIndex > maxIndex) {
if (aIndex > maxIndex) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -947,7 +947,7 @@ AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex)
nsresult
AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) {
if (aIndex < 0 || aIndex > sMaxStreamVolumeTbl[aStream]) {
if (aIndex > sMaxStreamVolumeTbl[aStream]) {
return NS_ERROR_INVALID_ARG;
}
mCurrentStreamVolumeTbl[aStream] = aIndex;
@ -1122,7 +1122,7 @@ AudioManager::UpdateProfileState(AudioOutputProfiles aProfile, bool aActive)
// are other profiles. The bluetooth and headset have the same priotity.
uint32_t profilesNum = mAudioProfiles.Length();
MOZ_ASSERT(profilesNum == DEVICE_TOTAL_NUMBER, "Error profile numbers!");
for (uint32_t idx = profilesNum - 1; idx >= 0; --idx) {
for (int32_t idx = profilesNum - 1; idx >= 0; --idx) {
if (mAudioProfiles[idx]->GetActive()) {
mPresentProfile = static_cast<AudioOutputProfiles>(idx);
break;
@ -1148,4 +1148,4 @@ AudioManager::UpdateVolumeFromProfile(AudioProfileData* aProfileData)
SetVolumeByCategory(gVolumeData[idx].mCategory,
aProfileData->mVolumeTable[gVolumeData[idx].mCategory]);
}
}
}

View File

@ -21,6 +21,8 @@ interface HTMLAnchorElement : HTMLElement {
attribute DOMString ping;
[SetterThrows]
attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrer;
readonly attribute DOMTokenList relList;
[SetterThrows]
attribute DOMString hreflang;

View File

@ -28,6 +28,8 @@ interface HTMLAreaElement : HTMLElement {
attribute DOMString ping;
[SetterThrows]
attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrer;
readonly attribute DOMTokenList relList;
// not implemented.

View File

@ -52,7 +52,14 @@ dictionary RTCDataChannelInit {
unsigned short stream; // now id
};
dictionary RTCOfferOptions {
dictionary RTCOfferAnswerOptions {
// boolean voiceActivityDetection = true; // TODO: support this (Bug 1184712)
};
dictionary RTCAnswerOptions : RTCOfferAnswerOptions {
};
dictionary RTCOfferOptions : RTCOfferAnswerOptions {
long offerToReceiveVideo;
long offerToReceiveAudio;
boolean mozDontOfferDataChannel;
@ -88,7 +95,7 @@ interface mozRTCPeerConnection : EventTarget {
[Pref="media.peerconnection.identity.enabled"]
Promise<DOMString> getIdentityAssertion();
Promise<mozRTCSessionDescription> createOffer (optional RTCOfferOptions options);
Promise<mozRTCSessionDescription> createAnswer ();
Promise<mozRTCSessionDescription> createAnswer (optional RTCAnswerOptions options);
Promise<void> setLocalDescription (mozRTCSessionDescription description);
Promise<void> setRemoteDescription (mozRTCSessionDescription description);
readonly attribute mozRTCSessionDescription? localDescription;

View File

@ -76,11 +76,15 @@ using namespace mozilla::dom;
static nsresult
GetDOMEventTarget(nsWebBrowser* aInBrowser, EventTarget** aTarget)
{
NS_ENSURE_ARG_POINTER(aInBrowser);
if (!aInBrowser) {
return NS_ERROR_INVALID_POINTER;
}
nsCOMPtr<nsIDOMWindow> domWindow;
aInBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
if (!domWindow) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);

View File

@ -360,7 +360,10 @@ nsWebBrowser::SetParentURIContentListener(
NS_IMETHODIMP
nsWebBrowser::GetContentDOMWindow(nsIDOMWindow** aResult)
{
NS_ENSURE_STATE(mDocShell);
if (!mDocShell) {
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIDOMWindow> retval = mDocShell->GetWindow();
retval.forget(aResult);
return *aResult ? NS_OK : NS_ERROR_FAILURE;

View File

@ -12,6 +12,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/TypeTraits.h"
#include <string.h>
@ -141,10 +142,15 @@ struct CStringHashPolicy
#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0),
#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize),
#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
#define SUB_OTHER_SIZE(tabKind, servoKind, mSize) MOZ_ASSERT(mSize >= other.mSize); \
mSize -= other.mSize;
#define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
MOZ_ASSERT(mSize >= other.mSize); \
mSize -= other.mSize;
#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) n += (ServoSizes::servoKind == ServoSizes::GCHeapUsed) ? mSize : 0;
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
/* Avoid self-comparison warnings by comparing enums indirectly. */ \
n += (mozilla::IsSame<int[ServoSizes::servoKind], int[ServoSizes::GCHeapUsed]>::value) \
? mSize \
: 0;
#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize);
#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize);

View File

@ -604,6 +604,156 @@ condIf(const ParseNode* pn, ParseNodeKind kind)
}
static bool
Fold(ExclusiveContext* cx, ParseNode** pnp,
FullParseHandler& handler, const ReadOnlyCompileOptions& options,
bool inGenexpLambda, SyntacticContext sc);
static bool
FoldTypeOfExpr(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_TYPEOFEXPR));
MOZ_ASSERT(node->isArity(PN_UNARY));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
return false;
// Constant-fold the entire |typeof| if given a constant with known type.
RootedPropertyName result(cx);
if (expr->isKind(PNK_STRING) || expr->isKind(PNK_TEMPLATE_STRING))
result = cx->names().string;
else if (expr->isKind(PNK_NUMBER))
result = cx->names().number;
else if (expr->isKind(PNK_NULL))
result = cx->names().object;
else if (expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE))
result = cx->names().boolean;
else if (expr->isKind(PNK_FUNCTION))
result = cx->names().function;
if (result) {
handler.prepareNodeForMutation(node);
node->setKind(PNK_STRING);
node->setArity(PN_NULLARY);
node->setOp(JSOP_NOP);
node->pn_atom = result;
}
return true;
}
static bool
FoldVoid(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
const ReadOnlyCompileOptions& options, bool inGenexpLambda, SyntacticContext sc)
{
MOZ_ASSERT(node->isKind(PNK_VOID));
MOZ_ASSERT(node->isArity(PN_UNARY));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
return false;
if (sc == SyntacticContext::Condition) {
if (expr->isKind(PNK_TRUE) ||
expr->isKind(PNK_FALSE) ||
expr->isKind(PNK_STRING) ||
expr->isKind(PNK_TEMPLATE_STRING) ||
expr->isKind(PNK_NUMBER) ||
expr->isKind(PNK_NULL) ||
expr->isKind(PNK_FUNCTION))
{
handler.prepareNodeForMutation(node);
node->setKind(PNK_FALSE);
node->setArity(PN_NULLARY);
node->setOp(JSOP_FALSE);
}
}
return true;
}
static bool
FoldDeleteExpr(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
MOZ_ASSERT(node->isArity(PN_UNARY));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
return false;
// Expression deletion evaluates the expression, then evaluates to
// true. For trivial expressions, eliminate the expression evaluation.
if (expr->isKind(PNK_TRUE) ||
expr->isKind(PNK_FALSE) ||
expr->isKind(PNK_STRING) ||
expr->isKind(PNK_TEMPLATE_STRING) ||
expr->isKind(PNK_NUMBER) ||
expr->isKind(PNK_NULL) ||
expr->isKind(PNK_FUNCTION))
{
handler.prepareNodeForMutation(node);
node->setKind(PNK_TRUE);
node->setArity(PN_NULLARY);
node->setOp(JSOP_TRUE);
}
return true;
}
static bool
FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEELEM) || node->isKind(PNK_DELETESUPERELEM));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM) || node->pn_kid->isKind(PNK_SUPERELEM));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
return false;
// If we're deleting an element, but constant-folding converted our
// element reference into a dotted property access, we must *also*
// morph the node's kind.
//
// In principle this also applies to |super["foo"] -> super.foo|,
// but we don't constant-fold |super["foo"]| yet.
if (node->isKind(PNK_DELETEELEM)) {
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
if (expr->isKind(PNK_DOT))
node->setKind(PNK_DELETEPROP);
}
return true;
}
static bool
FoldDeleteProperty(ExclusiveContext* cx, ParseNode* node, FullParseHandler& handler,
const ReadOnlyCompileOptions& options, bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEPROP) || node->isKind(PNK_DELETESUPERPROP));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT) || node->pn_kid->isKind(PNK_SUPERPROP));
ParseNode*& expr = node->pn_kid;
#ifdef DEBUG
ParseNodeKind oldKind = expr->getKind();
#endif
if (!Fold(cx, &expr, handler, options, inGenexpLambda, SyntacticContext::Other))
return false;
MOZ_ASSERT(expr->isKind(oldKind),
"kind should have remained invariant under folding");
return true;
}
bool
Fold(ExclusiveContext* cx, ParseNode** pnp,
FullParseHandler& handler, const ReadOnlyCompileOptions& options,
bool inGenexpLambda, SyntacticContext sc)
@ -629,6 +779,169 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
ParseNode* pn2 = nullptr;
ParseNode* pn3 = nullptr;
switch (pn->getKind()) {
case PNK_NEWTARGET:
case PNK_NOP:
case PNK_REGEXP:
case PNK_STRING:
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_ELISION:
case PNK_NUMBER:
case PNK_DEBUGGER:
case PNK_BREAK:
case PNK_CONTINUE:
case PNK_TEMPLATE_STRING:
case PNK_THIS:
case PNK_GENERATOR:
case PNK_EXPORT_BATCH_SPEC:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_SUPERPROP:
case PNK_FRESHENBLOCK:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
goto afterFolding;
case PNK_TYPEOFNAME:
MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
MOZ_ASSERT(!pn->pn_kid->maybeExpr());
return true;
case PNK_TYPEOFEXPR:
return FoldTypeOfExpr(cx, pn, handler, options, inGenexpLambda);
case PNK_VOID:
return FoldVoid(cx, pn, handler, options, inGenexpLambda, sc);
case PNK_DELETENAME: {
MOZ_ASSERT(pn->isArity(PN_UNARY));
MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
return true;
}
case PNK_DELETEEXPR:
return FoldDeleteExpr(cx, pn, handler, options, inGenexpLambda);
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
return FoldDeleteElement(cx, pn, handler, options, inGenexpLambda);
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
return FoldDeleteProperty(cx, pn, handler, options, inGenexpLambda);
case PNK_NOT:
case PNK_BITNOT:
case PNK_THROW:
case PNK_POS:
case PNK_NEG:
case PNK_PREINCREMENT:
case PNK_POSTINCREMENT:
case PNK_PREDECREMENT:
case PNK_POSTDECREMENT:
case PNK_COMPUTED_NAME:
case PNK_ARRAYPUSH:
case PNK_SPREAD:
case PNK_MUTATEPROTO:
case PNK_EXPORT:
case PNK_SEMI:
case PNK_ASSIGN:
case PNK_ADDASSIGN:
case PNK_SUBASSIGN:
case PNK_BITORASSIGN:
case PNK_BITXORASSIGN:
case PNK_BITANDASSIGN:
case PNK_LSHASSIGN:
case PNK_RSHASSIGN:
case PNK_URSHASSIGN:
case PNK_MULASSIGN:
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
case PNK_ELEM:
case PNK_SUPERELEM:
case PNK_COLON:
case PNK_CASE:
case PNK_SHORTHAND:
case PNK_DOWHILE:
case PNK_WHILE:
case PNK_SWITCH:
case PNK_LETBLOCK:
case PNK_FOR:
case PNK_CLASSMETHOD:
case PNK_WITH:
case PNK_CLASSNAMES:
case PNK_DEFAULT:
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_RETURN:
case PNK_IMPORT:
case PNK_EXPORT_FROM:
case PNK_EXPORT_DEFAULT:
case PNK_CONDITIONAL:
case PNK_FORIN:
case PNK_FOROF:
case PNK_FORHEAD:
case PNK_CLASS:
case PNK_IF:
case PNK_TRY:
case PNK_OR:
case PNK_AND:
case PNK_BITOR:
case PNK_BITXOR:
case PNK_BITAND:
case PNK_STRICTEQ:
case PNK_EQ:
case PNK_STRICTNE:
case PNK_NE:
case PNK_LT:
case PNK_LE:
case PNK_GT:
case PNK_GE:
case PNK_INSTANCEOF:
case PNK_IN:
case PNK_LSH:
case PNK_RSH:
case PNK_URSH:
case PNK_ADD:
case PNK_SUB:
case PNK_STAR:
case PNK_DIV:
case PNK_MOD:
case PNK_COMMA:
case PNK_NEW:
case PNK_CALL:
case PNK_GENEXP:
case PNK_ARRAY:
case PNK_STATEMENTLIST:
case PNK_ARGSBODY:
case PNK_ARRAYCOMP:
case PNK_VAR:
case PNK_CONST:
case PNK_LET:
case PNK_GLOBALCONST:
case PNK_OBJECT:
case PNK_CLASSMETHODLIST:
case PNK_TEMPLATE_STRING_LIST:
case PNK_TAGGED_TEMPLATE:
case PNK_EXPORT_SPEC_LIST:
case PNK_IMPORT_SPEC_LIST:
case PNK_CATCHLIST:
case PNK_LABEL:
case PNK_DOT:
case PNK_LEXICALSCOPE:
case PNK_NAME:
case PNK_FUNCTION:
case PNK_CATCH:
case PNK_EXPORT_SPEC:
case PNK_IMPORT_SPEC:
case PNK_CALLSITEOBJ:
break; // for now
case PNK_LIMIT: // invalid sentinel value
MOZ_CRASH("invalid node kind");
}
// First, recursively fold constants on the children of this node.
switch (pn->getArity()) {
case PN_CODE:
@ -653,7 +966,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
// Don't fold a parenthesized call expression. See bug 537673.
ParseNode** listp = &pn->pn_head;
if ((pn->isKind(PNK_CALL) || pn->isKind(PNK_NEW)) && (*listp)->isInParens())
if ((pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE)) && (*listp)->isInParens())
listp = &(*listp)->pn_next;
for (; *listp; listp = &(*listp)->pn_next) {
@ -728,13 +1041,12 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
break;
case PN_UNARY:
MOZ_ASSERT(!IsDeleteKind(pn->getKind()),
"should have been handled above");
if (pn->pn_kid) {
SyntacticContext kidsc =
pn->isKind(PNK_NOT)
? SyntacticContext::Condition
: IsDeleteKind(pn->getKind())
? SyntacticContext::Delete
: SyntacticContext::Other;
SyntacticContext kidsc = pn->isKind(PNK_NOT)
? SyntacticContext::Condition
: SyntacticContext::Other;
if (!Fold(cx, &pn->pn_kid, handler, options, inGenexpLambda, kidsc))
return false;
}
@ -1021,6 +1333,8 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
case PNK_VOID:
MOZ_CRASH("should have been fully handled above");
case PNK_NOT:
case PNK_BITNOT:
case PNK_POS:
@ -1137,6 +1451,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
default:;
}
afterFolding:
if (sc == SyntacticContext::Condition) {
Truthiness t = Boolish(pn);
if (t != Unknown) {

View File

@ -5732,7 +5732,7 @@ ICInNativeDoesNotExistCompiler::generateStubCode(MacroAssembler& masm)
masm.loadPtr(Address(ICStubReg, shapeOffset), scratch);
masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failurePopR0Scratch);
}
masm.addPtr(Imm32(sizeof(size_t)), StackPointer);
masm.addToStackPtr(Imm32(sizeof(size_t)));
// Shape and type checks succeeded, ok to proceed.
masm.moveValue(BooleanValue(false), R0);

View File

@ -1019,6 +1019,8 @@ class ICStubCompiler
#elif defined(JS_CODEGEN_MIPS)
MOZ_ASSERT(!regs.has(ICTailCallReg));
MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
#elif defined(JS_CODEGEN_ARM64)
MOZ_ASSERT(!regs.has(ICTailCallReg));
#endif
regs.take(BaselineFrameReg);
regs.take(ICStubReg);

View File

@ -2528,7 +2528,7 @@ namespace JS {
template <typename Outer>
class PropertyDescriptorOperations
{
const JSPropertyDescriptor * desc() const { return static_cast<const Outer*>(this)->extract(); }
const JSPropertyDescriptor* desc() const { return static_cast<const Outer*>(this)->extract(); }
bool has(unsigned bit) const {
MOZ_ASSERT(bit != 0);
@ -2770,17 +2770,12 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
namespace js {
template <>
struct GCMethods<JSPropertyDescriptor> {
static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
};
template <>
class RootedBase<JSPropertyDescriptor>
: public JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >
: public JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>
{
friend class JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
friend class JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
friend class JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>;
friend class JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor>>;
const JSPropertyDescriptor* extract() const {
return static_cast<const JS::Rooted<JSPropertyDescriptor>*>(this)->address();
}
@ -2791,9 +2786,9 @@ class RootedBase<JSPropertyDescriptor>
template <>
class HandleBase<JSPropertyDescriptor>
: public JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >
: public JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor>>
{
friend class JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >;
friend class JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor>>;
const JSPropertyDescriptor* extract() const {
return static_cast<const JS::Handle<JSPropertyDescriptor>*>(this)->address();
}
@ -2801,10 +2796,10 @@ class HandleBase<JSPropertyDescriptor>
template <>
class MutableHandleBase<JSPropertyDescriptor>
: public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >
: public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>
{
friend class JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
friend class JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
friend class JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>;
friend class JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor>>;
const JSPropertyDescriptor* extract() const {
return static_cast<const JS::MutableHandle<JSPropertyDescriptor>*>(this)->address();
}

View File

@ -0,0 +1,28 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
//-----------------------------------------------------------------------------
var BUGNUMBER = 1182373;
var summary =
"Don't let constant-folding in the MemberExpression part of a tagged " +
"template cause an incorrect |this| be passed to the callee";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var prop = "global";
var obj = { prop: "obj", f: function() { return this.prop; } };
assertEq(obj.f``, "obj");
assertEq((true ? obj.f : null)``, "global");
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -7,7 +7,6 @@
EXPORTS += [
'nsAXPCNativeCallContext.h',
'nsTArrayHelpers.h',
'SandboxPrivate.h',
'xpc_map_end.h',
]

View File

@ -15,8 +15,6 @@
#include "js/RootingAPI.h"
// This interface is public only because it is used in jsd.
// Once jsd is gone this file should be moved back to xpconnect/src.
class SandboxPrivate : public nsIGlobalObject,
public nsIScriptObjectPrincipal,

View File

@ -343,7 +343,7 @@ private:
uint32_t count = GetChildCount();
mFlags.mHasHashedFrames = 1;
uint32_t minLength = std::max(kMinChildCountForHashtable,
uint32_t(PL_DHASH_DEFAULT_INITIAL_LENGTH));
uint32_t(PLDHashTable::kDefaultInitialLength));
mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >(std::max(count, minLength));
for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
mFrames->PutEntry(f);

View File

@ -28,7 +28,9 @@
* does not have <atomic>. So be sure to check for <atomic> support
* along with C++0x support.
*/
#if defined(__clang__) || defined(__GNUC__)
#if defined(_MSC_VER)
# define MOZ_HAVE_CXX11_ATOMICS
#elif defined(__clang__) || defined(__GNUC__)
/*
* Clang doesn't like <atomic> from libstdc++ before 4.7 due to the
* loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline
@ -42,8 +44,6 @@
# elif MOZ_USING_LIBCXX && defined(__clang__)
# define MOZ_HAVE_CXX11_ATOMICS
# endif
#elif defined(_MSC_VER)
# define MOZ_HAVE_CXX11_ATOMICS
#endif
namespace mozilla {

View File

@ -289,7 +289,6 @@ pref("media.decoder.heuristic.dormant.enabled", true);
pref("media.decoder.heuristic.dormant.timeout", 60000);
#ifdef MOZ_WMF
pref("media.windows-media-foundation.enabled", true);
pref("media.wmf.decoder.thread-count", -1);
#endif
#ifdef MOZ_DIRECTSHOW

View File

@ -19,7 +19,7 @@ enum ReferrerPolicy {
/* spec tokens: default no-referrer-when-downgrade */
RP_No_Referrer_When_Downgrade = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
RP_Default = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
RP_Default = nsIHttpChannel::REFERRER_POLICY_DEFAULT,
/* spec tokens: origin-when-cross-origin */
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
@ -31,28 +31,47 @@ enum ReferrerPolicy {
RP_Unset = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE
};
/* spec tokens: never no-referrer */
const char kRPS_Never[] = "never";
const char kRPS_No_Referrer[] = "no-referrer";
/* spec tokens: origin */
const char kRPS_Origin[] = "origin";
/* spec tokens: default no-referrer-when-downgrade */
const char kRPS_Default[] = "default";
const char kRPS_No_Referrer_When_Downgrade[] = "no-referrer-when-downgrade";
/* spec tokens: origin-when-cross-origin */
const char kRPS_Origin_When_Cross_Origin[] = "origin-when-cross-origin";
const char kRPS_Origin_When_Crossorigin[] = "origin-when-crossorigin";
/* spec tokens: always unsafe-url */
const char kRPS_Always[] = "always";
const char kRPS_Unsafe_URL[] = "unsafe-url";
inline ReferrerPolicy
ReferrerPolicyFromString(const nsAString& content)
{
// This is implemented step by step as described in the Referrer Policy
// specification, section 6.4 "Determine token's Policy".
if (content.LowerCaseEqualsLiteral("never") ||
content.LowerCaseEqualsLiteral("no-referrer")) {
if (content.LowerCaseEqualsLiteral(kRPS_Never) ||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer)) {
return RP_No_Referrer;
}
if (content.LowerCaseEqualsLiteral("origin")) {
if (content.LowerCaseEqualsLiteral(kRPS_Origin)) {
return RP_Origin;
}
if (content.LowerCaseEqualsLiteral("default") ||
content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")) {
if (content.LowerCaseEqualsLiteral(kRPS_Default) ||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
return RP_No_Referrer_When_Downgrade;
}
if (content.LowerCaseEqualsLiteral("origin-when-cross-origin") ||
content.LowerCaseEqualsLiteral("origin-when-crossorigin")) {
if (content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)) {
return RP_Origin_When_Crossorigin;
}
if (content.LowerCaseEqualsLiteral("always") ||
content.LowerCaseEqualsLiteral("unsafe-url")) {
if (content.LowerCaseEqualsLiteral(kRPS_Always) ||
content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL)) {
return RP_Unsafe_URL;
}
// Spec says if none of the previous match, use No_Referrer.
@ -63,15 +82,42 @@ ReferrerPolicyFromString(const nsAString& content)
inline bool
IsValidReferrerPolicy(const nsAString& content)
{
return content.LowerCaseEqualsLiteral("never")
|| content.LowerCaseEqualsLiteral("no-referrer")
|| content.LowerCaseEqualsLiteral("origin")
|| content.LowerCaseEqualsLiteral("default")
|| content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")
|| content.LowerCaseEqualsLiteral("origin-when-cross-origin")
|| content.LowerCaseEqualsLiteral("origin-when-crossorigin")
|| content.LowerCaseEqualsLiteral("always")
|| content.LowerCaseEqualsLiteral("unsafe-url");
return content.LowerCaseEqualsLiteral(kRPS_Never)
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|| content.LowerCaseEqualsLiteral(kRPS_Origin)
|| content.LowerCaseEqualsLiteral(kRPS_Default)
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin)
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)
|| content.LowerCaseEqualsLiteral(kRPS_Always)
|| content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
}
inline bool
IsValidAttributeReferrerPolicy(const nsAString& aContent)
{
// Spec allows only these three policies at the moment
// See bug 1178337
return aContent.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|| aContent.LowerCaseEqualsLiteral(kRPS_Origin)
|| aContent.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
}
inline ReferrerPolicy
AttributeReferrerPolicyFromString(const nsAString& aContent)
{
// if the referrer attribute string is empty, return RP_Unset
if (aContent.IsEmpty()) {
return RP_Unset;
}
// if the referrer attribute string is not empty and contains a valid
// referrer policy, return the according enum value
if (IsValidAttributeReferrerPolicy(aContent)) {
return ReferrerPolicyFromString(aContent);
}
// in any other case the referrer attribute contains an invalid
// policy value, we thus return RP_No_Referrer
return RP_No_Referrer;
}
} // namespace net

View File

@ -11,7 +11,7 @@ interface nsIPrefBranch;
/**
* nsINetUtil provides various network-related utility methods.
*/
[scriptable, uuid(ca68c485-9db3-4c12-82a6-4fab7948e2d5)]
[scriptable, uuid(885d6940-1001-46e7-92ec-d494a78d7784)]
interface nsINetUtil : nsISupports
{
/**
@ -192,4 +192,16 @@ interface nsINetUtil : nsISupports
out AUTF8String aCharset,
out long aCharsetStart,
out long aCharsetEnd);
/**
* Parse an attribute referrer policy string (no-referrer, origin, unsafe-url)
* and return the according integer code (defined in nsIHttpChannel.idl)
*
* @param aPolicyString
* the policy string given as attribute
* @return aPolicyEnum
* referrer policy code from nsIHttpChannel.idl, (see parser in
* ReferrerPolicy.h for details)
*/
unsigned long parseAttributePolicyString(in AString aPolicyString);
};

View File

@ -45,6 +45,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/net/DNS.h"
#include "CaptivePortalService.h"
#include "ReferrerPolicy.h"
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkManager.h"
@ -1690,6 +1691,16 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
return NS_OK;
}
// parse policyString to policy enum value (see ReferrerPolicy.h)
NS_IMETHODIMP
nsIOService::ParseAttributePolicyString(const nsAString& policyString,
uint32_t *outPolicyEnum)
{
NS_ENSURE_ARG(outPolicyEnum);
*outPolicyEnum = (uint32_t)mozilla::net::AttributeReferrerPolicyFromString(policyString);
return NS_OK;
}
// nsISpeculativeConnect
class IOServiceProxyCallback final : public nsIProtocolProxyCallback
{

View File

@ -14,6 +14,7 @@
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkManager.h"
#include "nsProxyRelease.h"
#endif
//-----------------------------------------------------------------------------

View File

@ -17,12 +17,6 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace net {
// Behavior pref constants
static const int32_t BEHAVIOR_ACCEPT = 0;
static const int32_t BEHAVIOR_REJECTFOREIGN = 1;
// static const int32_t BEHAVIOR_REJECT = 2;
static const int32_t BEHAVIOR_LIMITFOREIGN = 3;
// Pref string constants
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
static const char kPrefThirdPartySession[] =
@ -46,7 +40,7 @@ NS_IMPL_ISUPPORTS(CookieServiceChild,
nsISupportsWeakReference)
CookieServiceChild::CookieServiceChild()
: mCookieBehavior(BEHAVIOR_ACCEPT)
: mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
, mThirdPartySession(false)
{
NS_ASSERTION(IsNeckoChild(), "not a child process");
@ -80,7 +74,9 @@ CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
int32_t val;
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
mCookieBehavior =
val >= BEHAVIOR_ACCEPT && val <= BEHAVIOR_LIMITFOREIGN ? val : BEHAVIOR_ACCEPT;
val >= nsICookieService::BEHAVIOR_ACCEPT &&
val <= nsICookieService::BEHAVIOR_LIMIT_FOREIGN
? val : nsICookieService::BEHAVIOR_ACCEPT;
bool boolval;
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
@ -95,7 +91,9 @@ CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
bool
CookieServiceChild::RequireThirdPartyCheck()
{
return mCookieBehavior == BEHAVIOR_REJECTFOREIGN || mCookieBehavior == BEHAVIOR_LIMITFOREIGN || mThirdPartySession;
return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
mThirdPartySession;
}
nsresult

View File

@ -109,13 +109,6 @@ static const uint32_t kMaxCookiesPerHost = 150;
static const uint32_t kMaxBytesPerCookie = 4096;
static const uint32_t kMaxBytesPerPath = 1024;
// behavior pref constants
static const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies
static const uint32_t BEHAVIOR_REJECTFOREIGN = 1; // reject all third-party cookies
static const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies
static const uint32_t BEHAVIOR_LIMITFOREIGN = 3; // reject third-party cookies unless the
// eTLD already has at least one cookie
// pref string constants
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
@ -711,7 +704,7 @@ NS_IMPL_ISUPPORTS(nsCookieService,
nsCookieService::nsCookieService()
: mDBState(nullptr)
, mCookieBehavior(BEHAVIOR_ACCEPT)
, mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
, mThirdPartySession(false)
, mMaxNumberOfCookies(kMaxNumberOfCookies)
, mMaxCookiesPerHost(kMaxCookiesPerHost)
@ -3490,22 +3483,22 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
}
// check default prefs
if (mCookieBehavior == BEHAVIOR_REJECT) {
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
return STATUS_REJECTED;
}
// check if cookie is foreign
if (aIsForeign) {
if (mCookieBehavior == BEHAVIOR_ACCEPT && mThirdPartySession)
if (mCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT && mThirdPartySession)
return STATUS_ACCEPT_SESSION;
if (mCookieBehavior == BEHAVIOR_REJECTFOREIGN) {
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
return STATUS_REJECTED;
}
if (mCookieBehavior == BEHAVIOR_LIMITFOREIGN) {
if (mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
uint32_t priorCookieCount = 0;
nsAutoCString hostFromURI;
aHostURI->GetHost(hostFromURI);

View File

@ -71,9 +71,26 @@ interface nsIChannel;
* to set the cookie.
* data : the referrer, or "?" if unknown
*/
[scriptable, uuid(2aaa897a-293c-4d2b-a657-8c9b7136996d)]
[scriptable, uuid(f5807c53-de48-461a-8117-bd156bc2dcf0)]
interface nsICookieService : nsISupports
{
/*
* Possible values for the "network.cookie.cookieBehavior" preference.
*/
const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies
const uint32_t BEHAVIOR_REJECT_FOREIGN = 1; // reject all third-party cookies
const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies
const uint32_t BEHAVIOR_LIMIT_FOREIGN = 3; // reject third-party cookies unless the
// eTLD already has at least one cookie
/*
* Possible values for the "network.cookie.lifetimePolicy" preference.
*/
const uint32_t ACCEPT_NORMALLY = 0; // accept normally
const uint32_t ASK_BEFORE_ACCEPT = 1; // ask before accepting
const uint32_t ACCEPT_SESSION = 2; // downgrade to session
const uint32_t ACCEPT_FOR_N_DAYS = 3; // limit lifetime to N days
/*
* Get the complete cookie string associated with the URI.
*

View File

@ -454,25 +454,24 @@ nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
class NotifyDNSResolution: public nsRunnable
{
public:
NotifyDNSResolution(nsMainThreadPtrHandle<nsIObserverService> &aObs,
const nsACString &aHostname)
: mObs(aObs)
, mHostname(aHostname)
explicit NotifyDNSResolution(const nsACString &aHostname)
: mHostname(aHostname)
{
MOZ_ASSERT(mObs);
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
mObs->NotifyObservers(nullptr,
"dns-resolution-request",
NS_ConvertUTF8toUTF16(mHostname).get());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr,
"dns-resolution-request",
NS_ConvertUTF8toUTF16(mHostname).get());
}
return NS_OK;
}
private:
nsMainThreadPtrHandle<nsIObserverService> mObs;
nsCString mHostname;
};
@ -606,8 +605,6 @@ nsDNSService::Init()
nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
nsRefPtr<nsHostResolver> res;
nsresult rv = nsHostResolver::Create(maxCacheEntries,
defaultCacheLifetime,
@ -635,10 +632,6 @@ nsDNSService::Init()
}
}
mNotifyResolution = notifyResolution;
if (mNotifyResolution) {
mObserverService =
new nsMainThreadPtrHolder<nsIObserverService>(obs);
}
}
#if !defined(MOZILLA_XPCOMRT_API)
@ -760,8 +753,7 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname,
}
if (mNotifyResolution) {
NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
aHostname));
NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
}
if (!res)
@ -874,8 +866,7 @@ nsDNSService::Resolve(const nsACString &aHostname,
}
if (mNotifyResolution) {
NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
aHostname));
NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
}
NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);

View File

@ -16,8 +16,6 @@
#include "nsString.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsIObserverService.h"
#include "nsProxyRelease.h"
#include "mozilla/Mutex.h"
#include "mozilla/Attributes.h"
@ -61,7 +59,6 @@ private:
bool mOffline;
bool mNotifyResolution;
bool mOfflineLocalhost;
nsMainThreadPtrHandle<nsIObserverService> mObserverService;
nsTHashtable<nsCStringHashKey> mLocalDomains;
};

View File

@ -12,6 +12,7 @@ TEST_DIRS += [
'test_cert_version',
'test_intermediate_basic_usage_constraints',
'test_pinning_dynamic',
'test_ocsp_url',
]
if not CONFIG['MOZ_NO_SMART_CARDS']:

View File

@ -26,6 +26,7 @@ extKeyUsage:[serverAuth,clientAuth,codeSigning,emailProtection
nsSGC, # Netscape Server Gated Crypto
OCSPSigning,timeStamping]
subjectAlternativeName:[<dNSName>,...]
authorityInformationAccess:<OCSP URI>
Where:
[] indicates an optional field or component of a field
@ -48,14 +49,14 @@ or as the subject public key information field, respectively.
from pyasn1.codec.der import decoder
from pyasn1.codec.der import encoder
from pyasn1.type import constraint, namedtype, tag, univ, useful
from pyasn1.type import constraint, tag, univ, useful
from pyasn1_modules import rfc2459
import base64
import binascii
import datetime
import hashlib
import sys
import rsa
import pykey
class UnknownBaseError(Exception):
"""Base class for handling unexpected input in this module."""
@ -99,14 +100,6 @@ class UnknownKeyPurposeTypeError(UnknownBaseError):
self.category = 'keyPurpose'
class UnknownKeySpecificationError(UnknownBaseError):
"""Helper exception type to handle unknown key specifications."""
def __init__(self, value):
UnknownBaseError.__init__(self, value)
self.category = 'key specification'
class UnknownKeyTargetError(UnknownBaseError):
"""Helper exception type to handle unknown key targets."""
@ -128,6 +121,18 @@ def getASN1Tag(asn1Type):
type from the pyasn1 package"""
return asn1Type.baseTagSet.getBaseTag().asTuple()[2]
def stringToAccessDescription(string):
"""Helper function that takes a string representing a URI
presumably identifying an OCSP authority information access
location. Returns an AccessDescription usable by pyasn1."""
accessMethod = rfc2459.id_ad_ocsp
accessLocation = rfc2459.GeneralName()
accessLocation.setComponentByName('uniformResourceIdentifier', string)
sequence = univ.Sequence()
sequence.setComponentByPosition(0, accessMethod)
sequence.setComponentByPosition(1, accessLocation)
return sequence
def stringToAlgorithmIdentifier(string):
"""Helper function that converts a description of an algorithm
to a representation usable by the pyasn1 package"""
@ -166,97 +171,10 @@ def datetimeToTime(dt):
time.setComponentByName('generalTime', useful.GeneralizedTime(dt.strftime('%Y%m%d%H%M%SZ')))
return time
def byteStringToHexifiedBitString(string):
"""Takes a string of bytes and returns a hex string representing
those bytes for use with pyasn1.type.univ.BitString. It must be of
the form "'<hex bytes>'H", where the trailing 'H' indicates to
pyasn1 that the input is a hex string."""
return "'%s'H" % binascii.hexlify(string)
class RSAPublicKey(univ.Sequence):
"""Helper type for encoding an RSA public key"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('N', univ.Integer()),
namedtype.NamedType('E', univ.Integer()))
class Certificate:
"""Utility class for reading a certificate specification and
generating a signed x509 certificate"""
# For reference, when encoded as a subject public key info, the
# base64-encoded sha-256 hash of this key is
# VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
sharedRSA_N = long(
'00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
'6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
'2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
'31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
'95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
'fe4923fa7251c431d503acda180a35ed8d', 16)
sharedRSA_E = 65537L
sharedRSA_D = long(
'009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
'3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
'39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
'7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
'79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
'6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
'5b62b30e6011f224725946eec57c6d9441', 16)
sharedRSA_P = long(
'00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
'8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
'3ca5d19301f48c742b', 16)
sharedRSA_Q = long(
'00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
'8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
'1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
'28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
'5810a77b9845bc3127', 16)
# For reference, when encoded as a subject public key info, the
# base64-encoded sha-256 hash of this key is
# K+uamI+1JmrxMsBxEfGOoydEDJVMa5MY/eaTj+43Lzc=
alternateRSA_N = long(
'00cd6e66a71b9a104c7c5f270b5869da966a52e547f8a026eef128c4d51f'
'a7d949b1df8a1e342c59cbad0fb6ef867427bd9e76f2e9bf0b582745c646'
'4446db7bdd4d0f2f361da724ff206d070b3d75ad87d690fa307dcccc2ad1'
'4283921f9621f2a564e7e9f708a98556194df12fb4b0a2f0b89f76ac7e59'
'668285aa50f14f310b6ebd8f001d0c115393bd27f3334f67780abfe0b19e'
'5ac3414c5b4a3819fbed39198050e1c660e44cacaf108cbe1671d5a14602'
'6090f371b2873d419eeb6de982fb493c3d4d33fb8a12bd65f1c59a3494dd'
'd7e1131aa45e896d817bbb28e6fd4c2323ed17a26dc8e4e49281decc641e'
'f7b7acfe65e7c0e5212fb2a9d472902c35', 16)
alternateRSA_E = 65537L
alternateRSA_D = long(
'6ae6e0946550aeda9e7e059b69ceebe90a3b490542e4545e53309bfd2c13'
'f486dd012ea6b90fbb4aba2c4b4e29f1981c9cb1d986b9dbf56bba6b8b75'
'4c4a3b12d65ee87a88c3ca04d9a2e2df7e84166171cecfe31c13cecb194a'
'3b9d76c271b80b498f45b93fd0b78a2e70d8e9b26598e51bae1fdb7384a2'
'4b99b31f9bf351d9692c00d6f05c30424be4b4de55331ac77532c3fdaf74'
'95dbf7aef601b517ed227d0efa3de443d56d8b29e556f6be938eabf4c0e4'
'2e2fe38bec60cba5b5ff9192b68620ee4b629b9d0b64b9a8810809813b0b'
'04e485d97fdad2961c0982a589863643974e3900dd8a75112a0fffc59f4b'
'24c31307901dd04a848b02db32f61a01', 16)
alternateRSA_P = long(
'00feeacc987c0494cb5e9550eefb9dc56f9d957022a11539dae04c6361ab'
'd5081dce2a6aec0905450886f5bb7e56e8bd2bef37cfa16fbda5ffc268ca'
'e0499017552c37fa4a041341d67d4d69d093d8950f50672fb085b636560e'
'2446689474b29be7abeba358ab7bc4cde3fd065d46f762adeb5c4b54ccca'
'651a14b498311615b1', 16)
alternateRSA_Q = long(
'00ce4dca3fdda86b8c800c268082446633c8aaf0f20c729878092198585b'
'd2ed134a7bdb2c93f829f99e6e9070db6598b3113627fd87bf6bc46cb2e5'
'121777cbea9c41e74c9c2c248931dbccb5ae8a1dccfad284784cc35b8329'
'abc420ce95640085dbf325fa7f6a2a567d487c1ef67d07a56c6beade9404'
'd039ba01adf328ebc5', 16)
def __init__(self, paramStream, now=datetime.datetime.utcnow()):
self.versionValue = 2 # a value of 2 is X509v3
self.signature = 'sha256WithRSAEncryption'
@ -267,13 +185,8 @@ class Certificate:
self.subject = 'Default Subject'
self.signatureAlgorithm = 'sha256WithRSAEncryption'
self.extensions = None
self.subjectRSA_N = self.sharedRSA_N
self.subjectRSA_E = self.sharedRSA_E
self.issuerRSA_N = self.sharedRSA_N
self.issuerRSA_E = self.sharedRSA_E
self.issuerRSA_D = self.sharedRSA_D
self.issuerRSA_P = self.sharedRSA_P
self.issuerRSA_Q = self.sharedRSA_Q
self.subjectKey = pykey.RSAKey()
self.issuerKey = pykey.RSAKey()
self.decodeParams(paramStream)
self.serialNumber = self.generateSerialNumber()
@ -347,24 +260,18 @@ class Certificate:
self.addExtKeyUsage(value)
elif extensionType == 'subjectAlternativeName':
self.addSubjectAlternativeName(value)
elif extensionType == 'authorityInformationAccess':
self.addAuthorityInformationAccess(value)
else:
raise UnknownExtensionTypeError(extensionType)
def setupKey(self, subjectOrIssuer, value):
if value == 'alternate':
if subjectOrIssuer == 'subject':
self.subjectRSA_N = self.alternateRSA_N
self.subjectRSA_E = self.alternateRSA_E
elif subjectOrIssuer == 'issuer':
self.issuerRSA_N = self.alternateRSA_N
self.issuerRSA_E = self.alternateRSA_E
self.issuerRSA_D = self.alternateRSA_D
self.issuerRSA_P = self.alternateRSA_P
self.issuerRSA_Q = self.alternateRSA_Q
else:
raise UnknownKeyTargetError(subjectOrIssuer)
if subjectOrIssuer == 'subject':
self.subjectKey = pykey.RSAKey(value)
elif subjectOrIssuer == 'issuer':
self.issuerKey = pykey.RSAKey(value)
else:
raise UnknownKeySpecificationError(value)
raise UnknownKeyTargetError(subjectOrIssuer)
def addExtension(self, extensionType, extensionValue):
if not self.extensions:
@ -429,6 +336,12 @@ class Certificate:
count += 1
self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName)
def addAuthorityInformationAccess(self, ocspURI):
sequence = univ.Sequence()
accessDescription = stringToAccessDescription(ocspURI)
sequence.setComponentByPosition(0, accessDescription)
self.addExtension(rfc2459.id_pe_authorityInfoAccess, sequence)
def getVersion(self):
return rfc2459.Version(self.versionValue).subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))
@ -460,21 +373,6 @@ class Certificate:
def getSignatureAlgorithm(self):
return stringToAlgorithmIdentifier(self.signature)
def getSubjectPublicKey(self):
rsaKey = RSAPublicKey()
rsaKey.setComponentByName('N', univ.Integer(self.subjectRSA_N))
rsaKey.setComponentByName('E', univ.Integer(self.subjectRSA_E))
return univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
def getSubjectPublicKeyInfo(self):
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
algorithmIdentifier.setComponentByName('parameters', univ.Null())
spki = rfc2459.SubjectPublicKeyInfo()
spki.setComponentByName('algorithm', algorithmIdentifier)
spki.setComponentByName('subjectPublicKey', self.getSubjectPublicKey())
return spki
def toDER(self):
tbsCertificate = rfc2459.TBSCertificate()
tbsCertificate.setComponentByName('version', self.getVersion())
@ -483,7 +381,8 @@ class Certificate:
tbsCertificate.setComponentByName('issuer', self.getIssuer())
tbsCertificate.setComponentByName('validity', self.getValidity())
tbsCertificate.setComponentByName('subject', self.getSubject())
tbsCertificate.setComponentByName('subjectPublicKeyInfo', self.getSubjectPublicKeyInfo())
tbsCertificate.setComponentByName('subjectPublicKeyInfo',
self.subjectKey.asSubjectPublicKeyInfo())
if self.extensions:
extensions = rfc2459.Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
@ -492,14 +391,11 @@ class Certificate:
extensions.setComponentByPosition(count, extension)
count += 1
tbsCertificate.setComponentByName('extensions', extensions)
tbsDER = encoder.encode(tbsCertificate)
rsaPrivateKey = rsa.PrivateKey(self.issuerRSA_N, self.issuerRSA_E, self.issuerRSA_D,
self.issuerRSA_P, self.issuerRSA_Q)
signature = rsa.sign(tbsDER, rsaPrivateKey, 'SHA-256')
certificate = rfc2459.Certificate()
certificate.setComponentByName('tbsCertificate', tbsCertificate)
certificate.setComponentByName('signatureAlgorithm', self.getSignatureAlgorithm())
certificate.setComponentByName('signatureValue', byteStringToHexifiedBitString(signature))
tbsDER = encoder.encode(tbsCertificate)
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER))
return encoder.encode(certificate)
def toPEM(self):

View File

@ -0,0 +1,282 @@
#!/usr/bin/env 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/.
"""
Reads a key specification from stdin or a file and outputs a
PKCS #8 file representing the (private) key. Also provides
methods for signing data and representing the key as a subject
public key info for use with pyasn1.
The key specification format is currently very simple. If it is
empty, one RSA key is used. If it consists of the string
'alternate', a different RSA key is used. In the future it will
be possible to specify other properties of the key (type,
strength, signature algorithm, etc.).
"""
from pyasn1.codec.der import encoder
from pyasn1.type import univ, namedtype
from pyasn1_modules import rfc2459
import base64
import binascii
import rsa
import sys
def byteStringToHexifiedBitString(string):
"""Takes a string of bytes and returns a hex string representing
those bytes for use with pyasn1.type.univ.BitString. It must be of
the form "'<hex bytes>'H", where the trailing 'H' indicates to
pyasn1 that the input is a hex string."""
return "'%s'H" % binascii.hexlify(string)
class UnknownBaseError(Exception):
"""Base class for handling unexpected input in this module."""
def __init__(self, value):
self.value = value
self.category = 'input'
def __str__(self):
return 'Unknown %s type "%s"' % (self.category, repr(self.value))
class UnknownKeySpecificationError(UnknownBaseError):
"""Helper exception type to handle unknown key specifications."""
def __init__(self, value):
UnknownBaseError.__init__(self, value)
self.category = 'key specification'
class RSAPublicKey(univ.Sequence):
"""Helper type for encoding an RSA public key"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('N', univ.Integer()),
namedtype.NamedType('E', univ.Integer()))
class RSAPrivateKey(univ.Sequence):
"""Helper type for encoding an RSA private key"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer()),
namedtype.NamedType('modulus', univ.Integer()),
namedtype.NamedType('publicExponent', univ.Integer()),
namedtype.NamedType('privateExponent', univ.Integer()),
namedtype.NamedType('prime1', univ.Integer()),
namedtype.NamedType('prime2', univ.Integer()),
namedtype.NamedType('exponent1', univ.Integer()),
namedtype.NamedType('exponent2', univ.Integer()),
namedtype.NamedType('coefficient', univ.Integer()),
)
class PrivateKeyInfo(univ.Sequence):
"""Helper type for encoding a PKCS #8 private key info"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer()),
namedtype.NamedType('privateKeyAlgorithm', rfc2459.AlgorithmIdentifier()),
namedtype.NamedType('privateKey', univ.OctetString())
)
class RSAKey:
# For reference, when encoded as a subject public key info, the
# base64-encoded sha-256 hash of this key is
# VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
sharedRSA_N = long(
'00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
'6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
'2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
'31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
'95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
'fe4923fa7251c431d503acda180a35ed8d', 16)
sharedRSA_E = 65537L
sharedRSA_D = long(
'009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
'3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
'39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
'7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
'79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
'6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
'5b62b30e6011f224725946eec57c6d9441', 16)
sharedRSA_P = long(
'00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
'8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
'3ca5d19301f48c742b', 16)
sharedRSA_Q = long(
'00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
'8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
'1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
'28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
'5810a77b9845bc3127', 16)
sharedRSA_exp1 = long(
'0096472b41a610c0ade1af2266c1600e3671355ba42d4b5a0eb4e9d7eb35'
'81400ba5dd132cdb1a5e9328c7bbc0bbb0155ea192972edf97d12751d8fc'
'f6ae572a30b1ea309a8712dd4e33241db1ee455fc093f5bc9b592d756e66'
'21474f32c07af22fb275d340792b32ba2590bbb261aefb95a258eea53765'
'5315be9c24d191992d', 16)
sharedRSA_exp2 = long(
'28b450a7a75a856413b2bda6f7a63e3d964fb9ecf50e3823ef6cc8e8fa26'
'ee413f8b9d1205540f12bbe7a0c76828b7ba65ad83cca4d0fe2a220114e1'
'b35d03d5a85bfe2706bd50fce6cfcdd571b46ca621b8ed47d605bbe765b0'
'aa4a0665ac25364da20154032e1204b8559d3e34fb5b177c9a56ff93510a'
'5a4a6287c151de2d', 16)
sharedRSA_coef = long(
'28067b9355801d2ef52dfa96d8adb589673cf8ee8a9c6ff72aeeabe9ef6b'
'e58a4f4abf05f788947dc851fdaa34542147a71a246bfb054ee76aa346ab'
'cd2692cfc9e44c51e6f069c735e073ba019f6a7214961c91b26871caeabf'
'8f064418a02690e39a8d5ff3067b7cdb7f50b1f53418a703966c4fc774bf'
'7402af6c43247f43', 16)
# For reference, when encoded as a subject public key info, the
# base64-encoded sha-256 hash of this key is
# MQj2tt1yGAfwFpWETYUCVrZxk2CD2705NKBQUlAaKJI=
alternateRSA_N = long(
'00c175c65266099f77082a6791f1b876c37f5ce538b06c4acd22b1cbd46f'
'a65ada2add41c8c2498ac4a3b3c1f61487f41b698941bd80a51c3c120244'
'c584a4c4483305e5138c0106cf08be9a862760bae6a2e8f36f23c5d98313'
'b9dfaf378345dace51d4d6dcd2a6cb3cc706ebcd3070ec98cce40aa591d7'
'295a7f71c5be66691d2b2dfec84944590bc5a3ea49fd93b1d753405f1773'
'7699958666254797ed426908880811422069988a43fee48ce68781dd22b6'
'a69cd28375131f932b128ce286fa7d251c062ad27ef016f187cdd54e832b'
'35b8930f74ba90aa8bc76167242ab1fd6d62140d18c4c0b8c68fc3748457'
'324ad7de86e6552f1d1e191d712168d3bb', 16)
alternateRSA_E = 65537L
alternateRSA_D = long(
'7e3f6d7cb839ef66ae5d7dd92ff5410bb341dc14728d39034570e1a37079'
'0f30f0681355fff41e2ad4e9a9d9fcebfbd127bdfab8c00affb1f3cea732'
'7ead47aa1621f2ac1ee14ca02f04b3b2786017980b181a449d03b03e69d1'
'12b83571e55434f012056575d2832ed6731dce799e37c83f6d51c55ab71e'
'b58015af05e1af15c747603ef7f27d03a6ff049d96bbf854c1e4e50ef5b0'
'58d0fb08180e0ac7f7be8f2ff1673d97fc9e55dba838077bbf8a7cff2962'
'857785269cd9d5bad2b57469e4afcd33c4ca2d2f699f11e7c8fbdcd484f0'
'8d8efb8a3cb8a972eb24bed972efaae4bb712093e48fe94a46eb629a8750'
'78c4021a9a2c93c9a70390e9d0a54401', 16)
alternateRSA_P = long(
'00e63fc725a6ba76925a7ff8cb59c4f56dd7ec83fe85bf1f53e11cac9a81'
'258bcfc0ae819077b0f2d1477aaf868de6a8ecbeaf7bb22b196f2a9ad82d'
'3286f0d0cc29de719e5f2be8e509b7284d5963edd362f927887a4c4a8979'
'9d340d51b301ac7601ab27179024fcaadd38bf6522af63eb16461ec02a7f'
'27b06fe09ddda7c0a1', 16)
alternateRSA_Q = long(
'00d718b1fe9f8f99f00e832ae1fbdc6fe2ab27f34e049c498010fa0eb708'
'4852182346083b5c96c3eee5592c014a410c6b930b165c13b5c26aa32eac'
'6e7c925a8551c25134f2f4a72c6421f19a73148a0edfaba5d3a6888b35cb'
'a18c00fd38ee5aaf0b545731d720761bbccdee744a52ca415e98e4de01cd'
'fe764c1967b3e8cadb', 16)
alternateRSA_exp1 = long(
'01e5aca266c94a88d22e13c2b92ea247116c657a076817bdfd30db4b3a9d'
'3095b9a4b6749647e2f84e7a784fc7838b08c85971cf7a036fa30e3b91c3'
'c4d0df278f80c1b6e859d8456adb137defaa9f1f0ac5bac9a9184fd4ea27'
'9d722ea626f160d78aad7bc83845ccb29df115c83f61b7622b99bd439c60'
'9b5790a63c595181', 16)
alternateRSA_exp2 = long(
'0080cc45d10d2484ee0d1297fc07bf80b3beff461ea27e1f38f371789c3a'
'f66b4a0edd2192c227791db4f1c77ae246bf342f31856b0f56581b58a95b'
'1131c0c5396db2a8c3c6f39ea2e336bc205ae6a2a0b36869fca98cbba733'
'cf01319a6f9bb26b7ca23d3017fc551cd8da8afdd17f6fa2e30d34868798'
'1cd6234d571e90b7df', 16)
alternateRSA_coef = long(
'6f77c0c1f2ae7ac169561cca499c52bdfbe04cddccdbdc12aec5a85691e8'
'594b7ee29908f30e7b96aa6254b80ed4aeec9b993782bdfc79b69d8d58c6'
'8870fa4be1bc0c3527288c5c82bb4aebaf15edff110403fc78e6ace6a828'
'27bf42f0cfa751e507651c5638db9393dd23dd1f6b295151de44b77fe55a'
'7b0df271e19a65c0', 16)
def __init__(self, specification = None):
if not specification:
self.RSA_N = self.sharedRSA_N
self.RSA_E = self.sharedRSA_E
self.RSA_D = self.sharedRSA_D
self.RSA_P = self.sharedRSA_P
self.RSA_Q = self.sharedRSA_Q
self.RSA_exp1 = self.sharedRSA_exp1
self.RSA_exp2 = self.sharedRSA_exp2
self.RSA_coef = self.sharedRSA_coef
elif specification == 'alternate':
self.RSA_N = self.alternateRSA_N
self.RSA_E = self.alternateRSA_E
self.RSA_D = self.alternateRSA_D
self.RSA_P = self.alternateRSA_P
self.RSA_Q = self.alternateRSA_Q
self.RSA_exp1 = self.alternateRSA_exp1
self.RSA_exp2 = self.alternateRSA_exp2
self.RSA_coef = self.alternateRSA_coef
else:
raise UnknownKeySpecificationError(specification)
def toDER(self):
privateKeyInfo = PrivateKeyInfo()
privateKeyInfo.setComponentByName('version', 0)
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
algorithmIdentifier.setComponentByName('parameters', univ.Null())
privateKeyInfo.setComponentByName('privateKeyAlgorithm', algorithmIdentifier)
rsaPrivateKey = RSAPrivateKey()
rsaPrivateKey.setComponentByName('version', 0)
rsaPrivateKey.setComponentByName('modulus', self.RSA_N)
rsaPrivateKey.setComponentByName('publicExponent', self.RSA_E)
rsaPrivateKey.setComponentByName('privateExponent', self.RSA_D)
rsaPrivateKey.setComponentByName('prime1', self.RSA_P)
rsaPrivateKey.setComponentByName('prime2', self.RSA_Q)
rsaPrivateKey.setComponentByName('exponent1', self.RSA_exp1)
rsaPrivateKey.setComponentByName('exponent2', self.RSA_exp2)
rsaPrivateKey.setComponentByName('coefficient', self.RSA_coef)
rsaPrivateKeyEncoded = encoder.encode(rsaPrivateKey)
privateKeyInfo.setComponentByName('privateKey', univ.OctetString(rsaPrivateKeyEncoded))
return encoder.encode(privateKeyInfo)
def toPEM(self):
output = '-----BEGIN PRIVATE KEY-----'
der = self.toDER()
b64 = base64.b64encode(der)
while b64:
output += '\n' + b64[:64]
b64 = b64[64:]
output += '\n-----END PRIVATE KEY-----'
return output
def asSubjectPublicKeyInfo(self):
"""Returns a subject public key info representing
this key for use by pyasn1."""
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
algorithmIdentifier.setComponentByName('parameters', univ.Null())
spki = rfc2459.SubjectPublicKeyInfo()
spki.setComponentByName('algorithm', algorithmIdentifier)
rsaKey = RSAPublicKey()
rsaKey.setComponentByName('N', univ.Integer(self.RSA_N))
rsaKey.setComponentByName('E', univ.Integer(self.RSA_E))
subjectPublicKey = univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
return spki
def sign(self, data):
"""Returns a hexified bit string representing a
signature by this key over the specified data.
Intended for use with pyasn1.type.univ.BitString"""
rsaPrivateKey = rsa.PrivateKey(self.RSA_N, self.RSA_E, self.RSA_D, self.RSA_P, self.RSA_Q)
signature = rsa.sign(data, rsaPrivateKey, 'SHA-256')
return byteStringToHexifiedBitString(signature)
# The build harness will call this function with an output file-like
# object and a path to a file containing a specification. This will
# read the specification and output the key as ASCII-encoded PKCS #8.
def main(output, inputPath):
with open(inputPath) as configStream:
output.write(RSAKey(configStream.read()).toPEM())
# When run as a standalone program, this will read a specification from
# stdin and output the certificate as PEM to stdout.
if __name__ == '__main__':
print RSAKey(sys.stdin.read()).toPEM()

View File

@ -25,14 +25,14 @@ function start_ocsp_responder(expectedCertNames, expectedPaths) {
}
function check_cert_err(cert_name, expected_error) {
let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".der");
let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".pem");
return checkCertErrorGeneric(certdb, cert, expected_error,
certificateUsageSSLServer);
}
function run_test() {
addCertFromFile(certdb, "test_ocsp_url/ca.der", 'CTu,CTu,CTu');
addCertFromFile(certdb, "test_ocsp_url/int.der", ',,');
addCertFromFile(certdb, "test_ocsp_url/ca.pem", 'CTu,CTu,CTu');
addCertFromFile(certdb, "test_ocsp_url/int.pem", ',,');
// Enabled so that we can force ocsp failure responses.
Services.prefs.setBoolPref("security.OCSP.require", true);
@ -44,7 +44,7 @@ function run_test() {
add_test(function() {
clearOCSPCache();
let ocspResponder = failingOCSPResponder();
check_cert_err("bad-scheme",SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
check_cert_err("bad-scheme", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
ocspResponder.stop(run_next_test);
});

View File

@ -0,0 +1,3 @@
issuer:int
subject:bad-scheme
extension:authorityInformationAccess:/www.example.com

View File

@ -0,0 +1,4 @@
issuer:ca
subject:ca
extension:basicConstraints:cA,
extension:keyUsage:keyCertSign,cRLSign

View File

@ -0,0 +1,3 @@
issuer:int
subject:empty-port
extension:authorityInformationAccess:http://www.example.com:/

View File

@ -0,0 +1,3 @@
issuer:int
subject:empty-scheme-url
extension:authorityInformationAccess:://www.example.com:8888/

View File

@ -0,0 +1,3 @@
issuer:int
subject:ftp-url
extension:authorityInformationAccess:ftp://www.example.com:8888/

View File

@ -1,40 +0,0 @@
#!/usr/bin/python
import tempfile, os, sys
libpath = os.path.abspath('../psm_common_py')
sys.path.append(libpath)
import CertUtils
srcdir = os.getcwd()
db = tempfile.mkdtemp()
def generate_ca_cert(db_dir, dest_dir, noise_file, name):
return CertUtils.generate_ca_cert(db_dir, dest_dir, noise_file, name,
3, True)
def generate_child_cert(db_dir, dest_dir, noise_file, name, ca_nick, is_ee,
ocsp_url):
return CertUtils.generate_child_cert(db_dir, dest_dir, noise_file, name,
ca_nick, 3, True, is_ee, ocsp_url)
def generate_certs():
[noise_file, pwd_file] = CertUtils.init_nss_db(srcdir)
generate_ca_cert(srcdir, srcdir, noise_file, 'ca')
generate_child_cert(srcdir, srcdir, noise_file, 'int', 'ca', False, '')
nick_baseurl = { 'no-path-url': "http://www.example.com:8888",
'ftp-url': "ftp://www.example.com:8888/",
'no-scheme-url': "www.example.com:8888/",
'empty-scheme-url': "://www.example.com:8888/",
'no-host-url': "http://:8888/",
'hTTp-url': "hTTp://www.example.com:8888/hTTp-url",
'https-url': "https://www.example.com:8888/https-url",
'bad-scheme': "/www.example.com",
'empty-port': "http://www.example.com:/",
'unknown-scheme': "ttp://www.example.com",
'negative-port': "http://www.example.com:-1",
'no-scheme-host-port': "/" }
for nick, url in nick_baseurl.iteritems():
generate_child_cert(srcdir, srcdir, noise_file, nick, 'int', True, url)
generate_certs()

View File

@ -0,0 +1,3 @@
issuer:int
subject:hTTp-url
extension:authorityInformationAccess:hTTp://www.example.com:8888/hTTp-url

View File

@ -0,0 +1,3 @@
issuer:int
subject:https-url
extension:authorityInformationAccess:https://www.example.com:8888/https-url

View File

@ -0,0 +1,4 @@
issuer:ca
subject:int
extension:basicConstraints:cA,
extension:keyUsage:keyCertSign,cRLSign

View File

@ -0,0 +1,42 @@
# -*- Mode: python; c-basic-offset: 4; 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/.
test_certificates = (
'bad-scheme.pem',
'ca.pem',
'empty-port.pem',
'empty-scheme-url.pem',
'ftp-url.pem',
'hTTp-url.pem',
'https-url.pem',
'int.pem',
'negative-port.pem',
'no-host-url.pem',
'no-path-url.pem',
'no-scheme-host-port.pem',
'no-scheme-url.pem',
'unknown-scheme.pem',
)
for test_certificate in test_certificates:
input_file = test_certificate + '.certspec'
GENERATED_FILES += [test_certificate]
props = GENERATED_FILES[test_certificate]
props.script = '../pycert.py'
props.inputs = [input_file, '!/config/buildid']
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_ocsp_url += ['!%s' % test_certificate]
test_keys = (
'int.key',
)
for test_key in test_keys:
input_file = test_key + '.keyspec'
GENERATED_FILES += [test_key]
props = GENERATED_FILES[test_key]
props.script = '../pykey.py'
props.inputs = [input_file]
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_ocsp_url += ['!%s' % test_key]

View File

@ -0,0 +1,3 @@
issuer:int
subject:negative-port
extension:authorityInformationAccess:http://www.example.com:-1

View File

@ -0,0 +1,3 @@
issuer:int
subject:no-host-url
extension:authorityInformationAccess:http://:8888/

View File

@ -0,0 +1,3 @@
issuer:int
subject:no-path-url
extension:authorityInformationAccess:http://www.example.com:8888

Some files were not shown because too many files have changed in this diff Show More