Commit 31c0322e authored by Peter Van der Beken's avatar Peter Van der Beken
Browse files

Fix for bug 741267 (UserScript's XMLHttpRequest is undefined in 20120401 nightly).

Pass two objects when creating a DOM interface object, the global used to cache
the DOM interface objects and a receiver object on which the named property is
that points to the DOM interface object.

--HG--
extra : rebase_source : b462393e7376fdb68f3b279ccd08b3ab25ac154a
parent 7753b719
Loading
Loading
Loading
Loading
+36 −23
Original line number Diff line number Diff line
@@ -801,7 +801,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
    properties should be a PropertyArrays instance.
    """
    def __init__(self, descriptor, properties):
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
                Argument('JSObject*', 'aReceiver')]
        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args)
        self.properties = properties
    def definition_body(self):
@@ -810,7 +811,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
            getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
        else:
            parentProtoName = self.descriptor.prototypeChain[-2]
            getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
            getParentProto = "%s::GetProtoObject(aCx, aGlobal, aReceiver)" % (parentProtoName)

        needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
        needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
@@ -849,7 +850,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
                          "  return NULL;\n"
                          "}") % getParentProto

        call = CGGeneric(("return bindings::CreateInterfaceObjects(aCx, aGlobal, parentProto,\n"
        call = CGGeneric(("return bindings::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
                          "                                        %s, %s,\n"
                          "                                        %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
                          "                                        %s);") % (
@@ -880,12 +881,20 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
    constructor object).
    """
    def __init__(self, descriptor, name, idPrefix=""):
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
                Argument('JSObject*', 'aReceiver')]
        CGAbstractMethod.__init__(self, descriptor, name,
                                  'JSObject*', args, inline=True)
        self.id = idPrefix + "id::" + self.descriptor.name
    def definition_body(self):
        return """

  /* aGlobal and aReceiver are usually the same, but they can be different
     too. For example a sandbox often has an xray wrapper for a window as the
     prototype of the sandbox's global. In that case aReceiver is the xray
     wrapper and aGlobal is the sandbox's global.
   */

  /* Make sure our global is sane.  Hopefully we can remove this sometime */
  if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
    return NULL;
@@ -894,7 +903,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
  JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal);
  JSObject* cachedObject = protoOrIfaceArray[%s];
  if (!cachedObject) {
    protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal);
    protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
  }

  /* cachedObject might _still_ be null, but that's OK */
@@ -905,7 +914,6 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
    A method for getting the interface prototype object.
    """
    def __init__(self, descriptor):
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
        CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject")
    def definition_body(self):
        return """
@@ -917,14 +925,13 @@ class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
    A method for getting the interface constructor object.
    """
    def __init__(self, descriptor):
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
        CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject", "constructors::")
    def definition_body(self):
        return """
  /* Get the interface object for this class.  This will create the object as
     needed. */""" + CGGetPerInterfaceObject.definition_body(self)

def CheckPref(descriptor, scopeName, varName, retval, wrapperCache = None):
def CheckPref(descriptor, globalName, varName, retval, wrapperCache = None):
    """
    Check whether bindings should be enabled for this descriptor.  If not, set
    varName to false and return retval.
@@ -936,11 +943,19 @@ def CheckPref(descriptor, scopeName, varName, retval, wrapperCache = None):
    else:
        wrapperCache = ""
    return """
  if (!%s->ExperimentalBindingsEnabled()) {
  {
    XPCWrappedNativeScope* scope =
      XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s);
    if (!scope) {
      return %s;
    }

    if (!scope->ExperimentalBindingsEnabled()) {
%s      %s = false;
      return %s;
    }
""" % (scopeName, wrapperCache, varName, retval)
  }
""" % (globalName, retval, wrapperCache, varName, retval)

class CGDefineDOMInterfaceMethod(CGAbstractMethod):
    """
@@ -948,7 +963,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
    a given interface.
    """
    def __init__(self, descriptor):
        args = [Argument('JSContext*', 'aCx'), Argument('XPCWrappedNativeScope*', 'aScope'),
        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aReceiver'),
                Argument('bool*', 'aEnabled')]
        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)

@@ -970,9 +985,11 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
        else:
            getter = "GetConstructorObject"

        return CheckPref(self.descriptor, "aScope", "*aEnabled", "false") + """
        return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
                CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
                """
  *aEnabled = true;
  return !!%s(aCx, aScope->GetGlobalJSObject());""" % (getter)
  return !!%s(aCx, global, aReceiver);""" % (getter))

class CGNativeToSupportsMethod(CGAbstractStaticMethod):
    """
@@ -1022,13 +1039,9 @@ class CGWrapMethod(CGAbstractMethod):
    }
  }

  XPCWrappedNativeScope* scope =
    XPCWrappedNativeScope::FindInJSObjectScope(aCx, parent);
  if (!scope) {
    return NULL;
  }
  JSObject* global = JS_GetGlobalForObject(aCx, parent);
%s
  JSObject* proto = GetProtoObject(aCx, scope->GetGlobalJSObject());
  JSObject* proto = GetProtoObject(aCx, global, global);
  if (!proto) {
    return NULL;
  }
@@ -1043,7 +1056,7 @@ class CGWrapMethod(CGAbstractMethod):

  aObject->SetWrapper(obj);

  return obj;""" % (CheckPref(self.descriptor, "scope", "*aTriedToWrap", "NULL", "aObject"))
  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aObject"))

