Bug 765704 - Don't throw when setting XHR.responseType to an invalid value; r=bz
authorMs2ger <ms2ger@gmail.com>
Thu, 21 Jun 2012 09:11:07 +0200
changeset 101933 9ce5e415d5da386955d6ad4552c8586f8aae6e54
parent 101932 df2e5f99504a2e465d4f05f561c6f7f467fafc06
child 101934 caf8e1be4566e795990d506221642561661045e9
push id1316
push userakeybl@mozilla.com
push dateMon, 27 Aug 2012 22:37:00 +0000
treeherdermozilla-beta@db4b09302ee2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs765704
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 765704 - Don't throw when setting XHR.responseType to an invalid value; r=bz
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/test/Makefile.in
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/test_enums.html
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -445,19 +445,18 @@ FindEnumStringIndex(JSContext* cx, JS::V
     }
 
     if (equal) {
       *ok = true;
       return i;
     }
   }
 
-  // XXX we don't know whether we're on the main thread, so play it safe
-  *ok = Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
-  return 0;
+  *ok = true;
+  return -1;
 }
 
 inline nsWrapperCache*
 GetWrapperCache(nsWrapperCache* cache)
 {
   return cache;
 }
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1337,17 +1337,18 @@ nsCOMPtr<${nativeType}> tmp = do_QueryOb
 if (!tmp) {
   ${codeOnFailure}
 }
 ${target} = tmp.forget();""").substitute(self.substitution)
 
 def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
                                     isDefinitelyObject=False,
                                     isMember=False,
-                                    isOptional=False):
+                                    isOptional=False,
+                                    invalidEnumValueFatal=True):
     """
     Get a template for converting a JS value to a native object based on the
     given type and descriptor.  If failureCode is given, then we're actually
     testing whether we can convert the argument to the desired type.  That
     means that failures to convert due to the JS value being the wrong type of
     value need to use failureCode instead of throwing exceptions.  Failures to
     convert that are due to JS exceptions (from toString or valueOf methods) or
     out of memory conditions need to throw exceptions no matter what
@@ -1712,22 +1713,27 @@ for (uint32_t i = 0; i < length; ++i) {
     if type.isEnum():
         if type.nullable():
             raise TypeError("We don't support nullable enumerated arguments "
                             "yet")
         enum = type.inner.identifier.name
         return (
             "{\n"
             "  bool ok;\n"
-            "  ${declName} = static_cast<%(enumtype)s>(FindEnumStringIndex(cx, ${val}, %(values)s, &ok));\n"
+            "  int index = FindEnumStringIndex(cx, ${val}, %(values)s, &ok);\n"
             "  if (!ok) {\n"
             "    return false;\n"
             "  }\n"
+            "  if (index < 0) {\n"
+            "    return %(failureCode)s;\n"
+            "  }\n"
+            "  ${declName} = static_cast<%(enumtype)s>(index);\n"
             "}" % { "enumtype" : enum,
-                      "values" : enum + "Values::strings" },
+                      "values" : enum + "Values::strings",
+                 "failureCode" : "Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS)" if invalidEnumValueFatal else "true" },
             CGGeneric(enum), None, isOptional)
 
     if type.isCallback():
         if isMember:
             raise TypeError("Can't handle member callbacks; need to sort out "
                             "rooting issues")
         # XXXbz we're going to assume that callback types are always
         # nullable and always have [TreatNonCallableAsNull] for now.
@@ -1915,17 +1921,18 @@ def convertIDLDefaultValueToJSVal(value)
     return convertConstIDLValueToJSVal(value)
 
 class CGArgumentConverter(CGThing):
     """
     A class that takes an IDL argument object, its index in the
     argument list, and the argv and argc strings and generates code to
     unwrap the argument to the right native type.
     """
-    def __init__(self, argument, index, argv, argc, descriptorProvider):
+    def __init__(self, argument, index, argv, argc, descriptorProvider,
+                 invalidEnumValueFatal=True):
         CGThing.__init__(self)
         self.argument = argument
         # XXXbz should optional jsval args get JSVAL_VOID? What about
         # others?
         replacer = {
             "index" : index,
             "argc" : argc,
             "argv" : argv
@@ -1948,22 +1955,24 @@ class CGArgumentConverter(CGThing):
                 ).substitute(replacer)
             self.replacementVariables["valPtr"] = (
                 "&" + self.replacementVariables["val"])
         self.descriptorProvider = descriptorProvider
         if self.argument.optional and not self.argument.defaultValue:
             self.argcAndIndex = replacer
         else:
             self.argcAndIndex = None
