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:
2023-12-29 16:00:23 +08:00
parent aec5e5666e
commit c5205b44c8
109 changed files with 2508 additions and 805 deletions
+2 -2
View File
@@ -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
+75 -43
View File
@@ -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);
+21
View File
@@ -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);
});
}
+5
View File
@@ -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
+5
View File
@@ -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 |
+4 -7
View File
@@ -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__
+1
View File
@@ -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 },
+16 -7
View File
@@ -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"];
+7 -7
View File
@@ -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;
};
-5
View File
@@ -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,
+7 -9
View File
@@ -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;
+3 -3
View File
@@ -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");
+3 -3
View File
@@ -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;
+3 -3
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+7 -8
View File
@@ -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;
+3 -2
View File
@@ -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;
}
+8 -3
View File
@@ -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,
+1 -2
View File
@@ -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");
+1 -1
View File
@@ -18,7 +18,7 @@
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () testCopyPaste(false));
addLoadEvent(() => testCopyPaste(false));
</script>
</pre>
+1 -1
View File
@@ -32,7 +32,7 @@ function modifySelectionDiv12() {
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () testCopyPaste(true));
addLoadEvent(() => testCopyPaste(true));
]]>
</script>
+1 -1
View File
@@ -510,6 +510,6 @@
[ 'addToDoc' ],
[ 'displayInherit' ]
)});
runWhenDone(function() SimpleTest.finish());
runWhenDone(() => SimpleTest.finish());
}
</script>
+7 -3
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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)
+9 -1
View File
@@ -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()
+25 -12
View File
@@ -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()
-5
View File
@@ -139,8 +139,3 @@ if CONFIG['MOZ_SIMPLEPUSH']:
PYTHON_UNIT_TESTS += [
'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
]
if CONFIG['GNU_CC']:
CXXFLAGS += [
'-Wno-uninitialized',
]
+9 -3
View File
@@ -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"
-5
View File
@@ -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.
+30 -30
View File
@@ -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");
+11 -11
View File
@@ -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
+1 -1
View File
@@ -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",
+6
View File
@@ -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
View File
@@ -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, &params,
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,
+2
View File
@@ -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]
+111 -1
View File
@@ -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"
)
}
]
}
+351
View File
@@ -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",
+110
View File
@@ -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>
+1 -1
View File
@@ -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" : "";
+32 -20
View File
@@ -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
View File
@@ -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;
}
+37 -23
View File
@@ -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;
}
+8 -7
View File
@@ -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;
+11 -5
View File
@@ -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
+3
View File
@@ -91,6 +91,9 @@ nsGenericHTMLFrameElement::GetContentDocument()
}
nsIDocument *doc = win->GetDoc();
if (!doc) {
return nullptr;
}
// Return null for cross-origin contentDocument.
if (!nsContentUtils::SubjectPrincipal()->
+14 -5
View File
@@ -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;
+6 -5
View File
@@ -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);
+15
View File
@@ -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
+1 -1
View File
@@ -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");
+6 -6
View File
@@ -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() {
+6 -4
View File
@@ -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);
}
}
+21 -5
View File
@@ -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;
}
}
+1 -1
View File
@@ -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.
+33
View File
@@ -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)
+6
View File
@@ -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();
+6 -4
View File
@@ -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();
});
},
/**
+11 -21
View File
@@ -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) {
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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,
});
}
+1 -1
View File
@@ -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();
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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 -1
View File
@@ -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]
+23 -14
View File
@@ -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;
};
+32
View File
@@ -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
+6
View File
@@ -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;
+7 -9
View File
@@ -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());
}
+7 -14
View File
@@ -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;
}
+8 -1
View File
@@ -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)
+2
View File
@@ -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;
+10
View File
@@ -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>
+1
View File
@@ -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
+24 -12
View File
@@ -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)
+1 -1
View File
@@ -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;
};
/*
+1 -2
View File
@@ -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;
+3
View File
@@ -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)">&#171;</button><!-- rewind button -->
<button onclick="step(true)">&lt;</button><!-- step back button -->
<button onclick="togglePlay()">|| &#9654;</button><!-- pause button -->
<button onclick="stopPlay()">&#9744;</button><!-- stop button -->
<button onclick="step(false)">&gt;</button><!-- step forward button -->
<button onclick="reset(false)">&#187;</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