зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1166350 - Push fixes for principals. r=kitcambridge,bholley
Fix xpcshell tests. Add support for webapps-clear-data. Trash old regs on idb version upgrade. Use principal for permission check. use principal in PushSubscription. --HG-- extra : source : d7554019b424327a3271e2c0debda995fff36cb5 extra : intermediate-source : be40dea6534771bdeedc9f7c6ccd8bbddb6e41c2
This commit is contained in:
Родитель
552b7cd770
Коммит
b8eea4d16b
|
@ -19,5 +19,14 @@ ChromeUtils::OriginAttributesToCookieJar(GlobalObject& aGlobal,
|
||||||
attrs.CookieJar(aCookieJar);
|
attrs.CookieJar(aCookieJar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||||
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
|
nsCString& aSuffix)
|
||||||
|
|
||||||
|
{
|
||||||
|
OriginAttributes attrs(aAttrs);
|
||||||
|
attrs.CreateSuffix(aSuffix);
|
||||||
|
}
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -44,6 +44,11 @@ public:
|
||||||
OriginAttributesToCookieJar(dom::GlobalObject& aGlobal,
|
OriginAttributesToCookieJar(dom::GlobalObject& aGlobal,
|
||||||
const dom::OriginAttributesDictionary& aAttrs,
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
nsCString& aCookieJar);
|
nsCString& aCookieJar);
|
||||||
|
|
||||||
|
static void
|
||||||
|
OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||||
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
|
nsCString& aSuffix);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -20,7 +20,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||||
void unregisterFailed();
|
void unregisterFailed();
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(103763c8-53ba-42e4-8b26-e601d5bc4afe)]
|
[scriptable, builtinclass, uuid(e633b73b-a734-4d04-a09c-b7779a439f3f)]
|
||||||
interface nsIServiceWorkerInfo : nsISupports
|
interface nsIServiceWorkerInfo : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute nsIPrincipal principal;
|
readonly attribute nsIPrincipal principal;
|
||||||
|
@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||||
readonly attribute DOMString waitingCacheName;
|
readonly attribute DOMString waitingCacheName;
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(aee94712-9adb-4c0b-80a7-a8df34dfa2e8)]
|
[scriptable, builtinclass, uuid(e9abb123-0099-4d9e-85db-c8cd0aff19e6)]
|
||||||
interface nsIServiceWorkerManager : nsISupports
|
interface nsIServiceWorkerManager : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -126,11 +126,11 @@ interface nsIServiceWorkerManager : nsISupports
|
||||||
in nsIServiceWorkerUnregisterCallback aCallback,
|
in nsIServiceWorkerUnregisterCallback aCallback,
|
||||||
in DOMString aScope);
|
in DOMString aScope);
|
||||||
|
|
||||||
[implicit_jscontext] void sendPushEvent(in jsval aOriginAttributes,
|
void sendPushEvent(in ACString aOriginAttributes,
|
||||||
in ACString aScope,
|
in ACString aScope,
|
||||||
in DOMString aData);
|
in DOMString aData);
|
||||||
[implicit_jscontext] void sendPushSubscriptionChangeEvent(in jsval aOriginAttributes,
|
void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
|
||||||
in ACString scope);
|
in ACString scope);
|
||||||
|
|
||||||
void updateAllRegistrations();
|
void updateAllRegistrations();
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* uses service workers to notify applications. This interface exists to allow
|
* uses service workers to notify applications. This interface exists to allow
|
||||||
* privileged code to receive messages without migrating to service workers.
|
* privileged code to receive messages without migrating to service workers.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(3da6a16c-69f8-4843-9149-1e89d58a53e2)]
|
[scriptable, uuid(abde228b-7d14-4cab-b1f9-9f87750ede0f)]
|
||||||
interface nsIPushNotificationService : nsISupports
|
interface nsIPushNotificationService : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -32,20 +32,20 @@ interface nsIPushNotificationService : nsISupports
|
||||||
* Servers may drop subscriptions at any time, so callers should recreate
|
* Servers may drop subscriptions at any time, so callers should recreate
|
||||||
* subscriptions if desired.
|
* subscriptions if desired.
|
||||||
*/
|
*/
|
||||||
jsval register(in string scope, [optional] in string pageURL);
|
jsval register(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revokes a push subscription for the given |scope|. Returns a promise
|
* Revokes a push subscription for the given |scope|. Returns a promise
|
||||||
* for the revoked subscription record, or `null` if the |scope| is not
|
* for the revoked subscription record, or `null` if the |scope| is not
|
||||||
* subscribed to receive notifications.
|
* subscribed to receive notifications.
|
||||||
*/
|
*/
|
||||||
jsval unregister(in string scope);
|
jsval unregister(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise for the subscription record associated with the
|
* Returns a promise for the subscription record associated with the
|
||||||
* given |scope|, or `null` if the |scope| does not have a subscription.
|
* given |scope|, or `null` if the |scope| does not have a subscription.
|
||||||
*/
|
*/
|
||||||
jsval registration(in string scope);
|
jsval registration(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all subscriptions
|
* Clear all subscriptions
|
||||||
|
|
|
@ -23,11 +23,11 @@ Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||||
|
|
||||||
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
|
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
|
||||||
|
|
||||||
function PushSubscription(pushEndpoint, scope, pageURL) {
|
function PushSubscription(pushEndpoint, scope, principal) {
|
||||||
debug("PushSubscription Constructor");
|
debug("PushSubscription Constructor");
|
||||||
this._pushEndpoint = pushEndpoint;
|
this._pushEndpoint = pushEndpoint;
|
||||||
this._scope = scope;
|
this._scope = scope;
|
||||||
this._pageURL = pageURL;
|
this._principal = principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
PushSubscription.prototype = {
|
PushSubscription.prototype = {
|
||||||
|
@ -53,10 +53,10 @@ PushSubscription.prototype = {
|
||||||
.getService(Ci.nsISyncMessageSender);
|
.getService(Ci.nsISyncMessageSender);
|
||||||
},
|
},
|
||||||
|
|
||||||
__init: function(endpoint, scope, pageURL) {
|
__init: function(endpoint, scope, principal) {
|
||||||
this._pushEndpoint = endpoint;
|
this._pushEndpoint = endpoint;
|
||||||
this._scope = scope;
|
this._scope = scope;
|
||||||
this._pageURL = pageURL;
|
this._principal = principal;
|
||||||
},
|
},
|
||||||
|
|
||||||
get endpoint() {
|
get endpoint() {
|
||||||
|
@ -71,11 +71,10 @@ PushSubscription.prototype = {
|
||||||
reject: reject });
|
reject: reject });
|
||||||
|
|
||||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||||
pageURL: this._pageURL,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
pushEndpoint: this._pushEndpoint,
|
pushEndpoint: this._pushEndpoint,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
return this.createPromise(promiseInit);
|
return this.createPromise(promiseInit);
|
||||||
|
@ -133,7 +132,6 @@ Push.prototype = {
|
||||||
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
||||||
debug("init()");
|
debug("init()");
|
||||||
|
|
||||||
this._pageURL = aWindow.document.nodePrincipal.URI;
|
|
||||||
this._window = aWindow;
|
this._window = aWindow;
|
||||||
|
|
||||||
this.initDOMRequestHelper(aWindow, [
|
this.initDOMRequestHelper(aWindow, [
|
||||||
|
@ -145,6 +143,7 @@ Push.prototype = {
|
||||||
|
|
||||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||||
.getService(Ci.nsISyncMessageSender);
|
.getService(Ci.nsISyncMessageSender);
|
||||||
|
this._principal = aWindow.document.nodePrincipal;
|
||||||
},
|
},
|
||||||
|
|
||||||
setScope: function(scope){
|
setScope: function(scope){
|
||||||
|
@ -160,8 +159,6 @@ Push.prototype = {
|
||||||
let permValue =
|
let permValue =
|
||||||
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
||||||
|
|
||||||
debug("Existing permission " + permValue);
|
|
||||||
|
|
||||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||||
aAllowCallback();
|
aAllowCallback();
|
||||||
return;
|
return;
|
||||||
|
@ -219,9 +216,9 @@ Push.prototype = {
|
||||||
switch (aMessage.name) {
|
switch (aMessage.name) {
|
||||||
case "PushService:Register:OK":
|
case "PushService:Register:OK":
|
||||||
{
|
{
|
||||||
let subscription = new this._window.PushSubscription(json.pushEndpoint,
|
let subscription =
|
||||||
this._scope,
|
new this._window.PushSubscription(json.pushEndpoint, this._scope,
|
||||||
this._pageURL.spec);
|
this._principal);
|
||||||
resolver.resolve(subscription);
|
resolver.resolve(subscription);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -232,8 +229,9 @@ Push.prototype = {
|
||||||
{
|
{
|
||||||
let subscription = null;
|
let subscription = null;
|
||||||
try {
|
try {
|
||||||
subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
|
subscription =
|
||||||
this._scope, this._pageURL.spec);
|
new this._window.PushSubscription(json.registration.pushEndpoint,
|
||||||
|
this._scope, this._principal);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
}
|
}
|
||||||
resolver.resolve(subscription);
|
resolver.resolve(subscription);
|
||||||
|
@ -255,10 +253,9 @@ Push.prototype = {
|
||||||
this.askPermission(
|
this.askPermission(
|
||||||
function() {
|
function() {
|
||||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||||
pageURL: this._pageURL.spec,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
|
@ -279,10 +276,9 @@ Push.prototype = {
|
||||||
this.askPermission(
|
this.askPermission(
|
||||||
function() {
|
function() {
|
||||||
this._cpmm.sendAsyncMessage("Push:Registration", {
|
this._cpmm.sendAsyncMessage("Push:Registration", {
|
||||||
pageURL: this._pageURL.spec,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
|
@ -294,11 +290,14 @@ Push.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
hasPermission: function() {
|
hasPermission: function() {
|
||||||
debug("getSubscription()" + this._scope);
|
debug("hasPermission()" + this._scope);
|
||||||
|
|
||||||
let p = this.createPromise(function(resolve, reject) {
|
let p = this.createPromise(function(resolve, reject) {
|
||||||
let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
let permissionManager = Cc["@mozilla.org/permissionmanager;1"]
|
||||||
let permission = permissionManager.testExactPermission(this._pageURL, "push");
|
.getService(Ci.nsIPermissionManager);
|
||||||
|
let permission =
|
||||||
|
permissionManager.testExactPermissionFromPrincipal(this._principal,
|
||||||
|
"push");
|
||||||
|
|
||||||
let pushPermissionStatus = "default";
|
let pushPermissionStatus = "default";
|
||||||
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||||
|
|
|
@ -147,9 +147,15 @@ this.PushDB.prototype = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Perform a unique match against { scope, originAttributes }
|
||||||
getByScope: function(aScope) {
|
getByIdentifiers: function(aPageRecord) {
|
||||||
debug("getByScope() " + aScope);
|
debug("getByIdentifiers() { " + aPageRecord.scope + ", " +
|
||||||
|
JSON.stringify(aPageRecord.originAttributes) + " }");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes == undefined) {
|
||||||
|
return Promise.reject(
|
||||||
|
new TypeError("Scope and originAttributes are required! " +
|
||||||
|
JSON.stringify(aPageRecord)));
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
this.newTxn(
|
this.newTxn(
|
||||||
|
@ -158,11 +164,11 @@ this.PushDB.prototype = {
|
||||||
function txnCb(aTxn, aStore) {
|
function txnCb(aTxn, aStore) {
|
||||||
aTxn.result = undefined;
|
aTxn.result = undefined;
|
||||||
|
|
||||||
let index = aStore.index("scope");
|
let index = aStore.index("identifiers");
|
||||||
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
|
let request = index.get(IDBKeyRange.only([aPageRecord.scope, aPageRecord.originAttributes]));
|
||||||
|
request.onsuccess = function setTxnResult(aEvent) {
|
||||||
aTxn.result = aEvent.target.result;
|
aTxn.result = aEvent.target.result;
|
||||||
debug("Fetch successful " + aEvent.target.result);
|
}
|
||||||
};
|
|
||||||
},
|
},
|
||||||
resolve,
|
resolve,
|
||||||
reject
|
reject
|
||||||
|
@ -170,6 +176,37 @@ this.PushDB.prototype = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getAllByKey: function(aKeyName, aKeyValue) {
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
this.newTxn(
|
||||||
|
"readonly",
|
||||||
|
this._dbStoreName,
|
||||||
|
function txnCb(aTxn, aStore) {
|
||||||
|
aTxn.result = undefined;
|
||||||
|
|
||||||
|
let index = aStore.index(aKeyName);
|
||||||
|
// It seems ok to use getAll here, since unlike contacts or other
|
||||||
|
// high storage APIs, we don't expect more than a handful of
|
||||||
|
// registrations per domain, and usually only one.
|
||||||
|
let getAllReq = index.mozGetAll(aKeyValue);
|
||||||
|
getAllReq.onsuccess = function setTxnResult(aEvent) {
|
||||||
|
aTxn.result = aEvent.target.result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// aOriginAttributes must be a string!
|
||||||
|
getAllByOriginAttributes: function(aOriginAttributes) {
|
||||||
|
if (typeof aOriginAttributes !== "string") {
|
||||||
|
return Promise.reject("Expected string!");
|
||||||
|
}
|
||||||
|
return this._getAllByKey("originAttributes", aOriginAttributes);
|
||||||
|
},
|
||||||
|
|
||||||
getAllKeyIDs: function() {
|
getAllKeyIDs: function() {
|
||||||
debug("getAllKeyIDs()");
|
debug("getAllKeyIDs()");
|
||||||
|
|
||||||
|
@ -178,6 +215,7 @@ this.PushDB.prototype = {
|
||||||
"readonly",
|
"readonly",
|
||||||
this._dbStoreName,
|
this._dbStoreName,
|
||||||
function txnCb(aTxn, aStore) {
|
function txnCb(aTxn, aStore) {
|
||||||
|
aTxn.result = undefined;
|
||||||
aStore.mozGetAll().onsuccess = function(event) {
|
aStore.mozGetAll().onsuccess = function(event) {
|
||||||
aTxn.result = event.target.result;
|
aTxn.result = event.target.result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,16 +38,16 @@ PushNotificationService.prototype = {
|
||||||
Ci.nsISupportsWeakReference,
|
Ci.nsISupportsWeakReference,
|
||||||
Ci.nsIPushNotificationService]),
|
Ci.nsIPushNotificationService]),
|
||||||
|
|
||||||
register: function register(scope, pageURL) {
|
register: function register(scope, originAttributes) {
|
||||||
return PushService._register({scope, pageURL});
|
return PushService._register({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
unregister: function unregister(scope) {
|
unregister: function unregister(scope, originAttributes) {
|
||||||
return PushService._unregister({scope});
|
return PushService._unregister({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
registration: function registration(scope) {
|
registration: function registration(scope, originAttributes) {
|
||||||
return PushService._registration({scope});
|
return PushService._registration({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
clearAll: function clearAll() {
|
clearAll: function clearAll() {
|
||||||
|
|
|
@ -116,6 +116,26 @@ this.PushService = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_makePendingKey: function(aPageRecord) {
|
||||||
|
return aPageRecord.scope + "|" + aPageRecord.originAttributes;
|
||||||
|
},
|
||||||
|
|
||||||
|
_lookupOrPutPendingRequest: function(aPageRecord) {
|
||||||
|
let key = this._makePendingKey(aPageRecord);
|
||||||
|
if (this._pendingRegisterRequest[key]) {
|
||||||
|
return this._pendingRegisterRequest[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._pendingRegisterRequest[key] = this._registerWithServer(aPageRecord);
|
||||||
|
},
|
||||||
|
|
||||||
|
_deletePendingRequest: function(aPageRecord) {
|
||||||
|
let key = this._makePendingKey(aPageRecord);
|
||||||
|
if (this._pendingRegisterRequest[key]) {
|
||||||
|
delete this._pendingRegisterRequest[key];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_setState: function(aNewState) {
|
_setState: function(aNewState) {
|
||||||
debug("new state: " + aNewState + " old state: " + this._state);
|
debug("new state: " + aNewState + " old state: " + this._state);
|
||||||
|
|
||||||
|
@ -233,24 +253,41 @@ this.PushService = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 1149274. We should support site permissions as well as a way to
|
var originAttributes =
|
||||||
// go from manifest url to 'all scopes registered for push in this app'
|
ChromeUtils.originAttributesToSuffix({ appId: data.appId,
|
||||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
inBrowser: data.browserOnly });
|
||||||
.getService(Ci.nsIAppsService);
|
this._db.getAllByOriginAttributes(originAttributes)
|
||||||
let scope = appsService.getScopeByLocalId(data.appId);
|
.then(records => {
|
||||||
if (!scope) {
|
records.forEach(record => {
|
||||||
debug("webapps-clear-data: No scope found for " + data.appId);
|
this._db.delete(this._service.getKeyFromRecord(record))
|
||||||
return;
|
.then(_ => {
|
||||||
}
|
// courtesy, but don't establish a connection
|
||||||
|
// just for it
|
||||||
|
if (this._ws) {
|
||||||
|
debug("Had a connection, so telling the server");
|
||||||
|
this._sendRequest("unregister", {channelID: records.channelID})
|
||||||
|
.catch(function(e) {
|
||||||
|
debug("Unregister errored " + e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, err => {
|
||||||
|
debug("webapps-clear-data: " + scope +
|
||||||
|
" Could not delete entry " + records.channelID);
|
||||||
|
|
||||||
this._db.getByScope(scope)
|
// courtesy, but don't establish a connection
|
||||||
.then(record =>
|
// just for it
|
||||||
Promise.all([
|
if (this._ws) {
|
||||||
this._db.delete(this._service.getKeyFromRecord(record)),
|
debug("Had a connection, so telling the server");
|
||||||
this._sendRequest("unregister", record)
|
this._sendRequest("unregister", {channelID: records.channelID})
|
||||||
])
|
.catch(function(e) {
|
||||||
).catch(_ => {
|
debug("Unregister errored " + e);
|
||||||
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
|
});
|
||||||
|
}
|
||||||
|
throw "Database error";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, _ => {
|
||||||
|
debug("webapps-clear-data: Error in getAllByOriginAttributes(" + originAttributes + ")");
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -623,13 +660,9 @@ this.PushService = {
|
||||||
// records are objects describing the registration as stored in IndexedDB.
|
// records are objects describing the registration as stored in IndexedDB.
|
||||||
return this._db.getAllKeyIDs()
|
return this._db.getAllKeyIDs()
|
||||||
.then(records => {
|
.then(records => {
|
||||||
let scopes = new Set();
|
|
||||||
for (let record of records) {
|
|
||||||
scopes.add(record.scope);
|
|
||||||
}
|
|
||||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
||||||
.getService(Ci.nsIMessageListenerManager);
|
.getService(Ci.nsIMessageListenerManager);
|
||||||
for (let scope of scopes) {
|
for (let record of records) {
|
||||||
// Notify XPCOM observers.
|
// Notify XPCOM observers.
|
||||||
Services.obs.notifyObservers(
|
Services.obs.notifyObservers(
|
||||||
null,
|
null,
|
||||||
|
@ -638,8 +671,8 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
|
globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
|
||||||
|
@ -659,7 +692,7 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: record.scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -681,7 +714,7 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: record.scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -695,7 +728,8 @@ this.PushService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifyApp: function(aPushRecord, message) {
|
_notifyApp: function(aPushRecord, message) {
|
||||||
if (!aPushRecord || !aPushRecord.scope) {
|
if (!aPushRecord || !aPushRecord.scope ||
|
||||||
|
aPushRecord.originAttributes === undefined) {
|
||||||
debug("notifyApp() something is undefined. Dropping notification: " +
|
debug("notifyApp() something is undefined. Dropping notification: " +
|
||||||
JSON.stringify(aPushRecord) );
|
JSON.stringify(aPushRecord) );
|
||||||
return;
|
return;
|
||||||
|
@ -728,7 +762,7 @@ this.PushService = {
|
||||||
// TODO data.
|
// TODO data.
|
||||||
let data = {
|
let data = {
|
||||||
payload: message,
|
payload: message,
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: aPushRecord.originAttributes,
|
||||||
scope: aPushRecord.scope
|
scope: aPushRecord.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -745,7 +779,7 @@ this.PushService = {
|
||||||
return this._db.getAllKeyIDs();
|
return this._db.getAllKeyIDs();
|
||||||
},
|
},
|
||||||
|
|
||||||
_sendRequest(action, aRecord) {
|
_sendRequest: function(action, aRecord) {
|
||||||
if (this._state == PUSH_SERVICE_CONNECTION_DISABLE) {
|
if (this._state == PUSH_SERVICE_CONNECTION_DISABLE) {
|
||||||
return Promise.reject({state: 0, error: "Service not active"});
|
return Promise.reject({state: 0, error: "Service not active"});
|
||||||
} else if (this._state == PUSH_SERVICE_ACTIVE_OFFLINE) {
|
} else if (this._state == PUSH_SERVICE_ACTIVE_OFFLINE) {
|
||||||
|
@ -759,37 +793,35 @@ this.PushService = {
|
||||||
* navigator.push, identifying the sending page and other fields.
|
* navigator.push, identifying the sending page and other fields.
|
||||||
*/
|
*/
|
||||||
_registerWithServer: function(aPageRecord) {
|
_registerWithServer: function(aPageRecord) {
|
||||||
debug("registerWithServer()");
|
debug("registerWithServer()" + JSON.stringify(aPageRecord));
|
||||||
|
|
||||||
return this._sendRequest("register", aPageRecord)
|
return this._sendRequest("register", aPageRecord)
|
||||||
.then(pushRecord => this._onRegisterSuccess(pushRecord),
|
.then(pushRecord => this._onRegisterSuccess(pushRecord),
|
||||||
err => this._onRegisterError(err))
|
err => this._onRegisterError(err))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
this._deletePendingRequest(aPageRecord);
|
||||||
delete this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
return pushRecord;
|
return pushRecord;
|
||||||
}, err => {
|
}, err => {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
this._deletePendingRequest(aPageRecord);
|
||||||
delete this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_register: function(aPageRecord) {
|
_register: function(aPageRecord) {
|
||||||
|
debug("_register()");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (pushRecord === undefined) {
|
if (pushRecord === undefined) {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
return this._lookupOrPutPendingRequest(aPageRecord);
|
||||||
return this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
return this._pendingRegisterRequest[aPageRecord.scope] = this._registerWithServer(aPageRecord);
|
|
||||||
}
|
}
|
||||||
return pushRecord;
|
return pushRecord;
|
||||||
}, error => {
|
}, error => {
|
||||||
debug("getByScope failed");
|
debug("getByIdentifiers failed");
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -833,10 +865,39 @@ this.PushService = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
|
if (!aMessage.target.assertPermission("push")) {
|
||||||
let json = aMessage.data;
|
debug("Got message from a child process that does not have 'push' permission.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this[aMessage.name.slice("Push:".length).toLowerCase()](json, mm);
|
let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
|
||||||
|
let pageRecord = aMessage.data;
|
||||||
|
|
||||||
|
let principal = aMessage.principal;
|
||||||
|
if (!principal) {
|
||||||
|
debug("No principal passed!");
|
||||||
|
let message = {
|
||||||
|
requestID: aPageRecord.requestID,
|
||||||
|
error: "SecurityError"
|
||||||
|
};
|
||||||
|
mm.sendAsyncMessage("PushService:Register:KO", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pageRecord.originAttributes =
|
||||||
|
ChromeUtils.originAttributesToSuffix(principal.originAttributes);
|
||||||
|
|
||||||
|
if (!pageRecord.scope || pageRecord.originAttributes === undefined) {
|
||||||
|
debug("Incorrect identifier values set! " + JSON.stringify(pageRecord));
|
||||||
|
let message = {
|
||||||
|
requestID: aPageRecord.requestID,
|
||||||
|
error: "SecurityError"
|
||||||
|
};
|
||||||
|
mm.sendAsyncMessage("PushService:Register:KO", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this[aMessage.name.slice("Push:".length).toLowerCase()](pageRecord, mm);
|
||||||
},
|
},
|
||||||
|
|
||||||
register: function(aPageRecord, aMessageManager) {
|
register: function(aPageRecord, aMessageManager) {
|
||||||
|
@ -883,13 +944,12 @@ this.PushService = {
|
||||||
*/
|
*/
|
||||||
_unregister: function(aPageRecord) {
|
_unregister: function(aPageRecord) {
|
||||||
debug("_unregister()");
|
debug("_unregister()");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
if (!aPageRecord.scope) {
|
|
||||||
return Promise.reject({state: 0, error: "NotFoundError"});
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(record => {
|
.then(record => {
|
||||||
// If the endpoint didn't exist, let's just fail.
|
// If the endpoint didn't exist, let's just fail.
|
||||||
if (record === undefined) {
|
if (record === undefined) {
|
||||||
|
@ -932,12 +992,12 @@ this.PushService = {
|
||||||
*/
|
*/
|
||||||
_registration: function(aPageRecord) {
|
_registration: function(aPageRecord) {
|
||||||
debug("_registration()");
|
debug("_registration()");
|
||||||
if (!aPageRecord.scope) {
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
return Promise.reject({state: 0, error: "Database error"});
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (!pushRecord) {
|
if (!pushRecord) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -33,7 +33,7 @@ function debug(s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
|
const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
|
||||||
const kPUSHHTTP2DB_DB_VERSION = 1; // Change this if the IndexedDB format changes
|
const kPUSHHTTP2DB_DB_VERSION = 3; // Change this if the IndexedDB format changes
|
||||||
const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
|
const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -291,6 +291,7 @@ SubscriptionListener.prototype = {
|
||||||
pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
|
pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
|
||||||
pageURL: this._subInfo.record.pageURL,
|
pageURL: this._subInfo.record.pageURL,
|
||||||
scope: this._subInfo.record.scope,
|
scope: this._subInfo.record.scope,
|
||||||
|
originAttributes: this._subInfo.record.originAttributes,
|
||||||
pushCount: 0,
|
pushCount: 0,
|
||||||
lastPush: 0
|
lastPush: 0
|
||||||
};
|
};
|
||||||
|
@ -385,15 +386,33 @@ this.PushServiceHttp2 = {
|
||||||
aDbInstance) {
|
aDbInstance) {
|
||||||
debug("upgradeSchemaHttp2()");
|
debug("upgradeSchemaHttp2()");
|
||||||
|
|
||||||
|
//XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
|
||||||
|
//registrations away without even informing the app.
|
||||||
|
if (aNewVersion != aOldVersion) {
|
||||||
|
try {
|
||||||
|
aDb.deleteObjectStore(aDbInstance._dbStoreName);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === "NotFoundError") {
|
||||||
|
debug("No existing object store found");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
||||||
{ keyPath: "subscriptionUri" });
|
{ keyPath: "subscriptionUri" });
|
||||||
|
|
||||||
// index to fetch records based on endpoints. used by unregister
|
// index to fetch records based on endpoints. used by unregister
|
||||||
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
||||||
|
|
||||||
// index to fetch records per scope, so we can identify endpoints
|
// index to fetch records by identifiers.
|
||||||
// associated with an app.
|
// In the current security model, the originAttributes distinguish between
|
||||||
objectStore.createIndex("scope", "scope", { unique: true });
|
// different 'apps' on the same origin. Since ServiceWorkers are
|
||||||
|
// same-origin to the scope they are registered for, the attributes and
|
||||||
|
// scope are enough to reconstruct a valid principal.
|
||||||
|
objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
|
||||||
|
objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
getKeyFromRecord: function(aRecord) {
|
getKeyFromRecord: function(aRecord) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ var threadManager = Cc["@mozilla.org/thread-manager;1"]
|
||||||
.getService(Ci.nsIThreadManager);
|
.getService(Ci.nsIThreadManager);
|
||||||
|
|
||||||
const kPUSHWSDB_DB_NAME = "pushapi";
|
const kPUSHWSDB_DB_NAME = "pushapi";
|
||||||
const kPUSHWSDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
|
const kPUSHWSDB_DB_VERSION = 3; // Change this if the IndexedDB format changes
|
||||||
const kPUSHWSDB_STORE_NAME = "pushapi";
|
const kPUSHWSDB_STORE_NAME = "pushapi";
|
||||||
|
|
||||||
const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
|
const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
|
||||||
|
@ -132,15 +132,33 @@ this.PushServiceWebSocket = {
|
||||||
aDbInstance) {
|
aDbInstance) {
|
||||||
debug("upgradeSchemaWS()");
|
debug("upgradeSchemaWS()");
|
||||||
|
|
||||||
|
//XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
|
||||||
|
//registrations away without even informing the app.
|
||||||
|
if (aNewVersion != aOldVersion) {
|
||||||
|
try {
|
||||||
|
aDb.deleteObjectStore(aDbInstance._dbStoreName);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === "NotFoundError") {
|
||||||
|
debug("No existing object store found");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
||||||
{ keyPath: "channelID" });
|
{ keyPath: "channelID" });
|
||||||
|
|
||||||
// index to fetch records based on endpoints. used by unregister
|
// index to fetch records based on endpoints. used by unregister
|
||||||
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
||||||
|
|
||||||
// index to fetch records per scope, so we can identify endpoints
|
// index to fetch records by identifiers.
|
||||||
// associated with an app.
|
// In the current security model, the originAttributes distinguish between
|
||||||
objectStore.createIndex("scope", "scope", { unique: true });
|
// different 'apps' on the same origin. Since ServiceWorkers are
|
||||||
|
// same-origin to the scope they are registered for, the attributes and
|
||||||
|
// scope are enough to reconstruct a valid principal.
|
||||||
|
objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
|
||||||
|
objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
getKeyFromRecord: function(aRecord) {
|
getKeyFromRecord: function(aRecord) {
|
||||||
|
@ -870,10 +888,12 @@ this.PushServiceWebSocket = {
|
||||||
pushEndpoint: reply.pushEndpoint,
|
pushEndpoint: reply.pushEndpoint,
|
||||||
pageURL: tmp.record.pageURL,
|
pageURL: tmp.record.pageURL,
|
||||||
scope: tmp.record.scope,
|
scope: tmp.record.scope,
|
||||||
|
originAttributes: tmp.record.originAttributes,
|
||||||
pushCount: 0,
|
pushCount: 0,
|
||||||
lastPush: 0,
|
lastPush: 0,
|
||||||
version: null
|
version: null
|
||||||
};
|
};
|
||||||
|
dump("PushWebSocket " + JSON.stringify(record));
|
||||||
tmp.resolve(record);
|
tmp.resolve(record);
|
||||||
} else {
|
} else {
|
||||||
tmp.reject(reply);
|
tmp.reject(reply);
|
||||||
|
|
|
@ -120,6 +120,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
SpecialPowers.pushPrefEnv({"set": [
|
SpecialPowers.pushPrefEnv({"set": [
|
||||||
["dom.push.enabled", true],
|
["dom.push.enabled", true],
|
||||||
|
["dom.push.debug", true],
|
||||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||||
["dom.serviceWorkers.enabled", true],
|
["dom.serviceWorkers.enabled", true],
|
||||||
["dom.serviceWorkers.testing.enabled", true]
|
["dom.serviceWorkers.testing.enabled", true]
|
||||||
|
|
|
@ -25,16 +25,19 @@ add_task(function* test_notification_ack() {
|
||||||
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||||
pushEndpoint: 'https://example.com/update/1',
|
pushEndpoint: 'https://example.com/update/1',
|
||||||
scope: 'https://example.org/1',
|
scope: 'https://example.org/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
||||||
pushEndpoint: 'https://example.com/update/2',
|
pushEndpoint: 'https://example.com/update/2',
|
||||||
scope: 'https://example.org/2',
|
scope: 'https://example.org/2',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
||||||
pushEndpoint: 'https://example.com/update/3',
|
pushEndpoint: 'https://example.com/update/3',
|
||||||
scope: 'https://example.org/3',
|
scope: 'https://example.org/3',
|
||||||
|
originAttributes: '',
|
||||||
version: 3
|
version: 3
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
|
|
@ -23,11 +23,13 @@ add_task(function* test_notification_duplicate() {
|
||||||
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.com/1',
|
scope: 'https://example.com/1',
|
||||||
|
originAttributes: "",
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
||||||
pushEndpoint: 'https://example.org/update/2',
|
pushEndpoint: 'https://example.org/update/2',
|
||||||
scope: 'https://example.com/2',
|
scope: 'https://example.com/2',
|
||||||
|
originAttributes: "",
|
||||||
version: 2
|
version: 2
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
|
|
@ -19,20 +19,25 @@ function run_test() {
|
||||||
add_task(function* test_notification_error() {
|
add_task(function* test_notification_error() {
|
||||||
let db = PushServiceWebSocket.newPushDB();
|
let db = PushServiceWebSocket.newPushDB();
|
||||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||||
|
|
||||||
|
let originAttributes = '';
|
||||||
let records = [{
|
let records = [{
|
||||||
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||||
pushEndpoint: 'https://example.org/update/success-1',
|
pushEndpoint: 'https://example.org/update/success-1',
|
||||||
scope: 'https://example.com/a',
|
scope: 'https://example.com/a',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||||
pushEndpoint: 'https://example.org/update/error',
|
pushEndpoint: 'https://example.org/update/error',
|
||||||
scope: 'https://example.com/b',
|
scope: 'https://example.com/b',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||||
pushEndpoint: 'https://example.org/update/success-2',
|
pushEndpoint: 'https://example.org/update/success-2',
|
||||||
scope: 'https://example.com/c',
|
scope: 'https://example.com/c',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 3
|
version: 3
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -107,19 +112,22 @@ add_task(function* test_notification_error() {
|
||||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||||
'Timed out waiting for acknowledgements');
|
'Timed out waiting for acknowledgements');
|
||||||
|
|
||||||
let aRecord = yield db.getByScope('https://example.com/a');
|
let aRecord = yield db.getByIdentifiers({scope: 'https://example.com/a',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||||
'Wrong channel ID for record A');
|
'Wrong channel ID for record A');
|
||||||
strictEqual(aRecord.version, 2,
|
strictEqual(aRecord.version, 2,
|
||||||
'Should return the new version for record A');
|
'Should return the new version for record A');
|
||||||
|
|
||||||
let bRecord = yield db.getByScope('https://example.com/b');
|
let bRecord = yield db.getByIdentifiers({scope: 'https://example.com/b',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||||
'Wrong channel ID for record B');
|
'Wrong channel ID for record B');
|
||||||
strictEqual(bRecord.version, 2,
|
strictEqual(bRecord.version, 2,
|
||||||
'Should return the previous version for record B');
|
'Should return the previous version for record B');
|
||||||
|
|
||||||
let cRecord = yield db.getByScope('https://example.com/c');
|
let cRecord = yield db.getByIdentifiers({scope: 'https://example.com/c',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||||
'Wrong channel ID for record C');
|
'Wrong channel ID for record C');
|
||||||
strictEqual(cRecord.version, 4,
|
strictEqual(cRecord.version, 4,
|
||||||
|
|
|
@ -21,6 +21,7 @@ add_task(function* test_notification_version_string() {
|
||||||
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
||||||
pushEndpoint: 'https://example.org/updates/1',
|
pushEndpoint: 'https://example.org/updates/1',
|
||||||
scope: 'https://example.com/page/1',
|
scope: 'https://example.com/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,8 @@ add_task(function* test1() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.com/retry5xxCode'
|
'https://example.com/retry5xxCode',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
var subscriptionUri = serverURL + '/subscription';
|
var subscriptionUri = serverURL + '/subscription';
|
||||||
|
|
|
@ -47,7 +47,8 @@ add_task(function* test_register_case() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield waitForPromise(
|
let newRecord = yield waitForPromise(
|
||||||
PushNotificationService.register('https://example.net/case'),
|
PushNotificationService.register('https://example.net/case',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
DEFAULT_TIMEOUT,
|
DEFAULT_TIMEOUT,
|
||||||
'Mixed-case register response timed out'
|
'Mixed-case register response timed out'
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,6 +29,7 @@ add_task(function* test_register_flush() {
|
||||||
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.com/page/1',
|
scope: 'https://example.com/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
};
|
};
|
||||||
yield db.put(record);
|
yield db.put(record);
|
||||||
|
@ -75,8 +76,7 @@ add_task(function* test_register_flush() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.com/page/2'
|
'https://example.com/page/2', '');
|
||||||
);
|
|
||||||
equal(newRecord.pushEndpoint, 'https://example.org/update/2',
|
equal(newRecord.pushEndpoint, 'https://example.org/update/2',
|
||||||
'Wrong push endpoint in record');
|
'Wrong push endpoint in record');
|
||||||
equal(newRecord.scope, 'https://example.com/page/2',
|
equal(newRecord.scope, 'https://example.com/page/2',
|
||||||
|
|
|
@ -48,7 +48,8 @@ add_task(function* test_register_invalid_channel() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/invalid-channel'),
|
PushNotificationService.register('https://example.com/invalid-channel',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'Invalid channel ID';
|
return error == 'Invalid channel ID';
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,8 @@ add_task(function* test_register_invalid_endpoint() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-endpoint'),
|
'https://example.net/page/invalid-endpoint',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes('Invalid pushEndpoint');
|
return error && error.includes('Invalid pushEndpoint');
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,8 @@ add_task(function* test_register_invalid_json() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.net/page/invalid-json'),
|
PushNotificationService.register('https://example.net/page/invalid-json',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,7 +53,8 @@ add_task(function* test_register_no_id() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/incomplete'),
|
PushNotificationService.register('https://example.com/incomplete',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,10 +45,12 @@ add_task(function* test_register_request_queue() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let firstRegister = PushNotificationService.register(
|
let firstRegister = PushNotificationService.register(
|
||||||
'https://example.com/page/1'
|
'https://example.com/page/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
let secondRegister = PushNotificationService.register(
|
let secondRegister = PushNotificationService.register(
|
||||||
'https://example.com/page/1'
|
'https://example.com/page/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
yield waitForPromise(Promise.all([
|
yield waitForPromise(Promise.all([
|
||||||
|
|
|
@ -74,7 +74,8 @@ add_task(function* test_register_rollback() {
|
||||||
|
|
||||||
// Should return a rejected promise if storage fails.
|
// Should return a rejected promise if storage fails.
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/storage-error'),
|
PushNotificationService.register('https://example.com/storage-error',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'universe has imploded';
|
return error == 'universe has imploded';
|
||||||
},
|
},
|
||||||
|
|
|
@ -57,7 +57,8 @@ add_task(function* test_register_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.org/1'
|
'https://example.org/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
equal(newRecord.channelID, channelID,
|
equal(newRecord.channelID, channelID,
|
||||||
'Wrong channel ID in registration record');
|
'Wrong channel ID in registration record');
|
||||||
|
|
|
@ -83,7 +83,8 @@ add_task(function* test_register_timeout() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.net/page/timeout'),
|
PushNotificationService.register('https://example.net/page/timeout',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -59,7 +59,8 @@ add_task(function* test_register_wrong_id() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/mismatched'),
|
PushNotificationService.register('https://example.com/mismatched',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,8 @@ add_task(function* test_register_wrong_type() {
|
||||||
let promise =
|
let promise =
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/mistyped'),
|
PushNotificationService.register('https://example.com/mistyped',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,7 @@ add_task(function* test_registrations_error() {
|
||||||
serverURI: "wss://push.example.org/",
|
serverURI: "wss://push.example.org/",
|
||||||
networkInfo: new MockDesktopNetworkInfo(),
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
db: makeStub(db, {
|
db: makeStub(db, {
|
||||||
getByScope(prev, scope) {
|
getByIdentifiers(prev, scope) {
|
||||||
return Promise.reject('Database error');
|
return Promise.reject('Database error');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -31,7 +31,8 @@ add_task(function* test_registrations_error() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.registration('https://example.net/1'),
|
PushNotificationService.registration('https://example.net/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'Database error';
|
return error == 'Database error';
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@ add_task(function* test_registrations_error() {
|
||||||
serverURI: "https://push.example.org/",
|
serverURI: "https://push.example.org/",
|
||||||
networkInfo: new MockDesktopNetworkInfo(),
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
db: makeStub(db, {
|
db: makeStub(db, {
|
||||||
getByScope(prev, scope) {
|
getByIdentifiers() {
|
||||||
return Promise.reject('Database error');
|
return Promise.reject('Database error');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -20,9 +20,9 @@ add_task(function* test_registration_missing_scope() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.registration(''),
|
PushNotificationService.registration('', ''),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error.error == 'Database error';
|
return error.error == 'NotFoundError';
|
||||||
},
|
},
|
||||||
'Record missing page and manifest URLs'
|
'Record missing page and manifest URLs'
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,6 +24,7 @@ add_task(function* test_registration_none() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let registration = yield PushNotificationService.registration(
|
let registration = yield PushNotificationService.registration(
|
||||||
'https://example.net/1');
|
'https://example.net/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
|
||||||
ok(!registration, 'Should not open a connection without registration');
|
ok(!registration, 'Should not open a connection without registration');
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,16 +20,19 @@ add_task(function* test_registration_success() {
|
||||||
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
||||||
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
||||||
scope: 'https://example.net/a',
|
scope: 'https://example.net/a',
|
||||||
|
originAttributes: '',
|
||||||
version: 5
|
version: 5
|
||||||
}, {
|
}, {
|
||||||
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
||||||
pushEndpoint: 'https://example.com/update/same-manifest/2',
|
pushEndpoint: 'https://example.com/update/same-manifest/2',
|
||||||
scope: 'https://example.net/b',
|
scope: 'https://example.net/b',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42 }),
|
||||||
version: 10
|
version: 10
|
||||||
}, {
|
}, {
|
||||||
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
||||||
pushEndpoint: 'https://example.org/update/different-manifest',
|
pushEndpoint: 'https://example.org/update/different-manifest',
|
||||||
scope: 'https://example.org/c',
|
scope: 'https://example.org/c',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42, inBrowser: true }),
|
||||||
version: 15
|
version: 15
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -59,7 +62,7 @@ add_task(function* test_registration_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let registration = yield PushNotificationService.registration(
|
let registration = yield PushNotificationService.registration(
|
||||||
'https://example.net/a');
|
'https://example.net/a', '');
|
||||||
equal(
|
equal(
|
||||||
registration.pushEndpoint,
|
registration.pushEndpoint,
|
||||||
'https://example.com/update/same-manifest/1',
|
'https://example.com/update/same-manifest/1',
|
||||||
|
|
|
@ -29,7 +29,8 @@ add_task(function* test_unregister_empty_scope() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.unregister(''),
|
PushNotificationService.unregister('',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error.error == 'NotFoundError';
|
return error.error == 'NotFoundError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,6 +20,7 @@ add_task(function* test_unregister_error() {
|
||||||
channelID: channelID,
|
channelID: channelID,
|
||||||
pushEndpoint: 'https://example.org/update/failure',
|
pushEndpoint: 'https://example.org/update/failure',
|
||||||
scope: 'https://example.net/page/failure',
|
scope: 'https://example.net/page/failure',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ add_task(function* test_unregister_error() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.net/page/failure');
|
'https://example.net/page/failure', '');
|
||||||
|
|
||||||
let result = yield db.getByKeyID(channelID);
|
let result = yield db.getByKeyID(channelID);
|
||||||
ok(!result, 'Deleted push record exists');
|
ok(!result, 'Deleted push record exists');
|
||||||
|
|
|
@ -24,11 +24,13 @@ add_task(function* test_unregister_invalid_json() {
|
||||||
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.edu/page/1',
|
scope: 'https://example.edu/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
|
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
|
||||||
pushEndpoint: 'https://example.com/update/2',
|
pushEndpoint: 'https://example.com/update/2',
|
||||||
scope: 'https://example.net/page/1',
|
scope: 'https://example.net/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -61,13 +63,13 @@ add_task(function* test_unregister_invalid_json() {
|
||||||
// "unregister" is fire-and-forget: it's sent via _send(), not
|
// "unregister" is fire-and-forget: it's sent via _send(), not
|
||||||
// _sendRequest().
|
// _sendRequest().
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.edu/page/1');
|
'https://example.edu/page/1', '');
|
||||||
let record = yield db.getByKeyID(
|
let record = yield db.getByKeyID(
|
||||||
'87902e90-c57e-4d18-8354-013f4a556559');
|
'87902e90-c57e-4d18-8354-013f4a556559');
|
||||||
ok(!record, 'Failed to delete unregistered record');
|
ok(!record, 'Failed to delete unregistered record');
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.net/page/1');
|
'https://example.net/page/1', '');
|
||||||
record = yield db.getByKeyID(
|
record = yield db.getByKeyID(
|
||||||
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
||||||
ok(!record,
|
ok(!record,
|
||||||
|
|
|
@ -29,7 +29,8 @@ add_task(function* test_unregister_not_found() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let promise = PushNotificationService.unregister(
|
let promise = PushNotificationService.unregister(
|
||||||
'https://example.net/nonexistent');
|
'https://example.net/nonexistent',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
|
||||||
yield rejects(promise, function(error) {
|
yield rejects(promise, function(error) {
|
||||||
return error == 'NotFoundError';
|
return error == 'NotFoundError';
|
||||||
}, 'Wrong error for nonexistent scope');
|
}, 'Wrong error for nonexistent scope');
|
||||||
|
|
|
@ -20,6 +20,7 @@ add_task(function* test_unregister_success() {
|
||||||
channelID,
|
channelID,
|
||||||
pushEndpoint: 'https://example.org/update/unregister-success',
|
pushEndpoint: 'https://example.org/update/unregister-success',
|
||||||
scope: 'https://example.com/page/unregister-success',
|
scope: 'https://example.com/page/unregister-success',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ add_task(function* test_unregister_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.com/page/unregister-success');
|
'https://example.com/page/unregister-success', '');
|
||||||
let record = yield db.getByKeyID(channelID);
|
let record = yield db.getByKeyID(channelID);
|
||||||
ok(!record, 'Unregister did not remove record');
|
ok(!record, 'Unregister did not remove record');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
|
||||||
|
|
||||||
|
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
|
||||||
|
const channelIDs = ['0ef2ad4a-6c49-41ad-af6e-95d2425276bf', '4818b54a-97c5-4277-ad5d-0bfe630e4e50'];
|
||||||
|
var channelIDCounter = 0;
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
do_get_profile();
|
||||||
|
setPrefs({
|
||||||
|
userAgentID,
|
||||||
|
requestTimeout: 1000,
|
||||||
|
retryBaseInterval: 150
|
||||||
|
});
|
||||||
|
disableServiceWorkerEvents(
|
||||||
|
'https://example.org/1'
|
||||||
|
);
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(function* test_webapps_cleardata() {
|
||||||
|
let db = PushServiceWebSocket.newPushDB();
|
||||||
|
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||||
|
|
||||||
|
PushService._generateID = () => channelID;
|
||||||
|
PushService.init({
|
||||||
|
serverURI: "wss://push.example.org",
|
||||||
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
|
db,
|
||||||
|
makeWebSocket(uri) {
|
||||||
|
return new MockWebSocket(uri, {
|
||||||
|
onHello(data) {
|
||||||
|
equal(data.messageType, 'hello', 'Handshake: wrong message type');
|
||||||
|
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
|
||||||
|
this.serverSendMsg(JSON.stringify({
|
||||||
|
messageType: 'hello',
|
||||||
|
status: 200,
|
||||||
|
uaid: userAgentID
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
onRegister(data) {
|
||||||
|
equal(data.messageType, 'register', 'Register: wrong message type');
|
||||||
|
this.serverSendMsg(JSON.stringify({
|
||||||
|
messageType: 'register',
|
||||||
|
status: 200,
|
||||||
|
channelID: data.channelID,
|
||||||
|
uaid: userAgentID,
|
||||||
|
pushEndpoint: 'https://example.com/update/' + Math.random(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let registers = yield Promise.all([
|
||||||
|
PushNotificationService.register(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false })),
|
||||||
|
PushNotificationService.register(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true })),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Services.obs.notifyObservers(
|
||||||
|
{ appId: 1, browserOnly: false,
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])},
|
||||||
|
"webapps-clear-data", "");
|
||||||
|
|
||||||
|
let waitAWhile = new Promise(function(res) {
|
||||||
|
setTimeout(res, 2000);
|
||||||
|
});
|
||||||
|
yield waitAWhile;
|
||||||
|
|
||||||
|
let registration;
|
||||||
|
registration = yield PushNotificationService.registration(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false }));
|
||||||
|
ok(!registration, 'Registration for { 1, false } should not exist.');
|
||||||
|
|
||||||
|
registration = yield PushNotificationService.registration(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true }));
|
||||||
|
ok(registration, 'Registration for { 1, true } should still exist.');
|
||||||
|
});
|
||||||
|
|
|
@ -30,6 +30,7 @@ skip-if = toolkit == 'android'
|
||||||
[test_unregister_invalid_json.js]
|
[test_unregister_invalid_json.js]
|
||||||
[test_unregister_not_found.js]
|
[test_unregister_not_found.js]
|
||||||
[test_unregister_success.js]
|
[test_unregister_success.js]
|
||||||
|
[test_webapps_cleardata.js]
|
||||||
#http2 test
|
#http2 test
|
||||||
[test_resubscribe_4xxCode_http2.js]
|
[test_resubscribe_4xxCode_http2.js]
|
||||||
[test_resubscribe_5xxCode_http2.js]
|
[test_resubscribe_5xxCode_http2.js]
|
||||||
|
|
|
@ -18,6 +18,14 @@ interface ChromeUtils : ThreadSafeChromeUtils {
|
||||||
*/
|
*/
|
||||||
static ByteString
|
static ByteString
|
||||||
originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs);
|
originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper that converts OriginAttributesDictionary to a opaque suffix string.
|
||||||
|
*
|
||||||
|
* @param originAttrs The originAttributes from the caller.
|
||||||
|
*/
|
||||||
|
static ByteString
|
||||||
|
originAttributesToSuffix(optional OriginAttributesDictionary originAttrs);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
* https://w3c.github.io/push-api/
|
* https://w3c.github.io/push-api/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
interface Principal;
|
||||||
|
|
||||||
[JSImplementation="@mozilla.org/push/PushSubscription;1",
|
[JSImplementation="@mozilla.org/push/PushSubscription;1",
|
||||||
Constructor(DOMString pushEndpoint, DOMString scope, DOMString pageURL), ChromeOnly]
|
Constructor(DOMString pushEndpoint, DOMString scope, Principal principal), ChromeOnly]
|
||||||
interface PushSubscription
|
interface PushSubscription
|
||||||
{
|
{
|
||||||
readonly attribute USVString endpoint;
|
readonly attribute USVString endpoint;
|
||||||
|
|
|
@ -2200,16 +2200,15 @@ public:
|
||||||
#endif /* ! MOZ_SIMPLEPUSH */
|
#endif /* ! MOZ_SIMPLEPUSH */
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
|
||||||
const nsACString& aScope,
|
const nsACString& aScope,
|
||||||
const nsAString& aData,
|
const nsAString& aData)
|
||||||
JSContext* aCx)
|
|
||||||
{
|
{
|
||||||
#ifdef MOZ_SIMPLEPUSH
|
#ifdef MOZ_SIMPLEPUSH
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
#else
|
#else
|
||||||
OriginAttributes attrs;
|
OriginAttributes attrs;
|
||||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2226,7 +2225,9 @@ ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
||||||
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
|
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
|
||||||
serviceWorkerHandle);
|
serviceWorkerHandle);
|
||||||
|
|
||||||
if (NS_WARN_IF(!r->Dispatch(aCx))) {
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2235,15 +2236,14 @@ ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ServiceWorkerManager::SendPushSubscriptionChangeEvent(JS::Handle<JS::Value> aOriginAttributes,
|
ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginAttributes,
|
||||||
const nsACString& aScope,
|
const nsACString& aScope)
|
||||||
JSContext* aCx)
|
|
||||||
{
|
{
|
||||||
#ifdef MOZ_SIMPLEPUSH
|
#ifdef MOZ_SIMPLEPUSH
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
#else
|
#else
|
||||||
OriginAttributes attrs;
|
OriginAttributes attrs;
|
||||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2259,7 +2259,9 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(JS::Handle<JS::Value> aOri
|
||||||
new SendPushSubscriptionChangeEventRunnable(
|
new SendPushSubscriptionChangeEventRunnable(
|
||||||
serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
|
serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
|
||||||
|
|
||||||
if (NS_WARN_IF(!r->Dispatch(aCx))) {
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ function display(info) {
|
||||||
createItem(bundle.GetStringFromName('waitingCacheName'), info.waitingCacheName);
|
createItem(bundle.GetStringFromName('waitingCacheName'), info.waitingCacheName);
|
||||||
|
|
||||||
let pushItem = createItem(bundle.GetStringFromName('pushEndpoint'), bundle.GetStringFromName('waiting'));
|
let pushItem = createItem(bundle.GetStringFromName('pushEndpoint'), bundle.GetStringFromName('waiting'));
|
||||||
PushNotificationService.registration(info.scope).then(
|
PushNotificationService.registration(info.scope, info.principal.originAttributes).then(
|
||||||
pushRecord => {
|
pushRecord => {
|
||||||
pushItem.data = JSON.stringify(pushRecord);
|
pushItem.data = JSON.stringify(pushRecord);
|
||||||
},
|
},
|
||||||
|
|
Загрузка…
Ссылка в новой задаче