From afe040fd02dcabee8e1c26845cf08610015818f0 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Mon, 12 Mar 2018 22:24:07 +0100 Subject: [PATCH] Bug 474043 - Part 1 - Get rid of the remaining mimeTypes.rdf references. r=Paolo MozReview-Commit-ID: 78LHYTVlEtR --HG-- extra : rebase_source : b16b0c5d202419bd39a287d2868f09fbf6ad45e7 --- browser/installer/package-manifest.in | 2 - mobile/android/installer/package-manifest.in | 2 - .../talos/talos/xtalos/xperf_whitelist.json | 8 +- toolkit/mozapps/downloads/nsHelperAppDlg.js | 8 +- uriloader/exthandler/moz.build | 2 - uriloader/exthandler/nsHandlerService-json.js | 76 +- uriloader/exthandler/nsHandlerService.js | 1444 ----------------- .../exthandler/nsHandlerService.manifest | 2 - .../tests/unit/common_test_handlerService.js | 6 - uriloader/exthandler/tests/unit/head.js | 39 - .../tests/unit/mimeTypes-android.rdf | 100 -- uriloader/exthandler/tests/unit/mimeTypes.rdf | 105 -- .../tests/unit/test_handlerService_json.js | 67 - .../tests/unit/test_handlerService_rdf.js | 14 - uriloader/exthandler/tests/unit/xpcshell.ini | 2 - 15 files changed, 12 insertions(+), 1865 deletions(-) delete mode 100644 uriloader/exthandler/nsHandlerService.js delete mode 100644 uriloader/exthandler/nsHandlerService.manifest delete mode 100644 uriloader/exthandler/tests/unit/mimeTypes-android.rdf delete mode 100644 uriloader/exthandler/tests/unit/mimeTypes.rdf delete mode 100644 uriloader/exthandler/tests/unit/test_handlerService_rdf.js diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 8549b44afaf8..63ebd701129c 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -457,8 +457,6 @@ @RESPATH@/components/nsContentDispatchChooser.js @RESPATH@/components/nsHandlerService-json.manifest @RESPATH@/components/nsHandlerService-json.js -@RESPATH@/components/nsHandlerService.manifest -@RESPATH@/components/nsHandlerService.js @RESPATH@/components/nsWebHandlerApp.manifest @RESPATH@/components/nsWebHandlerApp.js @RESPATH@/components/satchel.manifest diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index f7e49510c285..866abdfe5eee 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -330,8 +330,6 @@ @BINPATH@/components/ContentPrefService2.js @BINPATH@/components/nsHandlerService-json.manifest @BINPATH@/components/nsHandlerService-json.js -@BINPATH@/components/nsHandlerService.manifest -@BINPATH@/components/nsHandlerService.js @BINPATH@/components/nsWebHandlerApp.manifest @BINPATH@/components/nsWebHandlerApp.js @BINPATH@/components/satchel.manifest diff --git a/testing/talos/talos/xtalos/xperf_whitelist.json b/testing/talos/talos/xtalos/xperf_whitelist.json index 02527918fb6b..01d2aa5e6f07 100644 --- a/testing/talos/talos/xtalos/xperf_whitelist.json +++ b/testing/talos/talos/xtalos/xperf_whitelist.json @@ -395,12 +395,6 @@ "minbytes": 8192, "maxbytes": 8192 }, - "{profile}\\mimetypes.rdf": { - "mincount": 2, - "maxcount": 2, - "minbytes": 8192, - "maxbytes": 8192 - }, "{profile}\\permissions.sqlite": { "mincount": 14, "maxcount": 14, @@ -521,4 +515,4 @@ "minbytes": 0, "maxbytes": 16384 } -} \ No newline at end of file +} diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js index 7ba7d2de0dbf..dd16c359374e 100644 --- a/toolkit/mozapps/downloads/nsHelperAppDlg.js +++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js @@ -856,8 +856,8 @@ nsUnknownContentTypeDialog.prototype = { // One last special case: If the input "always ask" flag was false, then we always // update. In that case we are displaying the helper app dialog for the first - // time for this mime type and we need to store the user's action in the mimeTypes.rdf - // data source (whether that action has changed or not; if it didn't change, then we need + // time for this mime type and we need to store the user's action in the handler service + // (whether that action has changed or not; if it didn't change, then we need // to store the "always ask" flag so the helper app dialog will or won't display // next time, per the user's selection). needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling; @@ -868,8 +868,8 @@ nsUnknownContentTypeDialog.prototype = { return needUpdate && !discardUpdate; }, - // See if the user changed things, and if so, update the - // mimeTypes.rdf entry for this mime type. + // See if the user changed things, and if so, store this mime type in the + // handler service. updateHelperAppPref: function() { var handlerInfo = this.mLauncher.MIMEInfo; var hs = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build index 8f7e6f0b934b..154fecf06bdd 100644 --- a/uriloader/exthandler/moz.build +++ b/uriloader/exthandler/moz.build @@ -108,8 +108,6 @@ if CONFIG['MOZ_ENABLE_DBUS']: EXTRA_COMPONENTS += [ 'nsHandlerService-json.js', 'nsHandlerService-json.manifest', - 'nsHandlerService.js', - 'nsHandlerService.manifest', 'nsWebHandlerApp.js', 'nsWebHandlerApp.manifest', ] diff --git a/uriloader/exthandler/nsHandlerService-json.js b/uriloader/exthandler/nsHandlerService-json.js index 5fc9bdc3475f..52338922fe37 100644 --- a/uriloader/exthandler/nsHandlerService-json.js +++ b/uriloader/exthandler/nsHandlerService-json.js @@ -14,9 +14,6 @@ ChromeUtils.defineModuleGetter(this, "JSONFile", XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService", "@mozilla.org/uriloader/external-protocol-service;1", "nsIExternalProtocolService"); -XPCOMUtils.defineLazyServiceGetter(this, "gHandlerServiceRDF", - "@mozilla.org/uriloader/handler-service-rdf;1", - "nsIHandlerService"); XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService", "@mozilla.org/mime;1", "nsIMIMEService"); @@ -56,10 +53,7 @@ HandlerService.prototype = { this.__storeInitialized = true; this.__store.ensureDataReady(); - // We have to inject new default protocol handlers only if we haven't - // already done this when migrating data from the RDF back-end. - let alreadyInjected = this._migrateFromRDFIfNeeded(); - this._injectDefaultProtocolHandlersIfNeeded(alreadyInjected); + this._injectDefaultProtocolHandlersIfNeeded(); Services.obs.notifyObservers(null, "handlersvc-store-initialized"); } @@ -73,65 +67,11 @@ HandlerService.prototype = { }; }, - /** - * Migrates data from the RDF back-end, returning true if this happened. - */ - _migrateFromRDFIfNeeded() { - try { - if (Services.prefs.getBoolPref("gecko.handlerService.migrated")) { - return false; - } - } catch (ex) { - // If the preference does not exist, we need to import. - } - - try { - // Don't initialize the RDF back-end if the file does not exist, improving - // performance on first use for new profiles. - let rdfFile = FileUtils.getFile("ProfD", ["mimeTypes.rdf"]); - if (rdfFile.exists()) { - this._migrateFromRDF(); - return true; - } - } catch (ex) { - Cu.reportError(ex); - } finally { - // Don't attempt to import again even if the operation failed. - Services.prefs.setBoolPref("gecko.handlerService.migrated", true); - } - - return false; - }, - - _migrateFromRDF() { - // Initializing the RDF back-end has the side effect of triggering the - // injection of the default protocol handlers. If the version number is - // newer and this happens, then the "enumerate" call in the RDF back-end - // will re-enter the JSON back-end through the MIME service, but this is - // harmless. The injection will not be repeated in the JSON back-end, so we - // rely on the new handlers injected by the RDF back-end. - let handlerInfoEnumerator = gHandlerServiceRDF.enumerate(); - while (handlerInfoEnumerator.hasMoreElements()) { - let handlerInfo = handlerInfoEnumerator.getNext() - .QueryInterface(Ci.nsIHandlerInfo); - try { - // If the import from RDF is repeated by flipping the preference, then - // handlerInfo might already include some data from the JSON back-end, - // but any duplication is removed by the "store" method. - gHandlerServiceRDF.fillHandlerInfo(handlerInfo, ""); - this.store(handlerInfo); - } catch (ex) { - Cu.reportError(ex); - } - } - }, - /** * Injects new default protocol handlers if the version in the preferences is - * newer than the one in the data store. If we just imported data from the RDF - * back-end, we only need to update the version in the data store. + * newer than the one in the data store. */ - _injectDefaultProtocolHandlersIfNeeded(alreadyInjected) { + _injectDefaultProtocolHandlersIfNeeded() { let prefsDefaultHandlersVersion; try { prefsDefaultHandlersVersion = Services.prefs.getComplexValue( @@ -153,9 +93,7 @@ HandlerService.prototype = { let defaultHandlersVersion = this._store.data.defaultHandlersVersion[locale] || 0; if (defaultHandlersVersion < prefsDefaultHandlersVersion) { - if (!alreadyInjected) { - this._injectDefaultProtocolHandlers(); - } + this._injectDefaultProtocolHandlers(); this._store.data.defaultHandlersVersion[locale] = prefsDefaultHandlersVersion; } @@ -195,9 +133,9 @@ HandlerService.prototype = { // This clause is essentially a reimplementation of // nsIExternalProtocolHandlerService.getProtocolHandlerInfo(). - // Necessary because we want to use this instance of the service, - // but nsIExternalProtocolHandlerService would call the RDF-based based version - // until we complete the conversion. + // Necessary because calling that from here would make XPConnect barf + // when getService tried to re-enter the constructor for this + // service. let osDefaultHandlerFound = {}; let protoInfo = gExternalProtocolService.getProtocolHandlerInfoFromOS(scheme, osDefaultHandlerFound); diff --git a/uriloader/exthandler/nsHandlerService.js b/uriloader/exthandler/nsHandlerService.js deleted file mode 100644 index af4b945a9f06..000000000000 --- a/uriloader/exthandler/nsHandlerService.js +++ /dev/null @@ -1,1444 +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/. */ - -const CLASS_MIMEINFO = "mimetype"; -const CLASS_PROTOCOLINFO = "scheme"; - - -// namespace prefix -const NC_NS = "http://home.netscape.com/NC-rdf#"; - -// the most recent default handlers that have been injected. Note that -// this is used to construct an RDF resource, which needs to have NC_NS -// prepended, since that hasn't been done yet -const DEFAULT_HANDLERS_VERSION = "defaultHandlersVersion"; - -// type list properties - -const NC_MIME_TYPES = NC_NS + "MIME-types"; -const NC_PROTOCOL_SCHEMES = NC_NS + "Protocol-Schemes"; - -// content type ("type") properties - -// nsIHandlerInfo::type -const NC_VALUE = NC_NS + "value"; - -// additional extensions -const NC_FILE_EXTENSIONS = NC_NS + "fileExtensions"; - -// references nsIHandlerInfo record -const NC_HANDLER_INFO = NC_NS + "handlerProp"; - -// handler info ("info") properties - -// nsIHandlerInfo::preferredAction -const NC_SAVE_TO_DISK = NC_NS + "saveToDisk"; -const NC_HANDLE_INTERNALLY = NC_NS + "handleInternal"; -const NC_USE_SYSTEM_DEFAULT = NC_NS + "useSystemDefault"; - -// nsIHandlerInfo::alwaysAskBeforeHandling -const NC_ALWAYS_ASK = NC_NS + "alwaysAsk"; - -// references nsIHandlerApp records -const NC_PREFERRED_APP = NC_NS + "externalApplication"; -const NC_POSSIBLE_APP = NC_NS + "possibleApplication"; - -// handler app ("handler") properties - -// nsIHandlerApp::name -const NC_PRETTY_NAME = NC_NS + "prettyName"; - -// nsILocalHandlerApp::executable -const NC_PATH = NC_NS + "path"; - -// nsIWebHandlerApp::uriTemplate -const NC_URI_TEMPLATE = NC_NS + "uriTemplate"; - -// nsIDBusHandlerApp::service -const NC_SERVICE = NC_NS + "service"; - -// nsIDBusHandlerApp::method -const NC_METHOD = NC_NS + "method"; - -// nsIDBusHandlerApp::objectPath -const NC_OBJPATH = NC_NS + "objectPath"; - -// nsIDBusHandlerApp::dbusInterface -const NC_INTERFACE = NC_NS + "dBusInterface"; - -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); - - -function HandlerService() { - this._init(); -} - -const HandlerServiceFactory = { - _instance: null, - createInstance: function (outer, iid) { - if (this._instance) - return this._instance; - - let processType = Cc["@mozilla.org/xre/runtime;1"]. - getService(Ci.nsIXULRuntime).processType; - if (processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) - return Cr.NS_ERROR_NOT_IMPLEMENTED; - - return (this._instance = new HandlerService()); - } -}; - -HandlerService.prototype = { - //**************************************************************************// - // XPCOM Plumbing - - classID: Components.ID("{32314cc8-22f7-4f7f-a645-1a45453ba6a6}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIHandlerService]), - _xpcom_factory: HandlerServiceFactory, - - //**************************************************************************// - // Initialization & Destruction - - _init: function HS__init() { - // Observe profile-before-change so we can switch to the datasource - // in the new profile when the user changes profiles. - this._observerSvc.addObserver(this, "profile-before-change"); - - // Observe xpcom-shutdown so we can remove these observers - // when the application shuts down. - this._observerSvc.addObserver(this, "xpcom-shutdown"); - - // Observe profile-do-change so that non-default profiles get upgraded too - this._observerSvc.addObserver(this, "profile-do-change"); - - // Observe handlersvc-rdf-replace so we can switch to the datasource - this._observerSvc.addObserver(this, "handlersvc-rdf-replace"); - }, - - _updateDB: function HS__updateDB() { - try { - var defaultHandlersVersion = this._datastoreDefaultHandlersVersion; - } catch(ex) { - // accessing the datastore failed, we can't update anything - return; - } - - try { - // if we don't have the current version of the default prefs for - // this locale, inject any new default handers into the datastore - if (defaultHandlersVersion < this._prefsDefaultHandlersVersion) { - - // set the new version first so that if we recurse we don't - // call _injectNewDefaults several times - this._datastoreDefaultHandlersVersion = - this._prefsDefaultHandlersVersion; - this._injectNewDefaults(); - } - } catch (ex) { - // if injecting the defaults failed, set the version back to the - // previous value - this._datastoreDefaultHandlersVersion = defaultHandlersVersion; - } - }, - - get _currentLocale() { - const locSvc = Cc["@mozilla.org/intl/localeservice;1"]. - getService(Ci.mozILocaleService); - return locSvc.getAppLocaleAsLangTag(); - }, - - _destroy: function HS__destroy() { - this._observerSvc.removeObserver(this, "profile-before-change"); - this._observerSvc.removeObserver(this, "xpcom-shutdown"); - this._observerSvc.removeObserver(this, "profile-do-change"); - this._observerSvc.removeObserver(this, "handlersvc-rdf-replace"); - - // XXX Should we also null references to all the services that get stored - // by our memoizing getters in the Convenience Getters section? - }, - - _onProfileChange: function HS__onProfileChange() { - // Lose our reference to the datasource so we reacquire it - // from the new profile the next time we need it. - this.__ds = null; - }, - - _isInHandlerArray: function HS__isInHandlerArray(aArray, aHandler) { - var enumerator = aArray.enumerate(); - while (enumerator.hasMoreElements()) { - let handler = enumerator.getNext(); - handler.QueryInterface(Ci.nsIHandlerApp); - if (handler.equals(aHandler)) - return true; - } - - return false; - }, - - // note that this applies to the current locale only - get _datastoreDefaultHandlersVersion() { - var version = this._getValue("urn:root", NC_NS + this._currentLocale + - "_" + DEFAULT_HANDLERS_VERSION); - - return version ? version : -1; - }, - - set _datastoreDefaultHandlersVersion(aNewVersion) { - return this._setLiteral("urn:root", NC_NS + this._currentLocale + "_" + - DEFAULT_HANDLERS_VERSION, aNewVersion); - }, - - get _prefsDefaultHandlersVersion() { - // get handler service pref branch - var prefSvc = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - var handlerSvcBranch = prefSvc.getBranch("gecko.handlerService."); - - // get the version of the preferences for this locale - return Number(handlerSvcBranch. - getComplexValue("defaultHandlersVersion", - Ci.nsIPrefLocalizedString).data); - }, - - _injectNewDefaults: function HS__injectNewDefaults() { - // get handler service pref branch - var prefSvc = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - - let schemesPrefBranch = prefSvc.getBranch("gecko.handlerService.schemes."); - let schemePrefList = schemesPrefBranch.getChildList(""); - - var schemes = {}; - - // read all the scheme prefs into a hash - for (var schemePrefName of schemePrefList) { - - let [scheme, handlerNumber, attribute] = schemePrefName.split("."); - - try { - var attrData = - schemesPrefBranch.getComplexValue(schemePrefName, - Ci.nsIPrefLocalizedString).data; - if (!(scheme in schemes)) - schemes[scheme] = {}; - - if (!(handlerNumber in schemes[scheme])) - schemes[scheme][handlerNumber] = {}; - - schemes[scheme][handlerNumber][attribute] = attrData; - } catch (ex) {} - } - - let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Ci.nsIExternalProtocolService); - for (var scheme in schemes) { - - // This clause is essentially a reimplementation of - // nsIExternalProtocolHandlerService.getProtocolHandlerInfo(). - // Necessary because calling that from here would make XPConnect barf - // when getService tried to re-enter the constructor for this - // service. - let osDefaultHandlerFound = {}; - let protoInfo = protoSvc.getProtocolHandlerInfoFromOS(scheme, - osDefaultHandlerFound); - - if (this.exists(protoInfo)) - this.fillHandlerInfo(protoInfo, null); - else - protoSvc.setProtocolHandlerDefaults(protoInfo, - osDefaultHandlerFound.value); - - // cache the possible handlers to avoid extra xpconnect traversals. - let possibleHandlers = protoInfo.possibleApplicationHandlers; - - for (let handlerNumber in schemes[scheme]) { - let handlerPrefs = schemes[scheme][handlerNumber]; - let handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"]. - createInstance(Ci.nsIWebHandlerApp); - - handlerApp.uriTemplate = handlerPrefs.uriTemplate; - handlerApp.name = handlerPrefs.name; - - if (!this._isInHandlerArray(possibleHandlers, handlerApp)) { - possibleHandlers.appendElement(handlerApp); - } - } - - this.store(protoInfo); - } - }, - - //**************************************************************************// - // nsIObserver - - observe: function HS__observe(subject, topic, data) { - switch(topic) { - case "profile-before-change": - this._onProfileChange(); - break; - case "xpcom-shutdown": - this._destroy(); - break; - case "profile-do-change": - this._updateDB(); - break; - case "handlersvc-rdf-replace": - if (this.__ds) { - this._rdf.UnregisterDataSource(this.__ds); - this.__ds = null; - } - this._observerSvc.notifyObservers(null, "handlersvc-rdf-replace-complete"); - break; - } - }, - - - //**************************************************************************// - // nsIHandlerService - asyncInit: function HS_asyncInit() { - // noop - }, - - enumerate: function HS_enumerate() { - var handlers = Cc["@mozilla.org/array;1"]. - createInstance(Ci.nsIMutableArray); - this._appendHandlers(handlers, CLASS_MIMEINFO); - this._appendHandlers(handlers, CLASS_PROTOCOLINFO); - return handlers.enumerate(); - }, - - fillHandlerInfo: function HS_fillHandlerInfo(aHandlerInfo, aOverrideType) { - var type = aOverrideType || aHandlerInfo.type; - var typeID = this._getTypeID(this._getClass(aHandlerInfo), type); - - // Determine whether or not information about this handler is available - // in the datastore by looking for its "value" property, which stores its - // type and should always be present. - if (!this._hasValue(typeID, NC_VALUE)) - throw new Components.Exception("handlerSvc fillHandlerInfo: don't know this type", - Cr.NS_ERROR_NOT_AVAILABLE); - - // Note: for historical reasons, we don't actually check that the type - // record has a "handlerProp" property referencing the info record. It's - // unclear whether or not we should start doing this check; perhaps some - // legacy datasources don't have such references. - var infoID = this._getInfoID(this._getClass(aHandlerInfo), type); - - aHandlerInfo.preferredAction = this._retrievePreferredAction(infoID); - - var preferredHandlerID = - this._getPreferredHandlerID(this._getClass(aHandlerInfo), type); - - // Retrieve the preferred handler. - // Note: for historical reasons, we don't actually check that the info - // record has an "externalApplication" property referencing the preferred - // handler record. It's unclear whether or not we should start doing - // this check; perhaps some legacy datasources don't have such references. - aHandlerInfo.preferredApplicationHandler = - this._retrieveHandlerApp(preferredHandlerID); - - // Fill the array of possible handlers with the ones in the datastore. - this._fillPossibleHandlers(infoID, - aHandlerInfo.possibleApplicationHandlers, - aHandlerInfo.preferredApplicationHandler); - - // If we have an "always ask" flag stored in the RDF, always use its - // value. Otherwise, use the default value stored in the pref service. - var alwaysAsk; - if (this._hasValue(infoID, NC_ALWAYS_ASK)) { - alwaysAsk = (this._getValue(infoID, NC_ALWAYS_ASK) != "false"); - } else { - var prefSvc = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - var prefBranch = prefSvc.getBranch("network.protocol-handler."); - // If neither of the prefs exists, be paranoid and prompt. - alwaysAsk = - prefBranch.getBoolPref("warn-external." + type, - prefBranch.getBoolPref("warn-external-default", - true)); - } - aHandlerInfo.alwaysAskBeforeHandling = alwaysAsk; - - // If the object represents a MIME type handler, then also retrieve - // any file extensions. - if (aHandlerInfo instanceof Ci.nsIMIMEInfo) - for (let fileExtension of this._retrieveFileExtensions(typeID)) - aHandlerInfo.appendExtension(fileExtension); - }, - - store: function HS_store(aHandlerInfo) { - // FIXME: when we switch from RDF to something with transactions (like - // SQLite), enclose the following changes in a transaction so they all - // get rolled back if any of them fail and we don't leave the datastore - // in an inconsistent state. - - this._ensureRecordsForType(aHandlerInfo); - this._storePreferredAction(aHandlerInfo); - this._storePreferredHandler(aHandlerInfo); - this._storePossibleHandlers(aHandlerInfo); - this._storeAlwaysAsk(aHandlerInfo); - this._storeExtensions(aHandlerInfo); - - // Write the changes to the database immediately so we don't lose them - // if the application crashes. - if (this._ds instanceof Ci.nsIRDFRemoteDataSource) - this._ds.Flush(); - }, - - exists: function HS_exists(aHandlerInfo) { - var found; - - try { - var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type); - found = this._hasLiteralAssertion(typeID, NC_VALUE, aHandlerInfo.type); - } catch (e) { - // If the RDF threw (eg, corrupt file), treat as nonexistent. - found = false; - } - - return found; - }, - - remove: function HS_remove(aHandlerInfo) { - var preferredHandlerID = - this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type); - this._removeAssertions(preferredHandlerID); - - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - - // Get a list of possible handlers. After we have removed the info record, - // we'll check if any other info records reference these handlers, and we'll - // remove the handler records that aren't referenced by other info records. - var possibleHandlerIDs = []; - var possibleHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP); - while (possibleHandlerTargets.hasMoreElements()) { - let possibleHandlerTarget = possibleHandlerTargets.getNext(); - // Note: possibleHandlerTarget should always be an nsIRDFResource. - // The conditional is just here in case of a corrupt RDF datasource. - if (possibleHandlerTarget instanceof Ci.nsIRDFResource) - possibleHandlerIDs.push(possibleHandlerTarget.ValueUTF8); - } - - // Remove the info record. - this._removeAssertions(infoID); - - // Now that we've removed the info record, remove any possible handlers - // that aren't referenced by other info records. - for (let possibleHandlerID of possibleHandlerIDs) - if (!this._existsResourceTarget(NC_POSSIBLE_APP, possibleHandlerID)) - this._removeAssertions(possibleHandlerID); - - var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type); - this._removeAssertions(typeID); - - // Now that there's no longer a handler for this type, remove the type - // from the list of types for which there are known handlers. - var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo)); - var type = this._rdf.GetResource(typeID); - var typeIndex = typeList.IndexOf(type); - if (typeIndex != -1) - typeList.RemoveElementAt(typeIndex, true); - - // Write the changes to the database immediately so we don't lose them - // if the application crashes. - // XXX If we're removing a bunch of handlers at once, will flushing - // after every removal cause a significant performance hit? - if (this._ds instanceof Ci.nsIRDFRemoteDataSource) - this._ds.Flush(); - }, - - getTypeFromExtension: function HS_getTypeFromExtension(aFileExtension) { - var fileExtension = aFileExtension.toLowerCase(); - var typeID; - - // See bug 1100069 for why we want to fail gracefully and silently here. - try { - this._ds; - } catch (ex) { - Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE; - return; - } - - if (this._existsLiteralTarget(NC_FILE_EXTENSIONS, fileExtension)) - typeID = this._getSourceForLiteral(NC_FILE_EXTENSIONS, fileExtension); - - if (typeID && this._hasValue(typeID, NC_VALUE)) { - let type = this._getValue(typeID, NC_VALUE); - if (type == "") - throw Cr.NS_ERROR_FAILURE; - return type; - } - - return ""; - }, - - - //**************************************************************************// - // Retrieval Methods - - /** - * Retrieve the preferred action for the info record with the given ID. - * - * @param aInfoID {string} the info record ID - * - * @returns {integer} the preferred action enumeration value - */ - _retrievePreferredAction: function HS__retrievePreferredAction(aInfoID) { - if (this._getValue(aInfoID, NC_SAVE_TO_DISK) == "true") - return Ci.nsIHandlerInfo.saveToDisk; - - if (this._getValue(aInfoID, NC_USE_SYSTEM_DEFAULT) == "true") - return Ci.nsIHandlerInfo.useSystemDefault; - - if (this._getValue(aInfoID, NC_HANDLE_INTERNALLY) == "true") - return Ci.nsIHandlerInfo.handleInternally; - - return Ci.nsIHandlerInfo.useHelperApp; - }, - - /** - * Fill an array of possible handlers with the handlers for the given info ID. - * - * @param aInfoID {string} the ID of the info record - * @param aPossibleHandlers {nsIMutableArray} the array of possible handlers - * @param aPreferredHandler {nsIHandlerApp} the preferred handler, if any - */ - _fillPossibleHandlers: function HS__fillPossibleHandlers(aInfoID, - aPossibleHandlers, - aPreferredHandler) { - // The set of possible handlers should include the preferred handler, - // but legacy datastores (from before we added possible handlers) won't - // include the preferred handler, so check if it's included as we build - // the list of handlers, and, if it's not included, add it to the list. - if (aPreferredHandler) - aPossibleHandlers.appendElement(aPreferredHandler); - - var possibleHandlerTargets = this._getTargets(aInfoID, NC_POSSIBLE_APP); - - while (possibleHandlerTargets.hasMoreElements()) { - let possibleHandlerTarget = possibleHandlerTargets.getNext(); - if (!(possibleHandlerTarget instanceof Ci.nsIRDFResource)) - continue; - - let possibleHandlerID = possibleHandlerTarget.ValueUTF8; - let possibleHandler = this._retrieveHandlerApp(possibleHandlerID); - if (possibleHandler && (!aPreferredHandler || - !possibleHandler.equals(aPreferredHandler))) - aPossibleHandlers.appendElement(possibleHandler); - } - }, - - /** - * Retrieve the handler app object with the given ID. - * - * @param aHandlerAppID {string} the ID of the handler app to retrieve - * - * @returns {nsIHandlerApp} the handler app, if any; otherwise null - */ - _retrieveHandlerApp: function HS__retrieveHandlerApp(aHandlerAppID) { - var handlerApp; - - // If it has a path, it's a local handler; otherwise, it's a web handler. - if (this._hasValue(aHandlerAppID, NC_PATH)) { - let executable = - this._getFileWithPath(this._getValue(aHandlerAppID, NC_PATH)); - if (!executable) - return null; - - handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]. - createInstance(Ci.nsILocalHandlerApp); - handlerApp.executable = executable; - } - else if (this._hasValue(aHandlerAppID, NC_URI_TEMPLATE)) { - let uriTemplate = this._getValue(aHandlerAppID, NC_URI_TEMPLATE); - if (!uriTemplate) - return null; - - handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"]. - createInstance(Ci.nsIWebHandlerApp); - handlerApp.uriTemplate = uriTemplate; - } - else if (this._hasValue(aHandlerAppID, NC_SERVICE)) { - let service = this._getValue(aHandlerAppID, NC_SERVICE); - if (!service) - return null; - - let method = this._getValue(aHandlerAppID, NC_METHOD); - if (!method) - return null; - - let objpath = this._getValue(aHandlerAppID, NC_OBJPATH); - if (!objpath) - return null; - - let iface = this._getValue(aHandlerAppID, NC_INTERFACE); - if (!iface) - return null; - - handlerApp = Cc["@mozilla.org/uriloader/dbus-handler-app;1"]. - createInstance(Ci.nsIDBusHandlerApp); - handlerApp.service = service; - handlerApp.method = method; - handlerApp.objectPath = objpath; - handlerApp.dBusInterface = iface; - - } - else - return null; - - handlerApp.name = this._getValue(aHandlerAppID, NC_PRETTY_NAME); - - return handlerApp; - }, - - /* - * Retrieve file extensions, if any, for the MIME type with the given type ID. - * - * @param aTypeID {string} the type record ID - */ - _retrieveFileExtensions: function HS__retrieveFileExtensions(aTypeID) { - var fileExtensions = []; - - var fileExtensionTargets = this._getTargets(aTypeID, NC_FILE_EXTENSIONS); - - while (fileExtensionTargets.hasMoreElements()) { - let fileExtensionTarget = fileExtensionTargets.getNext(); - if (fileExtensionTarget instanceof Ci.nsIRDFLiteral && - fileExtensionTarget.Value != "") - fileExtensions.push(fileExtensionTarget.Value); - } - - return fileExtensions; - }, - - /** - * Get the file with the given path. This is not as simple as merely - * initializing a local file object with the path, because the path might be - * relative to the current process directory, in which case we have to - * construct a path starting from that directory. - * - * @param aPath {string} a path to a file - * - * @returns {nsIFile} the file, or null if the file does not exist - */ - _getFileWithPath: function HS__getFileWithPath(aPath) { - var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - - try { - file.initWithPath(aPath); - - if (file.exists()) - return file; - } - catch(ex) { - // Note: for historical reasons, we don't actually check to see - // if the exception is NS_ERROR_FILE_UNRECOGNIZED_PATH, which is what - // nsIFile::initWithPath throws when a path is relative. - - file = this._dirSvc.get("XCurProcD", Ci.nsIFile); - - try { - file.append(aPath); - if (file.exists()) - return file; - } - catch(ex) {} - } - - return null; - }, - - - //**************************************************************************// - // Storage Methods - - _storePreferredAction: function HS__storePreferredAction(aHandlerInfo) { - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - - switch(aHandlerInfo.preferredAction) { - case Ci.nsIHandlerInfo.saveToDisk: - this._setLiteral(infoID, NC_SAVE_TO_DISK, "true"); - this._removeTarget(infoID, NC_HANDLE_INTERNALLY); - this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT); - break; - - case Ci.nsIHandlerInfo.handleInternally: - this._setLiteral(infoID, NC_HANDLE_INTERNALLY, "true"); - this._removeTarget(infoID, NC_SAVE_TO_DISK); - this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT); - break; - - case Ci.nsIHandlerInfo.useSystemDefault: - this._setLiteral(infoID, NC_USE_SYSTEM_DEFAULT, "true"); - this._removeTarget(infoID, NC_SAVE_TO_DISK); - this._removeTarget(infoID, NC_HANDLE_INTERNALLY); - break; - - // This value is indicated in the datastore either by the absence of - // the three properties or by setting them all "false". Of these two - // options, the former seems preferable, because it reduces the size - // of the RDF file and thus the amount of stuff we have to parse. - case Ci.nsIHandlerInfo.useHelperApp: - default: - this._removeTarget(infoID, NC_SAVE_TO_DISK); - this._removeTarget(infoID, NC_HANDLE_INTERNALLY); - this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT); - break; - } - }, - - _handlerAppIsUnknownType: function HS__handlerAppIsUnknownType(aHandlerApp) { - if (aHandlerApp instanceof Ci.nsILocalHandlerApp || - aHandlerApp instanceof Ci.nsIWebHandlerApp || - aHandlerApp instanceof Ci.nsIDBusHandlerApp) { - return false; - } else { - return true; - } - }, - - - _storePreferredHandler: function HS__storePreferredHandler(aHandlerInfo) { - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - var handlerID = - this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type); - - var handler = aHandlerInfo.preferredApplicationHandler; - - if (handler && !this._handlerAppIsUnknownType(handler)) { - this._storeHandlerApp(handlerID, handler); - - // Make this app be the preferred app for the handler info. - // - // Note: nsExternalHelperAppService::FillContentHandlerProperties ignores - // this setting and instead identifies the preferred app as the resource - // whose URI follows the pattern urn::externalApplication:. - // But the old downloadactions.js code used to set this property, so just - // in case there is still some code somewhere that relies on its presence, - // we set it here. - this._setResource(infoID, NC_PREFERRED_APP, handlerID); - } - else { - // There isn't a preferred handler or the handler cannot be serialized, - // for example the Android default application handler. Remove the - // existing record for it, if any. - this._removeTarget(infoID, NC_PREFERRED_APP); - this._removeAssertions(handlerID); - } - }, - - /** - * Store the list of possible handler apps for the content type represented - * by the given handler info object. - * - * @param aHandlerInfo {nsIHandlerInfo} the handler info object - */ - _storePossibleHandlers: function HS__storePossibleHandlers(aHandlerInfo) { - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - - // First, retrieve the set of handler apps currently stored for the type, - // keeping track of their IDs in a hash that we'll use to determine which - // ones are no longer valid and should be removed. - var currentHandlerApps = {}; - var currentHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP); - while (currentHandlerTargets.hasMoreElements()) { - let handlerApp = currentHandlerTargets.getNext(); - if (handlerApp instanceof Ci.nsIRDFResource) { - let handlerAppID = handlerApp.ValueUTF8; - currentHandlerApps[handlerAppID] = true; - } - } - - // Next, store any new handler apps. - var newHandlerApps = - aHandlerInfo.possibleApplicationHandlers.enumerate(); - while (newHandlerApps.hasMoreElements()) { - let handlerApp = - newHandlerApps.getNext().QueryInterface(Ci.nsIHandlerApp); - // If the handlerApp is an unknown type, ignore it. - // Android default application handler is the case. - if (this._handlerAppIsUnknownType(handlerApp)) { - continue; - } - let handlerAppID = this._getPossibleHandlerAppID(handlerApp); - if (!this._hasResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID)) { - this._storeHandlerApp(handlerAppID, handlerApp); - this._addResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID); - } - delete currentHandlerApps[handlerAppID]; - } - - // Finally, remove any old handler apps that aren't being used anymore, - // and if those handler apps aren't being used by any other type either, - // then completely remove their record from the datastore so we don't - // leave it clogged up with information about handler apps we don't care - // about anymore. - for (let handlerAppID in currentHandlerApps) { - this._removeResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID); - if (!this._existsResourceTarget(NC_POSSIBLE_APP, handlerAppID)) - this._removeAssertions(handlerAppID); - } - }, - - /** - * Store the given handler app. - * - * Note: the reason this method takes the ID of the handler app in a param - * is that the ID is different than it usually is when the handler app - * in question is a preferred handler app, so this method can't just derive - * the ID of the handler app by calling _getPossibleHandlerAppID, its callers - * have to do that for it. - * - * @param aHandlerAppID {string} the ID of the handler app to store - * @param aHandlerApp {nsIHandlerApp} the handler app to store - */ - _storeHandlerApp: function HS__storeHandlerApp(aHandlerAppID, aHandlerApp) { - aHandlerApp.QueryInterface(Ci.nsIHandlerApp); - this._setLiteral(aHandlerAppID, NC_PRETTY_NAME, aHandlerApp.name); - - // In the case of the preferred handler, the handler ID could have been - // used to refer to a different kind of handler in the past (i.e. either - // a local hander or a web handler), so if the new handler is a local - // handler, then we remove any web handler properties and vice versa. - // This is unnecessary but harmless for possible handlers. - - if (aHandlerApp instanceof Ci.nsILocalHandlerApp) { - this._setLiteral(aHandlerAppID, NC_PATH, aHandlerApp.executable.path); - this._removeTarget(aHandlerAppID, NC_URI_TEMPLATE); - this._removeTarget(aHandlerAppID, NC_METHOD); - this._removeTarget(aHandlerAppID, NC_SERVICE); - this._removeTarget(aHandlerAppID, NC_OBJPATH); - this._removeTarget(aHandlerAppID, NC_INTERFACE); - } - else if(aHandlerApp instanceof Ci.nsIWebHandlerApp){ - aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp); - this._setLiteral(aHandlerAppID, NC_URI_TEMPLATE, aHandlerApp.uriTemplate); - this._removeTarget(aHandlerAppID, NC_PATH); - this._removeTarget(aHandlerAppID, NC_METHOD); - this._removeTarget(aHandlerAppID, NC_SERVICE); - this._removeTarget(aHandlerAppID, NC_OBJPATH); - this._removeTarget(aHandlerAppID, NC_INTERFACE); - } - else if(aHandlerApp instanceof Ci.nsIDBusHandlerApp){ - aHandlerApp.QueryInterface(Ci.nsIDBusHandlerApp); - this._setLiteral(aHandlerAppID, NC_SERVICE, aHandlerApp.service); - this._setLiteral(aHandlerAppID, NC_METHOD, aHandlerApp.method); - this._setLiteral(aHandlerAppID, NC_OBJPATH, aHandlerApp.objectPath); - this._setLiteral(aHandlerAppID, NC_INTERFACE, aHandlerApp.dBusInterface); - this._removeTarget(aHandlerAppID, NC_PATH); - this._removeTarget(aHandlerAppID, NC_URI_TEMPLATE); - } - else { - throw "unknown handler type"; - } - - }, - - _storeAlwaysAsk: function HS__storeAlwaysAsk(aHandlerInfo) { - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - this._setLiteral(infoID, - NC_ALWAYS_ASK, - aHandlerInfo.alwaysAskBeforeHandling ? "true" : "false"); - }, - - _storeExtensions: function HS__storeExtensions(aHandlerInfo) { - if (aHandlerInfo instanceof Ci.nsIMIMEInfo) { - var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type); - let source = this._rdf.GetResource(typeID); - let property = this._rdf.GetResource(NC_FILE_EXTENSIONS); - var extEnum = aHandlerInfo.getFileExtensions(); - while (extEnum.hasMore()) { - let ext = extEnum.getNext().toLowerCase(); - let target = this._rdf.GetLiteral(ext); - this._ds.Assert(source, property, target, true); - } - } - }, - - - //**************************************************************************// - // Convenience Getters - - // Observer Service - __observerSvc: null, - get _observerSvc() { - if (!this.__observerSvc) - this.__observerSvc = - Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - return this.__observerSvc; - }, - - // Directory Service - __dirSvc: null, - get _dirSvc() { - if (!this.__dirSvc) - this.__dirSvc = - Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - return this.__dirSvc; - }, - - // MIME Service - __mimeSvc: null, - get _mimeSvc() { - if (!this.__mimeSvc) - this.__mimeSvc = - Cc["@mozilla.org/mime;1"]. - getService(Ci.nsIMIMEService); - return this.__mimeSvc; - }, - - // Protocol Service - __protocolSvc: null, - get _protocolSvc() { - if (!this.__protocolSvc) - this.__protocolSvc = - Cc["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Ci.nsIExternalProtocolService); - return this.__protocolSvc; - }, - - // RDF Service - __rdf: null, - get _rdf() { - if (!this.__rdf) - this.__rdf = Cc["@mozilla.org/rdf/rdf-service;1"]. - getService(Ci.nsIRDFService); - return this.__rdf; - }, - - // RDF Container Utils - __containerUtils: null, - get _containerUtils() { - if (!this.__containerUtils) - this.__containerUtils = Cc["@mozilla.org/rdf/container-utils;1"]. - getService(Ci.nsIRDFContainerUtils); - return this.__containerUtils; - }, - - // RDF datasource containing content handling config (i.e. mimeTypes.rdf) - __ds: null, - get _ds() { - if (!this.__ds) { - var file = this._dirSvc.get("ProfD", Ci.nsIFile); - file.append("mimeTypes.rdf"); - // FIXME: make this a memoizing getter if we use it anywhere else. - var ioService = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var fileHandler = ioService.getProtocolHandler("file"). - QueryInterface(Ci.nsIFileProtocolHandler); - this.__ds = - this._rdf.GetDataSourceBlocking(fileHandler.getURLSpecFromFile(file)); - // do any necessary updating of the datastore - this._updateDB(); - } - - return this.__ds; - }, - - - //**************************************************************************// - // Datastore Utils - - /** - * Get the string identifying whether this is a MIME or a protocol handler. - * This string is used in the URI IDs of various RDF properties. - * - * @param aHandlerInfo {nsIHandlerInfo} the handler for which to get the class - * - * @returns {string} the class - */ - _getClass: function HS__getClass(aHandlerInfo) { - if (aHandlerInfo instanceof Ci.nsIMIMEInfo) - return CLASS_MIMEINFO; - else - return CLASS_PROTOCOLINFO; - }, - - /** - * Return the unique identifier for a content type record, which stores - * the value field plus a reference to the content type's handler info record. - * - * |urn::| - * - * XXX: should this be a property of nsIHandlerInfo? - * - * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO) - * @param aType {string} the type (a MIME type or protocol scheme) - * - * @returns {string} the ID - */ - _getTypeID: function HS__getTypeID(aClass, aType) { - return "urn:" + aClass + ":" + aType; - }, - - /** - * Return the unique identifier for a handler info record, which stores - * the preferredAction and alwaysAsk fields plus a reference to the preferred - * handler app. Roughly equivalent to the nsIHandlerInfo interface. - * - * |urn::handler:| - * - * FIXME: the type info record should be merged into the type record, - * since there's a one to one relationship between them, and this record - * merely stores additional attributes of a content type. - * - * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO) - * @param aType {string} the type (a MIME type or protocol scheme) - * - * @returns {string} the ID - */ - _getInfoID: function HS__getInfoID(aClass, aType) { - return "urn:" + aClass + ":handler:" + aType; - }, - - /** - * Return the unique identifier for a preferred handler record, which stores - * information about the preferred handler for a given content type, including - * its human-readable name and the path to its executable (for a local app) - * or its URI template (for a web app). - * - * |urn::externalApplication:| - * - * XXX: should this be a property of nsIHandlerApp? - * - * FIXME: this should be an arbitrary ID, and we should retrieve it from - * the datastore for a given content type via the NC:ExternalApplication - * property rather than looking for a specific ID, so a handler doesn't - * have to change IDs when it goes from being a possible handler to being - * the preferred one (once we support possible handlers). - * - * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO) - * @param aType {string} the type (a MIME type or protocol scheme) - * - * @returns {string} the ID - */ - _getPreferredHandlerID: function HS__getPreferredHandlerID(aClass, aType) { - return "urn:" + aClass + ":externalApplication:" + aType; - }, - - /** - * Return the unique identifier for a handler app record, which stores - * information about a possible handler for one or more content types, - * including its human-readable name and the path to its executable (for a - * local app) or its URI template (for a web app). - * - * Note: handler app IDs for preferred handlers are different. For those, - * see the _getPreferredHandlerID method. - * - * @param aHandlerApp {nsIHandlerApp} the handler app object - */ - _getPossibleHandlerAppID: function HS__getPossibleHandlerAppID(aHandlerApp) { - var handlerAppID = "urn:handler:"; - - if (aHandlerApp instanceof Ci.nsILocalHandlerApp) - handlerAppID += "local:" + aHandlerApp.executable.path; - else if(aHandlerApp instanceof Ci.nsIWebHandlerApp){ - aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp); - handlerAppID += "web:" + aHandlerApp.uriTemplate; - } - else if(aHandlerApp instanceof Ci.nsIDBusHandlerApp){ - aHandlerApp.QueryInterface(Ci.nsIDBusHandlerApp); - handlerAppID += "dbus:" + aHandlerApp.service + " " + aHandlerApp.method + " " + aHandlerApp.uriTemplate; - }else{ - throw "unknown handler type"; - } - - return handlerAppID; - }, - - /** - * Get the list of types for the given class, creating the list if it doesn't - * already exist. The class can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO - * (i.e. the result of a call to _getClass). - * - * |urn:s| - * |urn:s:root| - * - * @param aClass {string} the class for which to retrieve a list of types - * - * @returns {nsIRDFContainer} the list of types - */ - _ensureAndGetTypeList: function HS__ensureAndGetTypeList(aClass) { - var source = this._rdf.GetResource("urn:" + aClass + "s"); - var property = - this._rdf.GetResource(aClass == CLASS_MIMEINFO ? NC_MIME_TYPES - : NC_PROTOCOL_SCHEMES); - var target = this._rdf.GetResource("urn:" + aClass + "s:root"); - - // Make sure we have an arc from the source to the target. - if (!this._ds.HasAssertion(source, property, target, true)) - this._ds.Assert(source, property, target, true); - - // Make sure the target is a container. - if (!this._containerUtils.IsContainer(this._ds, target)) - this._containerUtils.MakeSeq(this._ds, target); - - // Get the type list as an RDF container. - var typeList = Cc["@mozilla.org/rdf/container;1"]. - createInstance(Ci.nsIRDFContainer); - typeList.Init(this._ds, target); - - return typeList; - }, - - /** - * Make sure there are records in the datasource for the given content type - * by creating them if they don't already exist. We have to do this before - * storing any specific data, because we can't assume the presence - * of the records (the nsIHandlerInfo object might have been created - * from the OS), and the records have to all be there in order for the helper - * app service to properly construct an nsIHandlerInfo object for the type. - * - * Based on old downloadactions.js::_ensureMIMERegistryEntry. - * - * @param aHandlerInfo {nsIHandlerInfo} the type to make sure has a record - */ - _ensureRecordsForType: function HS__ensureRecordsForType(aHandlerInfo) { - // Get the list of types. - var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo)); - - // If there's already a record in the datastore for this type, then we - // don't need to do anything more. - var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type); - var type = this._rdf.GetResource(typeID); - if (typeList.IndexOf(type) != -1) - return; - - // Create a basic type record for this type. - typeList.AppendElement(type); - this._setLiteral(typeID, NC_VALUE, aHandlerInfo.type); - - // Create a basic info record for this type. - var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type); - this._setLiteral(infoID, NC_ALWAYS_ASK, "false"); - this._setResource(typeID, NC_HANDLER_INFO, infoID); - // XXX Shouldn't we set preferredAction to useSystemDefault? - // That's what it is if there's no record in the datastore; why should it - // change to useHelperApp just because we add a record to the datastore? - - // Create a basic preferred handler record for this type. - // XXX Not sure this is necessary, since preferred handlers are optional, - // and nsExternalHelperAppService::FillHandlerInfoForTypeFromDS doesn't seem - // to require the record , but downloadactions.js::_ensureMIMERegistryEntry - // used to create it, so we'll do the same. - var preferredHandlerID = - this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type); - this._setLiteral(preferredHandlerID, NC_PATH, ""); - this._setResource(infoID, NC_PREFERRED_APP, preferredHandlerID); - }, - - /** - * Append known handlers of the given class to the given array. The class - * can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO. - * - * @param aHandlers {array} the array of handlers to append to - * @param aClass {string} the class for which to append handlers - */ - _appendHandlers: function HS__appendHandlers(aHandlers, aClass) { - var typeList = this._ensureAndGetTypeList(aClass); - var enumerator = typeList.GetElements(); - - while (enumerator.hasMoreElements()) { - var element = enumerator.getNext(); - - // This should never happen. If it does, that means our datasource - // is corrupted with type list entries that point to literal values - // instead of resources. If it does happen, let's just do our best - // to recover by ignoring this entry and moving on to the next one. - if (!(element instanceof Ci.nsIRDFResource)) - continue; - - // Get the value of the element's NC:value property, which contains - // the MIME type or scheme for which we're retrieving a handler info. - var type = this._getValue(element.ValueUTF8, NC_VALUE); - if (!type) - continue; - - var handler; - if (typeList.Resource.ValueUTF8 == "urn:mimetypes:root") - handler = this._mimeSvc.getFromTypeAndExtension(type, null); - else - handler = this._protocolSvc.getProtocolHandlerInfo(type); - - aHandlers.appendElement(handler); - } - }, - - /** - * Whether or not a property of an RDF source has a value. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @returns {boolean} whether or not the property has a value - */ - _hasValue: function HS__hasValue(sourceURI, propertyURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - return this._ds.hasArcOut(source, property); - }, - - /** - * Get the value of a property of an RDF source. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @returns {string} the value of the property - */ - _getValue: function HS__getValue(sourceURI, propertyURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - - var target = this._ds.GetTarget(source, property, true); - - if (!target) - return null; - - if (target instanceof Ci.nsIRDFResource) - return target.ValueUTF8; - - if (target instanceof Ci.nsIRDFLiteral) - return target.Value; - - return null; - }, - - /** - * Get all targets for the property of an RDF source. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * - * @returns {nsISimpleEnumerator} an enumerator of targets - */ - _getTargets: function HS__getTargets(sourceURI, propertyURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - - return this._ds.GetTargets(source, property, true); - }, - - /** - * Set a property of an RDF source to a literal value. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param value {string} the literal value - */ - _setLiteral: function HS__setLiteral(sourceURI, propertyURI, value) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetLiteral(value); - - this._setTarget(source, property, target); - }, - - /** - * Set a property of an RDF source to a resource target. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param targetURI {string} the URI of the target - */ - _setResource: function HS__setResource(sourceURI, propertyURI, targetURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetResource(targetURI); - - this._setTarget(source, property, target); - }, - - /** - * Assert an arc into the RDF datasource if there is no arc with the given - * source and property; otherwise, if there is already an existing arc, - * change it to point to the given target. _setLiteral and _setResource - * call this after converting their string arguments into resources - * and literals, and most callers should call one of those two methods - * instead of this one. - * - * @param source {nsIRDFResource} the source - * @param property {nsIRDFResource} the property - * @param target {nsIRDFNode} the target - */ - _setTarget: function HS__setTarget(source, property, target) { - if (this._ds.hasArcOut(source, property)) { - var oldTarget = this._ds.GetTarget(source, property, true); - this._ds.Change(source, property, oldTarget, target); - } - else - this._ds.Assert(source, property, target, true); - }, - - /** - * Assert that a property of an RDF source has a resource target. - * - * The difference between this method and _setResource is that this one adds - * an assertion even if one already exists, which allows its callers to make - * sets of assertions (i.e. to set a property to multiple targets). - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param targetURI {string} the URI of the target - */ - _addResourceAssertion: function HS__addResourceAssertion(sourceURI, - propertyURI, - targetURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetResource(targetURI); - - this._ds.Assert(source, property, target, true); - }, - - /** - * Remove an assertion with a resource target. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param targetURI {string} the URI of the target - */ - _removeResourceAssertion: function HS__removeResourceAssertion(sourceURI, - propertyURI, - targetURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetResource(targetURI); - - this._ds.Unassert(source, property, target); - }, - - /** - * Whether or not a property of an RDF source has a given resource target. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param targetURI {string} the URI of the target - * - * @returns {boolean} whether or not there is such an assertion - */ - _hasResourceAssertion: function HS__hasResourceAssertion(sourceURI, - propertyURI, - targetURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetResource(targetURI); - - return this._ds.HasAssertion(source, property, target, true); - }, - - /** - * Whether or not a property of an RDF source has a given literal value. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - * @param value {string} the literal value - * - * @returns {boolean} whether or not there is such an assertion - */ - _hasLiteralAssertion: function HS__hasLiteralAssertion(sourceURI, - propertyURI, - value) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetLiteral(value); - - return this._ds.HasAssertion(source, property, target, true); - }, - - /** - * Whether or not there is an RDF source that has the given property set to - * the given literal value. - * - * @param propertyURI {string} the URI of the property - * @param value {string} the literal value - * - * @returns {boolean} whether or not there is a source - */ - _existsLiteralTarget: function HS__existsLiteralTarget(propertyURI, value) { - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetLiteral(value); - - return this._ds.hasArcIn(target, property); - }, - - /** - * Get the source for a property set to a given literal value. - * - * @param propertyURI {string} the URI of the property - * @param value {string} the literal value - */ - _getSourceForLiteral: function HS__getSourceForLiteral(propertyURI, value) { - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetLiteral(value); - - var source = this._ds.GetSource(property, target, true); - if (source) - return source.ValueUTF8; - - return null; - }, - - /** - * Whether or not there is an RDF source that has the given property set to - * the given resource target. - * - * @param propertyURI {string} the URI of the property - * @param targetURI {string} the URI of the target - * - * @returns {boolean} whether or not there is a source - */ - _existsResourceTarget: function HS__existsResourceTarget(propertyURI, - targetURI) { - var property = this._rdf.GetResource(propertyURI); - var target = this._rdf.GetResource(targetURI); - - return this._ds.hasArcIn(target, property); - }, - - /** - * Remove a property of an RDF source. - * - * @param sourceURI {string} the URI of the source - * @param propertyURI {string} the URI of the property - */ - _removeTarget: function HS__removeTarget(sourceURI, propertyURI) { - var source = this._rdf.GetResource(sourceURI); - var property = this._rdf.GetResource(propertyURI); - - if (this._ds.hasArcOut(source, property)) { - var target = this._ds.GetTarget(source, property, true); - this._ds.Unassert(source, property, target); - } - }, - - /** - * Remove all assertions about a given RDF source. - * - * Note: not recursive. If some assertions point to other resources, - * and you want to remove assertions about those resources too, you need - * to do so manually. - * - * @param sourceURI {string} the URI of the source - */ - _removeAssertions: function HS__removeAssertions(sourceURI) { - var source = this._rdf.GetResource(sourceURI); - var properties = this._ds.ArcLabelsOut(source); - - while (properties.hasMoreElements()) { - let property = properties.getNext(); - let targets = this._ds.GetTargets(source, property, true); - while (targets.hasMoreElements()) { - let target = targets.getNext(); - this._ds.Unassert(source, property, target); - } - } - } - -}; - -//****************************************************************************// -// More XPCOM Plumbing - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HandlerService]); diff --git a/uriloader/exthandler/nsHandlerService.manifest b/uriloader/exthandler/nsHandlerService.manifest deleted file mode 100644 index 8249445815a2..000000000000 --- a/uriloader/exthandler/nsHandlerService.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {32314cc8-22f7-4f7f-a645-1a45453ba6a6} nsHandlerService.js -contract @mozilla.org/uriloader/handler-service-rdf;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6} process=main diff --git a/uriloader/exthandler/tests/unit/common_test_handlerService.js b/uriloader/exthandler/tests/unit/common_test_handlerService.js index e190c7b3a2e0..27bce2dcdadc 100644 --- a/uriloader/exthandler/tests/unit/common_test_handlerService.js +++ b/uriloader/exthandler/tests/unit/common_test_handlerService.js @@ -1,12 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -/* - * Loaded by "test_handlerService_json.js" and "test_handlerService_rdf.js" to - * check that the nsIHandlerService interface has the same behavior with both - * the JSON and RDF backends. - */ - HandlerServiceTestUtils.handlerService = gHandlerService; // Set up an nsIWebHandlerApp instance that can be used in multiple tests. diff --git a/uriloader/exthandler/tests/unit/head.js b/uriloader/exthandler/tests/unit/head.js index 9b4baca2301b..f40489182ebf 100644 --- a/uriloader/exthandler/tests/unit/head.js +++ b/uriloader/exthandler/tests/unit/head.js @@ -21,14 +21,10 @@ ChromeUtils.import("resource://testing-common/TestUtils.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "gHandlerServiceJSON", "@mozilla.org/uriloader/handler-service;1", "nsIHandlerService"); -XPCOMUtils.defineLazyServiceGetter(this, "gHandlerServiceRDF", - "@mozilla.org/uriloader/handler-service-rdf;1", - "nsIHandlerService"); do_get_profile(); let jsonPath = OS.Path.join(OS.Constants.Path.profileDir, "handlers.json"); -let rdfFile = FileUtils.getFile("ProfD", ["mimeTypes.rdf"]); /** * Unloads the nsIHandlerService data store, so the back-end file can be @@ -44,16 +40,6 @@ let unloadHandlerStoreJSON = async function() { Services.obs.notifyObservers(null, "handlersvc-json-replace", null); await promise; }; -let unloadHandlerStoreRDF = async function() { - // If this function is called before the nsIHandlerService instance has been - // initialized for the first time, the observer below will not be registered. - // We have to force initialization to prevent the function from stalling. - gHandlerServiceRDF; - - let promise = TestUtils.topicObserved("handlersvc-rdf-replace-complete"); - Services.obs.notifyObservers(null, "handlersvc-rdf-replace", null); - await promise; -}; /** * Unloads the data store and deletes it. @@ -63,11 +49,6 @@ let deleteHandlerStoreJSON = async function() { await OS.File.remove(jsonPath, { ignoreAbsent: true }); }; -let deleteHandlerStoreRDF = async function() { - await unloadHandlerStoreRDF(); - - await OS.File.remove(rdfFile.path, { ignoreAbsent: true }); -}; /** * Unloads the data store and replaces it with the test data file. @@ -77,30 +58,10 @@ let copyTestDataToHandlerStoreJSON = async function() { await OS.File.copy(do_get_file("handlers.json").path, jsonPath); }; -let copyTestDataToHandlerStoreRDF = async function() { - await unloadHandlerStoreRDF(); - - let fileName = AppConstants.platform == "android" ? "mimeTypes-android.rdf" - : "mimeTypes.rdf"; - await OS.File.copy(do_get_file(fileName).path, rdfFile.path); -}; - -/** - * Ensures the JSON implementation doesn't migrate entries from the legacy RDF - * data source during the other tests. This is important for both back-ends, - * because the JSON implementation is the default one and is always invoked by - * the MIME service when building new nsIHandlerInfo objects. - */ -add_task(async function test_initialize() { - // We don't need to reset this preference when the tests end, because it's - // irrelevant for any other test in the tree. - Services.prefs.setBoolPref("gecko.handlerService.migrated", true); -}); /** * Ensures the files are removed and the services unloaded when the tests end. */ registerCleanupFunction(async function test_terminate() { await deleteHandlerStoreJSON(); - await deleteHandlerStoreRDF(); }); diff --git a/uriloader/exthandler/tests/unit/mimeTypes-android.rdf b/uriloader/exthandler/tests/unit/mimeTypes-android.rdf deleted file mode 100644 index a3df9a5bf029..000000000000 --- a/uriloader/exthandler/tests/unit/mimeTypes-android.rdf +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - example_two - example_three - - - - - - - - - - - - - - - - - - example_two - example_three - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/uriloader/exthandler/tests/unit/mimeTypes.rdf b/uriloader/exthandler/tests/unit/mimeTypes.rdf deleted file mode 100644 index 682453569eff..000000000000 --- a/uriloader/exthandler/tests/unit/mimeTypes.rdf +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - example_two - example_three - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - example_two - example_three - - diff --git a/uriloader/exthandler/tests/unit/test_handlerService_json.js b/uriloader/exthandler/tests/unit/test_handlerService_json.js index 09e766e098a4..b42c880a98a8 100644 --- a/uriloader/exthandler/tests/unit/test_handlerService_json.js +++ b/uriloader/exthandler/tests/unit/test_handlerService_json.js @@ -70,73 +70,6 @@ add_task(async function test_race_async_init() { await unloadHandlerStore(); }); -/** - * Tests the migration from an existing RDF data source. - */ -add_task(async function test_migration_rdf_present() { - // Perform the most common migration, with the JSON file missing. - await deleteHandlerStore(); - await copyTestDataToHandlerStoreRDF(); - Services.prefs.setBoolPref("gecko.handlerService.migrated", false); - await assertAllHandlerInfosMatchTestData(); - Assert.ok(Services.prefs.getBoolPref("gecko.handlerService.migrated")); - - // Repeat the migration with the JSON file present. - await unloadHandlerStore(); - await unloadHandlerStoreRDF(); - Services.prefs.setBoolPref("gecko.handlerService.migrated", false); - await assertAllHandlerInfosMatchTestData(); - Assert.ok(Services.prefs.getBoolPref("gecko.handlerService.migrated")); -}); - -/** - * Tests that new entries are preserved if migration is triggered manually. - */ -add_task(async function test_migration_rdf_present_keeps_new_data() { - await deleteHandlerStore(); - - let handlerInfo = getKnownHandlerInfo("example/new"); - gHandlerService.store(handlerInfo); - - // Perform the migration with the JSON file present. - await unloadHandlerStore(); - await copyTestDataToHandlerStoreRDF(); - Services.prefs.setBoolPref("gecko.handlerService.migrated", false); - - let actualHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("example/new"); - HandlerServiceTestUtils.assertHandlerInfoMatches(actualHandlerInfo, { - type: "example/new", - preferredAction: Ci.nsIHandlerInfo.saveToDisk, - alwaysAskBeforeHandling: false, - }); - - Assert.ok(Services.prefs.getBoolPref("gecko.handlerService.migrated")); -}); - -/** - * Tests the injection of default protocol handlers when the RDF does not exist. - */ -add_task(async function test_migration_rdf_absent() { - if (!Services.prefs.getPrefType("gecko.handlerService.defaultHandlersVersion")) { - info("This platform or locale does not have default handlers."); - return; - } - - // Perform the most common migration, with the JSON file missing. - await deleteHandlerStore(); - await deleteHandlerStoreRDF(); - Services.prefs.setBoolPref("gecko.handlerService.migrated", false); - await assertAllHandlerInfosMatchDefaultHandlers(); - Assert.ok(Services.prefs.getBoolPref("gecko.handlerService.migrated")); - - // Repeat the migration with the JSON file present. - await unloadHandlerStore(); - await unloadHandlerStoreRDF(); - Services.prefs.setBoolPref("gecko.handlerService.migrated", false); - await assertAllHandlerInfosMatchDefaultHandlers(); - Assert.ok(Services.prefs.getBoolPref("gecko.handlerService.migrated")); -}); - /** * Test saving and reloading an instance of nsIGIOMimeApp. */ diff --git a/uriloader/exthandler/tests/unit/test_handlerService_rdf.js b/uriloader/exthandler/tests/unit/test_handlerService_rdf.js deleted file mode 100644 index 17cabaddfb04..000000000000 --- a/uriloader/exthandler/tests/unit/test_handlerService_rdf.js +++ /dev/null @@ -1,14 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -/* - * Tests the nsIHandlerService interface using the RDF backend. - */ - -let gHandlerService = gHandlerServiceRDF; -let unloadHandlerStore = unloadHandlerStoreRDF; -let deleteHandlerStore = deleteHandlerStoreRDF; -let copyTestDataToHandlerStore = copyTestDataToHandlerStoreRDF; - -var scriptFile = do_get_file("common_test_handlerService.js"); -Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec); diff --git a/uriloader/exthandler/tests/unit/xpcshell.ini b/uriloader/exthandler/tests/unit/xpcshell.ini index 48d0ab269a3e..3191eab5bb23 100644 --- a/uriloader/exthandler/tests/unit/xpcshell.ini +++ b/uriloader/exthandler/tests/unit/xpcshell.ini @@ -13,8 +13,6 @@ support-files = mailcap fail-if = os == "android" [test_handlerService_json.js] support-files = handlers.json -[test_handlerService_rdf.js] -support-files = mimeTypes.rdf mimeTypes-android.rdf [test_punycodeURIs.js] # Bug 676997: test consistently fails on Android fail-if = os == "android"