forked from mirrors/gecko-dev
		
	MozReview-Commit-ID: 78dXLYVW1gC --HG-- extra : rebase_source : 4d2c50697307177c76a71ca7989863f01b05290b
		
			
				
	
	
		
			1063 lines
		
	
	
	
		
			35 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1063 lines
		
	
	
	
		
			35 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 | 
						|
/* 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/. */
 | 
						|
 | 
						|
Components.utils.import("resource://gre/modules/Services.jsm");
 | 
						|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 | 
						|
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 | 
						|
 | 
						|
const Cc = Components.classes;
 | 
						|
const Ci = Components.interfaces;
 | 
						|
const Cr = Components.results;
 | 
						|
 | 
						|
function LOG(str) {
 | 
						|
  dump("*** " + str + "\n");
 | 
						|
}
 | 
						|
 | 
						|
const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
 | 
						|
const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
 | 
						|
 | 
						|
const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
 | 
						|
const WCC_CLASSNAME = "Web Service Handler";
 | 
						|
 | 
						|
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 | 
						|
const TYPE_ANY = "*/*";
 | 
						|
 | 
						|
const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto.";
 | 
						|
const PREF_CONTENTHANDLERS_BRANCH = "browser.contentHandlers.types.";
 | 
						|
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
 | 
						|
const PREF_SELECTED_ACTION = "browser.feeds.handler";
 | 
						|
const PREF_SELECTED_READER = "browser.feeds.handler.default";
 | 
						|
const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external";
 | 
						|
 | 
						|
const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
 | 
						|
 | 
						|
const NS_ERROR_MODULE_DOM = 2152923136;
 | 
						|
const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
 | 
						|
 | 
						|
function WebContentConverter() {
 | 
						|
}
 | 
						|
