Bug 1027734 - Convert mozPay to WebIDL. r=bzbarsky.

This commit is contained in:
Peter Van der Beken 2016-01-26 18:38:03 +01:00
parent 22b0583546
commit 0647b9863e
14 changed files with 225 additions and 210 deletions

View File

@ -128,6 +128,11 @@
#include <cutils/properties.h>
#endif
#ifdef MOZ_PAY
#include "nsIPaymentContentHelperService.h"
#include "mozilla/dom/DOMRequest.h"
#endif
namespace mozilla {
namespace dom {
@ -2672,6 +2677,36 @@ Navigator::MozE10sEnabled()
return true;
}
#ifdef MOZ_PAY
already_AddRefed<DOMRequest>
Navigator::MozPay(JSContext* aCx,
JS::Handle<JS::Value> aJwts,
ErrorResult& aRv)
{
if (!mWindow || !mWindow->GetDocShell()) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsresult rv;
nsCOMPtr<nsIPaymentContentHelperService> service =
do_GetService("@mozilla.org/payment/content-helper-service;1", &rv);
if (!service) {
aRv.Throw(rv);
return nullptr;
}
RefPtr<nsIDOMDOMRequest> request;
rv = service->Pay(mWindow, aJwts, getter_AddRefs(request));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
#endif // MOZ_PAY
/* static */
already_AddRefed<nsPIDOMWindowInner>
Navigator::GetWindowFromGlobal(JSObject* aGlobal)

View File

@ -42,6 +42,7 @@ class WakeLock;
class ArrayBufferViewOrBlobOrStringOrFormData;
struct MobileIdOptions;
class ServiceWorkerContainer;
class DOMRequest;
} // namespace dom
} // namespace mozilla
@ -315,6 +316,12 @@ public:
bool MozE10sEnabled();
#ifdef MOZ_PAY
already_AddRefed<DOMRequest> MozPay(JSContext* aCx,
JS::Handle<JS::Value> aJwts,
ErrorResult& aRv);
#endif // MOZ_PAY
static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
// WebIDL helper methods

View File