+        self.invalidEnumValueFatal = invalidEnumValueFatal
 
     def define(self):
         return instantiateJSToNativeConversionTemplate(
             getJSToNativeConversionTemplate(self.argument.type,
                                             self.descriptorProvider,
-                                            isOptional=(self.argcAndIndex is not None)),
+                                            isOptional=(self.argcAndIndex is not None),
+                                            invalidEnumValueFatal=self.invalidEnumValueFatal),
             self.replacementVariables,
             self.argcAndIndex).define()
 
 def getWrapTemplateForType(type, descriptorProvider, result, successCode,
                            isCreator):
     """
     Reflect a C++ value stored in "result", of IDL type "type" into JS.  The
     "successCode" is the code to run once we have successfully done the
@@ -2354,17 +2363,18 @@ class CGPerSignatureCall(CGThing):
         self.arguments = arguments
         self.argCount = len(arguments)
         if self.argCount > argConversionStartsAt:
             # Insert our argv in there
             cgThings = [CGGeneric(self.getArgvDecl())]
         else:
             cgThings = []
         cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
-                                             self.getArgc(), self.descriptor) for
+                                             self.getArgc(), self.descriptor,
+                                             invalidEnumValueFatal=not setter) for
                          i in range(argConversionStartsAt, self.argCount)])
 
         cgThings.append(CGCallGenerator(
                     self.getErrorReport() if self.isFallible() else None,
                     self.arguments, self.argsPre, returnType,
                     self.extendedAttributes, descriptor, nativeMethodName,
                     static))
         self.cgRoot = CGList(cgThings, "\n")
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -52,16 +52,17 @@ bindinggen_dependencies := \
 
 $(CPPSRCS): ../%Binding.cpp: $(bindinggen_dependencies) \
                              ../%.webidl \
                              $(NULL)
 	$(MAKE) -C .. $*Binding.h
 	$(MAKE) -C .. $*Binding.cpp
 
 _TEST_FILES = \
+  test_enums.html \
   test_interfaceToString.html \
   test_lookupGetter.html \
   test_InstanceOf.html \
   test_traceProtos.html \
   $(NULL)
 
 
 libs:: $(_TEST_FILES)
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -274,16 +274,19 @@ public:
   void PassOptionalString(const Optional<nsAString>&, ErrorResult&);
   void PassOptionalNullableString(const Optional<nsAString>&, ErrorResult&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&, ErrorResult&);
 
   // Enumarated types
   void PassEnum(TestEnum, ErrorResult&);
   void PassOptionalEnum(const Optional<TestEnum>&, ErrorResult&);
   TestEnum ReceiveEnum(ErrorResult&);
+  TestEnum GetEnumAttribute(ErrorResult&);
+  TestEnum GetReadonlyEnumAttribute(ErrorResult&);
+  void SetEnumAttribute(TestEnum, ErrorResult&);
 
   // Callback types
   void PassCallback(JSContext*, JSObject*, ErrorResult&);
   void PassNullableCallback(JSContext*, JSObject*, ErrorResult&);
   void PassOptionalCallback(JSContext*, const Optional<JSObject*>&,
                             ErrorResult&);
   void PassOptionalNullableCallback(JSContext*, const Optional<JSObject*>&,
                                     ErrorResult&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -207,16 +207,18 @@ interface TestInterface {
   // Enumerated types
   void passEnum(TestEnum arg);
   // No support for nullable enums yet
   // void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   // void passOptionalNullableEnum(optional TestEnum? arg);
   // void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
   TestEnum receiveEnum();
+  attribute TestEnum enumAttribute;
+  readonly attribute TestEnum readonlyEnumAttribute;
 
   // Callback types
   void passCallback(TestCallback arg);
   void passNullableCallback(TestCallback? arg);
   void passOptionalCallback(optional TestCallback arg);
   void passOptionalNullableCallback(optional TestCallback? arg);
   void passOptionalNullableCallbackWithDefaultValue(optional TestCallback? arg = null);
   TestCallback receiveCallback();
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_enums.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Enums</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+test(function() {
+  var xhr = new XMLHttpRequest();
+  xhr.open("get", "foo")
+  assert_equals(xhr.responseType, "");
+  xhr.responseType = "foo";
+  assert_equals(xhr.responseType, "");
+}, "Assigning an invalid value to an enum attribute should not throw.");
+</script>