Bug 1127501. Treat external interfaces as only being exposed in Window in Web IDL bindings. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 09 Feb 2015 11:42:27 -0500
changeset 241795 994141100597ebb910bc2c96c88d9891c7e97d29
parent 241794 be4a51e14f3fbde5181b492d59c68799d3079949
child 241798 6692016d516078192e4105303bf75812e8180a85
push id619
push usercliu@mozilla.com
push dateMon, 09 Feb 2015 21:57:21 +0000
reviewerspeterv
bugs1127501
milestone38.0a1
Bug 1127501. Treat external interfaces as only being exposed in Window in Web IDL bindings. r=peterv
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/parser/WebIDL.py
dom/webidl/XMLHttpRequest.webidl
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6829,17 +6829,16 @@ class CGMethodCall(CGThing):
                                       nativeMethodName, static, descriptor,
                                       method,
                                       argConversionStartsAt=argConversionStartsAt,
                                       isConstructor=isConstructor)
 
         def filteredSignatures(signatures, descriptor):
             def typeExposedInWorkers(type):
                 return (not type.isGeckoInterface() or
-                        type.inner.isExternal() or
                         type.inner.isExposedInAnyWorker())
             if descriptor.workers:
                 # Filter out the signatures that should not be exposed in a
                 # worker.  The IDL parser enforces the return value being
                 # exposed correctly, but we have to check the argument types.
                 #
                 # If this code changes, adjust the self._deps
                 # computation in CGDDescriptor.__init__ as needed.
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -201,24 +201,21 @@ class Configuration:
                 getter = lambda x: x.interface.isCallback()
             elif key == 'isExternal':
                 getter = lambda x: x.interface.isExternal()
             elif key == 'isJSImplemented':
                 getter = lambda x: x.interface.isJSImplemented()
             elif key == 'isNavigatorProperty':
                 getter = lambda x: x.interface.getNavigatorProperty() != None
             elif key == 'isExposedInAnyWorker':
-                getter = lambda x: (not x.interface.isExternal() and
-                                    x.interface.isExposedInAnyWorker())
+                getter = lambda x: x.interface.isExposedInAnyWorker()
             elif key == 'isExposedInSystemGlobals':
-                getter = lambda x: (not x.interface.isExternal() and
-                                    x.interface.isExposedInSystemGlobals())
+                getter = lambda x: x.interface.isExposedInSystemGlobals()
             elif key == 'isExposedInWindow':
