Use registerProtocolHandler without contentWindow

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-02 20:31:20

问题


I'm trying to install hotmail to my mailto handlers:

This is accomplished with this code from webpage scope:

navigator.registerProtocolHandler('mailto','http://mail.live.com/secure/start?action=compose&to=%s','Live Mail');

From XPCOM we would have to use this: MXR ::WebContentConverter.js#369) .

So from searching github code I figure you import it like this:

var nsiwchr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].getService(Ci.nsIWebContentHandlerRegistrar);

So I would register it like this:

nsiwchr.registerProtocolHandler('mailto','http://mail.live.com/secure/start?action=compose&to=%s','Live Mail', null);

I use null because I don't have a contentWindow but apparently you can't pass null for this. Because:

http://mxr.mozilla.org/mozilla-release/source/browser/components/feeds/src/WebContentConverter.js#372

var uri = this._checkAndGetURI(aURIString, aContentWindow);

And then it tests:

aContentWindow.location.hostname != uri.host)

So I figured to fake it out like this:

var fakeContentWindow = {
  document: {
    baseURIObject: {
      asciiHost:"mail.live.com",
      asciiSpec:"http://mail.live.com/secure",
      hasRef:true,
      host:"mail.live.com",
      hostPort:"mail.live.com",
      originCharset:"UTF-8",
      password:"",
      path:"/secure",
      port:-1,
      prePath:"http://mail.live.com",
      ref:"", //369
      scheme:"http",
      spec:"http://mail.live.com/secure",
      specIgnoringRef:"http://mail.live.com",
      userPass:"",
      username:""
    }
  },
  location: {
    hash:"", //#369
    host:"mail.live.com",
    hostname:"mail.live.com",
    href:"http://mail.live.com/secure",
    origin:"http://mxr.mozilla.org",
    pathname:"/secure",
    port:"",
    protocol:"http:",
    search:""
  }
};

nsiwchr.registerProtocolHandler('mailto','http://mail.live.com/secure/start?action=compose&to=%s','Live Mail', fakeContentWindow);

but it throws some totally weird error:

/* Exception: [object XPCWrappedNative_NoHelper] */ Browser Console throws:

"[object XPCWrappedNative_NoHelper]" scratchpad.js:999
SP_writeAsErrorComment/<() scratchpad.js:999
Handler.prototype.process() Promise-backend.js:863
this.PromiseWalker.walkerLoop() Promise-backend.js:742

This makes no sense. I want to successfully spoof this without using a real contentWindow.


回答1:


You simply cannot use that high-level API without a window (and you probably don't want to use it anyway, because it will not actually add the handler, but show a UI notification that first asks the user to add it; which is not only not what you want, but also won't work because there is no UI to display that notification in the first place).

Instead, you'll want to create your own version based on the implementation that omits all those security checks, UI notifications, etc.

Based on registerNotificiation, it would look something like this.

var protocolScheme = "mailtoorsomething";
var uri = Services.io.newURI("someuri?with_%s_replacement", null, null);
var name = "Some Name";
var desc = "Some description";

var protocolHandler = Services.io.getProtocolHandler(protocolScheme);
if (!(protocolHandler instanceof Ci.nsIExternalProtocolHandler)) {
  throw new Error("Cannot register handler for built-in protocol");
}

var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
          getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo(protocolScheme);
var handlers =  handlerInfo.possibleApplicationHandlers;
for (let i = 0; i < handlers.length; i++) {
  let h = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
  if (h.uriTemplate == uri.spec) {
    throw new Error("Already registered");
  }
}

var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
              createInstance(Ci.nsIWebHandlerApp);
handler.name = name;
handler.detailedDescription = desc;
handler.uriTemplate = uri.spec;
handlerInfo.possibleApplicationHandlers.appendElement(handler, false);

handlerInfo.alwaysAskBeforeHandling = false;
handlerInfo.preferredApplicationHandler = handler;
handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;

var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
          getService(Ci.nsIHandlerService);
hs.store(handlerInfo);


来源:https://stackoverflow.com/questions/24900655/use-registerprotocolhandler-without-contentwindow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!