зеркало из https://github.com/mozilla/pjs.git
bug 385740: make the handler service store possible applications when storing a handler info object; r=biesi, sr=dmose
This commit is contained in:
Родитель
2e57991122
Коммит
2bcbd52db6
|
@ -70,8 +70,9 @@ const NC_USE_SYSTEM_DEFAULT = NC_NS + "useSystemDefault";
|
|||
// nsIHandlerInfo::alwaysAskBeforeHandling
|
||||
const NC_ALWAYS_ASK = NC_NS + "alwaysAsk";
|
||||
|
||||
// references nsIHandlerApp record
|
||||
// references nsIHandlerApp records
|
||||
const NC_PREFERRED_APP = NC_NS + "externalApplication";
|
||||
const NC_POSSIBLE_APP = NC_NS + "possibleApplication";
|
||||
|
||||
// handler app ("handler") properties
|
||||
|
||||
|
@ -120,6 +121,7 @@ HandlerService.prototype = {
|
|||
this._ensureRecordsForType(aHandlerInfo);
|
||||
this._storePreferredAction(aHandlerInfo);
|
||||
this._storePreferredHandler(aHandlerInfo);
|
||||
this._storePossibleHandlers(aHandlerInfo);
|
||||
this._storeAlwaysAsk(aHandlerInfo);
|
||||
|
||||
// Write the changes to the database immediately so we don't lose them
|
||||
|
@ -164,20 +166,20 @@ HandlerService.prototype = {
|
|||
switch(aHandlerInfo.preferredAction) {
|
||||
case Ci.nsIHandlerInfo.saveToDisk:
|
||||
this._setLiteral(infoID, NC_SAVE_TO_DISK, "true");
|
||||
this._removeValue(infoID, NC_HANDLE_INTERNALLY);
|
||||
this._removeValue(infoID, NC_USE_SYSTEM_DEFAULT);
|
||||
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._removeValue(infoID, NC_SAVE_TO_DISK);
|
||||
this._removeValue(infoID, NC_USE_SYSTEM_DEFAULT);
|
||||
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._removeValue(infoID, NC_SAVE_TO_DISK);
|
||||
this._removeValue(infoID, NC_HANDLE_INTERNALLY);
|
||||
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
|
||||
|
@ -186,9 +188,9 @@ HandlerService.prototype = {
|
|||
// of the RDF file and thus the amount of stuff we have to parse.
|
||||
case Ci.nsIHandlerInfo.useHelperApp:
|
||||
default:
|
||||
this._removeValue(infoID, NC_SAVE_TO_DISK);
|
||||
this._removeValue(infoID, NC_HANDLE_INTERNALLY);
|
||||
this._removeValue(infoID, NC_USE_SYSTEM_DEFAULT);
|
||||
this._removeTarget(infoID, NC_SAVE_TO_DISK);
|
||||
this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
|
||||
this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -199,32 +201,104 @@ HandlerService.prototype = {
|
|||
var handler = aHandlerInfo.preferredApplicationHandler;
|
||||
|
||||
if (handler) {
|
||||
// First add a record for the preferred app to the datasource. In the
|
||||
// process we also need to remove any vestiges of an existing record, so
|
||||
// we remove any properties that we aren't overwriting.
|
||||
this._setLiteral(handlerID, NC_PRETTY_NAME, handler.name);
|
||||
if (handler instanceof Ci.nsILocalHandlerApp) {
|
||||
this._setLiteral(handlerID, NC_PATH, handler.executable.path);
|
||||
this._removeValue(handlerID, NC_URI_TEMPLATE);
|
||||
}
|
||||
else {
|
||||
handler.QueryInterface(Ci.nsIWebHandlerApp);
|
||||
this._setLiteral(handlerID, NC_URI_TEMPLATE, handler.uriTemplate);
|
||||
this._removeValue(handlerID, NC_PATH);
|
||||
}
|
||||
this._storeHandlerApp(handlerID, handler);
|
||||
|
||||
// Finally, make this app be the preferred app for the handler info.
|
||||
// Note: at least some code completely ignores this setting and assumes
|
||||
// the preferred app is the one whose URI follows the appropriate pattern.
|
||||
// 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:<class>:externalApplication:<type>.
|
||||
// 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. Remove the existing record for it,
|
||||
// if any.
|
||||
this._removeValue(handlerID, NC_PRETTY_NAME);
|
||||
this._removeValue(handlerID, NC_PATH);
|
||||
this._removeValue(handlerID, NC_URI_TEMPLATE);
|
||||
this._removeValue(infoID, NC_PREFERRED_APP);
|
||||
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(aHandlerInfo);
|
||||
|
||||
// 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.Value;
|
||||
currentHandlerApps[handlerAppID] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Next, store any new handler apps.
|
||||
var newHandlerApps =
|
||||
aHandlerInfo.possibleApplicationHandlers.enumerate();
|
||||
while (newHandlerApps.hasMoreElements()) {
|
||||
let handlerApp =
|
||||
newHandlerApps.getNext().QueryInterface(Ci.nsIHandlerApp);
|
||||
let handlerAppID = this._getPossibleHandlerAppID(handlerApp);
|
||||
if (!this._hasResourceTarget(infoID, NC_POSSIBLE_APP, handlerAppID)) {
|
||||
this._storeHandlerApp(handlerAppID, handlerApp);
|
||||
this._addResourceTarget(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._removeTarget(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);
|
||||
}
|
||||
else {
|
||||
aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
|
||||
this._setLiteral(aHandlerAppID, NC_URI_TEMPLATE, aHandlerApp.uriTemplate);
|
||||
this._removeTarget(aHandlerAppID, NC_PATH);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -376,6 +450,30 @@ HandlerService.prototype = {
|
|||
aHandlerInfo.type;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
|
||||
handlerAppID += "web:" + aHandlerApp.uriTemplate;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -522,6 +620,21 @@ HandlerService.prototype = {
|
|||
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.
|
||||
*
|
||||
|
@ -538,16 +651,16 @@ HandlerService.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Set a property of an RDF source to a resource.
|
||||
* 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 resourceURI {string} the URI of the resource
|
||||
* @param targetURI {string} the URI of the target
|
||||
*/
|
||||
_setResource: function HS__setResource(sourceURI, propertyURI, resourceURI) {
|
||||
_setResource: function HS__setResource(sourceURI, propertyURI, targetURI) {
|
||||
var source = this._rdf.GetResource(sourceURI);
|
||||
var property = this._rdf.GetResource(propertyURI);
|
||||
var target = this._rdf.GetResource(resourceURI);
|
||||
var target = this._rdf.GetResource(targetURI);
|
||||
|
||||
this._setTarget(source, property, target);
|
||||
},
|
||||
|
@ -555,11 +668,14 @@ HandlerService.prototype = {
|
|||
/**
|
||||
* 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.
|
||||
* 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 value {nsIRDFNode} the target
|
||||
* @param target {nsIRDFNode} the target
|
||||
*/
|
||||
_setTarget: function HS__setTarget(source, property, target) {
|
||||
if (this._ds.hasArcOut(source, property)) {
|
||||
|
@ -570,13 +686,72 @@ HandlerService.prototype = {
|
|||
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
|
||||
*/
|
||||
_addResourceTarget: function HS__addResourceTarget(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);
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not a property of an RDF source has a given 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
|
||||
*
|
||||
* @returns {boolean} whether or not there is such an assertion
|
||||
*/
|
||||
_hasResourceTarget: function HS__hasResourceTarget(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 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
|
||||
*/
|
||||
_removeValue: function HS__removeValue(sourceURI, propertyURI) {
|
||||
_removeTarget: function HS__removeTarget(sourceURI, propertyURI) {
|
||||
var source = this._rdf.GetResource(sourceURI);
|
||||
var property = this._rdf.GetResource(propertyURI);
|
||||
|
||||
|
|
|
@ -35,15 +35,15 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_uriloader_exthandler
|
||||
MODULE = test_uriloader_exthandler
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -35,12 +35,29 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function run_test() {
|
||||
//**************************************************************************//
|
||||
// Constants
|
||||
|
||||
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
|
||||
const mimeSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
|
||||
getService(Ci.nsIMIMEService);
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Sample Data
|
||||
|
||||
// It doesn't matter whether or not this nsIFile is actually executable,
|
||||
// only that it has a path and exists. Since we don't know any executable
|
||||
// that exists on all platforms (except possibly the application being
|
||||
// tested, but there doesn't seem to be a way to get a reference to that
|
||||
// from the directory service), we use the temporary directory itself.
|
||||
var executable = HandlerServiceTest._dirSvc.get("TmpD", Ci.nsIFile);
|
||||
// XXX We could, of course, create an actual executable in the directory:
|
||||
//executable.append("localhandler");
|
||||
//if (!executable.exists())
|
||||
// executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
|
||||
|
||||
var localHandler = {
|
||||
name: "Local Handler",
|
||||
|
@ -57,16 +74,28 @@ function run_test() {
|
|||
createInstance(Ci.nsIWebHandlerApp);
|
||||
webHandler.name = "Web Handler";
|
||||
webHandler.uriTemplate = "http://www.example.com/?%s";
|
||||
|
||||
var handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
|
||||
var mimeSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
|
||||
getService(Ci.nsIMIMEService);
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Default Properties
|
||||
// Helper Functions
|
||||
|
||||
function checkLocalHandlersAreEquivalent(handler1, handler2) {
|
||||
do_check_eq(handler1.name, handler2.name);
|
||||
do_check_eq(handler1.executable.path, handler2.executable.path);
|
||||
}
|
||||
|
||||
function checkWebHandlersAreEquivalent(handler1, handler2) {
|
||||
do_check_eq(handler1.name, handler2.name);
|
||||
do_check_eq(handler1.uriTemplate, handler2.uriTemplate);
|
||||
}
|
||||
|
||||
// FIXME: these tests create and manipulate enough variables that it would
|
||||
// make sense to move each test into its own scope so we don't run the risk
|
||||
// of one test stomping on another's data.
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Test Default Properties
|
||||
|
||||
// Get a handler info for a MIME type that neither the application nor
|
||||
// the OS knows about and make sure its properties are set to the proper
|
||||
|
@ -97,7 +126,7 @@ function run_test() {
|
|||
|
||||
|
||||
//**************************************************************************//
|
||||
// Round-Trip Data Integrity
|
||||
// Test Round-Trip Data Integrity
|
||||
|
||||
// Test round-trip data integrity by setting the properties of the handler
|
||||
// info object to different values, telling the handler service to store the
|
||||
|
@ -168,6 +197,70 @@ function run_test() {
|
|||
mimeSvc.getFromTypeAndExtension("nonexistent/rem-preferred-handler", null);
|
||||
do_check_eq(removePreferredHandlerInfo.preferredApplicationHandler, null);
|
||||
|
||||
// Make sure we can store and retrieve a handler info object with possible
|
||||
// handlers. We test both adding and removing handlers.
|
||||
|
||||
// Get a handler info and make sure it has no possible handlers.
|
||||
var possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 0);
|
||||
|
||||
// Store and re-retrieve the handler and make sure it still has no possible
|
||||
// handlers.
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 0);
|
||||
|
||||
// Add two handlers, store the object, re-retrieve it, and make sure it has
|
||||
// two handlers.
|
||||
possibleHandlersInfo.possibleApplicationHandlers.appendElement(localHandler,
|
||||
false);
|
||||
possibleHandlersInfo.possibleApplicationHandlers.appendElement(webHandler,
|
||||
false);
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 2);
|
||||
|
||||
// Figure out which is the local and which is the web handler and the index
|
||||
// in the array of the local handler, which is the one we're going to remove
|
||||
// to test removal of a handler.
|
||||
var handler1 = possibleHandlersInfo.possibleApplicationHandlers.
|
||||
queryElementAt(0, Ci.nsIHandlerApp);
|
||||
var handler2 = possibleHandlersInfo.possibleApplicationHandlers.
|
||||
queryElementAt(1, Ci.nsIHandlerApp);
|
||||
var localPossibleHandler, webPossibleHandler, localIndex;
|
||||
if (handler1 instanceof Ci.nsILocalHandlerApp)
|
||||
[localPossibleHandler, webPossibleHandler, localIndex] = [handler1,
|
||||
handler2,
|
||||
0];
|
||||
else
|
||||
[localPossibleHandler, webPossibleHandler, localIndex] = [handler2,
|
||||
handler1,
|
||||
1];
|
||||
localPossibleHandler.QueryInterface(Ci.nsILocalHandlerApp);
|
||||
webPossibleHandler.QueryInterface(Ci.nsIWebHandlerApp);
|
||||
|
||||
// Make sure the two handlers are the ones we stored.
|
||||
checkLocalHandlersAreEquivalent(localPossibleHandler, localHandler);
|
||||
checkWebHandlersAreEquivalent(webPossibleHandler, webHandler);
|
||||
|
||||
// Remove a handler, store the object, re-retrieve it, and make sure
|
||||
// it only has one handler.
|
||||
possibleHandlersInfo.possibleApplicationHandlers.removeElementAt(localIndex);
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 1);
|
||||
|
||||
// Make sure the handler is the one we didn't remove.
|
||||
checkWebHandlersAreEquivalent(possibleHandlersInfo.
|
||||
possibleApplicationHandlers.
|
||||
queryElementAt(0, Ci.nsIHandlerApp).
|
||||
QueryInterface(Ci.nsIWebHandlerApp),
|
||||
webHandler);
|
||||
|
||||
// FIXME: test round trip integrity for a protocol.
|
||||
// FIXME: test round trip integrity for a handler info with a web handler.
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче