summaryrefslogtreecommitdiffstats
path: root/browser/components/feeds/WebContentConverter.js
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-06-04 13:17:38 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-06-04 13:17:38 +0200
commita1be17c1cea81ebb1e8b131a662c698d78f3f7f2 (patch)
treea92f7de513be600cc07bac458183e9af40e00c06 /browser/components/feeds/WebContentConverter.js
parentbf11fdd304898ac675e39b01b280d39550e419d0 (diff)
downloadUXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.gz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.lz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.xz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.zip
Issue #303 Part 1: Move basilisk files from /browser to /application/basilisk
Diffstat (limited to 'browser/components/feeds/WebContentConverter.js')
-rw-r--r--browser/components/feeds/WebContentConverter.js1071
1 files changed, 0 insertions, 1071 deletions
diff --git a/browser/components/feeds/WebContentConverter.js b/browser/components/feeds/WebContentConverter.js
deleted file mode 100644
index 2cb5cd145..000000000
--- a/browser/components/feeds/WebContentConverter.js
+++ /dev/null
@@ -1,1071 +0,0 @@
-/* -*- 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 PREF_ALLOW_DIFFERENT_HOST = "gecko.handlerService.allowRegisterFromDifferentHost";
-
-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)
- // The pref allows us to test the feature
- let pb = Services.prefs;
- if (!pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST) &&
- (!["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 uri = aButtonInfo.protocolInfo.uri;
- let name = aButtonInfo.protocolInfo.name;
-
- let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
- createInstance(Ci.nsIWebHandlerApp);
- handler.name = name;
- handler.uriTemplate = 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 (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]);