WebContentConverter.prototype = {
 | 
						|
  convert() { },
 | 
						|
  asyncConvertData() { },
 | 
						|
  onDataAvailable() { },
 | 
						|
  onStopRequest() { },
 | 
						|
 | 
						|
  onStartRequest(request, context) {
 | 
						|
    let wccr =
 | 
						|
        Cc[WCCR_CONTRACTID].
 | 
						|
        getService(Ci.nsIWebContentConverterService);
 | 
						|
    wccr.loadPreferredHandler(request);
 | 
						|
  },
 | 
						|
 | 
						|
  QueryInterface(iid) {
 | 
						|
    if (iid.equals(Ci.nsIStreamConverter) ||
 | 
						|
        iid.equals(Ci.nsIStreamListener) ||
 | 
						|
        iid.equals(Ci.nsISupports))
 | 
						|
      return this;
 | 
						|
    throw Cr.NS_ERROR_NO_INTERFACE;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
let WebContentConverterFactory = {
 | 
						|
  createInstance(outer, iid) {
 | 
						|
    if (outer != null)
 | 
						|
      throw Cr.NS_ERROR_NO_AGGREGATION;
 | 
						|
    return new WebContentConverter().QueryInterface(iid);
 | 
						|
  },
 | 
						|
 | 
						|
  QueryInterface(iid) {
 | 
						|
    if (iid.equals(Ci.nsIFactory) ||
 | 
						|
        iid.equals(Ci.nsISupports))
 | 
						|
      return this;
 | 
						|
    throw Cr.NS_ERROR_NO_INTERFACE;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
function ServiceInfo(contentType, uri, name) {
 | 
						|
  this._contentType = contentType;
 | 
						|
  this._uri = uri;
 | 
						|
  this._name = name;
 | 
						|
}
 | 
						|
ServiceInfo.prototype = {
 | 
						|
  /**
 | 
						|
   * See nsIHandlerApp
 | 
						|
   */
 | 
						|
  get name() {
 | 
						|
    return this._name;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIHandlerApp
 | 
						|
   */
 | 
						|
  equals(aHandlerApp) {
 | 
						|
    if (!aHandlerApp)
 | 
						|
      throw Cr.NS_ERROR_NULL_POINTER;
 | 
						|
 | 
						|
    if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo &&
 | 
						|
        aHandlerApp.contentType == this.contentType &&
 | 
						|
        aHandlerApp.uri == this.uri)
 | 
						|
      return true;
 | 
						|
 | 
						|
    return false;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerInfo
 | 
						|
   */
 | 
						|
  get contentType() {
 | 
						|
    return this._contentType;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerInfo
 | 
						|
   */
 | 
						|
  get uri() {
 | 
						|
    return this._uri;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerInfo
 | 
						|
   */
 | 
						|
  getHandlerURI(uri) {
 | 
						|
    return this._uri.replace(/%s/gi, encodeURIComponent(uri));
 | 
						|
  },
 | 
						|
 | 
						|
  QueryInterface(iid) {
 | 
						|
    if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
 | 
						|
        iid.equals(Ci.nsISupports))
 | 
						|
      return this;
 | 
						|
    throw Cr.NS_ERROR_NO_INTERFACE;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
const Utils = {
 | 
						|
  makeURI(aURL, aOriginCharset, aBaseURI) {
 | 
						|
    return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
 | 
						|
  },
 | 
						|
 | 
						|
  checkAndGetURI(aURIString, aContentWindow) {
 | 
						|
    let uri;
 | 
						|
    try {
 | 
						|
      let baseURI = aContentWindow.document.baseURIObject;
 | 
						|
      uri = this.makeURI(aURIString, null, baseURI);
 | 
						|
    } catch (ex) {
 | 
						|
      throw NS_ERROR_DOM_SYNTAX_ERR;
 | 
						|
    }
 | 
						|
 | 
						|
    // For security reasons we reject non-http(s) urls (see bug 354316),
 | 
						|
    // we may need to revise this once we support more content types
 | 
						|
    if (uri.scheme != "http" && uri.scheme != "https") {
 | 
						|
      throw this.getSecurityError(
 | 
						|
        "Permission denied to add " + uri.spec + " as a content or protocol handler",
 | 
						|
        aContentWindow);
 | 
						|
    }
 | 
						|
 | 
						|
    // We also reject handlers registered from a different host (see bug 402287)
 | 
						|
    if (!["http:", "https:"].includes(aContentWindow.location.protocol) ||
 | 
						|
        aContentWindow.location.hostname != uri.host) {
 | 
						|
      throw this.getSecurityError(
 | 
						|
        "Permission denied to add " + uri.spec + " as a content or protocol handler",
 | 
						|
        aContentWindow);
 | 
						|
    }
 | 
						|
 | 
						|
    // If the uri doesn't contain '%s', it won't be a good handler
 | 
						|
    if (uri.spec.indexOf("%s") < 0)
 | 
						|
      throw NS_ERROR_DOM_SYNTAX_ERR;
 | 
						|
 | 
						|
    return uri;
 | 
						|
  },
 | 
						|
 | 
						|
  // NB: Throws if aProtocol is not allowed.
 | 
						|
  checkProtocolHandlerAllowed(aProtocol, aURIString, aWindowOrNull) {
 | 
						|
    // First, check to make sure this isn't already handled internally (we don't
 | 
						|
    // want to let them take over, say "chrome").
 | 
						|
    let handler = Services.io.getProtocolHandler(aProtocol);
 | 
						|
    if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
 | 
						|
      // This is handled internally, so we don't want them to register
 | 
						|
      throw this.getSecurityError(
 | 
						|
        `Permission denied to add ${aURIString} as a protocol handler`,
 | 
						|
        aWindowOrNull);
 | 
						|
    }
 | 
						|
 | 
						|
    // check if it is in the black list
 | 
						|
    let pb = Services.prefs;
 | 
						|
    let allowed;
 | 
						|
    try {
 | 
						|
      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
 | 
						|
    } catch (e) {
 | 
						|
      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
 | 
						|
    }
 | 
						|
    if (!allowed) {
 | 
						|
      throw this.getSecurityError(
 | 
						|
        `Not allowed to register a protocol handler for ${aProtocol}`,
 | 
						|
        aWindowOrNull);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // Return a SecurityError exception from the given Window if one is given.  If
 | 
						|
  // none is given, just return the given error string, for lack of anything
 | 
						|
  // better.
 | 
						|
  getSecurityError(errorString, aWindowOrNull) {
 | 
						|
    if (!aWindowOrNull) {
 | 
						|
      return errorString;
 | 
						|
    }
 | 
						|
 | 
						|
    return new aWindowOrNull.DOMException(errorString, "SecurityError");
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Mappings from known feed types to our internal content type.
 | 
						|
   */
 | 
						|
  _mappings: {
 | 
						|
    "application/rss+xml": TYPE_MAYBE_FEED,
 | 
						|
    "application/atom+xml": TYPE_MAYBE_FEED,
 | 
						|
  },
 | 
						|
 | 
						|
  resolveContentType(aContentType) {
 | 
						|
    if (aContentType in this._mappings)
 | 
						|
      return this._mappings[aContentType];
 | 
						|
    return aContentType;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
function WebContentConverterRegistrar() {
 | 
						|
  this._contentTypes = {};
 | 
						|
  this._autoHandleContentTypes = {};
 | 
						|
}
 | 
						|
 | 
						|
WebContentConverterRegistrar.prototype = {
 | 
						|
  get stringBundle() {
 | 
						|
    let sb = Services.strings.createBundle(STRING_BUNDLE_URI);
 | 
						|
    delete WebContentConverterRegistrar.prototype.stringBundle;
 | 
						|
    return WebContentConverterRegistrar.prototype.stringBundle = sb;
 | 
						|
  },
 | 
						|
 | 
						|
  _getFormattedString(key, params) {
 | 
						|
    return this.stringBundle.formatStringFromName(key, params, params.length);
 | 
						|
  },
 | 
						|
 | 
						|
  _getString(key) {
 | 
						|
    return this.stringBundle.GetStringFromName(key);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  getAutoHandler(contentType) {
 | 
						|
    contentType = Utils.resolveContentType(contentType);
 | 
						|
    if (contentType in this._autoHandleContentTypes)
 | 
						|
      return this._autoHandleContentTypes[contentType];
 | 
						|
    return null;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  setAutoHandler(contentType, handler) {
 | 
						|
    if (handler && !this._typeIsRegistered(contentType, handler.uri))
 | 
						|
      throw Cr.NS_ERROR_NOT_AVAILABLE;
 | 
						|
 | 
						|
    contentType = Utils.resolveContentType(contentType);
 | 
						|
    this._setAutoHandler(contentType, handler);
 | 
						|
 | 
						|
    let ps = Services.prefs;
 | 
						|
    let autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
 | 
						|
    if (handler)
 | 
						|
      autoBranch.setCharPref(contentType, handler.uri);
 | 
						|
    else if (autoBranch.prefHasUserValue(contentType))
 | 
						|
      autoBranch.clearUserPref(contentType);
 | 
						|
 | 
						|
    ps.savePrefFile(null);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Update the internal data structure (not persistent)
 | 
						|
   */
 | 
						|
  _setAutoHandler(contentType, handler) {
 | 
						|
    if (handler)
 | 
						|
      this._autoHandleContentTypes[contentType] = handler;
 | 
						|
    else if (contentType in this._autoHandleContentTypes)
 | 
						|
      delete this._autoHandleContentTypes[contentType];
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  getWebContentHandlerByURI(contentType, uri) {
 | 
						|
    return this.getContentHandlers(contentType)
 | 
						|
               .find(e => e.uri == uri) || null;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  loadPreferredHandler(request) {
 | 
						|
    let channel = request.QueryInterface(Ci.nsIChannel);
 | 
						|
    let contentType = Utils.resolveContentType(channel.contentType);
 | 
						|
    let handler = this.getAutoHandler(contentType);
 | 
						|
    if (handler) {
 | 
						|
      request.cancel(Cr.NS_ERROR_FAILURE);
 | 
						|
 | 
						|
      let webNavigation =
 | 
						|
          channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
 | 
						|
      webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec),
 | 
						|
                            Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
 | 
						|
                            null, null, null);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  removeProtocolHandler(aProtocol, aURITemplate) {
 | 
						|
    let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
 | 
						|
              getService(Ci.nsIExternalProtocolService);
 | 
						|
    let handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
 | 
						|
    let handlers =  handlerInfo.possibleApplicationHandlers;
 | 
						|
    for (let i = 0; i < handlers.length; i++) {
 | 
						|
      try { // We only want to test web handlers
 | 
						|
        let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
 | 
						|
        if (handler.uriTemplate == aURITemplate) {
 | 
						|
          handlers.removeElementAt(i);
 | 
						|
          let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
 | 
						|
                   getService(Ci.nsIHandlerService);
 | 
						|
          hs.store(handlerInfo);
 | 
						|
          return;
 | 
						|
        }
 | 
						|
      } catch (e) { /* it wasn't a web handler */ }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  removeContentHandler(contentType, uri) {
 | 
						|
    function notURI(serviceInfo) {
 | 
						|
      return serviceInfo.uri != uri;
 | 
						|
    }
 | 
						|
 | 
						|
    if (contentType in this._contentTypes) {
 | 
						|
      this._contentTypes[contentType] =
 | 
						|
        this._contentTypes[contentType].filter(notURI);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * These are types for which there is a separate content converter aside
 | 
						|
   * from our built in generic one. We should not automatically register
 | 
						|
   * a factory for creating a converter for these types.
 | 
						|
   */
 | 
						|
  _blockedTypes: {
 | 
						|
    "application/vnd.mozilla.maybe.feed": true,
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Determines if a web handler is already registered.
 | 
						|
   *
 | 
						|
   * @param aProtocol
 | 
						|
   *        The scheme of the web handler we are checking for.
 | 
						|
   * @param aURITemplate
 | 
						|
   *        The URI template that the handler uses to handle the protocol.
 | 
						|
   * @return true if it is already registered, false otherwise.
 | 
						|
   */
 | 
						|
  _protocolHandlerRegistered(aProtocol, aURITemplate) {
 | 
						|
    let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
 | 
						|
              getService(Ci.nsIExternalProtocolService);
 | 
						|
    let handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
 | 
						|
    let handlers =  handlerInfo.possibleApplicationHandlers;
 | 
						|
    for (let i = 0; i < handlers.length; i++) {
 | 
						|
      try { // We only want to test web handlers
 | 
						|
        let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
 | 
						|
        if (handler.uriTemplate == aURITemplate)
 | 
						|
          return true;
 | 
						|
      } catch (e) { /* it wasn't a web handler */ }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerRegistrar
 | 
						|
   */
 | 
						|
  registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
 | 
						|
    LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
 | 
						|
    let haveWindow = (aBrowserOrWindow instanceof Ci.nsIDOMWindow);
 | 
						|
    let uri;
 | 
						|
    if (haveWindow) {
 | 
						|
      uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
 | 
						|
    } else {
 | 
						|
      // aURIString must not be a relative URI.
 | 
						|
      uri = Utils.makeURI(aURIString, null);
 | 
						|
    }
 | 
						|
 | 
						|
    // If the protocol handler is already registered, just return early.
 | 
						|
    if (this._protocolHandlerRegistered(aProtocol, uri.spec)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let browser;
 | 
						|
    if (haveWindow) {
 | 
						|
      let browserWindow =
 | 
						|
        this._getBrowserWindowForContentWindow(aBrowserOrWindow);
 | 
						|
      browser = this._getBrowserForContentWindow(browserWindow,
 | 
						|
                                                 aBrowserOrWindow);
 | 
						|
    } else {
 | 
						|
      browser = aBrowserOrWindow;
 | 
						|
    }
 | 
						|
    if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
 | 
						|
      // Inside the private browsing mode, we don't want to alert the user to save
 | 
						|
      // a protocol handler.  We log it to the error console so that web developers
 | 
						|
      // would have some way to tell what's going wrong.
 | 
						|
      Services.console.
 | 
						|
      logStringMessage("Web page denied access to register a protocol handler inside private browsing mode");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    Utils.checkProtocolHandlerAllowed(aProtocol, aURIString,
 | 
						|
                                      haveWindow ? aBrowserOrWindow : null);
 | 
						|
 | 
						|
    // Now Ask the user and provide the proper callback
 | 
						|
    let message = this._getFormattedString("addProtocolHandler",
 | 
						|
                                           [aTitle, uri.host, aProtocol]);
 | 
						|
 | 
						|
    let notificationIcon = uri.prePath + "/favicon.ico";
 | 
						|
    let notificationValue = "Protocol Registration: " + aProtocol;
 | 
						|
    let addButton = {
 | 
						|
      label: this._getString("addProtocolHandlerAddButton"),
 | 
						|
      accessKey: this._getString("addProtocolHandlerAddButtonAccesskey"),
 | 
						|
      protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
 | 
						|
 | 
						|
      callback(aNotification, aButtonInfo) {
 | 
						|
          let protocol = aButtonInfo.protocolInfo.protocol;
 | 
						|
          let name     = aButtonInfo.protocolInfo.name;
 | 
						|
 | 
						|
          let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
 | 
						|
                        createInstance(Ci.nsIWebHandlerApp);
 | 
						|
          handler.name = name;
 | 
						|
          handler.uriTemplate = aButtonInfo.protocolInfo.uri;
 | 
						|
 | 
						|
          let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
 | 
						|
                    getService(Ci.nsIExternalProtocolService);
 | 
						|
          let handlerInfo = eps.getProtocolHandlerInfo(protocol);
 | 
						|
          handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
 | 
						|
 | 
						|
          // Since the user has agreed to add a new handler, chances are good
 | 
						|
          // that the next time they see a handler of this type, they're going
 | 
						|
          // to want to use it.  Reset the handlerInfo to ask before the next
 | 
						|
          // use.
 | 
						|
          handlerInfo.alwaysAskBeforeHandling = true;
 | 
						|
 | 
						|
          let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
 | 
						|
                   getService(Ci.nsIHandlerService);
 | 
						|
          hs.store(handlerInfo);
 | 
						|
        }
 | 
						|
    };
 | 
						|
    let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
 | 
						|
    notificationBox.appendNotification(message,
 | 
						|
                                       notificationValue,
 | 
						|
                                       notificationIcon,
 | 
						|
                                       notificationBox.PRIORITY_INFO_LOW,
 | 
						|
                                       [addButton]);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerRegistrar
 | 
						|
   * If a DOM window is provided, then the request came from content, so we
 | 
						|
   * prompt the user to confirm the registration.
 | 
						|
   */
 | 
						|
  registerContentHandler(aContentType, aURIString, aTitle, aWindowOrBrowser) {
 | 
						|
    LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
 | 
						|
 | 
						|
    // Make sure to do our URL checks up front, before our content type check,
 | 
						|
    // just like the WebContentConverterRegistrarContent does.
 | 
						|
    let haveWindow = aWindowOrBrowser &&
 | 
						|
                     (aWindowOrBrowser instanceof Ci.nsIDOMWindow);
 | 
						|
    let uri;
 | 
						|
    if (haveWindow) {
 | 
						|
      uri = Utils.checkAndGetURI(aURIString, aWindowOrBrowser);
 | 
						|
    } else if (aWindowOrBrowser) {
 | 
						|
      // uri was vetted in the content process.
 | 
						|
      uri = Utils.makeURI(aURIString, null);
 | 
						|
    }
 | 
						|
 | 
						|
    // We only support feed types at present.
 | 
						|
    let contentType = Utils.resolveContentType(aContentType);
 | 
						|
    // XXX We should be throwing a Utils.getSecurityError() here in at least
 | 
						|
    // some cases.  See bug 1266492.
 | 
						|
    if (contentType != TYPE_MAYBE_FEED) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (aWindowOrBrowser) {
 | 
						|
      let notificationBox;
 | 
						|
      if (haveWindow) {
 | 
						|
        let browserWindow = this._getBrowserWindowForContentWindow(aWindowOrBrowser);
 | 
						|
        let browserElement = this._getBrowserForContentWindow(browserWindow, aWindowOrBrowser);
 | 
						|
        notificationBox = browserElement.getTabBrowser().getNotificationBox(browserElement);
 | 
						|
      } else {
 | 
						|
        notificationBox = aWindowOrBrowser.getTabBrowser()
 | 
						|
                                          .getNotificationBox(aWindowOrBrowser);
 | 
						|
      }
 | 
						|
 | 
						|
      this._appendFeedReaderNotification(uri, aTitle, notificationBox);
 | 
						|
    } else {
 | 
						|
      this._registerContentHandler(contentType, aURIString, aTitle);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the browser chrome window in which the content window is in
 | 
						|
   */
 | 
						|
  _getBrowserWindowForContentWindow(aContentWindow) {
 | 
						|
    return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                         .getInterface(Ci.nsIWebNavigation)
 | 
						|
                         .QueryInterface(Ci.nsIDocShellTreeItem)
 | 
						|
                         .rootTreeItem
 | 
						|
                         .QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                         .getInterface(Ci.nsIDOMWindow)
 | 
						|
                         .wrappedJSObject;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the <xul:browser> element associated with the given content
 | 
						|
   * window.
 | 
						|
   *
 | 
						|
   * @param aBrowserWindow
 | 
						|
   *        The browser window in which the content window is in.
 | 
						|
   * @param aContentWindow
 | 
						|
   *        The content window. It's possible to pass a child content window
 | 
						|
   *        (i.e. the content window of a frame/iframe).
 | 
						|
   */
 | 
						|
  _getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
 | 
						|
    // This depends on pseudo APIs of browser.js and tabbrowser.xml
 | 
						|
    aContentWindow = aContentWindow.top;
 | 
						|
    return aBrowserWindow.gBrowser.browsers.find((browser) =>
 | 
						|
      browser.contentWindow == aContentWindow);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Appends a notifcation for the given feed reader details.
 | 
						|
   *
 | 
						|
   * The notification could be either a pseudo-dialog which lets
 | 
						|
   * the user to add the feed reader:
 | 
						|
   * [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader?  (Add) [x] ]
 | 
						|
   *
 | 
						|
   * or a simple message for the case where the feed reader is already registered:
 | 
						|
   * [ [icon] %feed-reader-name% is already registered as a Feed Reader             [x] ]
 | 
						|
   *
 | 
						|
   * A new notification isn't appended if the given notificationbox has a
 | 
						|
   * notification for the same feed reader.
 | 
						|
   *
 | 
						|
   * @param aURI
 | 
						|
   *        The url of the feed reader as a nsIURI object
 | 
						|
   * @param aName
 | 
						|
   *        The feed reader name as it was passed to registerContentHandler
 | 
						|
   * @param aNotificationBox
 | 
						|
   *        The notification box to which a notification might be appended
 | 
						|
   * @return true if a notification has been appended, false otherwise.
 | 
						|
   */
 | 
						|
  _appendFeedReaderNotification(aURI, aName, aNotificationBox) {
 | 
						|
    let uriSpec = aURI.spec;
 | 
						|
    let notificationValue = "feed reader notification: " + uriSpec;
 | 
						|
    let notificationIcon = aURI.prePath + "/favicon.ico";
 | 
						|
 | 
						|
    // Don't append a new notification if the notificationbox
 | 
						|
    // has a notification for the given feed reader already
 | 
						|
    if (aNotificationBox.getNotificationWithValue(notificationValue))
 | 
						|
      return false;
 | 
						|
 | 
						|
    let buttons;
 | 
						|
    let message;
 | 
						|
    if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
 | 
						|
      message = this._getFormattedString("handlerRegistered", [aName]);
 | 
						|
    else {
 | 
						|
      message = this._getFormattedString("addHandler", [aName, aURI.host]);
 | 
						|
      let self = this;
 | 
						|
      let addButton = {
 | 
						|
        _outer: self,
 | 
						|
        label: self._getString("addHandlerAddButton"),
 | 
						|
        accessKey: self._getString("addHandlerAddButtonAccesskey"),
 | 
						|
        feedReaderInfo: { uri: uriSpec, name: aName },
 | 
						|
 | 
						|
        /* static */
 | 
						|
        callback(aNotification, aButtonInfo) {
 | 
						|
          let uri = aButtonInfo.feedReaderInfo.uri;
 | 
						|
          let name = aButtonInfo.feedReaderInfo.name;
 | 
						|
          let outer = aButtonInfo._outer;
 | 
						|
 | 
						|
          // The reader could have been added from another window mean while
 | 
						|
          if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri))
 | 
						|
            outer._registerContentHandler(TYPE_MAYBE_FEED, uri, name);
 | 
						|
 | 
						|
          // avoid reference cycles
 | 
						|
          aButtonInfo._outer = null;
 | 
						|
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      };
 | 
						|
      buttons = [addButton];
 | 
						|
    }
 | 
						|
 | 
						|
    aNotificationBox.appendNotification(message,
 | 
						|
                                        notificationValue,
 | 
						|
                                        notificationIcon,
 | 
						|
                                        aNotificationBox.PRIORITY_INFO_LOW,
 | 
						|
                                        buttons);
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Save Web Content Handler metadata to persistent preferences.
 | 
						|
   * @param   contentType
 | 
						|
   *          The content Type being handled
 | 
						|
   * @param   uri
 | 
						|
   *          The uri of the web service
 | 
						|
   * @param   title
 | 
						|
   *          The human readable name of the web service
 | 
						|
   *
 | 
						|
   * This data is stored under:
 | 
						|
   *
 | 
						|
   *    browser.contentHandlers.type0 = content/type
 | 
						|
   *    browser.contentHandlers.uri0 = http://www.foo.com/q=%s
 | 
						|
   *    browser.contentHandlers.title0 = Foo 2.0alphr
 | 
						|
   */
 | 
						|
  _saveContentHandlerToPrefs(contentType, uri, title) {
 | 
						|
    let ps = Services.prefs;
 | 
						|
    let i = 0;
 | 
						|
    let typeBranch = null;
 | 
						|
    while (true) {
 | 
						|
      typeBranch =
 | 
						|
        ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
 | 
						|
      try {
 | 
						|
        typeBranch.getCharPref("type");
 | 
						|
        ++i;
 | 
						|
      } catch (e) {
 | 
						|
        // No more handlers
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (typeBranch) {
 | 
						|
      typeBranch.setCharPref("type", contentType);
 | 
						|
      let pls =
 | 
						|
          Cc["@mozilla.org/pref-localizedstring;1"].
 | 
						|
          createInstance(Ci.nsIPrefLocalizedString);
 | 
						|
      pls.data = uri;
 | 
						|
      typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
 | 
						|
      pls.data = title;
 | 
						|
      typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
 | 
						|
 | 
						|
      ps.savePrefFile(null);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Determines if there is a type with a particular uri registered for the
 | 
						|
   * specified content type already.
 | 
						|
   * @param   contentType
 | 
						|
   *          The content type that the uri handles
 | 
						|
   * @param   uri
 | 
						|
   *          The uri of the content type
 | 
						|
   */
 | 
						|
  _typeIsRegistered(contentType, uri) {
 | 
						|
    if (!(contentType in this._contentTypes))
 | 
						|
      return false;
 | 
						|
 | 
						|
    return this._contentTypes[contentType]
 | 
						|
               .some(t => t.uri == uri);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets a stream converter contract id for the specified content type.
 | 
						|
   * @param   contentType
 | 
						|
   *          The source content type for the conversion.
 | 
						|
   * @returns A contract id to construct a converter to convert between the
 | 
						|
   *          contentType and *\/*.
 | 
						|
   */
 | 
						|
  _getConverterContractID(contentType) {
 | 
						|
    const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
 | 
						|
    return template.replace(/%s/, contentType);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Register a web service handler for a content type.
 | 
						|
   *
 | 
						|
   * @param   contentType
 | 
						|
   *          the content type being handled
 | 
						|
   * @param   uri
 | 
						|
   *          the URI of the web service
 | 
						|
   * @param   title
 | 
						|
   *          the human readable name of the web service
 | 
						|
   */
 | 
						|
  _registerContentHandler(contentType, uri, title) {
 | 
						|
    this._updateContentTypeHandlerMap(contentType, uri, title);
 | 
						|
    this._saveContentHandlerToPrefs(contentType, uri, title);
 | 
						|
 | 
						|
    if (contentType == TYPE_MAYBE_FEED) {
 | 
						|
      // Make the new handler the last-selected reader in the preview page
 | 
						|
      // and make sure the preview page is shown the next time a feed is visited
 | 
						|
      let pb = Services.prefs.getBranch(null);
 | 
						|
      pb.setCharPref(PREF_SELECTED_READER, "web");
 | 
						|
 | 
						|
      let supportsString =
 | 
						|
        Cc["@mozilla.org/supports-string;1"].
 | 
						|
        createInstance(Ci.nsISupportsString);
 | 
						|
        supportsString.data = uri;
 | 
						|
      pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString,
 | 
						|
                         supportsString);
 | 
						|
      pb.setCharPref(PREF_SELECTED_ACTION, "ask");
 | 
						|
      this._setAutoHandler(TYPE_MAYBE_FEED, null);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Update the content type -> handler map. This mapping is not persisted, use
 | 
						|
   * registerContentHandler or _saveContentHandlerToPrefs for that purpose.
 | 
						|
   * @param   contentType
 | 
						|
   *          The content Type being handled
 | 
						|
   * @param   uri
 | 
						|
   *          The uri of the web service
 | 
						|
   * @param   title
 | 
						|
   *          The human readable name of the web service
 | 
						|
   */
 | 
						|
  _updateContentTypeHandlerMap(contentType, uri, title) {
 | 
						|
    if (!(contentType in this._contentTypes))
 | 
						|
      this._contentTypes[contentType] = [];
 | 
						|
 | 
						|
    // Avoid adding duplicates
 | 
						|
    if (this._typeIsRegistered(contentType, uri))
 | 
						|
      return;
 | 
						|
 | 
						|
    this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
 | 
						|
 | 
						|
    if (!(contentType in this._blockedTypes)) {
 | 
						|
      let converterContractID = this._getConverterContractID(contentType);
 | 
						|
      let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 | 
						|
      cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
 | 
						|
                         WebContentConverterFactory);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  getContentHandlers(contentType, countRef) {
 | 
						|
    if (countRef) {
 | 
						|
      countRef.value = 0;
 | 
						|
    }
 | 
						|
    if (!(contentType in this._contentTypes))
 | 
						|
      return [];
 | 
						|
 | 
						|
    let handlers = this._contentTypes[contentType];
 | 
						|
    if (countRef) {
 | 
						|
      countRef.value = handlers.length;
 | 
						|
    }
 | 
						|
    return handlers;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  resetHandlersForType(contentType) {
 | 
						|
    // currently unused within the tree, so only useful for extensions; previous
 | 
						|
    // impl. was buggy (and even infinite-looped!), so I argue that this is a
 | 
						|
    // definite improvement
 | 
						|
    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Registers a handler from the settings on a preferences branch.
 | 
						|
   *
 | 
						|
   * Since we support up to six predefined readers, we need to handle gaps
 | 
						|
   * better, since the first branch with user-added values will be .6
 | 
						|
   *
 | 
						|
   * How we deal with that is to check to see if there's no prefs in the
 | 
						|
   * branch and stop cycling once that's true.  This doesn't fix the case
 | 
						|
   * where a user manually removes a reader, but that's not supported yet!
 | 
						|
   *
 | 
						|
   * @param branch
 | 
						|
   *        an nsIPrefBranch containing "type", "uri", and "title" preferences
 | 
						|
   *        corresponding to the content handler to be registered
 | 
						|
   */
 | 
						|
  _registerContentHandlerHavingBranch(branch) {
 | 
						|
    let vals = branch.getChildList("");
 | 
						|
    if (vals.length == 0)
 | 
						|
      return;
 | 
						|
 | 
						|
    let type = branch.getCharPref("type");
 | 
						|
    let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
 | 
						|
    let title = branch.getComplexValue("title",
 | 
						|
                                       Ci.nsIPrefLocalizedString).data;
 | 
						|
    this._updateContentTypeHandlerMap(type, uri, title);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Load the auto handler, content handler and protocol tables from
 | 
						|
   * preferences.
 | 
						|
   */
 | 
						|
  _init() {
 | 
						|
    let ps = Services.prefs;
 | 
						|
 | 
						|
    let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
 | 
						|
                     .getChildList("");
 | 
						|
 | 
						|
    // first get the numbers of the providers by getting all ###.uri prefs
 | 
						|
    let nums = children.map((child) => {
 | 
						|
      let match = /^(\d+)\.uri$/.exec(child);
 | 
						|
      return match ? match[1] : "";
 | 
						|
    }).filter(child => !!child)
 | 
						|
      .sort();
 | 
						|
 | 
						|
 | 
						|
    // now register them
 | 
						|
    for (let num of nums) {
 | 
						|
      let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
 | 
						|
      try {
 | 
						|
        this._registerContentHandlerHavingBranch(branch);
 | 
						|
      } catch (ex) {
 | 
						|
        // do nothing, the next branch might have values
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // We need to do this _after_ registering all of the available handlers,
 | 
						|
    // so that getWebContentHandlerByURI can return successfully.
 | 
						|
    let autoBranch;
 | 
						|
    try {
 | 
						|
      autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
 | 
						|
    } catch (e) {
 | 
						|
      // No auto branch yet, that's fine
 | 
						|
      // LOG("WCCR.init: There is no auto branch, benign");
 | 
						|
    }
 | 
						|
 | 
						|
    if (autoBranch) {
 | 
						|
      for (let type of autoBranch.getChildList("")) {
 | 
						|
        let uri = autoBranch.getCharPref(type);
 | 
						|
        if (uri) {
 | 
						|
          let handler = this.getWebContentHandlerByURI(type, uri);
 | 
						|
          if (handler) {
 | 
						|
            this._setAutoHandler(type, handler);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIObserver
 | 
						|
   */
 | 
						|
  observe(subject, topic, data) {
 | 
						|
    let os = Services.obs;
 | 
						|
    switch (topic) {
 | 
						|
    case "app-startup":
 | 
						|
      os.addObserver(this, "browser-ui-startup-complete", false);
 | 
						|
      break;
 | 
						|
    case "browser-ui-startup-complete":
 | 
						|
      os.removeObserver(this, "browser-ui-startup-complete");
 | 
						|
      this._init();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIFactory
 | 
						|
   */
 | 
						|
  createInstance(outer, iid) {
 | 
						|
    if (outer != null)
 | 
						|
      throw Cr.NS_ERROR_NO_AGGREGATION;
 | 
						|
    return this.QueryInterface(iid);
 | 
						|
  },
 | 
						|
 | 
						|
  classID: WCCR_CLASSID,
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsISupports
 | 
						|
   */
 | 
						|
  QueryInterface: XPCOMUtils.generateQI(
 | 
						|
     [Ci.nsIWebContentConverterService,
 | 
						|
      Ci.nsIWebContentHandlerRegistrar,
 | 
						|
      Ci.nsIObserver,
 | 
						|
      Ci.nsIFactory]),
 | 
						|
 | 
						|
  _xpcom_categories: [{
 | 
						|
    category: "app-startup",
 | 
						|
    service: true
 | 
						|
  }]
 | 
						|
};
 | 
						|
 | 
						|
function WebContentConverterRegistrarContent() {
 | 
						|
  this._contentTypes = {};
 | 
						|
}
 | 
						|
 | 
						|
WebContentConverterRegistrarContent.prototype = {
 | 
						|
 | 
						|
  /**
 | 
						|
   * Load the auto handler, content handler and protocol tables from
 | 
						|
   * preferences.
 | 
						|
   */
 | 
						|
  _init() {
 | 
						|
    let ps = Services.prefs;
 | 
						|
 | 
						|
    let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
 | 
						|
                     .getChildList("");
 | 
						|
 | 
						|
    // first get the numbers of the providers by getting all ###.uri prefs
 | 
						|
    let nums = children.map((child) => {
 | 
						|
      let match = /^(\d+)\.uri$/.exec(child);
 | 
						|
      return match ? match[1] : "";
 | 
						|
    }).filter(child => !!child)
 | 
						|
      .sort();
 | 
						|
 | 
						|
    // now register them
 | 
						|
    for (let num of nums) {
 | 
						|
      let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
 | 
						|
      try {
 | 
						|
        this._registerContentHandlerHavingBranch(branch);
 | 
						|
      } catch (ex) {
 | 
						|
        // do nothing, the next branch might have values
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  _typeIsRegistered(contentType, uri) {
 | 
						|
    return this._contentTypes[contentType]
 | 
						|
               .some(e => e.uri == uri);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Since we support up to six predefined readers, we need to handle gaps
 | 
						|
   * better, since the first branch with user-added values will be .6
 | 
						|
   *
 | 
						|
   * How we deal with that is to check to see if there's no prefs in the
 | 
						|
   * branch and stop cycling once that's true.  This doesn't fix the case
 | 
						|
   * where a user manually removes a reader, but that's not supported yet!
 | 
						|
   *
 | 
						|
   * @param   branch
 | 
						|
   *          The pref branch to register the content handler under
 | 
						|
   *
 | 
						|
   */
 | 
						|
  _registerContentHandlerHavingBranch(branch) {
 | 
						|
    let vals = branch.getChildList("");
 | 
						|
    if (vals.length == 0)
 | 
						|
      return;
 | 
						|
 | 
						|
    let type = branch.getCharPref("type");
 | 
						|
    let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
 | 
						|
    let title = branch.getComplexValue("title",
 | 
						|
                                       Ci.nsIPrefLocalizedString).data;
 | 
						|
    this._updateContentTypeHandlerMap(type, uri, title);
 | 
						|
  },
 | 
						|
 | 
						|
  _updateContentTypeHandlerMap(contentType, uri, title) {
 | 
						|
    if (!(contentType in this._contentTypes))
 | 
						|
      this._contentTypes[contentType] = [];
 | 
						|
 | 
						|
    // Avoid adding duplicates
 | 
						|
    if (this._typeIsRegistered(contentType, uri))
 | 
						|
      return;
 | 
						|
 | 
						|
    this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
 | 
						|
 | 
						|
    if (!(contentType in this._blockedTypes)) {
 | 
						|
      let converterContractID = this._getConverterContractID(contentType);
 | 
						|
      let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 | 
						|
      cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
 | 
						|
                         WebContentConverterFactory);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentConverterService
 | 
						|
   */
 | 
						|
  getContentHandlers(contentType, countRef) {
 | 
						|
    this._init();
 | 
						|
    if (countRef) {
 | 
						|
      countRef.value = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(contentType in this._contentTypes))
 | 
						|
      return [];
 | 
						|
 | 
						|
    let handlers = this._contentTypes[contentType];
 | 
						|
    if (countRef) {
 | 
						|
      countRef.value = handlers.length;
 | 
						|
    }
 | 
						|
    return handlers;
 | 
						|
  },
 | 
						|
 | 
						|
  setAutoHandler(contentType, handler) {
 | 
						|
    Services.cpmm.sendAsyncMessage("WCCR:setAutoHandler",
 | 
						|
                                   { contentType, handler });
 | 
						|
  },
 | 
						|
 | 
						|
  getWebContentHandlerByURI(contentType, uri) {
 | 
						|
    return this.getContentHandlers(contentType)
 | 
						|
               .find(e => e.uri == uri) || null;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIWebContentHandlerRegistrar
 | 
						|
   */
 | 
						|
  registerContentHandler(aContentType, aURIString, aTitle, aBrowserOrWindow) {
 | 
						|
    // aBrowserOrWindow must be a window.
 | 
						|
    let messageManager = aBrowserOrWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                                         .getInterface(Ci.nsIWebNavigation)
 | 
						|
                                         .QueryInterface(Ci.nsIDocShell)
 | 
						|
                                         .QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                                         .getInterface(Ci.nsITabChild)
 | 
						|
                                         .messageManager;
 | 
						|
 | 
						|
    let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
 | 
						|
    // XXX We should be throwing a Utils.getSecurityError() here in at least
 | 
						|
    // some cases.  See bug 1266492.
 | 
						|
    if (Utils.resolveContentType(aContentType) != TYPE_MAYBE_FEED) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    messageManager.sendAsyncMessage("WCCR:registerContentHandler",
 | 
						|
                                    { contentType: aContentType,
 | 
						|
                                      uri: uri.spec,
 | 
						|
                                      title: aTitle });
 | 
						|
  },
 | 
						|
 | 
						|
  registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
 | 
						|
    // aBrowserOrWindow must be a window.
 | 
						|
    let messageManager = aBrowserOrWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                                         .getInterface(Ci.nsIWebNavigation)
 | 
						|
                                         .QueryInterface(Ci.nsIDocShell)
 | 
						|
                                         .QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                                         .getInterface(Ci.nsITabChild)
 | 
						|
                                         .messageManager;
 | 
						|
 | 
						|
    let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
 | 
						|
    Utils.checkProtocolHandlerAllowed(aProtocol, aURIString, aBrowserOrWindow);
 | 
						|
 | 
						|
    messageManager.sendAsyncMessage("WCCR:registerProtocolHandler",
 | 
						|
                                    { protocol: aProtocol,
 | 
						|
                                      uri: uri.spec,
 | 
						|
                                      title: aTitle });
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsIFactory
 | 
						|
   */
 | 
						|
  createInstance(outer, iid) {
 | 
						|
    if (outer != null)
 | 
						|
      throw Cr.NS_ERROR_NO_AGGREGATION;
 | 
						|
    return this.QueryInterface(iid);
 | 
						|
  },
 | 
						|
 | 
						|
  classID: WCCR_CLASSID,
 | 
						|
 | 
						|
  /**
 | 
						|
   * See nsISupports
 | 
						|
   */
 | 
						|
  QueryInterface: XPCOMUtils.generateQI(
 | 
						|
                     [Ci.nsIWebContentHandlerRegistrar,
 | 
						|
                      Ci.nsIWebContentConverterService,
 | 
						|
                      Ci.nsIFactory])
 | 
						|
};
 | 
						|
 | 
						|
this.NSGetFactory =
 | 
						|
  (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) ?
 | 
						|
    XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrarContent]) :
 | 
						|
    XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
 |