@ -10,9 +10,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
const PAYMENTCONTENTHELPER_CID =
Components.ID("{a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}");
const PAYMENT_IPC_MSG_NAMES = ["Payment:Success",
"Payment:Failed"];
@ -22,39 +19,82 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
function PaymentContentHelper() {
var _debug;
try {
_debug = Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
&& Services.prefs.getBoolPref(PREF_DEBUG);
} catch(e) {
_debug = false;
}
function LOG(s) {
if (!_debug) {
return;
}
dump("-*- PaymentContentHelper: " + s + "\n");
}
function PaymentContentHelper(aWindow) {
this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
};
PaymentContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavigatorPayment,
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
classID: PAYMENTCONTENTHELPER_CID,
classInfo: XPCOMUtils.generateCI({
classID: PAYMENTCONTENTHELPER_CID,
contractID: "@mozilla.org/payment/content-helper;1",
classDescription: "Payment Content Helper",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsINavigatorPayment]
}),
receiveMessage: function receiveMessage(aMessage) {
let name = aMessage.name;
let msg = aMessage.json;
if (_debug) {
LOG("Received message '" + name + "': " + JSON.stringify(msg));
}
let requestId = msg.requestId;
let request = this.takeRequest(requestId);
if (!request) {
return;
}
switch (name) {
case "Payment:Success":
Services.DOMRequest.fireSuccess(request, msg.result);
break;
case "Payment:Failed":
Services.DOMRequest.fireError(request, msg.errorMsg);
break;
}
},
};
function PaymentContentHelperService() {
};
PaymentContentHelperService.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentContentHelperService]),
classID: Components.ID("{80035846-6732-4fcc-961b-f336b65218f4}"),
contractID: "@mozilla.org/payment/content-helper-service;1",
_xpcom_factory: XPCOMUtils.generateSingletonFactory(PaymentContentHelperService),
// keys are windows and values are PaymentContentHelpers
helpers: new WeakMap(),
// nsINavigatorPayment
pay: function pay(aWindow, aJwts) {
let requestHelper = this.helpers.get(aWindow);
if (!requestHelper) {
requestHelper = new PaymentContentHelper(aWindow);
this.helpers.set(aWindow, requestHelper);
}
let request = requestHelper.createRequest();
let requestId = requestHelper.getRequestId(request);
pay: function pay(aJwts) {
let request = this.createRequest();
let requestId = this.getRequestId(request);
let docShell = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (!docShell.isActive) {
if (this._debug) {
this.LOG("The caller application is a background app. No request " +
"will be sent");
if (_debug) {
LOG("The caller application is a background app. No request will be " +
"sent");
}
let runnable = {
run: function run() {
Services.DOMRequest.fireError(request, "BACKGROUND_APP");
@ -75,61 +115,6 @@ PaymentContentHelper.prototype = {
});
return request;
},
// nsIDOMGlobalPropertyInitializer
init: function(aWindow) {
try {
if (!Services.prefs.getBoolPref("dom.mozPay.enabled")) {
return null;
}
} catch (e) {
return null;
}
this._window = aWindow;
this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
try {
this._debug =
Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
&& Services.prefs.getBoolPref(PREF_DEBUG);
} catch(e) {
this._debug = false;
}
return Cu.exportFunction(this.pay.bind(this), aWindow);
},
// nsIFrameMessageListener
receiveMessage: function receiveMessage(aMessage) {
let name = aMessage.name;
let msg = aMessage.json;
if (this._debug) {
this.LOG("Received message '" + name + "': " + JSON.stringify(msg));
}
let requestId = msg.requestId;
let request = this.takeRequest(requestId);
if (!request) {
return;
}
switch (name) {
case "Payment:Success":
Services.DOMRequest.fireSuccess(request, msg.result);
break;
case "Payment:Failed":
Services.DOMRequest.fireError(request, msg.errorMsg);
break;
}
},
LOG: function LOG(s) {
if (!this._debug) {
return;
}
dump("-*- PaymentContentHelper: " + s + "\n");
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelper]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelperService]);

View File

@ -1,6 +1,5 @@
component {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} Payment.js
contract @mozilla.org/payment/content-helper;1 {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}
category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helper;1
component {80035846-6732-4fcc-961b-f336b65218f4} Payment.js
contract @mozilla.org/payment/content-helper-service;1 {80035846-6732-4fcc-961b-f336b65218f4}
component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js
contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c}

View File

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsINavigatorPayment.idl',
'nsIPaymentContentHelperService.idl',
'nsIPaymentFlowInfo.idl',
'nsIPaymentProviderStrategy.idl',
'nsIPaymentUIGlue.idl',

View File

@ -5,13 +5,14 @@
#include "domstubs.idl"
interface nsIDOMDOMRequest;
interface mozIDOMWindow;
[scriptable, uuid(44fb7308-7d7b-4975-8a27-e01fe9623bdb)]
interface nsINavigatorPayment : nsISupports
[scriptable, uuid(80035846-6732-4fcc-961b-f336b65218f4)]
interface nsIPaymentContentHelperService : nsISupports
{
// The 'jwts' parameter can be either a single DOMString or an array of
// DOMStrings. In both cases, it represents the base64url encoded and
// digitally signed payment information. Each payment provider should
// define its supported JWT format.
nsIDOMDOMRequest pay(in jsval jwts);
nsIDOMDOMRequest pay(in mozIDOMWindow window, in jsval jwts);
};

View File

@ -0,0 +1,91 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cm = Components.manager;
const Cu = Components.utils;
const CONTRACT_ID = "@mozilla.org/payment/ui-glue;1";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
var oldClassID, oldFactory;
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
var newFactory = {
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return new MockPaymentsUIGlueInstance().QueryInterface(aIID);
},
lockFactory: function(aLock) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
};
addMessageListener("MockPaymentsUIGlue.init", function (message) {
try {
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(oldClassID, Ci.nsIFactory);
} catch (ex) {
oldClassID = "";
oldFactory = null;
dump("TEST-INFO | can't get payments ui glue registered component, " +
"assuming there is none\n");
}
if (oldFactory) {
registrar.unregisterFactory(oldClassID, oldFactory);
}
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);});
addMessageListener("MockPaymentsUIGlue.cleanup", function (message) {
if (oldClassID) {
registrar.registerFactory(oldClassID, "", CONTRACT_ID, null);
}
});
var payments = new Map();
function MockPaymentsUIGlueInstance() {
};
MockPaymentsUIGlueInstance.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
confirmPaymentRequest: function(aRequestId,
aRequests,
aSuccessCb,
aErrorCb) {
aSuccessCb.onresult(aRequestId, aRequests[0].type);
},
showPaymentFlow: function(aRequestId,
aPaymentFlowInfo,
aErrorCb) {
let win = Services.ww.openWindow(null,
null,
"_blank",
"chrome,dialog=no,resizable,scrollbars,centerscreen",
null);
payments.set(aRequestId, win);
let docshell = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
docshell.paymentRequestId = aRequestId;
win.document.location = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
},
closePaymentFlow: function(aRequestId) {
payments.get(aRequestId).close();
payments.delete(aRequestId);
return Promise.resolve();
},
};