-                getter = lambda x: (not x.interface.isExternal() and
-                                    x.interface.isExposedInWindow())
+                getter = lambda x: x.interface.isExposedInWindow()
             else:
                 # Have to watch out: just closing over "key" is not enough,
                 # since we're about to mutate its value
                 getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
             tofilter.append((getter, val))
         for f in tofilter:
             curr = filter(lambda x: f[0](x) == f[1], curr)
         return curr
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -443,25 +443,75 @@ class IDLIdentifierPlaceholder(IDLObject
             scope._lookupIdentifier(self.identifier)
         except:
             raise WebIDLError("Unresolved type '%s'." % self.identifier,
                               [self.location])
 
         obj = self.identifier.resolve(scope, None)
         return scope.lookupIdentifier(obj)
 
-class IDLExternalInterface(IDLObjectWithIdentifier):
+class IDLExposureMixins():
+    def __init__(self, location):
+        # _exposureGlobalNames are the global names listed in our [Exposed]
+        # extended attribute.  exposureSet is the exposure set as defined in the
+        # Web IDL spec: it contains interface names.
+        self._exposureGlobalNames = set()
+        self.exposureSet = set()
+        self._location = location
+
+    def finish(self, scope):
+        # Verify that our [Exposed] value, if any, makes sense.
+        for globalName in self._exposureGlobalNames:
+            if globalName not in scope.globalNames:
+                raise WebIDLError("Unknown [Exposed] value %s" % globalName,
+                                  [self._location])
+
+        if len(self._exposureGlobalNames) == 0:
+            self._exposureGlobalNames.add(scope.primaryGlobalName)
+
+        globalNameSetToExposureSet(scope, self._exposureGlobalNames,
+                                   self.exposureSet)
+
+    def isExposedInWindow(self):
+        return 'Window' in self.exposureSet
+
+    def isExposedInAnyWorker(self):
+        return len(self.getWorkerExposureSet()) > 0
+
+    def isExposedInSystemGlobals(self):
+        return 'BackstagePass' in self.exposureSet
+
+    def isExposedInSomeButNotAllWorkers(self):
+        """
+        Returns true if the Exposed extended attribute for this interface
+        exposes it in some worker globals but not others.  The return value does
+        not depend on whether the interface is exposed in Window or System
+        globals.
+        """
+        if not self.isExposedInAnyWorker():
+            return False
+        workerScopes = self.parentScope.globalNameMapping["Worker"]
+        return len(workerScopes.difference(self.exposureSet)) > 0
+
+    def getWorkerExposureSet(self):
+        # Subclasses that might be exposed in workers should override as needed
+        return set()
+
+
+class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
     def __init__(self, location, parentScope, identifier):
         assert isinstance(identifier, IDLUnresolvedIdentifier)
         assert isinstance(parentScope, IDLScope)
         self.parent = None
         IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
+        IDLExposureMixins.__init__(self, location)
         IDLObjectWithIdentifier.resolve(self, parentScope)
 
     def finish(self, scope):
+        IDLExposureMixins.finish(self, scope)
         pass
 
     def validate(self):
         pass
 
     def isExternal(self):
         return True
 
@@ -542,17 +592,17 @@ def convertExposedAttrToGlobalNameSet(ex
     else:
         assert exposedAttr.hasArgs()
         targetSet.update(exposedAttr.args())
 
 def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
     for name in nameSet:
         exposureSet.update(globalScope.globalNameMapping[name])
 
-class IDLInterface(IDLObjectWithScope):
+class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
     def __init__(self, location, parentScope, name, parent, members,
                  isKnownNonPartial):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert isKnownNonPartial or not parent
         assert isKnownNonPartial or len(members) == 0
 
         self.parent = None
@@ -577,23 +627,19 @@ class IDLInterface(IDLObjectWithScope):
         self.interfacesImplementingSelf = set()
         self._hasChildInterfaces = False
         self._isOnGlobalProtoChain = False
         # Tracking of the number of reserved slots we need for our
         # members and those of ancestor interfaces.
         self.totalMembersInSlots = 0
         # Tracking of the number of own own members we have in slots
         self._ownMembersInSlots = 0
-        # _exposureGlobalNames are the global names listed in our [Exposed]
-        # extended attribute.  exposureSet is the exposure set as defined in the
-        # Web IDL spec: it contains interface names.
-        self._exposureGlobalNames = set()
-        self.exposureSet = set()
 
         IDLObjectWithScope.__init__(self, location, parentScope, name)
+        IDLExposureMixins.__init__(self, location)
 
         if isKnownNonPartial:
             self.setNonPartial(location, parent, members)
 
     def __str__(self):
         return "Interface '%s'" % self.identifier.name
 
     def ctor(self):
@@ -623,27 +669,17 @@ class IDLInterface(IDLObjectWithScope):
 
         self._finished = True
 
         if not self._isKnownNonPartial:
             raise WebIDLError("Interface %s does not have a non-partial "
                               "declaration" % self.identifier.name,
                               [self.location])
 
-        # Verify that our [Exposed] value, if any, makes sense.
-        for globalName in self._exposureGlobalNames:
-            if globalName not in scope.globalNames:
-                raise WebIDLError("Unknown [Exposed] value %s" % globalName,
-                                  [self.location])
-
-        if len(self._exposureGlobalNames) == 0:
-            self._exposureGlobalNames.add(scope.primaryGlobalName)
-
-        globalNameSetToExposureSet(scope, self._exposureGlobalNames,
-                                   self.exposureSet)
+        IDLExposureMixins.finish(self, scope)
 
         # Now go ahead and merge in our partial interfaces.
         for partial in self._partialInterfaces:
             partial.finish(scope)
             self.addExtendedAttributes(partial.propagatedExtendedAttrs)
             self.members.extend(partial.members)
 
         # Now that we've merged in our partial interfaces, set the
@@ -1058,37 +1094,16 @@ class IDLInterface(IDLObjectWithScope):
             len(self.getConsequentialInterfaces()) == 0 and
             # No attributes of any kinds
             not any(m.isAttr() for m in self.members) and
             # There is at least one regular operation, and all regular
             # operations have the same identifier
             len(set(m.identifier.name for m in self.members if
                     m.isMethod() and not m.isStatic())) == 1)
 
-    def isExposedInWindow(self):
-        return 'Window' in self.exposureSet
-
-    def isExposedInAnyWorker(self):
-        return len(self.getWorkerExposureSet()) > 0
-
-    def isExposedInSystemGlobals(self):
-        return 'BackstagePass' in self.exposureSet
-
-    def isExposedInSomeButNotAllWorkers(self):
-        """
-        Returns true if the Exposed extended attribute for this interface
-        exposes it in some worker globals but not others.  The return value does
-        not depend on whether the interface is exposed in Window or System
-        globals.
-        """
-        if not self.isExposedInAnyWorker():
-            return False
-        workerScopes = self.parentScope.globalNameMapping["Worker"]
-        return len(workerScopes.difference(self.exposureSet)) > 0
-
     def getWorkerExposureSet(self):
         workerScopes = self.parentScope.globalNameMapping["Worker"]
         return workerScopes.intersection(self.exposureSet)
 
     def inheritanceDepth(self):
         depth = 0
         parent = self.parent
         while parent:
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -137,14 +137,14 @@ interface XMLHttpRequest : XMLHttpReques
   [ChromeOnly, SetterThrows=Workers]
   attribute boolean mozBackgroundRequest;
 
   [ChromeOnly, Exposed=Window]
   readonly attribute MozChannel? channel;
 
   [Throws]
   void sendAsBinary(DOMString body);
-  [Throws, ChromeOnly]
+  [Throws, ChromeOnly, Exposed=Window]
   any getInterface(IID iid);
 
   readonly attribute boolean mozAnon;
   readonly attribute boolean mozSystem;
 };