mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1240330 - mozAlarm debug messages are turned on r=khuey (aa938a4371) - fix (cdc44e8bc8) - Bug 1239788 - Don't include non-main-thread assertions in the constructor enabled check for [Exposed=System] WebIDL interfaces; r=bzbarsky (5d05b4066a) - Bug 1247346. Slot indices on IDL interface members that get a slot should be per-interface, not a single per-member number. r=peterv (640231c37e) - Bug 1157469 - null check wrapper in case WrapNode fails, r=bholley (9fd9b038db) - Bug 1242211 - Mark MozMapRooter as final; r=baku (f3b5cc7728) - Bug 1243438. Don't try to include the filename '<unknown>' when including headers for unions that have a built-in typedef they're referenced by. r=peterv (781d1ec0af) - Bug 1241021 part 1: Refactor GenerateCSS2PropertiesWebIDL.py to invoke a helper function for each line. r=bz (258b031fd8) - Bug 1241021 part 2: Make GenerateCSS2PropertiesWebIDL.py produce capitalized as well as uncapitalized WebkitFoo/webkitFoo DOM style accessors. r=bz (0bf2ec95ae) - Bug 1241021 part 3: Refactor CSS mochitest test_initial_storage.html to perform its DOM accessor consistency-checks via a helper-function. r=bz (3a0c1a1678) - Bug 1241021 part 4: Extend mochitest test_initial_storage.html to test that uppercase Webkit DOM accessors for css properties are functional. r=bz (5a6a23c7ab) - Bug 1240592 - Remove unnecessary -Wno-uninitialized from dom/bindings. r=khuey (c854f7b397) - Bug 1200341 - Implement HKDF for WebCrypto r=rbarnes,smaug (2c830d65a1) - Bug 1200341 - Use BufferSource instead of CryptoOperationData in the SubtleCrypto WebIDL spec r=smaug (8cece95b5c) - Bug 1191936 - Implement RSA-PSS key generation r=rbarnes (ec9654595c) - Bug 1191936 - Implement RSA-PSS signing and verification r=rbarnes,smaug (7653bdfced) - Bug 1204763 follow-up: Fix the comments, DONTBUILD (8b26e6f3a9) - Reformat clang-plugin.cpp using clang-format, no bug (9346eda9f4) - Bug 1214037 - Don't consider the result of an assignment expression MOZ_MUST_USE, r=ehsan (70c7830c3a) - Bug 1242789 - Allow lambdas to capture raw pointers to refcounted objects by reference, r=ehsan (e7158a7746) - Bug 1238042 - Add about:checkerboard. r=ehsan,botond (f234ce7fa0) - Bug 1237177. Make the this-rebinding callable proxy sandboxes use return the prototype of its target, not its own null prototype. r=efaust (694a8081dc) - Bug 1248521 - Pack PrefHashEntry better. r=froydnj. (55e9d609fe) - Bug 1240453 - enable shared memory in xpconnect. r=bz (58db0b406e) - Bug 1202014 - Don't use-after-move in ActorsChild.cpp, r=khuey (382e7183c0) - Bug 1136762 - TSan: data race xpcom/io/nsPipe3.cpp:1061 CloseWithStatus. r=nfroyd. (68fd82971d) - Bug 1237668 - Remove nsSimpleUnicharStreamFactory r=froydnj (8bb6ec081c) - Bug 1189998, Part 4 - Add authentication secret to Push data test. r=dragana (122a0bd5f9) - Bug 1205137 - Add a PushSubscription serializer. r=mt,smaug (aa9e847c42) - Bug 1232910 - Use channel.asyncOpen2 within dom/push/PushServiceHttp2.jsm. r=sicking r=dragana (a2f483a983) - Bug 1246632 - Fix ackMsgRecv in PushServiceHttp2.js. r=kitcambridge (c1559e0539) - Bug 1240615 - Make PushService protocol init method return a Promise. r=kitcambridge (4d52dc6a41) - Bug 1246784 - Expose Console to the WorkerDebuggerGlobalScope, r=khuey (a992fdc555) - misspatch (33708903c4) - Bug 1207494 - Part 5: Remove use of expression closure from dom/contacts/. r=reuben (256b3831a4) - Bug 1207494 - Part 4: Remove use of expression closure from dom/canvas/. r=gw280 (1666e49673) - Bug 1207494 - Part 3: Remove use of expression closure from dom/browser-element/. r=smaug (a891769373) - Bug 1207494 - Part 2: Remove use of expression closure from dom/base/test/. r=peterv (01762e3181) - Bug 1207494 - Part 1: Remove use of expression closure from dom/apps/. r=ferjm (2474c8619b) - Bug 1247108 - Pass securityFlag when creating a new channel within webapps (r=fabrice) (8305294f26) - Bug 1219004 - Improve error management in getFullAppByManifestURL r=ferjm (c3ad64df7a) - revert contains/includes (29c60a77e5) - Bug 1147562 - Update remaining callsites of newChannel before landing the shim in dom/ (r=sicking) (0cd64e20e1) - Bug 1243924 - Convert remaining callsites within dom/ to use channel.open2() (r=sicking) (43b01f88ba) - Bug 1162658 - Update FormData to match latest spec, r=smaug (a42ca52ad5) - Bug 1208895 - Fix a typo in nsGenericHTMLElement::GetItemId(); r=baku (2d6f2d79f4) - Bug 1223523. The named getter on document should not return images with an empty name. r=peterv (da3d1f52f5) - Bug 1183491. Null-check the document we get from our contentWindow in the contentDocument getter, because apparently it can end up null. r=bkelly (3002a4375c) - Bug 1203430 - Intermittent crash in PNeckoChild::SendHTMLDNSPrefetch. r=jdm (3b82b57cbf) - Bug 893332, part 1 - Rename misnamed SetValidityState/GetValidityState arguments. r=baku (d403b12c9a) - Bug 893332, part 2 - Update validity state before asserting range underflow state. r=baku (a4cbce224c) - Bug 893332, part 3 - Don't assert range underflow state under the parser. r=baku (763e99ed8e) - Bug 893332, part 4 - Crashtests. r=baku (7cdcdc02c4) - Bug 1240336 Setting same value to either <input> or <textarea> shouldn't cause committing existing composition r=ehsan (5cc2c35dbb) - Bug 1228708. Fix UndoManager to correctly suppress exceptions it wants to suppress on ErrorResults. r=smaug (905207a3b4) - Bug 1230295 - Add telemetry to report when Ogg chaining is used. r=rillian,r=vladan (e47c49f508)
This commit is contained in:
@@ -17,11 +17,11 @@ DSO_LDOPTS := -shared
|
||||
ifeq ($(HOST_OS_ARCH)_$(OS_ARCH),Linux_Darwin)
|
||||
# Use the host compiler instead of the target compiler.
|
||||
CXX := $(HOST_CXX)
|
||||
# Don't use --uselist with expandlibs_exec.py.
|
||||
EXPAND_MKSHLIB_ARGS :=
|
||||
# expandlibs doesn't know the distinction between host and target toolchains,
|
||||
# and on cross linux/darwin builds, the options to give to the linker for file
|
||||
# lists differ between both, so don't use file lists.
|
||||
EXPAND_MKSHLIB_ARGS :=
|
||||
# Don't pass OSX linker arguments.
|
||||
MOZ_FIX_LINK_PATHS :=
|
||||
endif
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendPluginRegistry.h"
|
||||
@@ -233,6 +233,33 @@ bool isInterestingDeclForImplicitConversion(const Decl *decl) {
|
||||
return !isInIgnoredNamespaceForImplicitConversion(decl) &&
|
||||
!isIgnoredPathForImplicitConversion(decl);
|
||||
}
|
||||
|
||||
bool isIgnoredExprForMustUse(const Expr *E) {
|
||||
if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
|
||||
switch (OpCall->getOperator()) {
|
||||
case OO_Equal:
|
||||
case OO_PlusEqual:
|
||||
case OO_MinusEqual:
|
||||
case OO_StarEqual:
|
||||
case OO_SlashEqual:
|
||||
case OO_PercentEqual:
|
||||
case OO_CaretEqual:
|
||||
case OO_AmpEqual:
|
||||
case OO_PipeEqual:
|
||||
case OO_LessLessEqual:
|
||||
case OO_GreaterGreaterEqual:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
|
||||
return Op->isAssignmentOp();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTypeAnnotation {
|
||||
@@ -359,7 +386,7 @@ public:
|
||||
const Expr *E = dyn_cast_or_null<Expr>(stmt);
|
||||
if (E) {
|
||||
QualType T = E->getType();
|
||||
if (MustUse.hasEffectiveAnnotation(T)) {
|
||||
if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "Unused value of must-use type %0");
|
||||
|
||||
@@ -963,7 +990,8 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
// lambda, where the declaration they reference is not inside the lambda.
|
||||
// This excludes arguments and local variables, leaving only captured
|
||||
// variables.
|
||||
astMatcher.addMatcher(lambdaExpr().bind("lambda"), &refCountedInsideLambdaChecker);
|
||||
astMatcher.addMatcher(lambdaExpr().bind("lambda"),
|
||||
&refCountedInsideLambdaChecker);
|
||||
|
||||
// Older clang versions such as the ones used on the infra recognize these
|
||||
// conversions as 'operator _Bool', but newer clang versions recognize these
|
||||
@@ -992,24 +1020,26 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
.bind("specialization"),
|
||||
&nonMemMovableChecker);
|
||||
|
||||
astMatcher.addMatcher(
|
||||
constructorDecl(isInterestingImplicitCtor(),
|
||||
ofClass(allOf(isConcreteClass(), decl().bind("class"))),
|
||||
unless(isMarkedImplicit()))
|
||||
.bind("ctor"),
|
||||
&explicitImplicitChecker);
|
||||
astMatcher.addMatcher(constructorDecl(isInterestingImplicitCtor(),
|
||||
ofClass(allOf(isConcreteClass(),
|
||||
decl().bind("class"))),
|
||||
unless(isMarkedImplicit()))
|
||||
.bind("ctor"),
|
||||
&explicitImplicitChecker);
|
||||
|
||||
astMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"),
|
||||
&noAutoTypeChecker);
|
||||
astMatcher.addMatcher(
|
||||
constructorDecl(isExplicitMoveConstructor()).bind("node"),
|
||||
&noExplicitMoveConstructorChecker);
|
||||
|
||||
astMatcher.addMatcher(constructorDecl(isExplicitMoveConstructor()).bind("node"),
|
||||
&noExplicitMoveConstructorChecker);
|
||||
|
||||
astMatcher.addMatcher(constructExpr(hasDeclaration(
|
||||
constructorDecl(
|
||||
isCompilerProvidedCopyConstructor(),
|
||||
ofClass(hasRefCntMember())))).bind("node"),
|
||||
&refCountedCopyConstructorChecker);
|
||||
astMatcher.addMatcher(
|
||||
constructExpr(
|
||||
hasDeclaration(constructorDecl(isCompilerProvidedCopyConstructor(),
|
||||
ofClass(hasRefCntMember()))))
|
||||
.bind("node"),
|
||||
&refCountedCopyConstructorChecker);
|
||||
}
|
||||
|
||||
// These enum variants determine whether an allocation has occured in the code.
|
||||
@@ -1024,7 +1054,8 @@ enum AllocationVariety {
|
||||
// XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
|
||||
// probably will be used at some point in the future, in order to produce better
|
||||
// error messages.
|
||||
typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *> AutomaticTemporaryMap;
|
||||
typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
|
||||
AutomaticTemporaryMap;
|
||||
AutomaticTemporaryMap AutomaticTemporaries;
|
||||
|
||||
void DiagnosticsMatcher::ScopeChecker::run(
|
||||
@@ -1036,9 +1067,11 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
|
||||
if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("parm_vardecl")) {
|
||||
if (const ParmVarDecl *D =
|
||||
Result.Nodes.getNodeAs<ParmVarDecl>("parm_vardecl")) {
|
||||
if (const Expr *Default = D->getDefaultArg()) {
|
||||
if (const MaterializeTemporaryExpr *E = dyn_cast<MaterializeTemporaryExpr>(Default)) {
|
||||
if (const MaterializeTemporaryExpr *E =
|
||||
dyn_cast<MaterializeTemporaryExpr>(Default)) {
|
||||
// We have just found a ParmVarDecl which has, as its default argument,
|
||||
// a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
|
||||
// automatic, by adding it to the AutomaticTemporaryMap.
|
||||
@@ -1077,18 +1110,17 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
// XXX We maybe should mark these lifetimes as being due to a temporary
|
||||
// which has had its lifetime extended, to improve the error messages.
|
||||
switch (E->getStorageDuration()) {
|
||||
case SD_FullExpression:
|
||||
{
|
||||
// Check if this temporary is allocated as a default argument!
|
||||
// if it is, we want to pretend that it is automatic.
|
||||
AutomaticTemporaryMap::iterator AutomaticTemporary = AutomaticTemporaries.find(E);
|
||||
if (AutomaticTemporary != AutomaticTemporaries.end()) {
|
||||
Variety = AV_Automatic;
|
||||
} else {
|
||||
Variety = AV_Temporary;
|
||||
}
|
||||
case SD_FullExpression: {
|
||||
// Check if this temporary is allocated as a default argument!
|
||||
// if it is, we want to pretend that it is automatic.
|
||||
AutomaticTemporaryMap::iterator AutomaticTemporary =
|
||||
AutomaticTemporaries.find(E);
|
||||
if (AutomaticTemporary != AutomaticTemporaries.end()) {
|
||||
Variety = AV_Automatic;
|
||||
} else {
|
||||
Variety = AV_Temporary;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case SD_Automatic:
|
||||
Variety = AV_Automatic;
|
||||
break;
|
||||
@@ -1153,8 +1185,8 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
case AV_Temporary:
|
||||
GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID);
|
||||
HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID);
|
||||
NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc,
|
||||
NonTemporaryID, TemporaryNoteID);
|
||||
NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc, NonTemporaryID,
|
||||
TemporaryNoteID);
|
||||
break;
|
||||
|
||||
case AV_Heap:
|
||||
@@ -1260,12 +1292,12 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
|
||||
const LambdaExpr *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
|
||||
|
||||
for (const LambdaCapture Capture : Lambda->captures()) {
|
||||
if (Capture.capturesVariable()) {
|
||||
if (Capture.capturesVariable() && Capture.getCaptureKind() != LCK_ByRef) {
|
||||
QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
|
||||
|
||||
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
|
||||
Diag.Report(Capture.getLocation(), errorID)
|
||||
<< Capture.getCapturedVar() << Pointee;
|
||||
Diag.Report(Capture.getLocation(), errorID) << Capture.getCapturedVar()
|
||||
<< Pointee;
|
||||
Diag.Report(Capture.getLocation(), noteID);
|
||||
}
|
||||
}
|
||||
@@ -1435,7 +1467,7 @@ void DiagnosticsMatcher::NoExplicitMoveConstructorChecker::run(
|
||||
// Everything we needed to know was checked in the matcher - we just report
|
||||
// the error here
|
||||
const CXXConstructorDecl *D =
|
||||
Result.Nodes.getNodeAs<CXXConstructorDecl>("node");
|
||||
Result.Nodes.getNodeAs<CXXConstructorDecl>("node");
|
||||
|
||||
Diag.Report(D->getLocation(), ErrorID);
|
||||
}
|
||||
@@ -1447,16 +1479,16 @@ void DiagnosticsMatcher::RefCountedCopyConstructorChecker::run(
|
||||
DiagnosticIDs::Error, "Invalid use of compiler-provided copy constructor "
|
||||
"on refcounted type");
|
||||
unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "The default copy constructor also copies the "
|
||||
"default mRefCnt property, leading to reference "
|
||||
"count imbalance issues. Please provide your own "
|
||||
"copy constructor which only copies the fields which "
|
||||
"need to be copied");
|
||||
DiagnosticIDs::Note,
|
||||
"The default copy constructor also copies the "
|
||||
"default mRefCnt property, leading to reference "
|
||||
"count imbalance issues. Please provide your own "
|
||||
"copy constructor which only copies the fields which "
|
||||
"need to be copied");
|
||||
|
||||
// Everything we needed to know was checked in the matcher - we just report
|
||||
// the error here
|
||||
const CXXConstructExpr *E =
|
||||
Result.Nodes.getNodeAs<CXXConstructExpr>("node");
|
||||
const CXXConstructExpr *E = Result.Nodes.getNodeAs<CXXConstructExpr>("node");
|
||||
|
||||
Diag.Report(E->getLocation(), ErrorID);
|
||||
Diag.Report(E->getLocation(), NoteID);
|
||||
|
||||
@@ -20,12 +20,15 @@ void use(MayUse&&);
|
||||
void use(bool);
|
||||
|
||||
void foo() {
|
||||
MustUse u;
|
||||
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
{
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
@@ -33,6 +36,7 @@ void foo() {
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
}
|
||||
if (true) {
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
@@ -41,6 +45,7 @@ void foo() {
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
} else {
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
@@ -48,6 +53,7 @@ void foo() {
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
}
|
||||
|
||||
if(true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
@@ -62,6 +68,8 @@ void foo() {
|
||||
else producesMayUsePointer();
|
||||
if(true) producesMayUseRef();
|
||||
else producesMayUseRef();
|
||||
if(true) u = producesMustUse();
|
||||
else u = producesMustUse();
|
||||
|
||||
while (true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true) producesMustUsePointer();
|
||||
@@ -69,6 +77,7 @@ void foo() {
|
||||
while (true) producesMayUse();
|
||||
while (true) producesMayUsePointer();
|
||||
while (true) producesMayUseRef();
|
||||
while (true) u = producesMustUse();
|
||||
|
||||
do producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true);
|
||||
@@ -82,6 +91,8 @@ void foo() {
|
||||
while (true);
|
||||
do producesMayUseRef();
|
||||
while (true);
|
||||
do u = producesMustUse();
|
||||
while (true);
|
||||
|
||||
for (;;) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;) producesMustUsePointer();
|
||||
@@ -89,6 +100,7 @@ void foo() {
|
||||
for (;;) producesMayUse();
|
||||
for (;;) producesMayUsePointer();
|
||||
for (;;) producesMayUseRef();
|
||||
for (;;) u = producesMustUse();
|
||||
|
||||
for (producesMustUse();;); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (producesMustUsePointer();;);
|
||||
@@ -96,6 +108,7 @@ void foo() {
|
||||
for (producesMayUse();;);
|
||||
for (producesMayUsePointer();;);
|
||||
for (producesMayUseRef();;);
|
||||
for (u = producesMustUse();;);
|
||||
|
||||
for (;;producesMustUse()); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;producesMustUsePointer());
|
||||
@@ -103,6 +116,7 @@ void foo() {
|
||||
for (;;producesMayUse());
|
||||
for (;;producesMayUsePointer());
|
||||
for (;;producesMayUseRef());
|
||||
for (;;u = producesMustUse());
|
||||
|
||||
use((producesMustUse(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
use((producesMustUsePointer(), false));
|
||||
@@ -110,6 +124,7 @@ void foo() {
|
||||
use((producesMayUse(), false));
|
||||
use((producesMayUsePointer(), false));
|
||||
use((producesMayUseRef(), false));
|
||||
use((u = producesMustUse(), false));
|
||||
|
||||
switch (1) {
|
||||
case 1:
|
||||
@@ -119,6 +134,7 @@ void foo() {
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
case 2:
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
case 3:
|
||||
@@ -131,6 +147,8 @@ void foo() {
|
||||
producesMayUsePointer();
|
||||
case 7:
|
||||
producesMayUseRef();
|
||||
case 8:
|
||||
u = producesMustUse();
|
||||
default:
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
@@ -138,6 +156,7 @@ void foo() {
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
u = producesMustUse();
|
||||
}
|
||||
|
||||
use(producesMustUse());
|
||||
@@ -146,6 +165,7 @@ void foo() {
|
||||
use(producesMayUse());
|
||||
use(producesMayUsePointer());
|
||||
use(producesMayUseRef());
|
||||
use(u = producesMustUse());
|
||||
|
||||
MustUse a = producesMustUse();
|
||||
MustUse *b = producesMustUsePointer();
|
||||
@@ -153,4 +173,5 @@ void foo() {
|
||||
MayUse d = producesMayUse();
|
||||
MayUse *e = producesMayUsePointer();
|
||||
MayUse &f = producesMayUseRef();
|
||||
MustUse g = u = producesMustUse();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ void foo() {
|
||||
SmartPtr<R> sp;
|
||||
take([&](R* argptr) {
|
||||
R* localptr;
|
||||
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
|
||||
ptr->method();
|
||||
argptr->method();
|
||||
localptr->method();
|
||||
});
|
||||
@@ -33,7 +33,7 @@ void foo() {
|
||||
});
|
||||
take([&](R* argptr) {
|
||||
R* localptr;
|
||||
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
|
||||
take(ptr);
|
||||
take(argptr);
|
||||
take(localptr);
|
||||
});
|
||||
@@ -91,4 +91,28 @@ void foo() {
|
||||
take(argsp);
|
||||
take(localsp);
|
||||
});
|
||||
take([&ptr](R* argptr) {
|
||||
R* localptr;
|
||||
ptr->method();
|
||||
argptr->method();
|
||||
localptr->method();
|
||||
});
|
||||
take([&sp](SmartPtr<R> argsp) {
|
||||
SmartPtr<R> localsp;
|
||||
sp->method();
|
||||
argsp->method();
|
||||
localsp->method();
|
||||
});
|
||||
take([&ptr](R* argptr) {
|
||||
R* localptr;
|
||||
take(ptr);
|
||||
take(argptr);
|
||||
take(localptr);
|
||||
});
|
||||
take([&sp](SmartPtr<R> argsp) {
|
||||
SmartPtr<R> localsp;
|
||||
take(sp);
|
||||
take(argsp);
|
||||
take(localsp);
|
||||
});
|
||||
}
|
||||
|
||||
Vendored
+5
@@ -401,6 +401,7 @@ PK11_LoadPrivKey
|
||||
PK11_Logout
|
||||
PK11_LogoutAll
|
||||
PK11_MakeIDFromPubKey
|
||||
PK11_MapSignKeyType
|
||||
PK11_MechanismToAlgtag
|
||||
PK11_MergeTokens
|
||||
PK11_NeedLogin
|
||||
@@ -425,11 +426,13 @@ PK11_SetPasswordFunc
|
||||
PK11_SetSlotPWValues
|
||||
PK11_Sign
|
||||
PK11_SignatureLen
|
||||
PK11_SignWithMechanism
|
||||
PK11_UnwrapPrivKey
|
||||
PK11_UnwrapSymKey
|
||||
PK11_UpdateSlotAttribute
|
||||
PK11_UserDisableSlot
|
||||
PK11_UserEnableSlot
|
||||
PK11_VerifyWithMechanism
|
||||
PK11_WrapPrivKey
|
||||
PK11_WrapSymKey
|
||||
PORT_Alloc
|
||||
@@ -630,9 +633,11 @@ SEC_StringToOID
|
||||
SEC_UTF8StringTemplate DATA
|
||||
SEC_UTF8StringTemplate_Util DATA
|
||||
SGN_Begin
|
||||
SGN_CreateDigestInfo
|
||||
SGN_CreateDigestInfo_Util
|
||||
SGN_DecodeDigestInfo
|
||||
SGN_DestroyContext
|
||||
SGN_DestroyDigestInfo
|
||||
SGN_DestroyDigestInfo_Util
|
||||
SGN_End
|
||||
SGN_NewContext
|
||||
|
||||
@@ -55,6 +55,11 @@ static RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::MAKE_LINKABLE
|
||||
},
|
||||
{
|
||||
"checkerboard", "chrome://global/content/aboutCheckerboard.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT
|
||||
},
|
||||
{
|
||||
"license", "chrome://global/content/license.html",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
|
||||
@@ -24,12 +24,9 @@ protected:
|
||||
virtual ~nsAboutRedirector() {}
|
||||
};
|
||||
|
||||
#define NS_ABOUT_REDIRECTOR_MODULE_CID \
|
||||
{ /* f0acde16-1dd1-11b2-9e35-f5786fff5a66*/ \
|
||||
0xf0acde16, \
|
||||
0x1dd1, \
|
||||
0x11b2, \
|
||||
{0x9e, 0x35, 0xf5, 0x78, 0x6f, 0xff, 0x5a, 0x66} \
|
||||
}
|
||||
/* 56ebedd4-6ccf-48e8-bdae-adc77f044567 */
|
||||
#define NS_ABOUT_REDIRECTOR_MODULE_CID \
|
||||
{ 0x56ebedd4, 0x6ccf, 0x48e8, \
|
||||
{ 0xbd, 0xae, 0xad, 0xc7, 0x7f, 0x04, 0x45, 0x67 } }
|
||||
|
||||
#endif // nsAboutRedirector_h__
|
||||
|
||||
@@ -170,6 +170,7 @@ const mozilla::Module::ContractIDEntry kDocShellContracts[] = {
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "buildconfig", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "checkerboard", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
|
||||
@@ -4,18 +4,27 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* static functions */
|
||||
const DEBUG = true;
|
||||
|
||||
function debug(aStr) {
|
||||
DEBUG && dump("AlarmService: " + aStr + "\n");
|
||||
}
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AlarmDB.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
function getLogger() {
|
||||
var logger = Log.repository.getLogger("AlarmsService");
|
||||
logger.addAppender(new Log.DumpAppender(new Log.BasicFormatter()));
|
||||
logger.level = Log.Level.Debug;
|
||||
return logger;
|
||||
}
|
||||
|
||||
const logger = getLogger();
|
||||
|
||||
/* Only log in B2G */
|
||||
function debug(aStr) {
|
||||
AppConstants.MOZ_B2G && logger.debug(aStr);
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["AlarmService"];
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@ support-files =
|
||||
system_message_chrome_script.js
|
||||
|
||||
[test_alarm_add_data.html]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = ((buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_alarm_add_date.html]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = ((buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_alarm_add_respectTimezone.html]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = ((buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_alarm_non_permitted_app.html]
|
||||
[test_alarm_permitted_app.html]
|
||||
[test_alarm_remove.html]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = ((buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug1015540.html]
|
||||
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug1037079.html]
|
||||
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug1090896.html]
|
||||
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
'use strict';
|
||||
|
||||
const { classes: Cc, interfaces: Ci } = Components;
|
||||
var { classes: Cc, interfaces: Ci } = Components;
|
||||
|
||||
const systemMessenger = Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
|
||||
@@ -15,8 +15,8 @@ const ALARM_OFFSET = 10000; // 10 seconds.
|
||||
const CLOCK_OFFSET = 20000; // 20 seconds.
|
||||
const MANIFEST_URL = "http://dummyurl.com/manifest.webapp";
|
||||
|
||||
let alarmDate;
|
||||
let alarmFired;
|
||||
var alarmDate;
|
||||
var alarmFired;
|
||||
function alarmCb() {
|
||||
alarmFired = true;
|
||||
};
|
||||
|
||||
@@ -375,11 +375,6 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"audio-capture:3gpp2": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"nfc": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
|
||||
@@ -3421,21 +3421,15 @@ this.DOMApplicationRegistry = {
|
||||
let requestChannel;
|
||||
|
||||
let appURI = NetUtil.newURI(aNewApp.origin, null, null);
|
||||
let principal =
|
||||
Services.scriptSecurityManager.createCodebasePrincipal(appURI,
|
||||
{appId: aNewApp.localId});
|
||||
|
||||
if (aIsLocalFileInstall) {
|
||||
requestChannel = NetUtil.newChannel({
|
||||
uri: aFullPackagePath,
|
||||
loadingPrincipal: principal,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
|
||||
loadUsingSystemPrincipal: true}
|
||||
).QueryInterface(Ci.nsIFileChannel);
|
||||
} else {
|
||||
requestChannel = NetUtil.newChannel({
|
||||
uri: aFullPackagePath,
|
||||
loadingPrincipal: principal,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
|
||||
loadUsingSystemPrincipal: true}
|
||||
).QueryInterface(Ci.nsIHttpChannel);
|
||||
requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
}
|
||||
@@ -4619,6 +4613,10 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
return this.getManifestFor(aManifestURL).then((aManifest) => {
|
||||
if (!aManifest) {
|
||||
return Promise.reject("NoManifest");
|
||||
}
|
||||
|
||||
let manifest = aEntryPoint && aManifest.entry_points &&
|
||||
aManifest.entry_points[aEntryPoint]
|
||||
? aManifest.entry_points[aEntryPoint]
|
||||
@@ -4790,7 +4788,7 @@ this.DOMApplicationRegistry = {
|
||||
/**
|
||||
* Appcache download observer
|
||||
*/
|
||||
let AppcacheObserver = function(aApp) {
|
||||
var AppcacheObserver = function(aApp) {
|
||||
debug("Creating AppcacheObserver for " + aApp.origin +
|
||||
" - " + aApp.installState);
|
||||
this.app = aApp;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/StoreTrustAnchor.jsm");
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
|
||||
ok(app, "App is non-null");
|
||||
if (app.installState == "pending") {
|
||||
ok(true, "App is pending. Waiting for progress");
|
||||
app.onprogress = function() ok(true, "Got download progress");
|
||||
app.onprogress = () => ok(true, "Got download progress");
|
||||
app.ondownloadsuccess = continueTest;
|
||||
app.ondownloaderror = mozAppsError;
|
||||
yield undefined;
|
||||
@@ -173,8 +173,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
|
||||
// manifest, so there should always be an update.
|
||||
var lastCheck = app.lastUpdateCheck;
|
||||
ok(true, "Setting callbacks");
|
||||
app.ondownloadapplied = function() ok(true, "downloadapplied fired.");
|
||||
app.ondownloadavailable = function() ok(false, "downloadavailable fired");
|
||||
app.ondownloadapplied = () => ok(true, "downloadapplied fired.");
|
||||
app.ondownloadavailable = () => ok(false, "downloadavailable fired");
|
||||
ok(true, "Checking for updates");
|
||||
var request = app.checkForUpdate();
|
||||
request.onerror = mozAppsError;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/OperatorApps.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
var dom_mozApps_debug = Services.prefs.getBoolPref("dom.mozApps.debug");
|
||||
Services.prefs.setBoolPref("dom.mozApps.debug", true);
|
||||
|
||||
+8
-8
@@ -967,23 +967,23 @@ BlobImplFile::LookupAndCacheIsDirectory()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BlobImplEmptyFile implementation
|
||||
// EmptyBlobImpl implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(BlobImplEmptyFile, BlobImpl)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(EmptyBlobImpl, BlobImpl)
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
BlobImplEmptyFile::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
EmptyBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!aStart && !aLength);
|
||||
RefPtr<BlobImpl> impl = new BlobImplEmptyFile(aContentType);
|
||||
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplEmptyFile::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
EmptyBlobImpl::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
||||
+5
-4
@@ -70,6 +70,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
|
||||
|
||||
// This creates a Blob or a File based on the type of BlobImpl.
|
||||
static Blob*
|
||||
Create(nsISupports* aParent, BlobImpl* aImpl);
|
||||
|
||||
@@ -837,13 +838,13 @@ private:
|
||||
bool mIsTemporary;
|
||||
};
|
||||
|
||||
class BlobImplEmptyFile final : public BlobImplBase
|
||||
class EmptyBlobImpl final : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
explicit BlobImplEmptyFile(const nsAString& aContentType)
|
||||
: BlobImplBase(EmptyString(), aContentType, 0 /* aLength */)
|
||||
explicit EmptyBlobImpl(const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, 0 /* aLength */)
|
||||
{}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
@@ -859,7 +860,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
~BlobImplEmptyFile() {}
|
||||
~EmptyBlobImpl() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
+39
-42
@@ -23,32 +23,16 @@ FormData::FormData(nsISupports* aOwner)
|
||||
|
||||
namespace {
|
||||
|
||||
// Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
|
||||
already_AddRefed<File>
|
||||
CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename,
|
||||
ErrorResult& aRv)
|
||||
already_AddRefed<Blob>
|
||||
GetBlobForFormDataStorage(Blob& aBlob, const Optional<nsAString>& aFilename,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Step 3 "If value is a Blob object and not a File object, set value to
|
||||
// a new File object, representing the same bytes, whose name attribute value
|
||||
// is "blob"."
|
||||
// Step 4 "If value is a File object and filename is given, set value to
|
||||
// a new File object, representing the same bytes, whose name attribute
|
||||
// value is filename."
|
||||
nsAutoString filename;
|
||||
if (aFilename.WasPassed()) {
|
||||
filename = aFilename.Value();
|
||||
} else {
|
||||
// If value is already a File and filename is not passed, the spec says not
|
||||
// to create a new instance.
|
||||
RefPtr<File> file = aBlob.ToFile();
|
||||
if (file) {
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
filename = NS_LITERAL_STRING("blob");
|
||||
if (!aFilename.WasPassed()) {
|
||||
RefPtr<Blob> blob = &aBlob;
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
RefPtr<File> file = aBlob.ToFile(filename, aRv);
|
||||
RefPtr<File> file = aBlob.ToFile(aFilename.Value(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -78,7 +62,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FormData)
|
||||
|
||||
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
|
||||
ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
|
||||
"mFormData[i].GetAsFile()", 0);
|
||||
"mFormData[i].GetAsBlob()", 0);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
@@ -116,14 +100,14 @@ FormData::Append(const nsAString& aName, const nsAString& aValue,
|
||||
void
|
||||
FormData::Append(const nsAString& aName, Blob& aBlob,
|
||||
const Optional<nsAString>& aFilename,
|
||||
ErrorResult& aRv)
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
|
||||
RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddNameFilePair(aName, file);
|
||||
AddNameBlobPair(aName, blob);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -140,7 +124,7 @@ FormData::Delete(const nsAString& aName)
|
||||
|
||||
void
|
||||
FormData::Get(const nsAString& aName,
|
||||
Nullable<OwningFileOrUSVString>& aOutValue)
|
||||
Nullable<OwningBlobOrUSVString>& aOutValue)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
@@ -154,11 +138,11 @@ FormData::Get(const nsAString& aName,
|
||||
|
||||
void
|
||||
FormData::GetAll(const nsAString& aName,
|
||||
nsTArray<OwningFileOrUSVString>& aValues)
|
||||
nsTArray<OwningBlobOrUSVString>& aValues)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (aName.Equals(mFormData[i].name)) {
|
||||
OwningFileOrUSVString* element = aValues.AppendElement();
|
||||
OwningBlobOrUSVString* element = aValues.AppendElement();
|
||||
*element = mFormData[i].value;
|
||||
}
|
||||
}
|
||||
@@ -177,12 +161,12 @@ FormData::Has(const nsAString& aName)
|
||||
}
|
||||
|
||||
nsresult
|
||||
FormData::AddNameFilePair(const nsAString& aName, File* aFile)
|
||||
FormData::AddNameBlobPair(const nsAString& aName, Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
FormDataTuple* data = mFormData.AppendElement();
|
||||
SetNameFilePair(data, aName, aFile);
|
||||
SetNameBlobPair(data, aName, aBlob);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -215,12 +199,12 @@ FormData::Set(const nsAString& aName, Blob& aBlob,
|
||||
{
|
||||
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
|
||||
if (tuple) {
|
||||
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
|
||||
RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetNameFilePair(tuple, aName, file);
|
||||
SetNameBlobPair(tuple, aName, blob);
|
||||
} else {
|
||||
Append(aName, aBlob, aFilename, aRv);
|
||||
}
|
||||
@@ -251,7 +235,7 @@ FormData::GetKeyAtIndex(uint32_t aIndex) const
|
||||
return mFormData[aIndex].name;
|
||||
}
|
||||
|
||||
const OwningFileOrUSVString&
|
||||
const OwningBlobOrUSVString&
|
||||
FormData::GetValueAtIndex(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < mFormData.Length());
|
||||
@@ -269,15 +253,15 @@ FormData::SetNameValuePair(FormDataTuple* aData,
|
||||
}
|
||||
|
||||
void
|
||||
FormData::SetNameFilePair(FormDataTuple* aData,
|
||||
FormData::SetNameBlobPair(FormDataTuple* aData,
|
||||
const nsAString& aName,
|
||||
File* aFile)
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
MOZ_ASSERT(aFile);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
aData->name = aName;
|
||||
aData->value.SetAsFile() = aFile;
|
||||
aData->value.SetAsBlob() = aBlob;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -358,8 +342,21 @@ FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
||||
if (mFormData[i].value.IsFile()) {
|
||||
fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
|
||||
if (mFormData[i].value.IsBlob()) {
|
||||
RefPtr<File> file = mFormData[i].value.GetAsBlob()->ToFile();
|
||||
if (file) {
|
||||
fs.AddNameBlobPair(mFormData[i].name, file);
|
||||
continue;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
file =
|
||||
mFormData[i].value.GetAsBlob()->ToFile(NS_LITERAL_STRING("blob"), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
fs.AddNameBlobPair(mFormData[i].name, file);
|
||||
} else if (mFormData[i].value.IsUSVString()) {
|
||||
fs.AddNameValuePair(mFormData[i].name,
|
||||
mFormData[i].value.GetAsUSVString());
|
||||
|
||||
+9
-9
@@ -35,7 +35,7 @@ private:
|
||||
struct FormDataTuple
|
||||
{
|
||||
nsString name;
|
||||
OwningFileOrUSVString value;
|
||||
OwningBlobOrUSVString value;
|
||||
};
|
||||
|
||||
// Returns the FormDataTuple to modify. This may be null, in which case
|
||||
@@ -47,9 +47,9 @@ private:
|
||||
const nsAString& aName,
|
||||
const nsAString& aValue);
|
||||
|
||||
void SetNameFilePair(FormDataTuple* aData,
|
||||
void SetNameBlobPair(FormDataTuple* aData,
|
||||
const nsAString& aName,
|
||||
File* aFile);
|
||||
Blob* aBlob);
|
||||
|
||||
public:
|
||||
explicit FormData(nsISupports* aOwner = nullptr);
|
||||
@@ -84,9 +84,9 @@ public:
|
||||
|
||||
void Delete(const nsAString& aName);
|
||||
|
||||
void Get(const nsAString& aName, Nullable<OwningFileOrUSVString>& aOutValue);
|
||||
void Get(const nsAString& aName, Nullable<OwningBlobOrUSVString>& aOutValue);
|
||||
|
||||
void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
|
||||
void GetAll(const nsAString& aName, nsTArray<OwningBlobOrUSVString>& aValues);
|
||||
|
||||
bool Has(const nsAString& aName);
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
|
||||
const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
|
||||
|
||||
const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
|
||||
const OwningBlobOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
|
||||
|
||||
// nsFormSubmission
|
||||
virtual nsresult
|
||||
@@ -114,11 +114,11 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
File* aFile) override;
|
||||
virtual nsresult AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob) override;
|
||||
|
||||
typedef bool (*FormDataEntryCallback)(const nsString& aName,
|
||||
const OwningFileOrUSVString& aValue,
|
||||
const OwningBlobOrUSVString& aValue,
|
||||
void* aClosure);
|
||||
|
||||
uint32_t
|
||||
|
||||
@@ -836,14 +836,13 @@ ReadFormData(JSContext* aCx,
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
aHolder->BlobImpls()[indexOrLengthOfString];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
RefPtr<File> file =
|
||||
File::Create(aHolder->ParentDuringRead(), blobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
RefPtr<Blob> blob =
|
||||
Blob::Create(aHolder->ParentDuringRead(), blobImpl);
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
ErrorResult rv;
|
||||
formData->Append(name, *file, thirdArg, rv);
|
||||
formData->Append(name, *blob, thirdArg, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -912,7 +911,7 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||
{ }
|
||||
|
||||
static bool
|
||||
Write(const nsString& aName, const OwningFileOrUSVString& aValue,
|
||||
Write(const nsString& aName, const OwningBlobOrUSVString& aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
Closure* closure = static_cast<Closure*>(aClosure);
|
||||
@@ -920,8 +919,8 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aValue.IsFile()) {
|
||||
BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
|
||||
if (aValue.IsBlob()) {
|
||||
BlobImpl* blobImpl = aValue.GetAsBlob()->Impl();
|
||||
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
|
||||
closure->mHolder->BlobImpls().Length())) {
|
||||
return false;
|
||||
|
||||
@@ -2941,8 +2941,9 @@ nsINode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, WrapNode(aCx, aGivenProto));
|
||||
MOZ_ASSERT_IF(ChromeOnlyAccess(),
|
||||
xpc::IsInContentXBLScope(obj) || !xpc::UseContentXBLScope(js::GetObjectCompartment(obj)));
|
||||
MOZ_ASSERT_IF(obj && ChromeOnlyAccess(),
|
||||
xpc::IsInContentXBLScope(obj) ||
|
||||
!xpc::UseContentXBLScope(js::GetObjectCompartment(obj)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,12 +42,14 @@ var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
|
||||
var PROTOCOL_SCHEME = "jsproto";
|
||||
|
||||
|
||||
function CustomChannel(uri) {
|
||||
function CustomChannel(uri, loadInfo) {
|
||||
this.URI = this.originalURI = uri;
|
||||
this.loadInfo = loadInfo;
|
||||
}
|
||||
CustomChannel.prototype = {
|
||||
URI: null,
|
||||
originalURI: null,
|
||||
loadInfo: null,
|
||||
contentCharset: "utf-8",
|
||||
contentLength: 0,
|
||||
contentType: "text/plain",
|
||||
@@ -123,8 +125,11 @@ CustomProtocol.prototype = {
|
||||
uri.spec = spec;
|
||||
return uri.QueryInterface(Ci.nsIURI);
|
||||
},
|
||||
newChannel: function newChannel(URI) {
|
||||
return new CustomChannel(URI);
|
||||
newChannel2: function newChannel2(URI, loadInfo) {
|
||||
return new CustomChannel(URI, loadInfo);
|
||||
},
|
||||
newChannel: function newChannel(URI) {
|
||||
return newChannel2(URI);
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsISupportsWeakReference,
|
||||
|
||||
@@ -16,9 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=789315
|
||||
<script type="text/javascript">
|
||||
var obj = new FormData(document.getElementById('a')).get('b');
|
||||
|
||||
ok(obj instanceof File, "This should return an empty File");
|
||||
ok(obj instanceof Blob, "This should return an empty Blob");
|
||||
is(obj.size, 0, "Size should be 0");
|
||||
is(obj.name, "", "Name should be an empty string");
|
||||
is(obj.type, "application/octet-stream", "Type should be application/octet-stream");
|
||||
|
||||
var o = obj.slice(10, 100, "foo/bar");
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function () testCopyPaste(false));
|
||||
addLoadEvent(() => testCopyPaste(false));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
@@ -32,7 +32,7 @@ function modifySelectionDiv12() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function () testCopyPaste(true));
|
||||
addLoadEvent(() => testCopyPaste(true));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
@@ -510,6 +510,6 @@
|
||||
[ 'addToDoc' ],
|
||||
[ 'displayInherit' ]
|
||||
)});
|
||||
runWhenDone(function() SimpleTest.finish());
|
||||
runWhenDone(() => SimpleTest.finish());
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://testing-common/httpd.js");
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const nsIDocumentEncoder = Components.interfaces.nsIDocumentEncoder;
|
||||
const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
|
||||
@@ -16,18 +17,21 @@ function loadContentFile(aFile, aCharset) {
|
||||
var file = do_get_file(aFile);
|
||||
var ios = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var chann = ios.newChannelFromURI ( ios.newFileURI (file) );
|
||||
var chann = NetUtil.newChannel({
|
||||
uri: ios.newFileURI(file),
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
chann.contentCharset = aCharset;
|
||||
|
||||
/*var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
inputStream.init(chann.open());
|
||||
inputStream.init(chann.open2());
|
||||
return inputStream.read(file.fileSize);
|
||||
*/
|
||||
|
||||
var inputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
inputStream.init(chann.open(), aCharset, 1024, replacementChar);
|
||||
inputStream.init(chann.open2(), aCharset, 1024, replacementChar);
|
||||
var str = {}, content = '';
|
||||
while (inputStream.readString(4096, str) != 0) {
|
||||
content += str.value;
|
||||
|
||||
@@ -1608,7 +1608,7 @@ WrapNativeParent(JSContext* cx, T* p, nsWrapperCache* cache,
|
||||
}
|
||||
|
||||
JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
|
||||
if (!useXBLScope) {
|
||||
if (!parent || !useXBLScope) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -2323,7 +2323,7 @@ public:
|
||||
|
||||
// Rooter class for MozMap; this is what we mostly use in the codegen.
|
||||
template<typename T>
|
||||
class MOZ_RAII MozMapRooter : private JS::CustomAutoRooter
|
||||
class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
|
||||
|
||||
+40
-29
@@ -31,8 +31,9 @@ ENUM_ENTRY_VARIABLE_NAME = 'strings'
|
||||
INSTANCE_RESERVED_SLOTS = 1
|
||||
|
||||
|
||||
def memberReservedSlot(member):
|
||||
return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
|
||||
def memberReservedSlot(member, descriptor):
|
||||
return ("(DOM_INSTANCE_RESERVED_SLOTS + %d)" %
|
||||
member.slotIndices[descriptor.interface.identifier.name])
|
||||
|
||||
|
||||
def toStringBool(arg):
|
||||
@@ -1036,10 +1037,7 @@ class CGHeaders(CGWrapper):
|
||||
headerSet.add("mozilla/dom/Nullable.h")
|
||||
unrolled = t.unroll()
|
||||
if unrolled.isUnion():
|
||||
if len(config.filenamesPerUnion[unrolled.name]) > 1:
|
||||
headerSet.add("mozilla/dom/UnionTypes.h")
|
||||
else:
|
||||
headerSet.add(self.getDeclarationFilename(unrolled))
|
||||
headerSet.add(self.getUnionDeclarationFilename(config, unrolled))
|
||||
bindingHeaders.add("mozilla/dom/UnionConversions.h")
|
||||
elif unrolled.isDate():
|
||||
if dictionary or jsImplementedDescriptors:
|
||||
@@ -1197,6 +1195,20 @@ class CGHeaders(CGWrapper):
|
||||
basename = os.path.basename(decl.filename())
|
||||
return basename.replace('.webidl', 'Binding.h')
|
||||
|
||||
@staticmethod
|
||||
def getUnionDeclarationFilename(config, unionType):
|
||||
assert unionType.isUnion()
|
||||
assert unionType.unroll() == unionType
|
||||
# If a union is "defined" in multiple files, it goes in UnionTypes.h.
|
||||
if len(config.filenamesPerUnion[unionType.name]) > 1:
|
||||
return "mozilla/dom/UnionTypes.h"
|
||||
# If a union is defined by a built-in typedef, it also goes in
|
||||
# UnionTypes.h.
|
||||
assert len(config.filenamesPerUnion[unionType.name]) == 1
|
||||
if "<unknown>" in config.filenamesPerUnion[unionType.name]:
|
||||
return "mozilla/dom/UnionTypes.h"
|
||||
return CGHeaders.getDeclarationFilename(unionType)
|
||||
|
||||
|
||||
def SortedDictValues(d):
|
||||
"""
|
||||
@@ -1292,10 +1304,7 @@ def UnionTypes(unionTypes, config):
|
||||
# And add headers for the type we're parametrized over
|
||||
addHeadersForType(f.inner)
|
||||
|
||||
if len(config.filenamesPerUnion[t.name]) > 1:
|
||||
implheaders.add("mozilla/dom/UnionTypes.h")
|
||||
else:
|
||||
implheaders.add(CGHeaders.getDeclarationFilename(t))
|
||||
implheaders.add(CGHeaders.getUnionDeclarationFilename(config, t))
|
||||
for f in t.flatMemberTypes:
|
||||
assert not f.nullable()
|
||||
addHeadersForType(f)
|
||||
@@ -1358,8 +1367,9 @@ def UnionConversions(unionTypes, config):
|
||||
# And the internal type of the MozMap
|
||||
addHeadersForType(f.inner, providers)
|
||||
|
||||
if len(config.filenamesPerUnion[t.name]) == 1:
|
||||
headers.add(CGHeaders.getDeclarationFilename(t))
|
||||
# We plan to include UnionTypes.h no matter what, so it's
|
||||
# OK if we throw it into the set here.
|
||||
headers.add(CGHeaders.getUnionDeclarationFilename(config, t))
|
||||
|
||||
for f in t.flatMemberTypes:
|
||||
addHeadersForType(f, providers)
|
||||
@@ -2142,7 +2152,7 @@ def clearableCachedAttrs(descriptor):
|
||||
m.isAttr() and
|
||||
# Constants should never need clearing!
|
||||
m.dependsOn != "Nothing" and
|
||||
m.slotIndex is not None)
|
||||
m.slotIndices is not None)
|
||||
|
||||
|
||||
def MakeClearCachedValueNativeName(member):
|
||||
@@ -3259,7 +3269,7 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
conditions = []
|
||||
iface = self.descriptor.interface
|
||||
|
||||
if not iface.isExposedInWindow():
|
||||
if not iface.isExposedOnMainThread():
|
||||
exposedInWindowCheck = dedent(
|
||||
"""
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
|
||||
@@ -3278,7 +3288,7 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
}
|
||||
""", workerCondition=workerCondition.define())
|
||||
exposedInWorkerCheck = CGGeneric(exposedInWorkerCheck)
|
||||
if iface.isExposedInWindow():
|
||||
if iface.isExposedOnMainThread():
|
||||
exposedInWorkerCheck = CGIfWrapper(exposedInWorkerCheck,
|
||||
"!NS_IsMainThread()")
|
||||
body.append(exposedInWorkerCheck)
|
||||
@@ -3813,8 +3823,6 @@ class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
|
||||
}
|
||||
// Getter handled setting our reserved slots
|
||||
""",
|
||||
slot=memberReservedSlot(m),
|
||||
interface=self.descriptor.interface.identifier.name,
|
||||
member=m.identifier.name)
|
||||
|
||||
body += "\nreturn true;\n"
|
||||
@@ -3836,7 +3844,7 @@ class CGClearCachedValueMethod(CGAbstractMethod):
|
||||
CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
|
||||
|
||||
def definition_body(self):
|
||||
slotIndex = memberReservedSlot(self.member)
|
||||
slotIndex = memberReservedSlot(self.member, self.descriptor)
|
||||
if self.member.getExtendedAttribute("StoreInSlot"):
|
||||
# We have to root things and save the old value in case
|
||||
# regetting fails, so we can restore it.
|
||||
@@ -7379,7 +7387,7 @@ class CGPerSignatureCall(CGThing):
|
||||
"NewObject implies that we need to keep the object alive with a strong reference.");
|
||||
""")
|
||||
|
||||
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndex is not None
|
||||
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
|
||||
if setSlot:
|
||||
# For attributes in slots, we want to do some
|
||||
# post-processing once we've wrapped them.
|
||||
@@ -7426,7 +7434,7 @@ class CGPerSignatureCall(CGThing):
|
||||
"args.rval().isObject()")
|
||||
postSteps += freezeValue.define()
|
||||
postSteps += ("js::SetReservedSlot(reflector, %s, args.rval());\n" %
|
||||
memberReservedSlot(self.idlNode))
|
||||
memberReservedSlot(self.idlNode, self.descriptor))
|
||||
# For the case of Cached attributes, go ahead and preserve our
|
||||
# wrapper if needed. We need to do this because otherwise the
|
||||
# wrapper could get garbage-collected and the cached value would
|
||||
@@ -8011,7 +8019,7 @@ class CGSetterCall(CGPerSignatureCall):
|
||||
|
||||
def wrap_return_value(self):
|
||||
attr = self.idlNode
|
||||
if self.descriptor.wrapperCache and attr.slotIndex is not None:
|
||||
if self.descriptor.wrapperCache and attr.slotIndices is not None:
|
||||
if attr.getExtendedAttribute("StoreInSlot"):
|
||||
args = "cx, self"
|
||||
else:
|
||||
@@ -8558,7 +8566,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
|
||||
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
|
||||
self.attr)
|
||||
if self.attr.slotIndex is not None:
|
||||
if self.attr.slotIndices is not None:
|
||||
if self.descriptor.hasXPConnectImpls:
|
||||
raise TypeError("Interface '%s' has XPConnect impls, so we "
|
||||
"can't use our slot for property '%s'!" %
|
||||
@@ -8584,7 +8592,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
}
|
||||
|
||||
""",
|
||||
slot=memberReservedSlot(self.attr),
|
||||
slot=memberReservedSlot(self.attr, self.descriptor),
|
||||
maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
|
||||
else:
|
||||
prefix = ""
|
||||
@@ -8835,10 +8843,13 @@ class CGMemberJITInfo(CGThing):
|
||||
slotIndex=slotIndex)
|
||||
return initializer.rstrip()
|
||||
|
||||
slotAssert = dedent(
|
||||
slotAssert = fill(
|
||||
"""
|
||||
static_assert(%s <= JSJitInfo::maxSlotIndex, "We won't fit");
|
||||
""" % slotIndex)
|
||||
static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
|
||||
static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
|
||||
""",
|
||||
slotIndex=slotIndex,
|
||||
classReservedSlots=INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots)
|
||||
if args is not None:
|
||||
argTypes = "%s_argTypes" % infoName
|
||||
args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
|
||||
@@ -8886,10 +8897,10 @@ class CGMemberJITInfo(CGThing):
|
||||
|
||||
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
|
||||
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
|
||||
if self.member.slotIndex is not None:
|
||||
if self.member.slotIndices is not None:
|
||||
assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
|
||||
isLazilyCachedInSlot = not isAlwaysInSlot
|
||||
slotIndex = memberReservedSlot(self.member)
|
||||
slotIndex = memberReservedSlot(self.member, self.descriptor)
|
||||
# We'll statically assert that this is not too big in
|
||||
# CGUpdateMemberSlotsMethod, in the case when
|
||||
# isAlwaysInSlot is true.
|
||||
@@ -15354,7 +15365,7 @@ def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=No
|
||||
PreserveWrapper<${selfType}>(self);
|
||||
}
|
||||
""",
|
||||
slot=memberReservedSlot(maplikeOrSetlike),
|
||||
slot=memberReservedSlot(maplikeOrSetlike, descriptor),
|
||||
func_prefix=func_prefix,
|
||||
errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
|
||||
selfType=descriptor.nativeType)
|
||||
|
||||
@@ -150,7 +150,15 @@ class Configuration:
|
||||
if t.isUnion():
|
||||
filenamesForUnion = self.filenamesPerUnion[t.name]
|
||||
if t.filename() not in filenamesForUnion:
|
||||
if len(filenamesForUnion) == 0:
|
||||
# We have a to be a bit careful: some of our built-in
|
||||
# typedefs are for unions, and those unions end up with
|
||||
# "<unknown>" as the filename. If that happens, we don't
|
||||
# want to try associating this union with one particular
|
||||
# filename, since there isn't one to associate it with,
|
||||
# really.
|
||||
if t.filename() == "<unknown>":
|
||||
uniqueFilenameForUnion = None
|
||||
elif len(filenamesForUnion) == 0:
|
||||
# This is the first file that we found a union with this
|
||||
# name in, record the union as part of the file.
|
||||
uniqueFilenameForUnion = t.filename()
|
||||
|
||||
@@ -5,20 +5,34 @@
|
||||
import sys
|
||||
import string
|
||||
|
||||
# Generates a line of WebIDL with the given spelling of the property name
|
||||
# (whether camelCase, _underscorePrefixed, etc.) and the given array of
|
||||
# extended attributes.
|
||||
def generateLine(propName, extendedAttrs):
|
||||
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
|
||||
propName)
|
||||
propList = eval(sys.stdin.read())
|
||||
props = ""
|
||||
for [name, prop, id, flags, pref, proptype] in propList:
|
||||
if "CSS_PROPERTY_INTERNAL" in flags:
|
||||
continue
|
||||
# Unfortunately, even some of the getters here are fallible
|
||||
# (e.g. on nsComputedDOMStyle).
|
||||
extendedAttrs = ["Throws", "TreatNullAs=EmptyString"]
|
||||
if pref is not "":
|
||||
extendedAttrs.append('Pref="%s"' % pref)
|
||||
|
||||
# webkit properties get a capitalized "WebkitFoo" accessor (added here)
|
||||
# as well as a camelcase "webkitFoo" accessor (added next).
|
||||
if (prop.startswith("Webkit")):
|
||||
props += generateLine(prop, extendedAttrs)
|
||||
|
||||
# Generate a line with camelCase spelling of property-name (or capitalized,
|
||||
# for Moz-prefixed properties):
|
||||
if not prop.startswith("Moz"):
|
||||
prop = prop[0].lower() + prop[1:]
|
||||
# Unfortunately, even some of the getters here are fallible
|
||||
# (e.g. on nsComputedDOMStyle).
|
||||
props += " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
|
||||
prop)
|
||||
props += generateLine(prop, extendedAttrs)
|
||||
|
||||
# Per spec, what's actually supposed to happen here is that we're supposed
|
||||
# to have properties for:
|
||||
#
|
||||
@@ -30,18 +44,17 @@ for [name, prop, id, flags, pref, proptype] in propList:
|
||||
# Note that "float" will cause a property called "float" to exist due to (1)
|
||||
# in that list.
|
||||
#
|
||||
# In practice, cssFloat is the only case in which "name" doesn't contain "-"
|
||||
# but also doesn't match "prop". So the stuff we did with "prop" covers (3)
|
||||
# and all of (1) except "float". If we now output attributes for all the
|
||||
# cases where "name" doesn't match "prop" and "name" doesn't start with "-",
|
||||
# that will cover "float" and (2).
|
||||
# In practice, cssFloat is the only case in which "name" doesn't contain
|
||||
# "-" but also doesn't match "prop". So the above generatePropLine() call
|
||||
# covered (3) and all of (1) except "float". If we now output attributes
|
||||
# for all the cases where "name" doesn't match "prop" and "name" doesn't
|
||||
# start with "-", that will cover "float" and (2).
|
||||
if prop != name and name[0] != "-":
|
||||
extendedAttrs.append('BinaryName="%s"' % prop)
|
||||
# Throw in a '_' before the attribute name, because some of these
|
||||
# property names collide with IDL reserved words.
|
||||
props += " [%s] attribute DOMString _%s;\n" % (
|
||||
", ".join(extendedAttrs),
|
||||
name)
|
||||
props += generateLine("_" + name, extendedAttrs)
|
||||
|
||||
|
||||
idlFile = open(sys.argv[1], "r")
|
||||
idlTemplate = idlFile.read()
|
||||
|
||||
@@ -139,8 +139,3 @@ if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
PYTHON_UNIT_TESTS += [
|
||||
'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CC']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-uninitialized',
|
||||
]
|
||||
|
||||
@@ -501,6 +501,10 @@ class IDLExposureMixins():
|
||||
def isExposedInWindow(self):
|
||||
return 'Window' in self.exposureSet
|
||||
|
||||
def isExposedOnMainThread(self):
|
||||
return (self.isExposedInWindow() or
|
||||
self.isExposedInSystemGlobals())
|
||||
|
||||
def isExposedInAnyWorker(self):
|
||||
return len(self.getWorkerExposureSet()) > 0
|
||||
|
||||
@@ -974,7 +978,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
(member.getExtendedAttribute("StoreInSlot") or
|
||||
member.getExtendedAttribute("Cached"))) or
|
||||
member.isMaplikeOrSetlike()):
|
||||
member.slotIndex = self.totalMembersInSlots
|
||||
if member.slotIndices is None:
|
||||
member.slotIndices = dict()
|
||||
member.slotIndices[self.identifier.name] = self.totalMembersInSlots
|
||||
self.totalMembersInSlots += 1
|
||||
if member.getExtendedAttribute("StoreInSlot"):
|
||||
self._ownMembersInSlots += 1
|
||||
@@ -3676,7 +3682,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
|
||||
IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType,
|
||||
keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike)
|
||||
self.readonly = readonly
|
||||
self.slotIndex = None
|
||||
self.slotIndices = None
|
||||
|
||||
# When generating JSAPI access code, we need to know the backing object
|
||||
# type prefix to create the correct function. Generate here for reuse.
|
||||
@@ -3861,7 +3867,7 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
self.stringifier = stringifier
|
||||
self.enforceRange = False
|
||||
self.clamp = False
|
||||
self.slotIndex = None
|
||||
self.slotIndices = None
|
||||
assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike)
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.dependsOn = "Everything"
|
||||
|
||||
@@ -52,8 +52,3 @@ LOCAL_INCLUDES += [
|
||||
'/js/xpconnect/src',
|
||||
'/js/xpconnect/wrappers',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CC']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-uninitialized',
|
||||
]
|
||||
|
||||
@@ -29,7 +29,7 @@ function runTest() {
|
||||
});
|
||||
|
||||
// Force the iframe to repaint.
|
||||
SimpleTest.executeSoon(function () iframe.src += '#next');
|
||||
SimpleTest.executeSoon(() => iframe.src += '#next');
|
||||
});
|
||||
|
||||
// Remove the first listener to make sure it's not called.
|
||||
|
||||
@@ -7524,25 +7524,25 @@ var _thrown = undefined; try {
|
||||
ctx.createImageData(Infinity, Infinity);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData({valueOf:function() Infinity}, 10);
|
||||
ctx.createImageData({valueOf:() => Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData({valueOf:function() -Infinity}, 10);
|
||||
ctx.createImageData({valueOf:() => -Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData({valueOf:function() NaN}, 10);
|
||||
ctx.createImageData({valueOf:() => NaN}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData(10, {valueOf:function() Infinity});
|
||||
ctx.createImageData(10, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData(10, {valueOf:function() -Infinity});
|
||||
ctx.createImageData(10, {valueOf:() => -Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData(10, {valueOf:function() NaN});
|
||||
ctx.createImageData(10, {valueOf:() => NaN});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.createImageData({valueOf:function() Infinity}, {valueOf:function() Infinity});
|
||||
ctx.createImageData({valueOf:() => Infinity}, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
|
||||
|
||||
@@ -7830,73 +7830,73 @@ var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, Infinity, Infinity);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, 10, 10, 10);
|
||||
ctx.getImageData({valueOf:() => Infinity}, 10, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() -Infinity}, 10, 10, 10);
|
||||
ctx.getImageData({valueOf:() => -Infinity}, 10, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() NaN}, 10, 10, 10);
|
||||
ctx.getImageData({valueOf:() => NaN}, 10, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() Infinity}, 10, 10);
|
||||
ctx.getImageData(10, {valueOf:() => Infinity}, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() -Infinity}, 10, 10);
|
||||
ctx.getImageData(10, {valueOf:() => -Infinity}, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() NaN}, 10, 10);
|
||||
ctx.getImageData(10, {valueOf:() => NaN}, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, {valueOf:function() Infinity}, 10);
|
||||
ctx.getImageData(10, 10, {valueOf:() => Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, {valueOf:function() -Infinity}, 10);
|
||||
ctx.getImageData(10, 10, {valueOf:() => -Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, {valueOf:function() NaN}, 10);
|
||||
ctx.getImageData(10, 10, {valueOf:() => NaN}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, 10, {valueOf:function() Infinity});
|
||||
ctx.getImageData(10, 10, 10, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, 10, {valueOf:function() -Infinity});
|
||||
ctx.getImageData(10, 10, 10, {valueOf:() => -Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, 10, {valueOf:function() NaN});
|
||||
ctx.getImageData(10, 10, 10, {valueOf:() => NaN});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, {valueOf:function() Infinity}, 10, 10);
|
||||
ctx.getImageData({valueOf:() => Infinity}, {valueOf:() => Infinity}, 10, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, {valueOf:function() Infinity}, {valueOf:function() Infinity}, 10);
|
||||
ctx.getImageData({valueOf:() => Infinity}, {valueOf:() => Infinity}, {valueOf:() => Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, {valueOf:function() Infinity}, {valueOf:function() Infinity}, {valueOf:function() Infinity});
|
||||
ctx.getImageData({valueOf:() => Infinity}, {valueOf:() => Infinity}, {valueOf:() => Infinity}, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, {valueOf:function() Infinity}, 10, {valueOf:function() Infinity});
|
||||
ctx.getImageData({valueOf:() => Infinity}, {valueOf:() => Infinity}, 10, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, 10, {valueOf:function() Infinity}, 10);
|
||||
ctx.getImageData({valueOf:() => Infinity}, 10, {valueOf:() => Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, 10, {valueOf:function() Infinity}, {valueOf:function() Infinity});
|
||||
ctx.getImageData({valueOf:() => Infinity}, 10, {valueOf:() => Infinity}, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData({valueOf:function() Infinity}, 10, 10, {valueOf:function() Infinity});
|
||||
ctx.getImageData({valueOf:() => Infinity}, 10, 10, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() Infinity}, {valueOf:function() Infinity}, 10);
|
||||
ctx.getImageData(10, {valueOf:() => Infinity}, {valueOf:() => Infinity}, 10);
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() Infinity}, {valueOf:function() Infinity}, {valueOf:function() Infinity});
|
||||
ctx.getImageData(10, {valueOf:() => Infinity}, {valueOf:() => Infinity}, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, {valueOf:function() Infinity}, 10, {valueOf:function() Infinity});
|
||||
ctx.getImageData(10, {valueOf:() => Infinity}, 10, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
var _thrown = undefined; try {
|
||||
ctx.getImageData(10, 10, {valueOf:function() Infinity}, {valueOf:function() Infinity});
|
||||
ctx.getImageData(10, 10, {valueOf:() => Infinity}, {valueOf:() => Infinity});
|
||||
} catch (e) { _thrown = e }; ok(_thrown && _thrown instanceof TypeError, "should throw TypeError");
|
||||
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ ContactDB.prototype = {
|
||||
uri: NetUtil.newURI(contactsFile),
|
||||
loadUsingSystemPrincipal: true});
|
||||
|
||||
let stream = chan.open();
|
||||
let stream = chan.open2();
|
||||
// Obtain a converter to read from a UTF-8 encoded input stream.
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
@@ -236,7 +236,7 @@ ContactDB.prototype = {
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
}
|
||||
// Delete old tel index.
|
||||
if (objectStore.indexNames.includes("tel")) {
|
||||
if (objectStore.indexNames.contains("tel")) {
|
||||
objectStore.deleteIndex("tel");
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ ContactDB.prototype = {
|
||||
}
|
||||
|
||||
// Delete old email index.
|
||||
if (objectStore.indexNames.includes("email")) {
|
||||
if (objectStore.indexNames.contains("email")) {
|
||||
objectStore.deleteIndex("email");
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ ContactDB.prototype = {
|
||||
}
|
||||
|
||||
// Delete old tel index (not on the right field).
|
||||
if (objectStore.indexNames.includes("tel")) {
|
||||
if (objectStore.indexNames.contains("tel")) {
|
||||
objectStore.deleteIndex("tel");
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ ContactDB.prototype = {
|
||||
if (!objectStore) {
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
}
|
||||
if (!objectStore.indexNames.includes("telMatch")) {
|
||||
if (!objectStore.indexNames.contains("telMatch")) {
|
||||
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
|
||||
}
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
@@ -693,7 +693,7 @@ ContactDB.prototype = {
|
||||
|
||||
// an earlier version of this code could have run, so checking whether
|
||||
// the index exists
|
||||
if (!objectStore.indexNames.includes("name")) {
|
||||
if (!objectStore.indexNames.contains("name")) {
|
||||
objectStore.createIndex("name", "properties.name", { multiEntry: true });
|
||||
objectStore.createIndex("nameLowerCase", "search.name", { multiEntry: true });
|
||||
}
|
||||
@@ -1039,7 +1039,7 @@ ContactDB.prototype = {
|
||||
contactsArray.push(aContacts[i]);
|
||||
}
|
||||
|
||||
let contactIdsArray = contactsArray.map(function(el) el.id);
|
||||
let contactIdsArray = contactsArray.map(el => el.id);
|
||||
|
||||
// save contact ids in cache
|
||||
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function(txn, store) {
|
||||
@@ -1225,7 +1225,7 @@ ContactDB.prototype = {
|
||||
if (DEBUG) debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp);
|
||||
let self = this;
|
||||
this.newTxn("readonly", STORE_NAME, function (txn, store) {
|
||||
let filterOps = ["equals", "includes", "match", "startsWith"];
|
||||
let filterOps = ["equals", "contains", "match", "startsWith"];
|
||||
if (aOptions && (filterOps.indexOf(aOptions.filterOp) >= 0)) {
|
||||
self._findWithIndex(txn, store, aOptions);
|
||||
} else {
|
||||
@@ -1327,9 +1327,9 @@ ContactDB.prototype = {
|
||||
|
||||
request = index.mozGetAll(normalized, limit);
|
||||
} else {
|
||||
// XXX: "includes" should be handled separately, this is "startsWith"
|
||||
if (options.filterOp === 'includes' && key !== 'tel') {
|
||||
dump("ContactDB: 'includes' only works for 'tel'. Falling back " +
|
||||
// XXX: "contains" should be handled separately, this is "startsWith"
|
||||
if (options.filterOp === 'contains' && key !== 'tel') {
|
||||
dump("ContactDB: 'contains' only works for 'tel'. Falling back " +
|
||||
"to 'startsWith'.\n");
|
||||
}
|
||||
// not case sensitive
|
||||
|
||||
@@ -27,7 +27,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
|
||||
|
||||
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
|
||||
let ContactService = this.ContactService = {
|
||||
var ContactService = this.ContactService = {
|
||||
init: function() {
|
||||
if (DEBUG) debug("Init");
|
||||
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
#define WEBCRYPTO_ALG_SHA384 "SHA-384"
|
||||
#define WEBCRYPTO_ALG_SHA512 "SHA-512"
|
||||
#define WEBCRYPTO_ALG_HMAC "HMAC"
|
||||
#define WEBCRYPTO_ALG_HKDF "HKDF"
|
||||
#define WEBCRYPTO_ALG_PBKDF2 "PBKDF2"
|
||||
#define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
|
||||
#define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
|
||||
#define WEBCRYPTO_ALG_RSA_PSS "RSA-PSS"
|
||||
#define WEBCRYPTO_ALG_ECDH "ECDH"
|
||||
#define WEBCRYPTO_ALG_ECDSA "ECDSA"
|
||||
#define WEBCRYPTO_ALG_DH "DH"
|
||||
@@ -238,12 +240,16 @@ NormalizeToken(const nsString& aName, nsString& aDest)
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HKDF)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_HKDF);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
|
||||
|
||||
+345
-104
@@ -20,6 +20,20 @@
|
||||
#include "mozilla/dom/WebCryptoTask.h"
|
||||
#include "mozilla/dom/WebCryptoThreadPool.h"
|
||||
|
||||
// Template taken from security/nss/lib/util/templates.c
|
||||
// This (or SGN_EncodeDigestInfo) would ideally be exported
|
||||
// by NSS and until that happens we have to keep our own copy.
|
||||
const SEC_ASN1Template SGN_DigestInfoTemplate[] = {
|
||||
{ SEC_ASN1_SEQUENCE,
|
||||
0, NULL, sizeof(SGNDigestInfo) },
|
||||
{ SEC_ASN1_INLINE,
|
||||
offsetof(SGNDigestInfo,digestAlgorithm),
|
||||
SEC_ASN1_GET(SECOID_AlgorithmIDTemplate) },
|
||||
{ SEC_ASN1_OCTET_STRING,
|
||||
offsetof(SGNDigestInfo,digest) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -70,6 +84,7 @@ enum TelemetryAlgorithm {
|
||||
TA_ECDH = 20,
|
||||
TA_PBKDF2 = 21,
|
||||
TA_ECDSA = 22,
|
||||
TA_HKDF = 23,
|
||||
};
|
||||
|
||||
// Convenience functions for extracting / converting information
|
||||
@@ -264,6 +279,41 @@ MapOIDTagToNamedCurve(SECOidTag aOIDTag, nsString& aResult)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline SECOidTag
|
||||
MapHashAlgorithmNameToOID(const nsString& aName)
|
||||
{
|
||||
SECOidTag hashOID(SEC_OID_UNKNOWN);
|
||||
|
||||
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
|
||||
hashOID = SEC_OID_SHA1;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
|
||||
hashOID = SEC_OID_SHA256;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
|
||||
hashOID = SEC_OID_SHA384;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
|
||||
hashOID = SEC_OID_SHA512;
|
||||
}
|
||||
|
||||
return hashOID;
|
||||
}
|
||||
|
||||
inline CK_MECHANISM_TYPE
|
||||
MapHashAlgorithmNameToMgfMechanism(const nsString& aName) {
|
||||
CK_MECHANISM_TYPE mech(UNKNOWN_CK_MECHANISM);
|
||||
|
||||
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
|
||||
mech = CKG_MGF1_SHA1;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
|
||||
mech = CKG_MGF1_SHA256;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
|
||||
mech = CKG_MGF1_SHA384;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
|
||||
mech = CKG_MGF1_SHA512;
|
||||
}
|
||||
|
||||
return mech;
|
||||
}
|
||||
|
||||
// Helper function to clone data from an ArrayBuffer or ArrayBufferView object
|
||||
inline bool
|
||||
CloneData(JSContext* aCx, CryptoBuffer& aDst, JS::Handle<JSObject*> aSrc)
|
||||
@@ -843,24 +893,15 @@ public:
|
||||
}
|
||||
// Otherwise mLabel remains the empty octet string, as intended
|
||||
|
||||
// Look up the MGF based on the KeyAlgorithm.
|
||||
// static_cast is safe because we only get here if the algorithm name
|
||||
// is RSA-OAEP, and that only happens if we've constructed
|
||||
// an RsaHashedKeyAlgorithm.
|
||||
mHashMechanism = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash);
|
||||
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
|
||||
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
|
||||
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlg.mName);
|
||||
|
||||
switch (mHashMechanism) {
|
||||
case CKM_SHA_1:
|
||||
mMgfMechanism = CKG_MGF1_SHA1; break;
|
||||
case CKM_SHA256:
|
||||
mMgfMechanism = CKG_MGF1_SHA256; break;
|
||||
case CKM_SHA384:
|
||||
mMgfMechanism = CKG_MGF1_SHA384; break;
|
||||
case CKM_SHA512:
|
||||
mMgfMechanism = CKG_MGF1_SHA512; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
// Check we found appropriate mechanisms.
|
||||
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
|
||||
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,11 +1086,14 @@ public:
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
: mOidTag(SEC_OID_UNKNOWN)
|
||||
, mHashMechanism(UNKNOWN_CK_MECHANISM)
|
||||
, mMgfMechanism(UNKNOWN_CK_MECHANISM)
|
||||
, mPrivKey(aKey.GetPrivateKey())
|
||||
, mPubKey(aKey.GetPublicKey())
|
||||
, mSaltLength(0)
|
||||
, mSign(aSign)
|
||||
, mVerified(false)
|
||||
, mEcdsa(false)
|
||||
, mAlgorithm(Algorithm::UNKNOWN)
|
||||
{
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
if (!aSign) {
|
||||
@@ -1057,34 +1101,44 @@ public:
|
||||
}
|
||||
|
||||
nsString algName;
|
||||
nsString hashAlgName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Look up the SECOidTag
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
mEcdsa = false;
|
||||
mAlgorithm = Algorithm::RSA_PKCS1;
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
|
||||
hashAlgName = aKey.Algorithm().mRsa.mHash.mName;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
|
||||
mAlgorithm = Algorithm::RSA_PSS;
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS);
|
||||
|
||||
// For RSA, the hash name comes from the key algorithm
|
||||
nsString hashName = aKey.Algorithm().mRsa.mHash.mName;
|
||||
switch (MapAlgorithmNameToMechanism(hashName)) {
|
||||
case CKM_SHA_1:
|
||||
mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA256:
|
||||
mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA384:
|
||||
mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA512:
|
||||
mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
|
||||
hashAlgName = hashAlg.mName;
|
||||
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
|
||||
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlgName);
|
||||
|
||||
// Check we found appropriate mechanisms.
|
||||
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
|
||||
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
RootedDictionary<RsaPssParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mSaltLength = params.mSaltLength;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
mEcdsa = true;
|
||||
mAlgorithm = Algorithm::ECDSA;
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA);
|
||||
|
||||
@@ -1096,38 +1150,27 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
nsString hashName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
|
||||
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashAlgName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
CK_MECHANISM_TYPE hashMechanism = MapAlgorithmNameToMechanism(hashName);
|
||||
if (hashMechanism == UNKNOWN_CK_MECHANISM) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hashMechanism) {
|
||||
case CKM_SHA_1:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
|
||||
case CKM_SHA256:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
|
||||
case CKM_SHA384:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
|
||||
case CKM_SHA512:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// This shouldn't happen; CreateSignVerifyTask shouldn't create
|
||||
// one of these unless it's for the above algorithms.
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
// Must have a valid algorithm by now.
|
||||
MOZ_ASSERT(mAlgorithm != Algorithm::UNKNOWN);
|
||||
|
||||
// Determine hash algorithm to use.
|
||||
mOidTag = MapHashAlgorithmNameToOID(hashAlgName);
|
||||
if (mOidTag == SEC_OID_UNKNOWN) {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we have the appropriate key
|
||||
if ((mSign && !mPrivKey) || (!mSign && !mPubKey)) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
@@ -1137,63 +1180,88 @@ public:
|
||||
|
||||
private:
|
||||
SECOidTag mOidTag;
|
||||
CK_MECHANISM_TYPE mHashMechanism;
|
||||
CK_MECHANISM_TYPE mMgfMechanism;
|
||||
ScopedSECKEYPrivateKey mPrivKey;
|
||||
ScopedSECKEYPublicKey mPubKey;
|
||||
CryptoBuffer mSignature;
|
||||
CryptoBuffer mData;
|
||||
uint32_t mSaltLength;
|
||||
bool mSign;
|
||||
bool mVerified;
|
||||
bool mEcdsa;
|
||||
|
||||
// The signature algorithm to use.
|
||||
enum class Algorithm: uint8_t {ECDSA, RSA_PKCS1, RSA_PSS, UNKNOWN};
|
||||
Algorithm mAlgorithm;
|
||||
|
||||
virtual nsresult DoCrypto() override
|
||||
{
|
||||
nsresult rv;
|
||||
if (mSign) {
|
||||
ScopedSECItem signature(::SECITEM_AllocItem(nullptr, nullptr, 0));
|
||||
if (!signature.get()) {
|
||||
SECStatus rv;
|
||||
ScopedSECItem hash(::SECITEM_AllocItem(nullptr, nullptr,
|
||||
HASH_ResultLenByOidTag(mOidTag)));
|
||||
if (!hash) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// Compute digest over given data.
|
||||
rv = PK11_HashBuf(mOidTag, hash->data, mData.Elements(), mData.Length());
|
||||
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
// Wrap hash in a digest info template (RSA-PKCS1 only).
|
||||
if (mAlgorithm == Algorithm::RSA_PKCS1) {
|
||||
ScopedSGNDigestInfo di(SGN_CreateDigestInfo(mOidTag, hash->data, hash->len));
|
||||
if (!di) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
rv = MapSECStatus(SEC_SignData(signature, mData.Elements(),
|
||||
mData.Length(), mPrivKey, mOidTag));
|
||||
|
||||
if (mEcdsa) {
|
||||
// DER-decode the signature
|
||||
int signatureLength = PK11_SignatureLen(mPrivKey);
|
||||
ScopedSECItem rawSignature(DSAU_DecodeDerSigToLen(signature.get(),
|
||||
signatureLength));
|
||||
if (!rawSignature.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, rawSignature);
|
||||
} else {
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, signature);
|
||||
// Reuse |hash|.
|
||||
SECITEM_FreeItem(hash, false);
|
||||
if (!SEC_ASN1EncodeItem(nullptr, hash, di, SGN_DigestInfoTemplate)) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
SECItem* params = nullptr;
|
||||
CK_MECHANISM_TYPE mech = PK11_MapSignKeyType((mSign ? mPrivKey->keyType :
|
||||
mPubKey->keyType));
|
||||
|
||||
CK_RSA_PKCS_PSS_PARAMS rsaPssParams;
|
||||
SECItem rsaPssParamsItem = { siBuffer, };
|
||||
|
||||
// Set up parameters for RSA-PSS.
|
||||
if (mAlgorithm == Algorithm::RSA_PSS) {
|
||||
rsaPssParams.hashAlg = mHashMechanism;
|
||||
rsaPssParams.mgf = mMgfMechanism;
|
||||
rsaPssParams.sLen = mSaltLength;
|
||||
|
||||
rsaPssParamsItem.data = (unsigned char*)&rsaPssParams;
|
||||
rsaPssParamsItem.len = sizeof(rsaPssParams);
|
||||
params = &rsaPssParamsItem;
|
||||
|
||||
mech = CKM_RSA_PKCS_PSS;
|
||||
}
|
||||
|
||||
// Allocate SECItem to hold the signature.
|
||||
uint32_t len = mSign ? PK11_SignatureLen(mPrivKey) : 0;
|
||||
ScopedSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
|
||||
if (!sig) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
if (mSign) {
|
||||
// Sign the hash.
|
||||
rv = PK11_SignWithMechanism(mPrivKey, mech, params, sig, hash);
|
||||
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, sig);
|
||||
} else {
|
||||
ScopedSECItem signature(::SECITEM_AllocItem(nullptr, nullptr, 0));
|
||||
if (!signature.get()) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
// Copy the given signature to the SECItem.
|
||||
if (!mSignature.ToSECItem(nullptr, sig)) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
if (mEcdsa) {
|
||||
// DER-encode the signature
|
||||
ScopedSECItem rawSignature(::SECITEM_AllocItem(nullptr, nullptr, 0));
|
||||
if (!rawSignature || !mSignature.ToSECItem(nullptr, rawSignature)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
rv = MapSECStatus(DSAU_EncodeDerSigWithLen(signature, rawSignature,
|
||||
rawSignature->len));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
} else if (!mSignature.ToSECItem(nullptr, signature)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
rv = MapSECStatus(VFY_VerifyData(mData.Elements(), mData.Length(),
|
||||
mPubKey, signature, mOidTag, nullptr));
|
||||
mVerified = NS_SUCCEEDED(rv);
|
||||
// Verify the signature.
|
||||
rv = PK11_VerifyWithMechanism(mPubKey, mech, params, sig, hash, nullptr);
|
||||
mVerified = NS_SUCCEEDED(MapSECStatus(rv));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -1228,22 +1296,19 @@ public:
|
||||
|
||||
TelemetryAlgorithm telemetryAlg;
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
|
||||
mOidTag = SEC_OID_SHA1;
|
||||
telemetryAlg = TA_SHA_1;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
|
||||
mOidTag = SEC_OID_SHA256;
|
||||
telemetryAlg = TA_SHA_224;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
|
||||
mOidTag = SEC_OID_SHA384;
|
||||
telemetryAlg = TA_SHA_256;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
|
||||
mOidTag = SEC_OID_SHA512;
|
||||
telemetryAlg = TA_SHA_384;
|
||||
} else {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
|
||||
mOidTag = MapHashAlgorithmNameToOID(algName);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1448,6 +1513,13 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// This task only supports raw and JWK format.
|
||||
if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
|
||||
!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an HMAC key, import the hash name
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
RootedDictionary<HmacImportParams> params(aCx);
|
||||
@@ -1512,14 +1584,15 @@ public:
|
||||
!mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
|
||||
if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS)) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
mKey->Algorithm().MakeAes(mAlgName, length);
|
||||
|
||||
if (mDataIsJwk && mJwk.mUse.WasPassed()) {
|
||||
// There is not a 'use' value consistent with PBKDF
|
||||
// There is not a 'use' value consistent with PBKDF or HKDF
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
};
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
@@ -2288,7 +2361,8 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
|
||||
// Construct an appropriate KeyAlorithm
|
||||
uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
|
||||
RootedDictionary<RsaHashedKeyGenParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
@@ -2391,6 +2465,7 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
|
||||
|
||||
// Set key usages.
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
privateAllowedUsages = CryptoKey::SIGN;
|
||||
publicAllowedUsages = CryptoKey::VERIFY;
|
||||
@@ -2401,6 +2476,8 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
|
||||
privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
|
||||
publicAllowedUsages = 0;
|
||||
} else {
|
||||
MOZ_ASSERT(false); // This shouldn't happen.
|
||||
}
|
||||
|
||||
mKeyPair->mPrivateKey.get()->SetExtractable(aExtractable);
|
||||
@@ -2502,6 +2579,156 @@ GenerateAsymmetricKeyTask::Cleanup()
|
||||
mKeyPair = nullptr;
|
||||
}
|
||||
|
||||
class DeriveHkdfBitsTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
DeriveHkdfBitsTask(JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
|
||||
: mSymKey(aKey.GetSymKey())
|
||||
{
|
||||
Init(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
DeriveHkdfBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
|
||||
: mSymKey(aKey.GetSymKey())
|
||||
{
|
||||
size_t length;
|
||||
mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, length);
|
||||
|
||||
if (NS_SUCCEEDED(mEarlyRv)) {
|
||||
Init(aCx, aAlgorithm, aKey, length);
|
||||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
|
||||
uint32_t aLength)
|
||||
{
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_HKDF);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HKDF);
|
||||
|
||||
// Check that we have a key.
|
||||
if (mSymKey.Length() == 0) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
RootedDictionary<HkdfParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// length must be greater than zero.
|
||||
if (aLength == 0) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the hash algorithm.
|
||||
nsString hashName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the given hash algorithm.
|
||||
switch (MapAlgorithmNameToMechanism(hashName)) {
|
||||
case CKM_SHA_1: mMechanism = CKM_NSS_HKDF_SHA1; break;
|
||||
case CKM_SHA256: mMechanism = CKM_NSS_HKDF_SHA256; break;
|
||||
case CKM_SHA384: mMechanism = CKM_NSS_HKDF_SHA384; break;
|
||||
case CKM_SHA512: mMechanism = CKM_NSS_HKDF_SHA512; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mSalt, params.mSalt)
|
||||
ATTEMPT_BUFFER_INIT(mInfo, params.mInfo)
|
||||
mLengthInBytes = ceil((double)aLength / 8);
|
||||
mLengthInBits = aLength;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mLengthInBits;
|
||||
size_t mLengthInBytes;
|
||||
CryptoBuffer mSalt;
|
||||
CryptoBuffer mInfo;
|
||||
CryptoBuffer mSymKey;
|
||||
CK_MECHANISM_TYPE mMechanism;
|
||||
|
||||
virtual nsresult DoCrypto() override
|
||||
{
|
||||
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
if (!arena) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// Import the key
|
||||
SECItem keyItem = { siBuffer, nullptr, 0 };
|
||||
ATTEMPT_BUFFER_TO_SECITEM(arena, &keyItem, mSymKey);
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
ScopedPK11SymKey baseKey(PK11_ImportSymKey(slot, mMechanism,
|
||||
PK11_OriginUnwrap, CKA_WRAP,
|
||||
&keyItem, nullptr));
|
||||
if (!baseKey) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
|
||||
SECItem salt = { siBuffer, nullptr, 0 };
|
||||
SECItem info = { siBuffer, nullptr, 0 };
|
||||
ATTEMPT_BUFFER_TO_SECITEM(arena, &salt, mSalt);
|
||||
ATTEMPT_BUFFER_TO_SECITEM(arena, &info, mInfo);
|
||||
|
||||
CK_NSS_HKDFParams hkdfParams = { true, salt.data, salt.len,
|
||||
true, info.data, info.len };
|
||||
SECItem params = { siBuffer, (unsigned char*)&hkdfParams,
|
||||
sizeof(hkdfParams) };
|
||||
|
||||
// CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
|
||||
// derived symmetric key and don't matter because we ignore them anyway.
|
||||
ScopedPK11SymKey symKey(PK11_Derive(baseKey, mMechanism, ¶ms,
|
||||
CKM_SHA512_HMAC, CKA_SIGN,
|
||||
mLengthInBytes));
|
||||
|
||||
if (!symKey.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// This doesn't leak, because the SECItem* returned by PK11_GetKeyData
|
||||
// just refers to a buffer managed by symKey. The assignment copies the
|
||||
// data, so mResult manages one copy, while symKey manages another.
|
||||
ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey));
|
||||
|
||||
if (mLengthInBytes > mResult.Length()) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
|
||||
if (!mResult.SetLength(mLengthInBytes, fallible)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
// If the number of bits to derive is not a multiple of 8 we need to
|
||||
// zero out the remaining bits that were derived but not requested.
|
||||
if (mLengthInBits % 8) {
|
||||
mResult[mResult.Length() - 1] &= 0xff << (mLengthInBits % 8);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
@@ -3040,6 +3267,7 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx,
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature,
|
||||
aData, aSign);
|
||||
@@ -3108,6 +3336,7 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx,
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new ImportSymmetricKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
@@ -3197,6 +3426,7 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
|
||||
@@ -3232,6 +3462,12 @@ WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
|
||||
return new FailureTask(rv);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
|
||||
return new DeriveKeyTask<DeriveHkdfBitsTask>(aCx, aAlgorithm, aBaseKey,
|
||||
aDerivedKeyType, aExtractable,
|
||||
aKeyUsages);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
|
||||
return new DeriveKeyTask<DerivePbkdfBitsTask>(aCx, aAlgorithm, aBaseKey,
|
||||
aDerivedKeyType, aExtractable,
|
||||
@@ -3278,6 +3514,10 @@ WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx,
|
||||
return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
|
||||
return new DeriveHkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
@@ -3363,6 +3603,7 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
|
||||
if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HKDF) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
|
||||
importTask = new ImportSymmetricKeyTask(aCx, aFormat,
|
||||
aUnwrappedKeyAlgorithm,
|
||||
|
||||
@@ -11,9 +11,11 @@ support-files =
|
||||
[test_WebCrypto_DH.html]
|
||||
[test_WebCrypto_ECDH.html]
|
||||
[test_WebCrypto_ECDSA.html]
|
||||
[test_WebCrypto_HKDF.html]
|
||||
[test_WebCrypto_JWK.html]
|
||||
[test_WebCrypto_Normalize.html]
|
||||
[test_WebCrypto_PBKDF2.html]
|
||||
[test_WebCrypto_Reject_Generating_Keys_Without_Usages.html]
|
||||
[test_WebCrypto_RSA_OAEP.html]
|
||||
[test_WebCrypto_RSA_PSS.html]
|
||||
[test_WebCrypto_Wrap_Unwrap.html]
|
||||
|
||||
@@ -452,7 +452,12 @@ tv = {
|
||||
|
||||
derived: util.hex2abv(
|
||||
"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"
|
||||
)
|
||||
),
|
||||
|
||||
jwk: {
|
||||
kty: "oct",
|
||||
k: "cGFzc3dvcmRQQVNTV09SRHBhc3N3b3Jk"
|
||||
}
|
||||
},
|
||||
|
||||
// https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
|
||||
@@ -753,4 +758,109 @@ tv = {
|
||||
"ba3d9acbf9e8ac"
|
||||
)
|
||||
},
|
||||
|
||||
// Taken from appendix A of RFC 5869.
|
||||
// <https://tools.ietf.org/html/rfc5869>
|
||||
hkdf: [
|
||||
{
|
||||
prf: "SHA-256",
|
||||
key: util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||
salt: util.hex2abv("000102030405060708090a0b0c"),
|
||||
info: util.hex2abv("f0f1f2f3f4f5f6f7f8f9"),
|
||||
data: util.hex2abv(
|
||||
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
|
||||
"34007208d5b887185865"
|
||||
),
|
||||
jwk: {
|
||||
kty: "oct",
|
||||
k: "CwsLCwsLCwsLCwsLCwsLCwsLCwsLCw"
|
||||
}
|
||||
},
|
||||
{
|
||||
prf: "SHA-256",
|
||||
key: util.hex2abv(
|
||||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
|
||||
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
|
||||
"404142434445464748494a4b4c4d4e4f"
|
||||
),
|
||||
salt: util.hex2abv(
|
||||
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
|
||||
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
|
||||
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
||||
),
|
||||
info: util.hex2abv(
|
||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
|
||||
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
|
||||
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||
),
|
||||
data: util.hex2abv(
|
||||
"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c" +
|
||||
"59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71" +
|
||||
"cc30c58179ec3e87c14c01d5c1f3434f1d87"
|
||||
)
|
||||
},
|
||||
{
|
||||
prf: "SHA-256",
|
||||
key: util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||
salt: util.hex2abv(""),
|
||||
info: util.hex2abv(""),
|
||||
data: util.hex2abv(
|
||||
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d" +
|
||||
"9d201395faa4b61a96c8"
|
||||
)
|
||||
},
|
||||
{
|
||||
prf: "SHA-1",
|
||||
key: util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b"),
|
||||
salt: util.hex2abv("000102030405060708090a0b0c"),
|
||||
info: util.hex2abv("f0f1f2f3f4f5f6f7f8f9"),
|
||||
data: util.hex2abv(
|
||||
"085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2" +
|
||||
"c22e422478d305f3f896"
|
||||
)
|
||||
},
|
||||
{
|
||||
prf: "SHA-1",
|
||||
key: util.hex2abv(
|
||||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
|
||||
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
|
||||
"404142434445464748494a4b4c4d4e4f"
|
||||
),
|
||||
salt: util.hex2abv(
|
||||
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
|
||||
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
|
||||
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
||||
),
|
||||
info: util.hex2abv(
|
||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
|
||||
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
|
||||
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||
),
|
||||
data: util.hex2abv(
|
||||
"0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe" +
|
||||
"8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e" +
|
||||
"927336d0441f4c4300e2cff0d0900b52d3b4"
|
||||
)
|
||||
},
|
||||
{
|
||||
prf: "SHA-1",
|
||||
key: util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||
salt: util.hex2abv(""),
|
||||
info: util.hex2abv(""),
|
||||
data: util.hex2abv(
|
||||
"0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0" +
|
||||
"ea00033de03984d34918"
|
||||
)
|
||||
},
|
||||
{
|
||||
prf: "SHA-1",
|
||||
key: util.hex2abv("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
|
||||
salt: util.hex2abv(""),
|
||||
info: util.hex2abv(""),
|
||||
data: util.hex2abv(
|
||||
"2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5" +
|
||||
"673a081d70cce7acfc48"
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>WebCrypto Test Suite</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<link rel="stylesheet" href="./test_WebCrypto.css"/>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- Utilities for manipulating ABVs -->
|
||||
<script src="util.js"></script>
|
||||
|
||||
<!-- A simple wrapper around IndexedDB -->
|
||||
<script src="simpledb.js"></script>
|
||||
|
||||
<!-- Test vectors drawn from the literature -->
|
||||
<script src="./test-vectors.js"></script>
|
||||
|
||||
<!-- General testing framework -->
|
||||
<script src="./test-array.js"></script>
|
||||
|
||||
<script>/*<![CDATA[*/
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Deriving zero bits should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"])
|
||||
.then(x => crypto.subtle.deriveBits(alg, x, 0), error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive four bits with HKDF, no salt or info given",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"])
|
||||
.then(x => crypto.subtle.deriveBits(alg, x, 4))
|
||||
// The last 4 bits should be zeroes (1000 1101 => 1000 0000).
|
||||
.then(memcmp_complete(that, new Uint8Array([0x80])))
|
||||
.catch(error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Deriving too many bits should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
function deriveBits(x) {
|
||||
// The maximum length (in bytes) of output material for HKDF is 255 times
|
||||
// the digest length. In this case, the digest length (in bytes) of
|
||||
// SHA-256 is 32; 32*255 = 8160. deriveBits expects the length to be in
|
||||
// bits, so 8160*8=65280 and add 1 to exceed the maximum length.
|
||||
return crypto.subtle.deriveBits(alg, x, 65281);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"])
|
||||
.then(deriveBits, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Deriving with an unsupported PRF should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "HMAC",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
function deriveBits(x) {
|
||||
return crypto.subtle.deriveBits(alg, x, 4);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"])
|
||||
.then(deriveBits, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Deriving with a non-HKDF key should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "HMAC",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
function deriveBits(x) {
|
||||
return crypto.subtle.deriveBits(alg, x, 4);
|
||||
}
|
||||
|
||||
var ecAlg = {name: "ECDH", namedCurve: "P-256"};
|
||||
crypto.subtle.generateKey(ecAlg, false, ["deriveBits"])
|
||||
.then(deriveBits, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive known values from test vectors (SHA-1 and SHA-256)",
|
||||
function() {
|
||||
var that = this;
|
||||
var tests = tv.hkdf.slice();
|
||||
|
||||
function next() {
|
||||
if (!tests.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
var {key, data} = test;
|
||||
|
||||
return crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveBits"])
|
||||
.then(function (key) {
|
||||
return crypto.subtle.deriveBits({
|
||||
name: "HKDF",
|
||||
hash: test.prf,
|
||||
salt: test.salt,
|
||||
info: test.info
|
||||
}, key, test.data.byteLength * 8);
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!util.memcmp(data, test.data)) {
|
||||
throw new Error("derived bits don't match expected value");
|
||||
}
|
||||
|
||||
// Next test vector.
|
||||
return next();
|
||||
});
|
||||
}
|
||||
|
||||
next().then(complete(that), error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive known values from test vectors (JWK, SHA-256)",
|
||||
function() {
|
||||
var that = this;
|
||||
var test = tv.hkdf[0];
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: test.prf,
|
||||
salt: test.salt,
|
||||
info: test.info
|
||||
};
|
||||
|
||||
crypto.subtle.importKey("jwk", test.jwk, "HKDF", false, ["deriveBits"])
|
||||
.then(x => crypto.subtle.deriveBits(alg, x, test.data.byteLength * 8))
|
||||
.then(memcmp_complete(that, test.data), error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test wrapping/unwrapping an HKDF key",
|
||||
function() {
|
||||
var that = this;
|
||||
var hkdfKey = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
var alg = {name: "AES-GCM", length: 256, iv: new Uint8Array(16)};
|
||||
var wrappingKey;
|
||||
|
||||
function wrap(x) {
|
||||
wrappingKey = x;
|
||||
return crypto.subtle.encrypt(alg, wrappingKey, hkdfKey);
|
||||
}
|
||||
|
||||
function unwrap(wrappedKey) {
|
||||
return crypto.subtle.unwrapKey(
|
||||
"raw", wrappedKey, wrappingKey, alg, "HKDF", false, ["deriveBits"])
|
||||
.then(rawKey => {
|
||||
return crypto.subtle.deriveBits({
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
}, rawKey, 4);
|
||||
})
|
||||
.then(derivedBits => {
|
||||
if (!util.memcmp(derivedBits, new Uint8Array([0x80]))) {
|
||||
throw new Error("deriving bits failed");
|
||||
}
|
||||
|
||||
// Forward to reuse.
|
||||
return wrappedKey;
|
||||
});
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["encrypt", "unwrapKey"])
|
||||
.then(wrap)
|
||||
.then(unwrap)
|
||||
.then(complete(that), error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Unwrapping an HKDF key in PKCS8 format should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var hkdfKey = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
var alg = {name: "AES-GCM", length: 256, iv: new Uint8Array(16)};
|
||||
var wrappingKey;
|
||||
|
||||
function wrap(x) {
|
||||
wrappingKey = x;
|
||||
return crypto.subtle.encrypt(alg, wrappingKey, hkdfKey);
|
||||
}
|
||||
|
||||
function unwrap(x) {
|
||||
return crypto.subtle.unwrapKey(
|
||||
"pkcs8", x, wrappingKey, alg, "HKDF", false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["encrypt", "unwrapKey"])
|
||||
.then(wrap, error(that))
|
||||
.then(unwrap, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive an AES key using with HKDF",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
function deriveKey(x) {
|
||||
var targetAlg = {name: "AES-GCM", length: 256};
|
||||
return crypto.subtle.deriveKey(alg, x, targetAlg, false, ["encrypt"]);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"])
|
||||
.then(deriveKey)
|
||||
.then(complete(that), error(that))
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Deriving an HKDF key with HKDF should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var key = util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
|
||||
|
||||
var alg = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array()
|
||||
};
|
||||
|
||||
function deriveKey(x) {
|
||||
return crypto.subtle.deriveKey(alg, x, "HKDF", false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"])
|
||||
.then(deriveKey)
|
||||
.then(error(that), complete(that))
|
||||
}
|
||||
);
|
||||
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<div id="head">
|
||||
<b>Web</b>Crypto<br>
|
||||
</div>
|
||||
|
||||
<div id="start" onclick="start();">RUN ALL</div>
|
||||
|
||||
<div id="resultDiv" class="content">
|
||||
Summary:
|
||||
<span class="pass"><span id="passN">0</span> passed, </span>
|
||||
<span class="fail"><span id="failN">0</span> failed, </span>
|
||||
<span class="pending"><span id="pendingN">0</span> pending.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<table id="results">
|
||||
<tr>
|
||||
<th>Test</th>
|
||||
<th>Result</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="foot"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -37,6 +37,32 @@ TestArray.addTest(
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Unwrapping a PBKDF2 key in PKCS8 format should fail",
|
||||
function() {
|
||||
var that = this;
|
||||
var pbkdf2Key = new TextEncoder("utf-8").encode("password");
|
||||
var alg = {name: "AES-GCM", length: 256, iv: new Uint8Array(16)};
|
||||
var wrappingKey;
|
||||
|
||||
function wrap(x) {
|
||||
wrappingKey = x;
|
||||
return crypto.subtle.encrypt(alg, wrappingKey, pbkdf2Key);
|
||||
}
|
||||
|
||||
function unwrap(x) {
|
||||
return crypto.subtle.unwrapKey(
|
||||
"pkcs8", x, wrappingKey, alg, "PBKDF2", false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["encrypt", "unwrapKey"])
|
||||
.then(wrap, error(that))
|
||||
.then(unwrap, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Import raw PBKDF2 key and derive bits using HMAC-SHA-1",
|
||||
@@ -66,6 +92,34 @@ TestArray.addTest(
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Import a PBKDF2 key in JWK format and derive bits using HMAC-SHA-1",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = "PBKDF2";
|
||||
|
||||
function doDerive(x) {
|
||||
if (!hasKeyFields(x)) {
|
||||
throw "Invalid key; missing field(s)";
|
||||
}
|
||||
|
||||
var alg = {
|
||||
name: "PBKDF2",
|
||||
hash: "SHA-1",
|
||||
salt: tv.pbkdf2_sha1.salt,
|
||||
iterations: tv.pbkdf2_sha1.iterations
|
||||
};
|
||||
return crypto.subtle.deriveBits(alg, x, tv.pbkdf2_sha1.length);
|
||||
}
|
||||
function fail(x) { console.log("failing"); error(that)(x); }
|
||||
|
||||
crypto.subtle.importKey("jwk", tv.pbkdf2_sha1.jwk, alg, false, ["deriveBits"])
|
||||
.then( doDerive, fail )
|
||||
.then( memcmp_complete(that, tv.pbkdf2_sha1.derived), fail );
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Import raw PBKDF2 key and derive a new key using HMAC-SHA-1",
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>WebCrypto Test Suite</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<link rel="stylesheet" href="./test_WebCrypto.css"/>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- Utilities for manipulating ABVs -->
|
||||
<script src="util.js"></script>
|
||||
|
||||
<!-- A simple wrapper around IndexedDB -->
|
||||
<script src="simpledb.js"></script>
|
||||
|
||||
<!-- Test vectors drawn from the literature -->
|
||||
<script src="./test-vectors.js"></script>
|
||||
|
||||
<!-- General testing framework -->
|
||||
<script src="./test-array.js"></script>
|
||||
|
||||
<script>/*<![CDATA[*/
|
||||
"use strict";
|
||||
|
||||
// Generating 2048-bit keys takes some time.
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-PSS key generation (SHA-1, 1024-bit)",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "RSA-PSS",
|
||||
hash: "SHA-1",
|
||||
modulusLength: 1024,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["sign", "verify"])
|
||||
.then(complete(that), error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-PSS key generation and sign/verify round-trip (SHA-256, 2048-bit)",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "RSA-PSS",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
var privKey, pubKey;
|
||||
var data = crypto.getRandomValues(new Uint8Array(128));
|
||||
function setKey(x) { pubKey = x.publicKey; privKey = x.privateKey; }
|
||||
function doSign() {
|
||||
var alg = {name: "RSA-PSS", saltLength: 32};
|
||||
return crypto.subtle.sign(alg, privKey, data);
|
||||
}
|
||||
function doVerify(x) {
|
||||
var alg = {name: "RSA-PSS", saltLength: 32};
|
||||
return crypto.subtle.verify(alg, pubKey, x, data);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["sign", "verify"])
|
||||
.then(setKey, error(that))
|
||||
.then(doSign, error(that))
|
||||
.then(doVerify, error(that))
|
||||
.then(complete(that, x => x), error(that))
|
||||
}
|
||||
);
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<div id="head">
|
||||
<b>Web</b>Crypto<br>
|
||||
</div>
|
||||
|
||||
<div id="start" onclick="start();">RUN ALL</div>
|
||||
|
||||
<div id="resultDiv" class="content">
|
||||
Summary:
|
||||
<span class="pass"><span id="passN">0</span> passed, </span>
|
||||
<span class="fail"><span id="failN">0</span> failed, </span>
|
||||
<span class="pending"><span id="pendingN">0</span> pending.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<table id="results">
|
||||
<tr>
|
||||
<th>Test</th>
|
||||
<th>Result</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="foot"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,7 +21,7 @@ var util = {
|
||||
|
||||
// Convert an ArrayBufferView to a hex string
|
||||
abv2hex: function util_abv2hex(abv) {
|
||||
var b = new Uint8Array(abv.buffer, abv.byteOffset, abv.byteLength);
|
||||
var b = new Uint8Array(abv);
|
||||
var hex = "";
|
||||
for (var i=0; i <b.length; ++i) {
|
||||
var zeropad = (b[i] < 0x10) ? "0" : "";
|
||||
|
||||
@@ -1175,7 +1175,6 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
UpdateTypeMismatchValidityState();
|
||||
} else if (aName == nsGkAtoms::max) {
|
||||
UpdateHasRange();
|
||||
UpdateRangeOverflowValidityState();
|
||||
if (mType == NS_FORM_INPUT_RANGE) {
|
||||
// The value may need to change when @max changes since the value may
|
||||
// have been invalid and can now change to a valid value, or vice
|
||||
@@ -1193,25 +1192,34 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsresult rv =
|
||||
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow this");
|
||||
}
|
||||
// Validity state must be updated *after* the SetValueInternal call above
|
||||
// or else the following assert will not be valid.
|
||||
// We don't assert the state of underflow during parsing since
|
||||
// DoneCreatingElement sanitizes.
|
||||
UpdateRangeOverflowValidityState();
|
||||
MOZ_ASSERT(mParserCreating ||
|
||||
mType != NS_FORM_INPUT_RANGE ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
} else if (aName == nsGkAtoms::min) {
|
||||
UpdateHasRange();
|
||||
if (mType == NS_FORM_INPUT_RANGE) {
|
||||
// See @max comment
|
||||
nsAutoString value;
|
||||
GetValue(value);
|
||||
nsresult rv =
|
||||
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
// See corresponding @max comment
|
||||
UpdateRangeUnderflowValidityState();
|
||||
UpdateStepMismatchValidityState();
|
||||
if (mType == NS_FORM_INPUT_RANGE) {
|
||||
// See @max comment
|
||||
nsAutoString value;
|
||||
GetValue(value);
|
||||
nsresult rv =
|
||||
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow this");
|
||||
}
|
||||
MOZ_ASSERT(mParserCreating ||
|
||||
mType != NS_FORM_INPUT_RANGE ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
} else if (aName == nsGkAtoms::step) {
|
||||
UpdateStepMismatchValidityState();
|
||||
if (mType == NS_FORM_INPUT_RANGE) {
|
||||
// See @max comment
|
||||
nsAutoString value;
|
||||
@@ -1219,9 +1227,13 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsresult rv =
|
||||
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow this");
|
||||
}
|
||||
// See corresponding @max comment
|
||||
UpdateStepMismatchValidityState();
|
||||
MOZ_ASSERT(mParserCreating ||
|
||||
mType != NS_FORM_INPUT_RANGE ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
} else if (aName == nsGkAtoms::dir &&
|
||||
aValue && aValue->Equals(nsGkAtoms::_auto, eIgnoreCase)) {
|
||||
SetDirectionIfAuto(true, aNotify);
|
||||
@@ -5562,14 +5574,14 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
||||
const nsTArray<RefPtr<File>>& files = GetFilesInternal();
|
||||
|
||||
for (uint32_t i = 0; i < files.Length(); ++i) {
|
||||
aFormSubmission->AddNameFilePair(name, files[i]);
|
||||
aFormSubmission->AddNameBlobPair(name, files[i]);
|
||||
}
|
||||
|
||||
if (files.IsEmpty()) {
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
new BlobImplEmptyFile(NS_LITERAL_STRING("application/octet-stream"));
|
||||
RefPtr<File> file = File::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
|
||||
aFormSubmission->AddNameFilePair(name, file);
|
||||
new EmptyBlobImpl(NS_LITERAL_STRING("application/octet-stream"));
|
||||
RefPtr<Blob> blob = Blob::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
|
||||
aFormSubmission->AddNameBlobPair(name, blob);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
+11
-11
@@ -379,7 +379,7 @@ UndoContentAppend::UndoTransaction()
|
||||
{
|
||||
for (int32_t i = mChildren.Count() - 1; i >= 0; i--) {
|
||||
if (mChildren[i]->GetParentNode() == mContent) {
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
mContent->RemoveChild(*mChildren[i], error);
|
||||
}
|
||||
}
|
||||
@@ -443,7 +443,7 @@ UndoContentInsert::RedoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
nsCOMPtr<nsIContent> refNode = mNextNode;
|
||||
mContent->InsertBefore(*mChild, refNode, error);
|
||||
return NS_OK;
|
||||
@@ -471,7 +471,7 @@ UndoContentInsert::UndoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
mContent->RemoveChild(*mChild, error);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -538,7 +538,7 @@ UndoContentRemove::UndoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
nsCOMPtr<nsIContent> refNode = mNextNode;
|
||||
mContent->InsertBefore(*mChild, refNode, error);
|
||||
return NS_OK;
|
||||
@@ -566,7 +566,7 @@ UndoContentRemove::RedoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
IgnoredErrorResult error;
|
||||
mContent->RemoveChild(*mChild, error);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -770,13 +770,13 @@ FunctionCallTxn::RedoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
// We ignore rv because we want to avoid the rollback behavior of the
|
||||
// nsITransactionManager.
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<DOMTransactionCallback> redo = mTransaction->GetRedo(rv);
|
||||
if (!rv.Failed() && redo) {
|
||||
redo->Call(mTransaction.get(), rv);
|
||||
}
|
||||
// We ignore rv because we want to avoid the rollback behavior of the
|
||||
// nsITransactionManager.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -788,13 +788,13 @@ FunctionCallTxn::UndoTransaction()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
// We ignore rv because we want to avoid the rollback behavior of the
|
||||
// nsITransactionManager.
|
||||
IgnoredErrorResult rv;
|
||||
RefPtr<DOMTransactionCallback> undo = mTransaction->GetUndo(rv);
|
||||
if (!rv.Failed() && undo) {
|
||||
undo->Call(mTransaction.get(), rv);
|
||||
}
|
||||
// We ignore rv because we want to avoid the rollback behavior of the
|
||||
// nsITransactionManager.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,17 @@ SendJSWarning(nsIDocument* aDocument,
|
||||
aWarningArgs, aWarningArgsLen);
|
||||
}
|
||||
|
||||
static void
|
||||
RetrieveFileName(Blob* aBlob, nsAString& aFilename)
|
||||
{
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
RefPtr<File> file = aBlob->ToFile();
|
||||
if (file) {
|
||||
file->GetName(aFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
class nsFSURLEncoded : public nsEncodingFormSubmission
|
||||
@@ -77,8 +88,8 @@ public:
|
||||
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue) override;
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile) override;
|
||||
virtual nsresult AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob) override;
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream)
|
||||
override;
|
||||
@@ -164,10 +175,10 @@ nsFSURLEncoded::AddIsindex(const nsAString& aValue)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile)
|
||||
nsFSURLEncoded::AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
if (!mWarnedFileControl) {
|
||||
SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
|
||||
@@ -175,8 +186,7 @@ nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsAutoString filename;
|
||||
aFile->GetName(filename);
|
||||
|
||||
RetrieveFileName(aBlob, filename);
|
||||
return AddNameValuePair(aName, filename);
|
||||
}
|
||||
|
||||
@@ -438,10 +448,10 @@ nsFSMultipartFormData::AddNameValuePair(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile)
|
||||
nsFSMultipartFormData::AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(aFile);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
// Encode the control name
|
||||
nsAutoCString nameStr;
|
||||
@@ -449,13 +459,16 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString filename16;
|
||||
aFile->GetName(filename16);
|
||||
RetrieveFileName(aBlob, filename16);
|
||||
|
||||
ErrorResult error;
|
||||
nsAutoString filepath16;
|
||||
aFile->GetPath(filepath16, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
RefPtr<File> file = aBlob->ToFile();
|
||||
if (file) {
|
||||
file->GetPath(filepath16, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (!filepath16.IsEmpty()) {
|
||||
@@ -469,7 +482,7 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
|
||||
// Get content type
|
||||
nsAutoString contentType16;
|
||||
aFile->GetType(contentType16);
|
||||
aBlob->GetType(contentType16);
|
||||
if (contentType16.IsEmpty()) {
|
||||
contentType16.AssignLiteral("application/octet-stream");
|
||||
}
|
||||
@@ -482,7 +495,7 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
|
||||
// Get input stream
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
aFile->GetInternalStream(getter_AddRefs(fileStream), error);
|
||||
aBlob->GetInternalStream(getter_AddRefs(fileStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
@@ -517,7 +530,7 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
// if we try to update a file that actually do not exist.
|
||||
if (fileStream) {
|
||||
ErrorResult error;
|
||||
uint64_t size = aFile->GetSize(error);
|
||||
uint64_t size = aBlob->GetSize(error);
|
||||
if (error.Failed()) {
|
||||
error.SuppressException();
|
||||
} else {
|
||||
@@ -590,8 +603,8 @@ public:
|
||||
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue) override;
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile) override;
|
||||
virtual nsresult AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob) override;
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream)
|
||||
override;
|
||||
@@ -614,12 +627,13 @@ nsFSTextPlain::AddNameValuePair(const nsAString& aName,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFSTextPlain::AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile)
|
||||
nsFSTextPlain::AddNameBlobPair(const nsAString& aName,
|
||||
Blob* aBlob)
|
||||
{
|
||||
nsAutoString filename;
|
||||
aFile->GetName(filename);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
nsAutoString filename;
|
||||
RetrieveFileName(aBlob, filename);
|
||||
AddNameValuePair(aName, filename);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class nsIMultiplexInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class File;
|
||||
class Blob;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -45,13 +45,14 @@ public:
|
||||
const nsAString& aValue) = 0;
|
||||
|
||||
/**
|
||||
* Submit a name/file pair
|
||||
* Submit a name/blob pair
|
||||
*
|
||||
* @param aName the name of the parameter
|
||||
* @param aFile the file to submit. The file's name will be used
|
||||
* @param aBlob the blob to submit. The file's name will be used if the Blob
|
||||
* is actually a File, otherwise 'blob' string is used instead.
|
||||
*/
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile) = 0;
|
||||
virtual nsresult AddNameBlobPair(const nsAString& aName,
|
||||
mozilla::dom::Blob* aBlob) = 0;
|
||||
|
||||
/**
|
||||
* Reports whether the instance supports AddIsindex().
|
||||
@@ -159,8 +160,8 @@ public:
|
||||
|
||||
virtual nsresult AddNameValuePair(const nsAString& aName,
|
||||
const nsAString& aValue) override;
|
||||
virtual nsresult AddNameFilePair(const nsAString& aName,
|
||||
mozilla::dom::File* aFile) override;
|
||||
virtual nsresult AddNameBlobPair(const nsAString& aName,
|
||||
mozilla::dom::Blob* aBlob) override;
|
||||
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
||||
nsIInputStream** aPostDataStream) override;
|
||||
|
||||
|
||||
@@ -412,7 +412,7 @@ public:
|
||||
NS_IMETHOD GetItemId(nsAString& aId) final override {
|
||||
nsString id;
|
||||
GetItemId(id);
|
||||
aId.Assign(aId);
|
||||
aId.Assign(id);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD SetItemId(const nsAString& aId) final override {
|
||||
@@ -960,10 +960,16 @@ public:
|
||||
static inline bool
|
||||
ShouldExposeIdAsHTMLDocumentProperty(Element* aElement)
|
||||
{
|
||||
return aElement->IsAnyOfHTMLElements(nsGkAtoms::img,
|
||||
nsGkAtoms::applet,
|
||||
nsGkAtoms::embed,
|
||||
nsGkAtoms::object);
|
||||
if (aElement->IsAnyOfHTMLElements(nsGkAtoms::applet,
|
||||
nsGkAtoms::embed,
|
||||
nsGkAtoms::object)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Per spec, <img> is exposed by id only if it also has a nonempty
|
||||
// name (which doesn't have to match the id or anything).
|
||||
// HasName() is true precisely when name is nonempty.
|
||||
return aElement->IsHTMLElement(nsGkAtoms::img) && aElement->HasName();
|
||||
}
|
||||
|
||||
static bool
|
||||
|
||||
@@ -91,6 +91,9 @@ nsGenericHTMLFrameElement::GetContentDocument()
|
||||
}
|
||||
|
||||
nsIDocument *doc = win->GetDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return null for cross-origin contentDocument.
|
||||
if (!nsContentUtils::SubjectPrincipal()->
|
||||
|
||||
@@ -140,7 +140,10 @@ nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname, uint16_t flags)
|
||||
// considers empty strings to be valid hostnames
|
||||
if (!hostname.IsEmpty() &&
|
||||
net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
|
||||
gNeckoChild->SendHTMLDNSPrefetch(nsAutoString(hostname), flags);
|
||||
// during shutdown gNeckoChild might be null
|
||||
if (gNeckoChild) {
|
||||
gNeckoChild->SendHTMLDNSPrefetch(nsAutoString(hostname), flags);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -197,8 +200,11 @@ nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
|
||||
// considers empty strings to be valid hostnames
|
||||
if (!hostname.IsEmpty() &&
|
||||
net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
|
||||
gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname), flags,
|
||||
aReason);
|
||||
// during shutdown gNeckoChild might be null
|
||||
if (gNeckoChild) {
|
||||
gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname), flags,
|
||||
aReason);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -326,8 +332,11 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
|
||||
|
||||
if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource) {
|
||||
if (IsNeckoChild()) {
|
||||
gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
|
||||
mEntries[mTail].mFlags);
|
||||
// during shutdown gNeckoChild might be null
|
||||
if (gNeckoChild) {
|
||||
gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
|
||||
mEntries[mTail].mFlags);
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsICancelable> tmpOutstanding;
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
VALIDITY_STATE_CUSTOM_ERROR = 0x1 << 9,
|
||||
};
|
||||
|
||||
void SetValidityState(ValidityStateType mState,
|
||||
bool mValue);
|
||||
void SetValidityState(ValidityStateType aState,
|
||||
bool aValue);
|
||||
|
||||
// Web IDL binding methods
|
||||
bool WillValidate() const {
|
||||
@@ -83,9 +83,10 @@ protected:
|
||||
nsresult CheckValidity(bool* aValidity);
|
||||
void SetCustomValidity(const nsAString& aError);
|
||||
|
||||
bool GetValidityState(ValidityStateType mState) const {
|
||||
return mValidityBitField & mState;
|
||||
}
|
||||
bool GetValidityState(ValidityStateType aState) const
|
||||
{
|
||||
return mValidityBitField & aState;
|
||||
}
|
||||
|
||||
void SetBarredFromConstraintValidation(bool aBarred);
|
||||
|
||||
|
||||
@@ -1951,6 +1951,21 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
|
||||
// be set later with the updated mValueBeingSet.
|
||||
return true;
|
||||
}
|
||||
if (NS_WARN_IF(!mBoundFrame)) {
|
||||
// We're not sure if this case is possible.
|
||||
} else {
|
||||
// If setting value won't change current value, we shouldn't commit
|
||||
// composition for compatibility with the other browsers.
|
||||
nsAutoString currentValue;
|
||||
mBoundFrame->GetText(currentValue);
|
||||
if (newValue == currentValue) {
|
||||
// Note that in this case, we shouldn't fire any events with setting
|
||||
// value because event handlers may try to set value recursively but
|
||||
// we cannot commit composition at that time due to unsafe to run
|
||||
// script (see below).
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If there is composition, need to commit composition first because
|
||||
// other browsers do that.
|
||||
// NOTE: We don't need to block nested calls of this because input nor
|
||||
|
||||
@@ -85,7 +85,7 @@ function testFilename() {
|
||||
var f = new FormData();
|
||||
// Spec says if a Blob (which is not a File) is added, the name parameter is set to "blob".
|
||||
f.append("blob", new Blob(["hi"]));
|
||||
is(f.get("blob").name, "blob", "Blob's filename should be blob.");
|
||||
ok(f.get("blob") instanceof Blob, "We should have a blob back.");
|
||||
|
||||
// If a filename is passed, that should replace the original.
|
||||
f.append("blob2", new Blob(["hi"]), "blob2.txt");
|
||||
|
||||
@@ -590,7 +590,7 @@ var expectedAugment = [
|
||||
//{ name: "aNameUndef", value: "undefined" },
|
||||
];
|
||||
|
||||
function checkMPSubmission(sub, expected, test) {
|
||||
function checkMPSubmission(sub, expected, test, isFormData = false) {
|
||||
function getPropCount(o) {
|
||||
var x, l = 0;
|
||||
for (x in o) ++l;
|
||||
@@ -625,7 +625,7 @@ function checkMPSubmission(sub, expected, test) {
|
||||
else {
|
||||
is(sub[i].headers["Content-Disposition"],
|
||||
"form-data; name=\"" + mpquote(expected[i].name) + "\"; filename=\"" +
|
||||
mpquote(expected[i].fileName) + "\"",
|
||||
mpquote(expected[i].fileName != "" || !isFormData ? expected[i].fileName : "blob") + "\"",
|
||||
"Correct name in " + test);
|
||||
is(sub[i].headers["Content-Type"],
|
||||
expected[i].contentType,
|
||||
@@ -782,14 +782,14 @@ function runTest() {
|
||||
xhr.open("POST", "form_submit_server.sjs");
|
||||
xhr.send(new FormData(form));
|
||||
yield undefined; // Wait for XHR load
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), expectedSub, "send form using XHR and FormData");
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), expectedSub, "send form using XHR and FormData", true);
|
||||
|
||||
// Send disabled form using XHR and FormData
|
||||
setDisabled(document.querySelectorAll("input, select, textarea"), true);
|
||||
xhr.open("POST", "form_submit_server.sjs");
|
||||
xhr.send(new FormData(form));
|
||||
yield undefined;
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), [], "send disabled form using XHR and FormData");
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), [], "send disabled form using XHR and FormData", true);
|
||||
setDisabled(document.querySelectorAll("input, select, textarea"), false);
|
||||
|
||||
// Send FormData
|
||||
@@ -804,7 +804,7 @@ function runTest() {
|
||||
xhr.open("POST", "form_submit_server.sjs");
|
||||
xhr.send(fd);
|
||||
yield undefined;
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment, "send FormData");
|
||||
checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment, "send FormData", true);
|
||||
|
||||
// Augment <form> using FormData
|
||||
fd = new FormData(form);
|
||||
@@ -813,7 +813,7 @@ function runTest() {
|
||||
xhr.send(fd);
|
||||
yield undefined;
|
||||
checkMPSubmission(JSON.parse(xhr.responseText),
|
||||
expectedSub.concat(expectedAugment), "send augmented FormData");
|
||||
expectedSub.concat(expectedAugment), "send augmented FormData", true);
|
||||
|
||||
SimpleTest.finish();
|
||||
yield undefined;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{
|
||||
"If there are two imgs, a collection should be returned. (name)": true,
|
||||
"If there is one img, it should not be returned (id)": true,
|
||||
"If there are two imgs, nothing should be returned. (id)": true
|
||||
"If there are two imgs, a collection should be returned. (name)": true
|
||||
}
|
||||
|
||||
@@ -63,9 +63,7 @@ test(function() {
|
||||
assert_equals(img2.id, "test4");
|
||||
|
||||
assert_false("test4" in document, '"test4" in document should be false');
|
||||
var collection = document.test4;
|
||||
assert_class_string(collection, "HTMLCollection", "collection should be an HTMLCollection");
|
||||
assert_array_equals(collection, [img1, img2]);
|
||||
assert_equals(document.test4, undefined);
|
||||
}, "If there are two imgs, nothing should be returned. (id)");
|
||||
|
||||
test(function() {
|
||||
|
||||
@@ -2390,11 +2390,13 @@ BackgroundRequestChild::HandleResponse(
|
||||
|
||||
StructuredCloneReadInfo* cloneReadInfo = cloneReadInfos.AppendElement();
|
||||
|
||||
*cloneReadInfo = Move(serializedCloneInfo);
|
||||
// Get the files
|
||||
nsTArray<StructuredCloneFile> files;
|
||||
ConvertActorsToBlobs(database, serializedCloneInfo, files);
|
||||
|
||||
ConvertActorsToBlobs(database,
|
||||
serializedCloneInfo,
|
||||
cloneReadInfo->mFiles);
|
||||
// Move relevant data into the cloneReadInfo
|
||||
*cloneReadInfo = Move(serializedCloneInfo);
|
||||
cloneReadInfo->mFiles = Move(files);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ extern "C" {
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::media;
|
||||
@@ -148,6 +150,17 @@ OggReader::~OggReader()
|
||||
{
|
||||
ogg_sync_clear(&mOggState);
|
||||
MOZ_COUNT_DTOR(OggReader);
|
||||
if (HasAudio() || HasVideo()) {
|
||||
// If we were able to initialize our decoders, report whether we encountered
|
||||
// a chained stream or not.
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
bool isChained = mIsChained;
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
|
||||
LOG(LogLevel::Debug, (nsPrintfCString("Reporting telemetry MEDIA_OGG_LOADED_IS_CHAINED=%d", isChained).get()));
|
||||
Telemetry::Accumulate(Telemetry::ID::MEDIA_OGG_LOADED_IS_CHAINED, isChained);
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(task.forget());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult OggReader::Init() {
|
||||
@@ -704,10 +717,13 @@ bool OggReader::DecodeAudioData()
|
||||
return true;
|
||||
}
|
||||
|
||||
void OggReader::SetChained(bool aIsChained) {
|
||||
void OggReader::SetChained() {
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mIsChained = aIsChained;
|
||||
if (mIsChained) {
|
||||
return;
|
||||
}
|
||||
mIsChained = true;
|
||||
}
|
||||
mOnMediaNotSeekable.Notify();
|
||||
}
|
||||
@@ -800,7 +816,7 @@ bool OggReader::ReadOggChain()
|
||||
}
|
||||
|
||||
if (chained) {
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
{
|
||||
auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
|
||||
mTimedMetadataEvent.Notify(
|
||||
@@ -1139,7 +1155,7 @@ int64_t OggReader::RangeEndTime(int64_t aStartOffset,
|
||||
// This page is from a bitstream which we haven't encountered yet.
|
||||
// It's probably from a new "link" in a "chained" ogg. Don't
|
||||
// bother even trying to find a duration...
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
endTime = -1;
|
||||
break;
|
||||
}
|
||||
@@ -1913,7 +1929,7 @@ media::TimeIntervals OggReader::GetBuffered()
|
||||
// ogg), return OK to abort the finding any further ranges. This
|
||||
// prevents us searching through the rest of the media when we
|
||||
// may not be able to extract timestamps from it.
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
return buffered;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ private:
|
||||
|
||||
// Set this media as being a chain and notifies the state machine that the
|
||||
// media is no longer seekable.
|
||||
void SetChained(bool aIsChained);
|
||||
void SetChained();
|
||||
|
||||
// Returns the next Ogg packet for an bitstream/codec state. Returns a
|
||||
// pointer to an ogg_packet on success, or nullptr if the read failed.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/PushManager.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/unused.h"
|
||||
@@ -65,6 +66,26 @@ GetPermissionState(nsIPrincipal* aPrincipal,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionToJSON(PushSubscriptionJSON& aJSON, const nsString& aEndpoint,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
{
|
||||
aJSON.mEndpoint.Construct();
|
||||
aJSON.mEndpoint.Value() = aEndpoint;
|
||||
|
||||
aJSON.mKeys.mP256dh.Construct();
|
||||
nsresult rv = Base64URLEncode(aRawP256dhKey.Length(),
|
||||
aRawP256dhKey.Elements(),
|
||||
aJSON.mKeys.mP256dh.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
aJSON.mKeys.mAuth.Construct();
|
||||
rv = Base64URLEncode(aAuthSecret.Length(), aAuthSecret.Elements(),
|
||||
aJSON.mKeys.mAuth.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
@@ -123,6 +144,12 @@ PushSubscription::Unsubscribe(ErrorResult& aRv)
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
@@ -507,6 +534,12 @@ WorkerPushSubscription::Unsubscribe(ErrorResult &aRv)
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription)
|
||||
|
||||
@@ -104,6 +104,9 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~PushSubscription();
|
||||
|
||||
@@ -197,6 +200,9 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~WorkerPushSubscription();
|
||||
|
||||
|
||||
@@ -515,7 +515,7 @@ this.PushService = {
|
||||
console.debug("startService()");
|
||||
|
||||
if (this._state != PUSH_SERVICE_ACTIVATING) {
|
||||
return;
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
this._service = service;
|
||||
@@ -525,9 +525,11 @@ this.PushService = {
|
||||
this._db = this._service.newPushDB();
|
||||
}
|
||||
|
||||
this._service.init(options, this, serverURI);
|
||||
this._startObservers();
|
||||
return this._dropExpiredRegistrations();
|
||||
return this._service.init(options, this, serverURI)
|
||||
.then(() => {
|
||||
this._startObservers();
|
||||
return this._dropExpiredRegistrations();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ const {PushDB} = Cu.import("resource://gre/modules/PushDB.jsm");
|
||||
const {PushRecord} = Cu.import("resource://gre/modules/PushRecord.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
@@ -103,7 +104,7 @@ PushSubscriptionListener.prototype = {
|
||||
onPush: function(associatedChannel, pushChannel) {
|
||||
console.debug("PushSubscriptionListener: onPush()");
|
||||
var pushChannelListener = new PushChannelListener(this);
|
||||
pushChannel.asyncOpen(pushChannelListener, pushChannel);
|
||||
pushChannel.asyncOpen2(pushChannelListener);
|
||||
},
|
||||
|
||||
disconnect: function() {
|
||||
@@ -434,19 +435,8 @@ this.PushServiceHttp2 = {
|
||||
},
|
||||
|
||||
_makeChannel: function(aUri) {
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
var chan = ios.newChannel2(aUri,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER)
|
||||
.QueryInterface(Ci.nsIHttpChannel);
|
||||
var chan = NetUtil.newChannel({uri: aUri, loadUsingSystemPrincipal: true})
|
||||
.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
var loadGroup = Cc["@mozilla.org/network/load-group;1"]
|
||||
.createInstance(Ci.nsILoadGroup);
|
||||
@@ -495,7 +485,7 @@ this.PushServiceHttp2 = {
|
||||
|
||||
var chan = this._makeChannel(this._serverURI.spec);
|
||||
chan.requestMethod = "POST";
|
||||
chan.asyncOpen(listener, null);
|
||||
chan.asyncOpen2(listener);
|
||||
})
|
||||
.catch(err => {
|
||||
if ("retry" in err) {
|
||||
@@ -511,7 +501,7 @@ this.PushServiceHttp2 = {
|
||||
return new Promise((resolve,reject) => {
|
||||
var chan = this._makeChannel(aUri);
|
||||
chan.requestMethod = "DELETE";
|
||||
chan.asyncOpen(new PushServiceDelete(resolve, reject), null);
|
||||
chan.asyncOpen2(new PushServiceDelete(resolve, reject));
|
||||
});
|
||||
},
|
||||
|
||||
@@ -545,10 +535,10 @@ this.PushServiceHttp2 = {
|
||||
chan.notificationCallbacks = listener;
|
||||
|
||||
try {
|
||||
chan.asyncOpen(listener, chan);
|
||||
chan.asyncOpen2(listener);
|
||||
} catch (e) {
|
||||
console.error("listenForMsgs: Error connecting to push server.",
|
||||
"asyncOpen failed", e);
|
||||
"asyncOpen2 failed", e);
|
||||
conn.listener.disconnect();
|
||||
chan.cancel(Cr.NS_ERROR_ABORT);
|
||||
this._retryAfterBackoff(aSubscriptionUri, -1);
|
||||
@@ -563,15 +553,15 @@ this.PushServiceHttp2 = {
|
||||
|
||||
_ackMsgRecv: function(aAckUri) {
|
||||
console.debug("ackMsgRecv()", aAckUri);
|
||||
// We can't do anything about it if it fails,
|
||||
// so we don't listen for response.
|
||||
this._deleteResource(aAckUri);
|
||||
return this._deleteResource(aAckUri);
|
||||
},
|
||||
|
||||
init: function(aOptions, aMainPushService, aServerURL) {
|
||||
console.debug("init()");
|
||||
this._mainPushService = aMainPushService;
|
||||
this._serverURI = aServerURL;
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
_retryAfterBackoff: function(aSubscriptionUri, retryAfter) {
|
||||
|
||||
@@ -299,6 +299,8 @@ this.PushServiceWebSocket = {
|
||||
this._requestTimeout = prefs.get("requestTimeout");
|
||||
this._adaptiveEnabled = prefs.get('adaptive.enabled');
|
||||
this._upperLimit = prefs.get('adaptive.upperLimit');
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
_reconnect: function () {
|
||||
|
||||
+154
-119
@@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1185544</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/webpush.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
@@ -24,32 +25,47 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var registration;
|
||||
SimpleTest.registerCleanupFunction(() =>
|
||||
new Promise(resolve => SpecialPowers.popPermissions(resolve))
|
||||
);
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then(swr => { registration = swr; return swr; });
|
||||
}
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPermissions([
|
||||
{ type: "desktop-notification", allow: true, context: document },
|
||||
], resolve);
|
||||
});
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, resolve);
|
||||
});
|
||||
|
||||
var url = "worker.js" + "?" + (Math.random());
|
||||
registration = yield navigator.serviceWorker.register(url, {scope: "."});
|
||||
});
|
||||
|
||||
var controlledFrame;
|
||||
function createControlledIFrame(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
add_task(function* createControlledIFrame() {
|
||||
yield new Promise(function(res, rej) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.id = "controlledFrame";
|
||||
iframe.src = "http://mochi.test:8888/tests/dom/push/test/frame.html";
|
||||
|
||||
iframe.onload = function() {
|
||||
res(swr)
|
||||
}
|
||||
iframe.onload = () => res();
|
||||
controlledFrame = iframe;
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
});
|
||||
|
||||
function subscribe(swr) {
|
||||
return swr.pushManager.subscribe();
|
||||
}
|
||||
var pushSubscription;
|
||||
add_task(function* subscribe() {
|
||||
pushSubscription = yield registration.pushManager.subscribe();
|
||||
});
|
||||
|
||||
function sendRequestToWorker(request) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -61,22 +77,65 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
});
|
||||
}
|
||||
|
||||
function comparePublicKey(pushSubscription) {
|
||||
// FIXME(kitcambridge): Enable when `ServiceWorkerMessageEvent` is
|
||||
// implemented (bug 1143717).
|
||||
return Promise.resolve(pushSubscription);
|
||||
/*
|
||||
return sendRequestToWorker({ type: "publicKey" }).then(data => {
|
||||
return registration.pushManager.getSubscription().then(
|
||||
pushSubscription => {
|
||||
isDeeply(pushSubscription.getKey("p256dh"), data,
|
||||
"Mismatched key share");
|
||||
return pushSubscription;
|
||||
});
|
||||
});
|
||||
*/
|
||||
function base64UrlDecode(s) {
|
||||
s = s.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
// Replace padding if it was stripped by the sender.
|
||||
// See http://tools.ietf.org/html/rfc4648#section-4
|
||||
switch (s.length % 4) {
|
||||
case 0:
|
||||
break; // No pad chars in this case
|
||||
case 2:
|
||||
s += '==';
|
||||
break; // Two pad chars
|
||||
case 3:
|
||||
s += '=';
|
||||
break; // One pad char
|
||||
default:
|
||||
throw new Error('Illegal base64url string!');
|
||||
}
|
||||
|
||||
// With correct padding restored, apply the standard base64 decoder
|
||||
var decoded = atob(s);
|
||||
|
||||
var array = new Uint8Array(new ArrayBuffer(decoded.length));
|
||||
for (var i = 0; i < decoded.length; i++) {
|
||||
array[i] = decoded.charCodeAt(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
add_task(function* compareJSONSubscription() {
|
||||
var json = pushSubscription.toJSON();
|
||||
is(json.endpoint, pushSubscription.endpoint, "Wrong endpoint");
|
||||
|
||||
["p256dh", "auth"].forEach(keyName => {
|
||||
isDeeply(
|
||||
base64UrlDecode(json.keys[keyName]),
|
||||
new Uint8Array(pushSubscription.getKey(keyName)),
|
||||
"Mismatched Base64-encoded key: " + keyName
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* comparePublicKey() {
|
||||
var data = yield sendRequestToWorker({ type: "publicKey" });
|
||||
var p256dhKey = new Uint8Array(pushSubscription.getKey("p256dh"));
|
||||
ok(p256dhKey.length > 0, "Missing key share");
|
||||
isDeeply(
|
||||
p256dhKey,
|
||||
new Uint8Array(data.p256dh),
|
||||
"Mismatched key share"
|
||||
);
|
||||
var authSecret = new Uint8Array(pushSubscription.getKey("auth"));
|
||||
ok(authSecret.length > 0, "Missing auth secret");
|
||||
isDeeply(
|
||||
authSecret,
|
||||
new Uint8Array(data.auth),
|
||||
"Mismatched auth secret"
|
||||
);
|
||||
});
|
||||
|
||||
function waitForMessage(pushSubscription, message) {
|
||||
return Promise.all([
|
||||
controlledFrame.contentWindow.waitOnPushMessage(pushSubscription),
|
||||
@@ -84,103 +143,79 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
]).then(([message]) => message);
|
||||
}
|
||||
|
||||
function sendPushMessageFromPage(pushSubscription) {
|
||||
add_task(function* sendPushMessageFromPage() {
|
||||
var typedArray = new Uint8Array([226, 130, 40, 240, 40, 140, 188]);
|
||||
var json = { hello: "world" };
|
||||
return waitForMessage(pushSubscription, "Text message from page")
|
||||
.then(message => {
|
||||
is(message.data.text, "Text message from page", "Wrong text message data");
|
||||
return waitForMessage(
|
||||
pushSubscription,
|
||||
typedArray
|
||||
);
|
||||
}).then(message => {
|
||||
isDeeply(new Uint8Array(message.data.arrayBuffer), typedArray,
|
||||
"Wrong array buffer message data");
|
||||
return waitForMessage(
|
||||
pushSubscription,
|
||||
JSON.stringify(json)
|
||||
);
|
||||
}).then(message => {
|
||||
ok(message.data.json.ok, "Unexpected error parsing JSON");
|
||||
isDeeply(message.data.json.value, json, "Wrong JSON message data");
|
||||
return waitForMessage(
|
||||
pushSubscription,
|
||||
""
|
||||
);
|
||||
}).then(message => {
|
||||
ok(message, "Should include data for empty messages");
|
||||
is(message.data.text, "", "Wrong text for empty message");
|
||||
is(message.data.arrayBuffer.byteLength, 0, "Wrong buffer length for empty message");
|
||||
ok(!message.data.json.ok, "Expected JSON parse error for empty message");
|
||||
return waitForMessage(
|
||||
pushSubscription,
|
||||
new Uint8Array([0x48, 0x69, 0x21, 0x20, 0xf0, 0x9f, 0x91, 0x80])
|
||||
);
|
||||
}).then(message => {
|
||||
is(message.data.text, "Hi! \ud83d\udc40", "Wrong text for message with emoji");
|
||||
return new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = event => {
|
||||
if (reader.error) {
|
||||
reject(reader.error);
|
||||
} else {
|
||||
resolve(reader.result);
|
||||
}
|
||||
};
|
||||
reader.readAsText(message.data.blob);
|
||||
});
|
||||
}).then(text => {
|
||||
is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
|
||||
is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
|
||||
// Send a blank message.
|
||||
return Promise.all([
|
||||
controlledFrame.contentWindow.waitOnPushMessage(pushSubscription),
|
||||
fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"X-Push-Method": "POST",
|
||||
"X-Push-Server": pushSubscription.endpoint,
|
||||
},
|
||||
}),
|
||||
]).then(([message]) => message);
|
||||
}).then(message => {
|
||||
ok(!message.data, "Should exclude data for blank messages");
|
||||
return pushSubscription;
|
||||
});
|
||||
}
|
||||
|
||||
function unsubscribe(pushSubscription) {
|
||||
var message = yield waitForMessage(pushSubscription, "Text message from page");
|
||||
is(message.data.text, "Text message from page", "Wrong text message data");
|
||||
|
||||
message = yield waitForMessage(
|
||||
pushSubscription,
|
||||
typedArray
|
||||
);
|
||||
isDeeply(new Uint8Array(message.data.arrayBuffer), typedArray,
|
||||
"Wrong array buffer message data");
|
||||
|
||||
message = yield waitForMessage(
|
||||
pushSubscription,
|
||||
JSON.stringify(json)
|
||||
);
|
||||
ok(message.data.json.ok, "Unexpected error parsing JSON");
|
||||
isDeeply(message.data.json.value, json, "Wrong JSON message data");
|
||||
|
||||
message = yield waitForMessage(
|
||||
pushSubscription,
|
||||
""
|
||||
);
|
||||
ok(message, "Should include data for empty messages");
|
||||
is(message.data.text, "", "Wrong text for empty message");
|
||||
is(message.data.arrayBuffer.byteLength, 0, "Wrong buffer length for empty message");
|
||||
ok(!message.data.json.ok, "Expected JSON parse error for empty message");
|
||||
|
||||
message = yield waitForMessage(
|
||||
pushSubscription,
|
||||
new Uint8Array([0x48, 0x69, 0x21, 0x20, 0xf0, 0x9f, 0x91, 0x80])
|
||||
);
|
||||
is(message.data.text, "Hi! \ud83d\udc40", "Wrong text for message with emoji");
|
||||
var text = yield new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = event => {
|
||||
if (reader.error) {
|
||||
reject(reader.error);
|
||||
} else {
|
||||
resolve(reader.result);
|
||||
}
|
||||
};
|
||||
reader.readAsText(message.data.blob);
|
||||
});
|
||||
is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
|
||||
is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
|
||||
|
||||
// Send a blank message.
|
||||
var [message] = yield Promise.all([
|
||||
controlledFrame.contentWindow.waitOnPushMessage(pushSubscription),
|
||||
fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"X-Push-Method": "POST",
|
||||
"X-Push-Server": pushSubscription.endpoint,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
ok(!message.data, "Should exclude data for blank messages");
|
||||
});
|
||||
|
||||
add_task(function* unsubscribe() {
|
||||
controlledFrame.parentNode.removeChild(controlledFrame);
|
||||
controlledFrame = null;
|
||||
return pushSubscription.unsubscribe();
|
||||
}
|
||||
yield pushSubscription.unsubscribe();
|
||||
});
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister();
|
||||
}
|
||||
add_task(function* unregister() {
|
||||
yield registration.unregister();
|
||||
});
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(createControlledIFrame)
|
||||
.then(subscribe)
|
||||
.then(comparePublicKey)
|
||||
.then(sendPushMessageFromPage)
|
||||
.then(unsubscribe)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+16
-9
@@ -19,7 +19,7 @@ function getJSON(data) {
|
||||
|
||||
function handlePush(event) {
|
||||
|
||||
self.clients.matchAll().then(function(result) {
|
||||
event.waitUntil(self.clients.matchAll().then(function(result) {
|
||||
if (event instanceof PushEvent) {
|
||||
if (!('data' in event)) {
|
||||
result[0].postMessage({type: "finished", okay: "yes"});
|
||||
@@ -41,17 +41,24 @@ function handlePush(event) {
|
||||
return;
|
||||
}
|
||||
result[0].postMessage({type: "finished", okay: "no"});
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function handleMessage(event) {
|
||||
// FIXME(kitcambridge): Enable when `ServiceWorkerMessageEvent` is
|
||||
// implemented (bug 1143717).
|
||||
/*
|
||||
if (event.data.type == "publicKey") {
|
||||
self.registration.pushManager.getSubscription().then(subscription => {
|
||||
event.ports[0].postMessage(subscription.getKey("p256dh"));
|
||||
});
|
||||
event.waitUntil(self.registration.pushManager.getSubscription().then(subscription => {
|
||||
event.ports[0].postMessage({
|
||||
p256dh: subscription.getKey("p256dh"),
|
||||
auth: subscription.getKey("auth"),
|
||||
});
|
||||
}).catch(error => {
|
||||
event.ports[0].postMessage({
|
||||
error: String(error),
|
||||
});
|
||||
}));
|
||||
return;
|
||||
}
|
||||
*/
|
||||
event.ports[0].postMessage({
|
||||
error: "Invalid message type: " + event.data.type,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ SettingsDB.prototype = {
|
||||
let chan = NetUtil.newChannel({
|
||||
uri: NetUtil.newURI(settingsFile),
|
||||
loadUsingSystemPrincipal: true});
|
||||
let stream = chan.open();
|
||||
let stream = chan.open2();
|
||||
// Obtain a converter to read from a UTF-8 encoded input stream.
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
||||
@@ -31,6 +31,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
|
||||
|
||||
function doTest() {
|
||||
var win = $("t").contentWindow;
|
||||
ok(isXrayWrapper(win),
|
||||
"We want to be testing things with an Xray as sandboxPrototype here");
|
||||
|
||||
var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
|
||||
|
||||
is(sandbox._content, undefined, "_content does nothing over Xray");
|
||||
@@ -285,6 +288,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
|
||||
ok(false, "Setting expandos on Xrays shouldn't throw " + e);
|
||||
}
|
||||
|
||||
// Test that binding a bareword window method produces something
|
||||
// which has a .call
|
||||
try {
|
||||
var binary = Components.utils.evalInSandbox(
|
||||
'btoa.bind(window).call(null, "foo")', sandbox);
|
||||
is(binary, "Zm9v", "Should get the right result from .call on bound btoa");
|
||||
} catch (e) {
|
||||
ok(false, ".call on bound btoa shouldn't throw " + e);
|
||||
}
|
||||
|
||||
// Test that binding a bareword window method produces something
|
||||
// which has a .apply
|
||||
try {
|
||||
var binary = Components.utils.evalInSandbox(
|
||||
'btoa.bind(window).apply(null, ["foo"])', sandbox);
|
||||
is(binary, "Zm9v", "Should get the right result from .apply on bound btoa");
|
||||
} catch (e) {
|
||||
ok(false, ".apply on bound btoa shouldn't throw " + e);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
[ChromeOnly,
|
||||
Exposed=(Window,Worker)]
|
||||
Exposed=(Window,Worker, WorkerDebugger)]
|
||||
interface Console {
|
||||
void log(any... data);
|
||||
void info(any... data);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* http://xhr.spec.whatwg.org
|
||||
*/
|
||||
|
||||
typedef (File or USVString) FormDataEntryValue;
|
||||
typedef (Blob or USVString) FormDataEntryValue;
|
||||
|
||||
[Constructor(optional HTMLFormElement form),
|
||||
Exposed=(Window,Worker)]
|
||||
|
||||
@@ -15,6 +15,18 @@ enum PushEncryptionKeyName
|
||||
"auth"
|
||||
};
|
||||
|
||||
dictionary PushSubscriptionKeys
|
||||
{
|
||||
ByteString p256dh;
|
||||
ByteString auth;
|
||||
};
|
||||
|
||||
dictionary PushSubscriptionJSON
|
||||
{
|
||||
USVString endpoint;
|
||||
PushSubscriptionKeys keys;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
|
||||
ChromeConstructor(DOMString pushEndpoint, DOMString scope,
|
||||
ArrayBuffer? key, ArrayBuffer? authSecret)]
|
||||
@@ -24,7 +36,9 @@ interface PushSubscription
|
||||
ArrayBuffer? getKey(PushEncryptionKeyName name);
|
||||
[Throws, UseCounter]
|
||||
Promise<boolean> unsubscribe();
|
||||
jsonifier;
|
||||
|
||||
// Implements the custom serializer specified in Push API, section 9.
|
||||
PushSubscriptionJSON toJSON();
|
||||
|
||||
// Used to set the principal from the JS implemented PushManager.
|
||||
[Exposed=Window,ChromeOnly]
|
||||
|
||||
@@ -19,17 +19,17 @@ dictionary Algorithm {
|
||||
};
|
||||
|
||||
dictionary AesCbcParams : Algorithm {
|
||||
required CryptoOperationData iv;
|
||||
required BufferSource iv;
|
||||
};
|
||||
|
||||
dictionary AesCtrParams : Algorithm {
|
||||
required CryptoOperationData counter;
|
||||
required BufferSource counter;
|
||||
[EnforceRange] required octet length;
|
||||
};
|
||||
|
||||
dictionary AesGcmParams : Algorithm {
|
||||
required CryptoOperationData iv;
|
||||
CryptoOperationData additionalData;
|
||||
required BufferSource iv;
|
||||
BufferSource additionalData;
|
||||
[EnforceRange] octet tagLength;
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ dictionary HmacImportParams : Algorithm {
|
||||
};
|
||||
|
||||
dictionary Pbkdf2Params : Algorithm {
|
||||
required CryptoOperationData salt;
|
||||
required BufferSource salt;
|
||||
[EnforceRange] required unsigned long iterations;
|
||||
required AlgorithmIdentifier hash;
|
||||
};
|
||||
@@ -63,7 +63,11 @@ dictionary RsaHashedKeyGenParams : Algorithm {
|
||||
};
|
||||
|
||||
dictionary RsaOaepParams : Algorithm {
|
||||
CryptoOperationData label;
|
||||
BufferSource label;
|
||||
};
|
||||
|
||||
dictionary RsaPssParams : Algorithm {
|
||||
[EnforceRange] required unsigned long saltLength;
|
||||
};
|
||||
|
||||
dictionary DhKeyGenParams : Algorithm {
|
||||
@@ -104,6 +108,12 @@ dictionary EcKeyImportParams : Algorithm {
|
||||
NamedCurve namedCurve;
|
||||
};
|
||||
|
||||
dictionary HkdfParams : Algorithm {
|
||||
required AlgorithmIdentifier hash;
|
||||
required BufferSource salt;
|
||||
required BufferSource info;
|
||||
};
|
||||
|
||||
/***** JWK *****/
|
||||
|
||||
dictionary RsaOtherPrimesInfo {
|
||||
@@ -155,30 +165,29 @@ dictionary CryptoKeyPair {
|
||||
};
|
||||
|
||||
typedef DOMString KeyFormat;
|
||||
typedef (ArrayBufferView or ArrayBuffer) CryptoOperationData;
|
||||
typedef (object or DOMString) AlgorithmIdentifier;
|
||||
|
||||
interface SubtleCrypto {
|
||||
[Throws]
|
||||
Promise<any> encrypt(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
CryptoOperationData data);
|
||||
BufferSource data);
|
||||
[Throws]
|
||||
Promise<any> decrypt(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
CryptoOperationData data);
|
||||
BufferSource data);
|
||||
[Throws]
|
||||
Promise<any> sign(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
CryptoOperationData data);
|
||||
BufferSource data);
|
||||
[Throws]
|
||||
Promise<any> verify(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
CryptoOperationData signature,
|
||||
CryptoOperationData data);
|
||||
BufferSource signature,
|
||||
BufferSource data);
|
||||
[Throws]
|
||||
Promise<any> digest(AlgorithmIdentifier algorithm,
|
||||
CryptoOperationData data);
|
||||
BufferSource data);
|
||||
|
||||
[Throws]
|
||||
Promise<any> generateKey(AlgorithmIdentifier algorithm,
|
||||
@@ -212,7 +221,7 @@ interface SubtleCrypto {
|
||||
|
||||
[Throws]
|
||||
Promise<any> unwrapKey(KeyFormat format,
|
||||
CryptoOperationData wrappedKey,
|
||||
BufferSource wrappedKey,
|
||||
CryptoKey unwrappingKey,
|
||||
AlgorithmIdentifier unwrapAlgorithm,
|
||||
AlgorithmIdentifier unwrappedKeyAlgorithm,
|
||||
|
||||
@@ -29,4 +29,7 @@ interface WorkerDebuggerGlobalScope : EventTarget {
|
||||
// So you can debug while you debug
|
||||
partial interface WorkerDebuggerGlobalScope {
|
||||
void dump(optional DOMString string);
|
||||
|
||||
[Throws, Replaceable]
|
||||
readonly attribute Console console;
|
||||
};
|
||||
|
||||
@@ -663,6 +663,25 @@ WorkerDebuggerGlobalScope::~WorkerDebuggerGlobalScope()
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerDebuggerGlobalScope)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper)
|
||||
|
||||
@@ -905,6 +924,19 @@ WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
|
||||
mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
|
||||
}
|
||||
|
||||
Console*
|
||||
WorkerDebuggerGlobalScope::GetConsole(ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// Debugger console has its own console object.
|
||||
if (!mConsole) {
|
||||
mConsole = new Console(nullptr);
|
||||
}
|
||||
|
||||
return mConsole;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
|
||||
const Optional<nsAString>& aString) const
|
||||
|
||||
@@ -275,11 +275,14 @@ class WorkerDebuggerGlobalScope final : public DOMEventTargetHelper,
|
||||
public nsIGlobalObject
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
RefPtr<Console> mConsole;
|
||||
|
||||
public:
|
||||
explicit WorkerDebuggerGlobalScope(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerDebuggerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
@@ -327,6 +330,9 @@ public:
|
||||
void
|
||||
ReportError(JSContext* aCx, const nsAString& aMessage);
|
||||
|
||||
Console*
|
||||
GetConsole(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Dump(JSContext* aCx, const Optional<nsAString>& aString) const;
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
const STDURL_CTRID = "@mozilla.org/network/standard-url;1";
|
||||
const nsIURI = Components.interfaces.nsIURI;
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var gStop = false;
|
||||
|
||||
function loadFile(aUriSpec)
|
||||
@@ -22,17 +24,13 @@ function loadFile(aUriSpec)
|
||||
if (!serv) {
|
||||
throw Components.results.ERR_FAILURE;
|
||||
}
|
||||
var chan = serv.newChannel2(aUriSpec,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
var chan = NetUtil.newChannel({
|
||||
uri: aUriSpec,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
var instream =
|
||||
Components.classes[SIS_CTRID].createInstance(nsISIS);
|
||||
instream.init(chan.open());
|
||||
instream.init(chan.open2());
|
||||
|
||||
return instream.read(instream.available());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var parser = new DOMParser();
|
||||
var methodExpr = (new XPathEvaluator).createExpression("xsl:output/@method",
|
||||
{
|
||||
@@ -307,21 +309,12 @@ runItem.prototype =
|
||||
|
||||
loadTextFile : function(url)
|
||||
{
|
||||
var serv = Components.classes[IOSERVICE_CTRID].
|
||||
getService(nsIIOService);
|
||||
if (!serv) {
|
||||
throw Components.results.ERR_FAILURE;
|
||||
}
|
||||
var chan = serv.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
var chan = NetUtil.newChannel({
|
||||
uri: url,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
var instream = doCreate(SIS_CTRID, nsISIS);
|
||||
instream.init(chan.open());
|
||||
instream.init(chan.open2());
|
||||
|
||||
return instream.read(instream.available());
|
||||
}
|
||||
|
||||
@@ -287,8 +287,7 @@ void mozPersonalDictionary::SyncLoadInternal()
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(inStream), mFile);
|
||||
|
||||
nsCOMPtr<nsIUnicharInputStream> convStream;
|
||||
rv = nsSimpleUnicharStreamFactory::GetInstance()->
|
||||
CreateInstanceFromUTF8Stream(inStream, getter_AddRefs(convStream));
|
||||
rv = NS_NewUnicharInputStream(inStream, getter_AddRefs(convStream));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -710,8 +710,12 @@ WrapCallable(JSContext* cx, HandleObject callable, HandleObject sandboxProtoProx
|
||||
&xpc::sandboxProxyHandler);
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*callable));
|
||||
// We want to claim to have the same proto as our wrapped callable, so set
|
||||
// ourselves up with a lazy proto.
|
||||
js::ProxyOptions options;
|
||||
options.setLazyProto(true);
|
||||
JSObject* obj = js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
|
||||
priv, nullptr);
|
||||
priv, nullptr, options);
|
||||
if (obj) {
|
||||
js::SetProxyExtra(obj, SandboxCallableProxyHandler::SandboxProxySlot,
|
||||
ObjectValue(*sandboxProtoProxy));
|
||||
@@ -1016,6 +1020,9 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
||||
|
||||
auto& creationOptions = compartmentOptions.creationOptions();
|
||||
|
||||
if (xpc::SharedMemoryEnabled())
|
||||
creationOptions.setSharedMemoryAndAtomicsEnabled(true);
|
||||
|
||||
if (options.sameZoneAs)
|
||||
creationOptions.setSameZoneAs(js::UncheckedUnwrap(options.sameZoneAs));
|
||||
else if (options.freshZone)
|
||||
|
||||
@@ -183,6 +183,8 @@ XPCWrappedNative::WrapNewGlobal(xpcObjectHelper& nativeHelper,
|
||||
|
||||
// Create the global.
|
||||
aOptions.creationOptions().setTrace(XPCWrappedNative::Trace);
|
||||
if (xpc::SharedMemoryEnabled())
|
||||
aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
|
||||
RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions));
|
||||
if (!global)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<input min="-10" max="10" step="0.1" type="range" value="-5"/>
|
||||
<input max="50" min="10" step="2" type="range" value="7"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -55,6 +55,7 @@ load 639733.xhtml
|
||||
load 669767.html
|
||||
load 682684.xhtml
|
||||
load 865602.html
|
||||
load 893332-1.html
|
||||
load 944198.html
|
||||
load 949891.xhtml
|
||||
load 959311.html
|
||||
|
||||
@@ -27,6 +27,27 @@ var gDeclaration = document.getElementById("testnode").style;
|
||||
|
||||
var gTestUnset = SpecialPowers.getBoolPref("layout.css.unset-value.enabled");
|
||||
|
||||
/**
|
||||
* Checks that the passed-in property-value (returned by getPropertyValue) is
|
||||
* consistent with the DOM accessors that we know about for the given sproperty.
|
||||
*/
|
||||
function check_consistency(sproperty, valFromGetPropertyValue, messagePrefix)
|
||||
{
|
||||
var sinfo = gCSSProperties[sproperty];
|
||||
is(valFromGetPropertyValue, gDeclaration[sinfo.domProp],
|
||||
`(${messagePrefix}) consistency between ` +
|
||||
`decl.getPropertyValue(${sproperty}) and decl.${sinfo.domProp}`);
|
||||
|
||||
if (sinfo.domProp.startsWith("webkit")) {
|
||||
// For webkit-prefixed DOM accessors, test with lowercase and uppercase
|
||||
// first letter.
|
||||
var uppercaseDomProp = "W" + sinfo.domProp.substring(1);
|
||||
is(valFromGetPropertyValue, gDeclaration[uppercaseDomProp],
|
||||
`(${messagePrefix}) consistency between ` +
|
||||
`decl.getPropertyValue(${sproperty}) and decl.${uppercaseDomProp}`);
|
||||
}
|
||||
}
|
||||
|
||||
function test_property(property)
|
||||
{
|
||||
var info = gCSSProperties[property];
|
||||
@@ -37,12 +58,9 @@ function test_property(property)
|
||||
|
||||
keywords.forEach(function(keyword) {
|
||||
function check_initial(sproperty) {
|
||||
var sinfo = gCSSProperties[sproperty];
|
||||
var val = gDeclaration.getPropertyValue(sproperty);
|
||||
is(val, "", "value of '" + sproperty + "' before we do anything");
|
||||
is(val, gDeclaration[sinfo.domProp],
|
||||
"(initial) consistency between decl.getPropertyValue('" + sproperty +
|
||||
"') and decl." + sinfo.domProp);
|
||||
check_consistency(sproperty, val, "initial");
|
||||
}
|
||||
check_initial(property);
|
||||
if ("subproperties" in info)
|
||||
@@ -52,13 +70,10 @@ function test_property(property)
|
||||
gDeclaration.setProperty(property, keyword, "");
|
||||
|
||||
function check_set(sproperty) {
|
||||
var sinfo = gCSSProperties[sproperty];
|
||||
val = gDeclaration.getPropertyValue(sproperty);
|
||||
is(val, keyword,
|
||||
keyword + " reported back for property '" + sproperty + "'");
|
||||
is(val, gDeclaration[sinfo.domProp],
|
||||
"(set) consistency between decl.getPropertyValue('" + sproperty +
|
||||
"') and decl." + sinfo.domProp);
|
||||
check_consistency(sproperty, val, "set");
|
||||
}
|
||||
check_set(property);
|
||||
if ("subproperties" in info)
|
||||
@@ -78,12 +93,9 @@ function test_property(property)
|
||||
gDeclaration.removeProperty(property);
|
||||
|
||||
function check_final(sproperty) {
|
||||
var sinfo = gCSSProperties[sproperty];
|
||||
var val = gDeclaration.getPropertyValue(sproperty);
|
||||
is(val, "", "value of '" + sproperty + "' after removal of value");
|
||||
is(val, gDeclaration[sinfo.domProp],
|
||||
"(final) consistency between decl.getPropertyValue('" + sproperty +
|
||||
"') and decl." + sinfo.domProp);
|
||||
check_consistency(sproperty, val, "final");
|
||||
}
|
||||
check_final(property);
|
||||
if ("subproperties" in info)
|
||||
|
||||
@@ -30,10 +30,10 @@ typedef union
|
||||
|
||||
struct PrefHashEntry : PLDHashEntryHdr
|
||||
{
|
||||
uint16_t flags; // This field goes first to minimize struct size on 64-bit.
|
||||
const char *key;
|
||||
PrefValue defaultPref;
|
||||
PrefValue userPref;
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -725,8 +725,7 @@ nsExpatDriver::HandleExternalEntityRef(const char16_t *openEntityNames,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIUnicharInputStream> uniIn;
|
||||
rv = nsSimpleUnicharStreamFactory::GetInstance()->
|
||||
CreateInstanceFromUTF8Stream(in, getter_AddRefs(uniIn));
|
||||
rv = NS_NewUnicharInputStream(in, getter_AddRefs(uniIn));
|
||||
NS_ENSURE_SUCCESS(rv, 1);
|
||||
|
||||
int result = 1;
|
||||
|
||||
@@ -131,6 +131,9 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPK11Context,
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSGNContext,
|
||||
SGNContext,
|
||||
mozilla::psm::SGN_DestroyContext_true)
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSGNDigestInfo,
|
||||
SGNDigestInfo,
|
||||
SGN_DestroyDigestInfo)
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedVFYContext,
|
||||
VFYContext,
|
||||
mozilla::psm::VFY_DestroyContext_true)
|
||||
|
||||
@@ -2,10 +2,3 @@
|
||||
type: testharness
|
||||
[If there are two imgs, a collection should be returned. (name)]
|
||||
expected: FAIL
|
||||
|
||||
[If there is one img, it should not be returned (id)]
|
||||
expected: FAIL
|
||||
|
||||
[If there are two imgs, nothing should be returned. (id)]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<img id=test3>
|
||||
|
||||
<img id=test4>
|
||||
<img id=test4>
|
||||
<img id=test4 name="">
|
||||
|
||||
<img name=test5>
|
||||
<img id=test5>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/* 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/. */
|
||||
|
||||
table.listing {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table th, table td {
|
||||
padding: 5px;
|
||||
border: inset 2px black;
|
||||
margin: 0px;
|
||||
width: 50%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
hr {
|
||||
clear: both;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 900px;
|
||||
}
|
||||
|
||||
#player, #raw {
|
||||
width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#controls {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
border: solid 1px black;
|
||||
}
|
||||
|
||||
#active {
|
||||
width: 100%;
|
||||
border: solid 1px black;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#trace {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var trace;
|
||||
var service;
|
||||
var reports;
|
||||
|
||||
function onLoad() {
|
||||
trace = document.getElementById('trace');
|
||||
service = new CheckerboardReportService();
|
||||
updateEnabled();
|
||||
reports = service.getReports();
|
||||
for (var i = 0; i < reports.length; i++) {
|
||||
let text = "Severity " + reports[i].severity + " at " + new Date(reports[i].timestamp).toString();
|
||||
let link = document.createElement('a');
|
||||
link.href = 'javascript:showReport(' + i + ')';
|
||||
link.textContent = text;
|
||||
let bullet = document.createElement('li');
|
||||
bullet.appendChild(link);
|
||||
document.getElementById(reports[i].reason).appendChild(bullet);
|
||||
}
|
||||
}
|
||||
|
||||
function updateEnabled() {
|
||||
let enabled = document.getElementById('enabled');
|
||||
if (service.isRecordingEnabled()) {
|
||||
enabled.textContent = 'enabled';
|
||||
enabled.style.color = 'green';
|
||||
} else {
|
||||
enabled.textContent = 'disabled';
|
||||
enabled.style.color = 'red';
|
||||
}
|
||||
}
|
||||
|
||||
function toggleEnabled() {
|
||||
service.setRecordingEnabled(!service.isRecordingEnabled());
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
function showReport(index) {
|
||||
trace.value = reports[index].log;
|
||||
loadData();
|
||||
}
|
||||
|
||||
// -- Code to load and render the trace --
|
||||
|
||||
const CANVAS_USE_RATIO = 0.75;
|
||||
const FRAME_INTERVAL_MS = 50;
|
||||
const VECTOR_NORMALIZED_MAGNITUDE = 30.0;
|
||||
|
||||
var renderData = new Array();
|
||||
var currentFrame = 0;
|
||||
var playing = false;
|
||||
var timerId = 0;
|
||||
|
||||
var minX = undefined;
|
||||
var minY = undefined;
|
||||
var maxX = undefined;
|
||||
var maxY = undefined;
|
||||
|
||||
function log(x) {
|
||||
if (console) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
|
||||
function getFlag(flag) {
|
||||
return document.getElementById(flag).checked;
|
||||
}
|
||||
|
||||
// parses the lines in the textarea, ignoring anything that doesn't have RENDERTRACE.
|
||||
// for each matching line, tokenizes on whitespace and ignores all tokens prior to
|
||||
// RENDERTRACE. Additional info can be included at the end of the line, and will be
|
||||
// displayed but not parsed. Allowed syntaxes:
|
||||
// <junk> RENDERTRACE <timestamp> rect <color> <x> <y> <width> <height> [extraInfo]
|
||||
function loadData() {
|
||||
stopPlay();
|
||||
renderData = new Array();
|
||||
currentFrame = 0;
|
||||
minX = undefined;
|
||||
minY = undefined;
|
||||
maxX = undefined;
|
||||
maxY = undefined;
|
||||
|
||||
var charPos = 0;
|
||||
var lastLineLength = 0;
|
||||
var lines = trace.value.split(/\r|\n/);
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
charPos += lastLineLength;
|
||||
lastLineLength = lines[i].length + 1;
|
||||
// skip lines without RENDERTRACE
|
||||
if (! /RENDERTRACE/.test(lines[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tokens = lines[i].split(/\s+/);
|
||||
var j = 0;
|
||||
// skip tokens until RENDERTRACE
|
||||
while (j < tokens.length && tokens[j++] != "RENDERTRACE"); // empty loop body
|
||||
if (j >= tokens.length - 2) {
|
||||
log("Error parsing line: " + lines[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
var timestamp = tokens[j++];
|
||||
var destIndex = renderData.length;
|
||||
if (destIndex == 0) {
|
||||
// create the initial frame
|
||||
renderData.push({
|
||||
timestamp: timestamp,
|
||||
rects: {},
|
||||
});
|
||||
} else if (renderData[destIndex - 1].timestamp == timestamp) {
|
||||
// timestamp hasn't changed use, so update the previous object
|
||||
destIndex--;
|
||||
} else {
|
||||
// clone a new copy of the last frame and update timestamp
|
||||
renderData.push(JSON.parse(JSON.stringify(renderData[destIndex - 1])));
|
||||
renderData[destIndex].timestamp = timestamp;
|
||||
}
|
||||
|
||||
switch (tokens[j++]) {
|
||||
case "rect":
|
||||
if (j > tokens.length - 5) {
|
||||
log("Error parsing line: " + lines[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
var rect = {};
|
||||
var color = tokens[j++];
|
||||
renderData[destIndex].rects[color] = rect;
|
||||
rect.x = parseFloat(tokens[j++]);
|
||||
rect.y = parseFloat(tokens[j++]);
|
||||
rect.width = parseFloat(tokens[j++]);
|
||||
rect.height = parseFloat(tokens[j++]);
|
||||
rect.dataText = trace.value.substring(charPos, charPos + lines[i].length);
|
||||
|
||||
if (!getFlag('excludePageFromZoom') || color != 'brown') {
|
||||
if (typeof minX == "undefined") {
|
||||
minX = rect.x;
|
||||
minY = rect.y;
|
||||
maxX = rect.x + rect.width;
|
||||
maxY = rect.y + rect.height;
|
||||
} else {
|
||||
minX = Math.min(minX, rect.x);
|
||||
minY = Math.min(minY, rect.y);
|
||||
maxX = Math.max(maxX, rect.x + rect.width);
|
||||
maxY = Math.max(maxY, rect.y + rect.height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log("Error parsing line " + lines[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! renderFrame()) {
|
||||
alert("No data found; nothing to render!");
|
||||
}
|
||||
}
|
||||
|
||||
// render the current frame (i.e. renderData[currentFrame])
|
||||
// returns false if currentFrame is out of bounds, true otherwise
|
||||
function renderFrame() {
|
||||
var frame = currentFrame;
|
||||
if (frame < 0 || frame >= renderData.length) {
|
||||
log("Invalid frame index");
|
||||
return false;
|
||||
}
|
||||
|
||||
var canvas = document.getElementById('canvas');
|
||||
if (! canvas.getContext) {
|
||||
log("No canvas context");
|
||||
}
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
// midpoint of the bounding box
|
||||
var midX = (minX + maxX) / 2.0;
|
||||
var midY = (minY + maxY) / 2.0;
|
||||
|
||||
// midpoint of the canvas
|
||||
var cmx = canvas.width / 2.0;
|
||||
var cmy = canvas.height / 2.0;
|
||||
|
||||
// scale factor
|
||||
var scale = CANVAS_USE_RATIO * Math.min(canvas.width / (maxX - minX), canvas.height / (maxY - minY));
|
||||
|
||||
function projectX(value) {
|
||||
return cmx + ((value - midX) * scale);
|
||||
}
|
||||
|
||||
function projectY(value) {
|
||||
return cmy + ((value - midY) * scale);
|
||||
}
|
||||
|
||||
function drawRect(color, rect) {
|
||||
context.strokeStyle = color;
|
||||
context.strokeRect(
|
||||
projectX(rect.x),
|
||||
projectY(rect.y),
|
||||
rect.width * scale,
|
||||
rect.height * scale);
|
||||
}
|
||||
|
||||
// clear canvas
|
||||
context.fillStyle = 'white';
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
var activeData = '';
|
||||
// draw rects
|
||||
for (var i in renderData[frame].rects) {
|
||||
drawRect(i, renderData[frame].rects[i]);
|
||||
activeData += "\n" + renderData[frame].rects[i].dataText;
|
||||
}
|
||||
// draw timestamp and frame counter
|
||||
context.fillStyle = 'black';
|
||||
context.fillText((frame + 1) + "/" + renderData.length + ": " + renderData[frame].timestamp, 5, 15);
|
||||
|
||||
document.getElementById('active').textContent = activeData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -- Player controls --
|
||||
|
||||
function reset(beginning) {
|
||||
currentFrame = (beginning ? 0 : renderData.length - 1);
|
||||
renderFrame();
|
||||
}
|
||||
|
||||
function step(backwards) {
|
||||
if (playing) {
|
||||
togglePlay();
|
||||
}
|
||||
currentFrame += (backwards ? -1 : 1);
|
||||
if (! renderFrame()) {
|
||||
currentFrame -= (backwards ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
function pause() {
|
||||
clearInterval(timerId);
|
||||
playing = false;
|
||||
}
|
||||
|
||||
function togglePlay() {
|
||||
if (playing) {
|
||||
pause();
|
||||
} else {
|
||||
timerId = setInterval(function() {
|
||||
currentFrame++;
|
||||
if (! renderFrame()) {
|
||||
currentFrame--;
|
||||
togglePlay();
|
||||
}
|
||||
}, FRAME_INTERVAL_MS);
|
||||
playing = true;
|
||||
}
|
||||
}
|
||||
|
||||
function stopPlay() {
|
||||
if (playing) {
|
||||
togglePlay();
|
||||
}
|
||||
currentFrame = 0;
|
||||
renderFrame();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<link rel="stylesheet" href="chrome://global/content/aboutCheckerboard.css" type="text/css"/>
|
||||
<script type="text/javascript;version=1.8" src="chrome://global/content/aboutCheckerboard.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="onLoad()">
|
||||
<p>Checkerboard recording is <span id="enabled" style="color: red">undetermined</span>.
|
||||
<button onclick="toggleEnabled()">Toggle it!</button>.</p>
|
||||
<table class="listing" cellspacing="0">
|
||||
<tr>
|
||||
<th>Most severe checkerboarding reports</th>
|
||||
<th>Most recent checkerboarding reports</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><ul id="severe"></ul></td>
|
||||
<td><ul id="recent"></ul></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div id="player">
|
||||
<div id="controls">
|
||||
<button onclick="reset(true)">«</button><!-- rewind button -->
|
||||
<button onclick="step(true)"><</button><!-- step back button -->
|
||||
<button onclick="togglePlay()">|| ▶</button><!-- pause button -->
|
||||
<button onclick="stopPlay()">☐</button><!-- stop button -->
|
||||
<button onclick="step(false)">></button><!-- step forward button -->
|
||||
<button onclick="reset(false)">»</button><!-- forward button -->
|
||||
</div>
|
||||
<canvas id="canvas" width="800" height="600">Canvas not supported!</canvas>
|
||||
<pre id="active">(Details for currently visible replay frame)</pre>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div id="raw">
|
||||
Raw log:<br/>
|
||||
<textarea id="trace" rows="10"></textarea>
|
||||
<div>
|
||||
<input type="checkbox" id="excludePageFromZoom" onclick="loadData()"/><label for="excludePageFromZoom">Exclude page coordinates from zoom calculations</label><br/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
# 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/.
|
||||
|
||||
toolkit.jar:
|
||||
content/global/aboutCheckerboard.js (content/aboutCheckerboard.js)
|
||||
content/global/aboutCheckerboard.xhtml (content/aboutCheckerboard.xhtml)
|
||||
content/global/aboutCheckerboard.css (content/aboutCheckerboard.css)
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- 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/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Core', 'Panning and Zooming')
|
||||
@@ -5947,6 +5947,13 @@
|
||||
"n_values": 256,
|
||||
"description": "WMF media decoder error or success (0) codes."
|
||||
},
|
||||
"MEDIA_OGG_LOADED_IS_CHAINED": {
|
||||
"alert_emails": ["cpearce@mozilla.com"],
|
||||
"expires_in_version": "53",
|
||||
"kind": "boolean",
|
||||
"description": "Whether Ogg audio/video encountered are chained or not.",
|
||||
"bug_numbers": [1230295]
|
||||
},
|
||||
"VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG": {
|
||||
"expires_in_version": "40",
|
||||
"kind": "enumerated",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user