View File

@ -1,12 +1,11 @@
[DEFAULT]
skip-if=true # This test uses MockPaymentsUIGlue which uses __exposedProps__
# we need to move this to a chrome test, but these are not
# available in b2g or android for now.
skip-if=buildapp != 'b2g' && toolkit != 'android'
support-files=
file_mozpayproviderchecker.html
file_payprovidersuccess.html
file_payproviderfailure.html
MockPaymentsUIChromeScript.js
[test_mozpaymentprovider.html]
[test_mozpay_callbacks.html]

View File

@ -79,7 +79,11 @@ function runTest() {
tests.shift()();
}
SpecialPowers.MockPaymentsUIGlue.init(window);
const uiGlue = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('MockPaymentsUIChromeScript.js'));
SimpleTest.registerCleanupFunction(() => {
uiGlue.sendAsyncMessage("MockPaymentsUIGlue.cleanup", {});
});
uiGlue.sendAsyncMessage("MockPaymentsUIGlue.init", {});
SpecialPowers.pushPrefEnv({
"set": [
@ -88,13 +92,13 @@ SpecialPowers.pushPrefEnv({
["dom.payment.provider.1.name", "SuccessProvider"],
["dom.payment.provider.1.description", ""],
["dom.payment.provider.1.uri",
"http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
"https://example.com:443/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
["dom.payment.provider.1.type", "mozilla/payments/test/success"],
["dom.payment.provider.1.requestMethod", "GET"],
["dom.payment.provider.2.name", "FailureProvider"],
["dom.payment.provider.2.description", ""],
["dom.payment.provider.2.uri",
"http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
"https://example.com:443/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
["dom.payment.provider.2.type", "mozilla/payments/test/failure"],
["dom.payment.provider.2.requestMethod", "GET"],
]

View File

@ -465,3 +465,14 @@ partial interface Navigator {
readonly attribute boolean mozE10sEnabled;
};
#endif
#ifdef MOZ_PAY
partial interface Navigator {
[Throws, NewObject, Pref="dom.mozPay.enabled"]
// The 'jwts' parameter can be either a single DOMString or an array of
// DOMStrings. In both cases, it represents the base64url encoded and
// digitally signed payment information. Each payment provider should
// define its supported JWT format.
DOMRequest mozPay(any jwts);
};
#endif

View File

@ -42,5 +42,4 @@ marionette.jar:
content/MockFilePicker.jsm (../specialpowers/content/MockFilePicker.jsm)
content/MockColorPicker.jsm (../specialpowers/content/MockColorPicker.jsm)
content/MockPermissionPrompt.jsm (../specialpowers/content/MockPermissionPrompt.jsm)
content/MockPaymentsUIGlue.jsm (../specialpowers/content/MockPaymentsUIGlue.jsm)
content/Assert.jsm (../modules/Assert.jsm)

View File

@ -1,110 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["MockPaymentsUIGlue"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cm = Components.manager;
const Cu = Components.utils;
const CONTRACT_ID = "@mozilla.org/payment/ui-glue;1";
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
var classID;
var oldFactory;
var newFactory = function(window) {
return {
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return new MockPaymentsUIGlueInstance(window).QueryInterface(aIID);
},
lockFactory: function(aLock) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
};
};
this.MockPaymentsUIGlue = {
init: function(aWindow) {
try {
classID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
} catch (ex) {
oldClassID = "";
oldFactory = null;
dump("TEST-INFO | can't get payments ui glue registered component, " +
"assuming there is none");
}
if (oldFactory) {
registrar.unregisterFactory(classID, oldFactory);
}
registrar.registerFactory(classID, "", CONTRACT_ID,
new newFactory(aWindow));
},
reset: function() {
},
cleanup: function() {
this.reset();
if (oldFactory) {
registrar.unregisterFactory(classID, newFactory);
registrar.registerFactory(classID, "", CONTRACT_ID, oldFactory);
}
}
};
function MockPaymentsUIGlueInstance(aWindow) {
this.window = aWindow;
};
MockPaymentsUIGlueInstance.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
confirmPaymentRequest: function(aRequestId,
aRequests,
aSuccessCb,
aErrorCb) {
aSuccessCb.onresult(aRequestId, aRequests[0].type);
},
showPaymentFlow: function(aRequestId,
aPaymentFlowInfo,
aErrorCb) {
let document = this.window.document;
let frame = document.createElement("iframe");
frame.setAttribute("mozbrowser", true);
frame.setAttribute("remote", true);
document.body.appendChild(frame);
let docshell = frame.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
docshell.paymentRequestId = aRequestId;
frame.src = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
},
closePaymentFlow: function(aRequestId) {
return Promise.resolve();
}
};
// Expose everything to content. We call reset() here so that all of the relevant
// lazy expandos get added.
MockPaymentsUIGlue.reset();
function exposeAll(obj) {
var props = {};
for (var prop in obj)
props[prop] = 'rw';
obj.__exposedProps__ = props;
}
exposeAll(MockPaymentsUIGlue);
exposeAll(MockPaymentsUIGlueInstance.prototype);

View File

@ -14,7 +14,6 @@ var Cu = Components.utils;
Cu.import("chrome://specialpowers/content/MockFilePicker.jsm");
Cu.import("chrome://specialpowers/content/MockColorPicker.jsm");
Cu.import("chrome://specialpowers/content/MockPermissionPrompt.jsm");
Cu.import("chrome://specialpowers/content/MockPaymentsUIGlue.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -461,10 +460,6 @@ SpecialPowersAPI.prototype = {
return MockPermissionPrompt;
},
get MockPaymentsUIGlue() {
return MockPaymentsUIGlue;
},
loadChromeScript: function (url) {
// Create a unique id for this chrome script
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]

View File

@ -8,5 +8,4 @@ specialpowers.jar:
content/MockFilePicker.jsm (content/MockFilePicker.jsm)
content/MockColorPicker.jsm (content/MockColorPicker.jsm)
content/MockPermissionPrompt.jsm (content/MockPermissionPrompt.jsm)
content/MockPaymentsUIGlue.jsm (content/MockPaymentsUIGlue.jsm)
content/Assert.jsm (../modules/Assert.jsm)