builtinNames = {
    IDLType.Tags.bool: 'bool',
+10 −10
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
}

static JSObject*
CreateInterfaceObject(JSContext* cx, JSObject* global,
CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
                      JSClass* constructorClass, JSObject* proto,
                      JSFunctionSpec* staticMethods, ConstantSpec* constants,
                      const char* name)
@@ -54,7 +54,7 @@ CreateInterfaceObject(JSContext* cx, JSObject* global,
  }

  // This is Enumerable: False per spec.
  if (!JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor), NULL,
  if (!JS_DefineProperty(cx, receiver, name, OBJECT_TO_JSVAL(constructor), NULL,
                         NULL, 0)) {
    return NULL;
  }
@@ -91,11 +91,11 @@ CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
}

JSObject*
CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,
                       JSClass *protoClass, JSClass *constructorClass,
                       JSFunctionSpec *methods, JSPropertySpec *properties,
                       ConstantSpec *constants, JSFunctionSpec *staticMethods,
                       const char* name)
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                       JSObject* protoProto, JSClass* protoClass,
                       JSClass* constructorClass, JSFunctionSpec* methods,
                       JSPropertySpec* properties, ConstantSpec* constants,
                       JSFunctionSpec* staticMethods, const char* name)
{
  MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
  MOZ_ASSERT(!(methods || properties) || protoClass,
@@ -107,7 +107,7 @@ CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,

  JSObject* proto;
  if (protoClass) {
    proto = CreateInterfacePrototypeObject(cx, global, parentProto, protoClass,
    proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
                                           methods, properties, constants);
    if (!proto) {
      return NULL;
@@ -119,8 +119,8 @@ CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,

  JSObject* interface;
  if (constructorClass) {
    interface = CreateInterfaceObject(cx, global, constructorClass, proto,
                                      staticMethods, constants, name);
    interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
                                      proto, staticMethods, constants, name);
    if (!interface) {
      return NULL;
    }
+10 −6
Original line number Diff line number Diff line
@@ -219,7 +219,11 @@ struct ConstantSpec
 * Create a DOM interface object (if constructorClass is non-null) and/or a
 * DOM interface prototype object (if protoClass is non-null).
 *
 * parentProto is the prototype to use for the interface prototype object.
 * global is used as the parent of the interface object and the interface
 *        prototype object
 * receiver is the object on which we need to define the interface object as a
 *          property
 * protoProto is the prototype to use for the interface prototype object.
 * protoClass is the JSClass to use for the interface prototype object.
 *            This is null if we should not create an interface prototype
 *            object.
@@ -242,11 +246,11 @@ struct ConstantSpec
 * returns the interface object.
 */
JSObject*
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* parentProto,
                       JSClass* protoClass, JSClass* constructorClass,
                       JSFunctionSpec* methods, JSPropertySpec* properties,
                       ConstantSpec* constants, JSFunctionSpec* staticMethods,
                       const char* name);
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                       JSObject* protoProto, JSClass* protoClass,
                       JSClass* constructorClass, JSFunctionSpec* methods,
                       JSPropertySpec* properties, ConstantSpec* constants,
                       JSFunctionSpec* staticMethods, const char* name);

template <class T>
inline bool
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ _TEST_FILES = \
		test_callback_wrapping.xul \
		window_callback_wrapping.xul \
		test_sandbox_postMessage.html \
		test_sandbox_bindings.xul \
		$(NULL)

ifeq (WINNT,$(OS_ARCH))
+52 −0
Original line number Diff line number Diff line
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=741267
-->
<window title="Mozilla Bug 741267"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>

  <iframe id="t"></iframe>

  <!-- test results are displayed in the html:body -->
  <body xmlns="http://www.w3.org/1999/xhtml">
  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741267"
     target="_blank">Mozilla Bug 741267</a>
  </body>

  <!-- test code goes here -->
  <script type="application/javascript">
  <![CDATA[

  /** Test for Bug 741267 **/
    function doTest() {
      var win = $("t").contentWindow;
      var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
      try {
        var nl = Components.utils.evalInSandbox("NodeList", sandbox);
        is(nl, "[object NodeList]", "'NodeList' in a sandbox should return the NodeList interface prototype object");
      } catch (e) {
        ok(false, "'NodeList' shouldn't throw in a sandbox");
      }
      try {
        var et = Components.utils.evalInSandbox("EventTarget", sandbox);
        ok(et, "'EventTarget' in a sandbox should return the EventTarget interface prototype object");
      } catch (e) {
        ok(false, "'EventTarget' shouldn't throw in a sandbox");
      }
      try {
        var xhr = Components.utils.evalInSandbox("XMLHttpRequest()", sandbox);
        is(xhr, "[object XMLHttpRequest]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
      } catch (e) {
        ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox");
      }
      SimpleTest.finish();
    }

    SimpleTest.waitForExplicitFinish();
    addLoadEvent(doTest);
  ]]>
  </script>
</window>
Loading