--- a/dom/push/PushComponents.js
+++ b/dom/push/PushComponents.js
@@ -140,18 +140,17 @@ Object.assign(PushServiceParent.prototyp
}).then(result => {
this._deliverSubscription(callback, result);
}, error => {
callback.onPushSubscription(Cr.NS_ERROR_FAILURE, null);
}).catch(Cu.reportError);
},
clearForDomain(domain, callback) {
- let principal = Services.scriptSecurityManager.getSystemPrincipal();
- return this._handleRequest("Push:Clear", principal, {
+ return this._handleRequest("Push:Clear", null, {
domain: domain,
}).then(result => {
callback.onClear(Cr.NS_OK);
}, error => {
callback.onClear(Cr.NS_ERROR_FAILURE);
}).catch(Cu.reportError);
},
@@ -205,28 +204,35 @@ Object.assign(PushServiceParent.prototyp
_handleReady() {
this._service.init();
},
_toPageRecord(principal, data) {
if (!data.scope) {
throw new Error("Invalid page record: missing scope");
}
+ if (!principal) {
+ throw new Error("Invalid page record: missing principal");
+ }
+ if (principal.isNullPrincipal || principal.isExpandedPrincipal) {
+ throw new Error("Invalid page record: unsupported principal");
+ }
+
+ // System subscriptions can only be created by chrome callers, and are
+ // exempt from the background message quota and permission checks. They
+ // also use XPCOM observer notifications instead of service worker events.
+ data.systemRecord = principal.isSystemPrincipal;
data.originAttributes =
ChromeUtils.originAttributesToSuffix(principal.originAttributes);
return data;
},
_handleRequest(name, principal, data) {
- if (!principal) {
- return Promise.reject(new Error("Invalid request: missing principal"));
- }
-
if (name == "Push:Clear") {
return this._service.clear(data);
}
let pageRecord;
try {
pageRecord = this._toPageRecord(principal, data);
} catch (e) {
--- a/dom/push/PushRecord.jsm
+++ b/dom/push/PushRecord.jsm
@@ -35,31 +35,33 @@ function PushRecord(props) {
this.pushEndpoint = props.pushEndpoint;
this.scope = props.scope;
this.originAttributes = props.originAttributes;
this.pushCount = props.pushCount || 0;
this.lastPush = props.lastPush || 0;
this.p256dhPublicKey = props.p256dhPublicKey;
this.p256dhPrivateKey = props.p256dhPrivateKey;
this.authenticationSecret = props.authenticationSecret;
+ this.systemRecord = !!props.systemRecord;
this.setQuota(props.quota);
this.ctime = (typeof props.ctime === "number") ? props.ctime : 0;
}
PushRecord.prototype = {
setQuota(suggestedQuota) {
- if (!isNaN(suggestedQuota) && suggestedQuota >= 0) {
+ if (this.quotaApplies() && !isNaN(suggestedQuota) && suggestedQuota >= 0) {
this.quota = suggestedQuota;
} else {
this.resetQuota();
}
},
resetQuota() {
- this.quota = prefs.get("maxQuotaPerSubscription");
+ this.quota = this.quotaApplies() ?
+ prefs.get("maxQuotaPerSubscription") : Infinity;
},
updateQuota(lastVisit) {
if (this.isExpired() || !this.quotaApplies()) {
// Ignore updates if the registration is already expired, or isn't
// subject to quota.
return;
}
@@ -83,16 +85,19 @@ PushRecord.prototype = {
receivedPush(lastVisit) {
this.updateQuota(lastVisit);
this.pushCount++;
this.lastPush = Date.now();
},
reduceQuota() {
+ if (!this.quotaApplies()) {
+ return;
+ }
this.quota = Math.max(this.quota - 1, 0);
// We check for ctime > 0 to skip older records that did not have ctime.
if (this.isExpired() && this.ctime > 0) {
let duration = Date.now() - this.ctime;
Services.telemetry.getHistogramById("PUSH_API_QUOTA_EXPIRATION_TIME").add(duration / 1000);
}
},
@@ -184,41 +189,48 @@ PushRecord.prototype = {
}
}
}
return false;
},
/**
* Indicates whether the registration can deliver push messages to its
- * associated service worker.
+ * associated service worker. System subscriptions are exempt from the
+ * permission check.
*/
hasPermission() {
+ if (this.systemRecord || prefs.get("testing.ignorePermission")) {
+ return true;
+ }
let permission = Services.perms.testExactPermissionFromPrincipal(
this.principal, "desktop-notification");
return permission == Ci.nsIPermissionManager.ALLOW_ACTION;
},
quotaChanged() {
if (!this.hasPermission()) {
return Promise.resolve(false);
}
return this.getLastVisit()
.then(lastVisit => lastVisit > this.lastPush);
},
quotaApplies() {
- return Number.isFinite(this.quota);
+ return !this.systemRecord;
},
isExpired() {
return this.quota === 0;
},
matchesOriginAttributes(pattern) {
+ if (this.systemRecord) {
+ return false;
+ }
return ChromeUtils.originAttributesMatchPattern(
this.principal.originAttributes, pattern);
},
toSubscription() {
return {
endpoint: this.pushEndpoint,
lastPush: this.lastPush,
@@ -231,16 +243,19 @@ PushRecord.prototype = {
};
// Define lazy getters for the principal and scope URI. IndexedDB can't store
// `nsIPrincipal` objects, so we keep them in a private weak map.
var principals = new WeakMap();
Object.defineProperties(PushRecord.prototype, {
principal: {
get() {
+ if (this.systemRecord) {
+ return Services.scriptSecurityManager.getSystemPrincipal();
+ }
let principal = principals.get(this);
if (!principal) {
let url = this.scope;
if (this.originAttributes) {
// Allow tests to omit origin attributes.
url += this.originAttributes;
}
principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(url);
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -603,16 +603,20 @@ this.PushService = {
this._stateChangeProcessEnqueue(_ =>
this._changeServerURL("", UNINIT_EVENT));
console.debug("uninit: shutdown complete!");
},
/** |delay| should be in milliseconds. */
setAlarm: function(delay) {
+ if (this._state <= PUSH_SERVICE_ACTIVATING) {
+ return;
+ }
+
// Bug 909270: Since calls to AlarmService.add() are async, calls must be
// 'queued' to ensure only one alarm is ever active.
if (this._settingAlarm) {
// onSuccess will handle the set. Overwriting the variable enforces the
// last-writer-wins semantics.
this._queuedAlarmDelay = delay;
this._waitingForAlarmSet = true;
return;
@@ -892,17 +896,17 @@ this.PushService = {
// Record may have expired from an earlier quota update.
if (record.isExpired()) {
console.debug(
"updateQuota: Trying to update quota for expired record", record);
return null;
}
// If there are visible notifications, don't apply the quota penalty
// for the message.
- if (!this._visibleNotifications.has(record.uri.prePath)) {
+ if (record.uri && !this._visibleNotifications.has(record.uri.prePath)) {
record.reduceQuota();
}
return record;
}).then(record => {
if (record && record.isExpired()) {
this._recordDidNotNotify(kDROP_NOTIFICATION_REASON_EXPIRED);
// Drop the registration in the background. If the user returns to the
// site, the service worker will be notified on the next `idle-daily`
@@ -1198,17 +1202,17 @@ this.PushService = {
// exact match) the character before the index is a dot or slash.
let prevChar = str[index - 1];
return (index == (str.length - aDomain.length)) &&
(prevChar == "." || prevChar == "/");
}
let clear = (db, domain) => {
db.clearIf(record => {
- return hasRootDomain(record.uri.prePath, domain);
+ return record.uri && hasRootDomain(record.uri.prePath, domain);
});
}
return this._checkActivated()
.then(_ => clear(this._db, domain))
.catch(e => {
console.warn("clearForDomain: Error forgetting about domain", e);
return Promise.resolve();
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -316,17 +316,17 @@ SubscriptionListener.prototype = {
}
let reply = new PushRecordHttp2({
subscriptionUri: subscriptionUri,
pushEndpoint: linkParserResult.pushEndpoint,
pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
scope: this._subInfo.record.scope,
originAttributes: this._subInfo.record.originAttributes,
- quota: this._subInfo.record.maxQuota,
+ systemRecord: this._subInfo.record.systemRecord,
ctime: Date.now(),
});
Services.telemetry.getHistogramById("PUSH_API_SUBSCRIBE_HTTP2_TIME").add(Date.now() - this._ctime);
this._resolve(reply);
},
};
--- a/dom/push/PushServiceWebSocket.jsm
+++ b/dom/push/PushServiceWebSocket.jsm
@@ -837,17 +837,17 @@ this.PushServiceWebSocket = {
}
let record = new PushRecordWebSocket({
channelID: reply.channelID,
pushEndpoint: reply.pushEndpoint,
scope: tmp.record.scope,
originAttributes: tmp.record.originAttributes,
version: null,
- quota: tmp.record.maxQuota,
+ systemRecord: tmp.record.systemRecord,
ctime: Date.now(),
});
Services.telemetry.getHistogramById("PUSH_API_SUBSCRIBE_WS_TIME").add(Date.now() - tmp.ctime);
tmp.resolve(record);
} else {
console.error("handleRegisterReply: Unexpected server response", reply);
tmp.reject(new Error("Wrong status code for register reply: " +
reply.status));
--- a/dom/push/test/xpcshell/test_notification_ack.js
+++ b/dom/push/test/xpcshell/test_notification_ack.js
@@ -23,30 +23,33 @@ add_task(function* test_notification_ack
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
let records = [{
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
pushEndpoint: 'https://example.com/update/1',
scope: 'https://example.org/1',
originAttributes: '',
version: 1,
quota: Infinity,
+ systemRecord: true,
}, {
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
pushEndpoint: 'https://example.com/update/2',
scope: 'https://example.org/2',
originAttributes: '',
version: 2,
quota: Infinity,
+ systemRecord: true,
}, {
channelID: '5477bfda-22db-45d4-9614-fee369630260',
pushEndpoint: 'https://example.com/update/3',
scope: 'https://example.org/3',
originAttributes: '',
version: 3,
quota: Infinity,
+ systemRecord: true,
}];
for (let record of records) {
yield db.put(record);
}
let notifyPromise = Promise.all([
promiseObserverNotification('push-notification'),
promiseObserverNotification('push-notification'),
--- a/dom/push/test/xpcshell/test_notification_data.js
+++ b/dom/push/test/xpcshell/test_notification_data.js
@@ -21,16 +21,17 @@ function putRecord(channelID, scope, pub
return db.put({
channelID: channelID,
pushEndpoint: 'https://example.org/push/' + channelID,
scope: scope,
pushCount: 0,
lastPush: 0,
originAttributes: '',
quota: Infinity,
+ systemRecord: true,
p256dhPublicKey: base64UrlDecode(publicKey),
p256dhPrivateKey: privateKey,
authenticationSecret: base64UrlDecode(authSecret),
});
}
let ackDone;
let server;
--- a/dom/push/test/xpcshell/test_notification_duplicate.js
+++ b/dom/push/test/xpcshell/test_notification_duplicate.js
@@ -25,23 +25,25 @@ add_task(function* test_notification_dup
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
let records = [{
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.com/1',
originAttributes: "",
version: 2,
quota: Infinity,
+ systemRecord: true,
}, {
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
pushEndpoint: 'https://example.org/update/2',
scope: 'https://example.com/2',
originAttributes: "",
version: 2,
quota: Infinity,
+ systemRecord: true,
}];
for (let record of records) {
yield db.put(record);
}
let notifyPromise = promiseObserverNotification('push-notification');
let acks = 0;
--- a/dom/push/test/xpcshell/test_notification_error.js
+++ b/dom/push/test/xpcshell/test_notification_error.js
@@ -27,30 +27,33 @@ add_task(function* test_notification_err
let originAttributes = '';
let records = [{
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
pushEndpoint: 'https://example.org/update/success-1',
scope: 'https://example.com/a',
originAttributes: originAttributes,
version: 1,
quota: Infinity,
+ systemRecord: true,
}, {
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
pushEndpoint: 'https://example.org/update/error',
scope: 'https://example.com/b',
originAttributes: originAttributes,
version: 2,
quota: Infinity,
+ systemRecord: true,
}, {
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
pushEndpoint: 'https://example.org/update/success-2',
scope: 'https://example.com/c',
originAttributes: originAttributes,
version: 3,
quota: Infinity,
+ systemRecord: true,
}];
for (let record of records) {
yield db.put(record);
}
let notifyPromise = Promise.all([
promiseObserverNotification(
'push-notification',
--- a/dom/push/test/xpcshell/test_notification_http2.js
+++ b/dom/push/test/xpcshell/test_notification_http2.js
@@ -73,16 +73,17 @@ add_task(function* test_pushNotification
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
+ systemRecord: true,
}, {
subscriptionUri: serverURL + '/pushNotifications/subscription2',
pushEndpoint: serverURL + '/pushEndpoint2',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
scope: 'https://example.com/page/2',
p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E',
p256dhPrivateKey: {
crv: 'P-256',
@@ -91,16 +92,17 @@ add_task(function* test_pushNotification
key_ops: ["deriveBits"],
kty: 'EC',
x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE',
y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E'
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
+ systemRecord: true,
}, {
subscriptionUri: serverURL + '/pushNotifications/subscription3',
pushEndpoint: serverURL + '/pushEndpoint3',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
scope: 'https://example.com/page/3',
p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI',
p256dhPrivateKey: {
crv: 'P-256',
@@ -109,16 +111,17 @@ add_task(function* test_pushNotification
key_ops: ["deriveBits"],
kty: 'EC',
x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po',
y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI'
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
+ systemRecord: true,
}];
for (let record of records) {
yield db.put(record);
}
let notifyPromise = Promise.all([
promiseObserverNotification('push-notification', function(subject, data) {
--- a/dom/push/test/xpcshell/test_notification_version_string.js
+++ b/dom/push/test/xpcshell/test_notification_version_string.js
@@ -23,16 +23,17 @@ add_task(function* test_notification_ver
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
yield db.put({
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
pushEndpoint: 'https://example.org/updates/1',
scope: 'https://example.com/page/1',
originAttributes: '',
version: 2,
quota: Infinity,
+ systemRecord: true,
});
let notifyPromise = promiseObserverNotification('push-notification');
let ackDone;
let ackPromise = new Promise(resolve => ackDone = resolve);
PushService.init({
serverURI: "wss://push.example.org/",
--- a/dom/push/test/xpcshell/test_permissions.js
+++ b/dom/push/test/xpcshell/test_permissions.js
@@ -28,16 +28,17 @@ function putRecord(channelID, scope, quo
channelID: channelID,
pushEndpoint: 'https://example.org/push/' + channelID,
scope: scope,
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
quota: quota,
+ systemRecord: quota == Infinity,
});
}
function makePushPermission(url, capability) {
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPermission]),
capability: Ci.nsIPermissionManager[capability],
expireTime: 0,
--- a/dom/push/test/xpcshell/test_quota_exceeded.js
+++ b/dom/push/test/xpcshell/test_quota_exceeded.js
@@ -8,16 +8,17 @@ const {PushDB, PushService, PushServiceW
Cu.import("resource://gre/modules/Task.jsm");
const userAgentID = '7eb873f9-8d47-4218-804b-fff78dc04e88';
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
+ 'testing.ignorePermission': true,
});
run_next_test();
}
add_task(function* test_expiration_origin_threshold() {
let db = PushServiceWebSocket.newPushDB();
do_register_cleanup(() => db.drop().then(_ => db.close()));
--- a/dom/push/test/xpcshell/test_quota_with_notification.js
+++ b/dom/push/test/xpcshell/test_quota_with_notification.js
@@ -9,25 +9,26 @@ Cu.import("resource://gre/modules/Task.j
const userAgentID = 'aaabf1f8-2f68-44f1-a920-b88e9e7d7559';
const nsIPushQuotaManager = Components.interfaces.nsIPushQuotaManager;
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
+ 'testing.ignorePermission': true,
});
run_next_test();
}
add_task(function* test_expiration_origin_threshold() {
let db = PushServiceWebSocket.newPushDB();
do_register_cleanup(() => {
- db.drop().then(_ => db.close())
PushService.notificationForOriginClosed("https://example.com");
+ return db.drop().then(_ => db.close());
});
// Simulate a notification being shown for the origin,
// this should relax the quota and allow as many push messages
// as we want.
PushService.notificationForOriginShown("https://example.com");
yield db.put({
--- a/dom/push/test/xpcshell/test_register_flush.js
+++ b/dom/push/test/xpcshell/test_register_flush.js
@@ -27,16 +27,17 @@ add_task(function* test_register_flush()
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
let record = {
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.com/page/1',
originAttributes: '',
version: 2,
quota: Infinity,
+ systemRecord: true,
};
yield db.put(record);
let notifyPromise = promiseObserverNotification('push-notification');
let ackDone;
let ackPromise = new Promise(resolve => ackDone = after(2, resolve));
PushService.init({
--- a/dom/push/test/xpcshell/test_register_success_http2.js
+++ b/dom/push/test/xpcshell/test_register_success_http2.js
@@ -6,16 +6,17 @@
Cu.import("resource://gre/modules/Services.jsm");
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var tlsProfile;
var serverURL;
var serverPort = -1;
+var db;
function run_test() {
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
serverPort = env.get("MOZHTTP2_PORT");
do_check_neq(serverPort, null);
do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
@@ -39,23 +40,27 @@ function run_test() {
disableServiceWorkerEvents(
'https://example.org/1',
'https://example.org/no_receiptEndpoint'
);
run_next_test();
}
-add_task(function* test_pushSubscriptionSuccess() {
+add_task(function* test_setup() {
- let db = PushServiceHttp2.newPushDB();
+ db = PushServiceHttp2.newPushDB();
do_register_cleanup(() => {
return db.drop().then(_ => db.close());
});
+});
+
+add_task(function* test_pushSubscriptionSuccess() {
+
PushService.init({
serverURI: serverURL + "/pushSubscriptionSuccess/subscribe",
db
});
let newRecord = yield PushService.register({
scope: 'https://example.org/1',
originAttributes: ChromeUtils.originAttributesToSuffix(
@@ -76,26 +81,21 @@ add_task(function* test_pushSubscription
'Wrong subscription ID in database record');
equal(record.pushEndpoint, pushEndpoint,
'Wrong push endpoint in database record');
equal(record.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in database record');
equal(record.scope, 'https://example.org/1',
'Wrong scope in database record');
- db.drop().then(PushService.uninit());
+ PushService.uninit()
});
add_task(function* test_pushSubscriptionMissingLink2() {
- let db = PushServiceHttp2.newPushDB();
- do_register_cleanup(() => {
- return db.drop().then(_ => db.close());
- });
-
PushService.init({
serverURI: serverURL + "/pushSubscriptionMissingLink2/subscribe",
db
});
let newRecord = yield PushService.register({
scope: 'https://example.org/no_receiptEndpoint',
originAttributes: ChromeUtils.originAttributesToSuffix(
--- a/dom/push/test/xpcshell/test_service_child.js
+++ b/dom/push/test/xpcshell/test_service_child.js
@@ -29,16 +29,17 @@ add_test(function test_subscribe_success
service.subscribe(
'https://example.com/sub/ok',
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error creating subscription');
ok(subscription.endpoint.startsWith('https://example.org/push'), 'Wrong endpoint prefix');
equal(subscription.pushCount, 0, 'Wrong push count');
equal(subscription.lastPush, 0, 'Wrong last push time');
+ equal(subscription.quota, -1, 'Wrong quota for system subscription');
do_test_finished();
run_next_test();
}
);
});
add_test(function test_subscribe_error() {
@@ -62,16 +63,17 @@ add_test(function test_getSubscription_e
'https://example.com/get/ok',
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error getting subscription');
equal(subscription.endpoint, 'https://example.org/push/get', 'Wrong endpoint');
equal(subscription.pushCount, 10, 'Wrong push count');
equal(subscription.lastPush, 1438360548322, 'Wrong last push');
+ equal(subscription.quota, 16, 'Wrong quota for subscription');
do_test_finished();
run_next_test();
}
);
});
add_test(function test_getSubscription_missing() {
@@ -144,28 +146,80 @@ add_test(function test_unsubscribe_error
strictEqual(success, false, 'Unexpected successful unsubscribe');
do_test_finished();
run_next_test();
}
);
});
-add_test(function test_subscribe_principal() {
+add_test(function test_subscribe_app_principal() {
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
Services.io.newURI('https://example.net/app/1', null, null),
1, /* appId */
true /* browserOnly */
);
+ do_test_pending();
service.subscribe('https://example.net/scope/1', principal, (result, subscription) => {
ok(Components.isSuccessCode(result), 'Error creating subscription');
ok(subscription.endpoint.startsWith('https://example.org/push'),
'Wrong push endpoint in app subscription');
+ equal(subscription.quota, 16, 'Wrong quota for app subscription');
+
+ do_test_finished();
+ run_next_test();
+ });
+});
+
+add_test(function test_subscribe_origin_principal() {
+ let scope = 'https://example.net/origin-principal';
+ let principal =
+ Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(scope);
+
+ do_test_pending();
+ service.subscribe(scope, principal, (result, subscription) => {
+ ok(Components.isSuccessCode(result),
+ 'Expected error creating subscription with origin principal');
+ equal(subscription.quota, 16, 'Wrong quota for origin subscription');
+
+ do_test_finished();
run_next_test();
});
});
+add_test(function test_subscribe_null_principal() {
+ do_test_pending();
+ service.subscribe(
+ 'chrome://push/null-principal',
+ Services.scriptSecurityManager.createNullPrincipal({}),
+ (result, subscription) => {
+ ok(!Components.isSuccessCode(result),
+ 'Expected error creating subscription with expanded principal');
+ strictEqual(subscription, null,
+ 'Unexpected subscription with expanded principal');
+
+ do_test_finished();
+ run_next_test();
+ }
+ );
+});
+
+add_test(function test_subscribe_missing_principal() {
+ do_test_pending();
+ service.subscribe('chrome://push/missing-principal', null,
+ (result, subscription) => {
+ ok(!Components.isSuccessCode(result),
+ 'Expected error creating subscription without principal');
+ strictEqual(subscription, null,
+ 'Unexpected subscription without principal');
+
+ do_test_finished();
+ run_next_test();
+ }
+ );
+});
+
if (isParent) {
add_test(function tearDown() {
tearDownServiceInParent(db).then(run_next_test, run_next_test);
});
}
--- a/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_http2.js
+++ b/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_http2.js
@@ -52,16 +52,17 @@ add_task(function* test1() {
let record = {
subscriptionUri: serverURL + '/subscriptionNoKey',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
originAttributes: '',
quota: Infinity,
+ systemRecord: true,
};
yield db.put(record);
let notifyPromise = promiseObserverNotification('push-subscription-change',
_ => true);
PushService.init({