Bug 687220 - 'XHR POST in worker with null body and upload load event listener leads to Assertion failure'. r=mrbkap, a=legneato.
authorBen Turner <bent.mozilla@gmail.com>
Thu, 03 Nov 2011 19:51:33 -0700
changeset 78342 f95e13ba4a584468d44630ed04a3061bdeb06c78
parent 78341 9addd25bb7306ab73c3c3f8af02a1133102023f9
child 78343 66f33a0dc3939f741fe13126ad34e996455ca9ed
push id501
push userbturner@mozilla.com
push dateMon, 07 Nov 2011 23:21:33 +0000
treeherdermozilla-aurora@66f33a0dc393 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, legneato
bugs687220
milestone9.0a2
Bug 687220 - 'XHR POST in worker with null body and upload load event listener leads to Assertion failure'. r=mrbkap, a=legneato.
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequest.h
dom/workers/XMLHttpRequestPrivate.cpp
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -76,44 +76,57 @@ class XMLHttpRequestUpload : public even
     STRING_onprogress,
     STRING_onloadend,
 
     STRING_COUNT
   };
 
   static const char* const sEventStrings[STRING_COUNT];
 
+  enum SLOT {
+    SLOT_xhrParent = 0,
+
+    SLOT_COUNT
+  };
+
 public:
   static JSClass*
   Class()
   {
     return &sClass;
   }
 
   static JSObject*
   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
   {
     return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
                         sProperties, NULL, NULL, NULL);
   }
 
   static JSObject*
-  Create(JSContext* aCx)
+  Create(JSContext* aCx, JSObject* aParentObj)
   {
+    JS_ASSERT(aParentObj);
+
     JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
     if (obj) {
       XMLHttpRequestUpload* priv = new XMLHttpRequestUpload();
-      if (!SetJSPrivateSafeish(aCx, obj, priv)) {
+      if (!JS_SetReservedSlot(aCx, obj, SLOT_xhrParent,
+                              OBJECT_TO_JSVAL(aParentObj)) ||
+          !SetJSPrivateSafeish(aCx, obj, priv)) {
         delete priv;
         return NULL;
       }
     }
     return obj;
   }
 
+  static bool
+  UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState);
+
 private:
   XMLHttpRequestUpload()
   {
     MOZ_COUNT_CTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
   }
 
   ~XMLHttpRequestUpload()
   {
@@ -212,17 +225,17 @@ private:
     }
 
     return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
   }
 };
 
 JSClass XMLHttpRequestUpload::sClass = {
   "XMLHttpRequestUpload",
-  JSCLASS_HAS_PRIVATE,
+  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
   NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
 };
 
 JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
   { sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
     GetEventListener, SetEventListener },
@@ -482,17 +495,17 @@ private:
     }
 
     jsval uploadVal;
     if (!JS_GetReservedSlot(aCx, aObj, slot, &uploadVal)) {
       return false;
     }
 
     if (JSVAL_IS_NULL(uploadVal)) {
-      JSObject* uploadObj = XMLHttpRequestUpload::Create(aCx);
+      JSObject* uploadObj = XMLHttpRequestUpload::Create(aCx, aObj);
       if (!uploadObj) {
         return false;
       }
 
       uploadVal = OBJECT_TO_JSVAL(uploadObj);
 
       if (!JS_SetReservedSlot(aCx, aObj, slot, uploadVal)) {
         return false;
@@ -823,30 +836,53 @@ const char* const XMLHttpRequest::sEvent
   "onabort",
   "onerror",
   "onload",
   "onloadstart",
   "onprogress",
   "onloadend"
 };
 
+// static
+bool
+XMLHttpRequestUpload::UpdateState(JSContext* aCx, JSObject* aObj,
+                                  const xhr::StateData& aNewState)
+{
+  JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
+
+  jsval parentVal;
+  if (!JS_GetReservedSlot(aCx, aObj, SLOT_xhrParent, &parentVal)) {
+    return false;
+  }
+
+  if (!JSVAL_IS_PRIMITIVE(parentVal)) {
+    return XMLHttpRequest::UpdateState(aCx, JSVAL_TO_OBJECT(parentVal),
+                                       aNewState);
+  }
+
+  return true;
+}
+
 } // anonymous namespace
 
 BEGIN_WORKERS_NAMESPACE
 
 namespace xhr {
 
 bool
 InitClasses(JSContext* aCx, JSObject* aGlobal, JSObject* aProto)
 {
   return XMLHttpRequest::InitClass(aCx, aGlobal, aProto) &&
          XMLHttpRequestUpload::InitClass(aCx, aGlobal, aProto);
 }
 
 bool
-UpdateXHRState(JSContext* aCx, JSObject* aObj, const StateData& aNewState)
+UpdateXHRState(JSContext* aCx, JSObject* aObj, bool aIsUpload,
+               const StateData& aNewState)
 {
-  return XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
+  return aIsUpload ?
+         XMLHttpRequestUpload::UpdateState(aCx, aObj, aNewState) :
+         XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
 }
 
 } // namespace xhr
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -58,15 +58,16 @@ struct StateData
   jsval mReadyState;
   bool mResponseTextException;
   bool mStatusException;
   bool mStatusTextException;
   bool mReadyStateException;
 };
 
 bool
-UpdateXHRState(JSContext* aCx, JSObject* aObj, const StateData& aNewState);
+UpdateXHRState(JSContext* aCx, JSObject* aObj, bool aIsUpload,
+               const StateData& aNewState);
 
 } // namespace xhr
 
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_xmlhttprequest_h__ */
--- a/dom/workers/XMLHttpRequestPrivate.cpp
+++ b/dom/workers/XMLHttpRequestPrivate.cpp
@@ -603,17 +603,17 @@ public:
       state.mStatusText = STRING_TO_JSVAL(statusText);
     }
 
     state.mReadyStateException = mReadyStateException;
     state.mReadyState = mReadyStateException ?
                         JSVAL_VOID :
                         INT_TO_JSVAL(mReadyState);
 
-    if (!xhr::UpdateXHRState(aCx, target, state)) {
+    if (!xhr::UpdateXHRState(aCx, target, mUploadEvent, state)) {
       return false;
     }
 
     JSString* type = JS_NewUCStringCopyN(aCx, mType.get(), mType.Length());
     if (!type) {
       return false;
     }
 
@@ -1683,30 +1683,30 @@ XMLHttpRequestPrivate::MaybeDispatchPrem
     JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, INT_TO_JSVAL(4),
     false, false, false, false
   };
 
   if (mProxy->mSeenUploadLoadStart) {
     JSObject* target = mProxy->mXMLHttpRequestPrivate->GetUploadJSObject();
     NS_ASSERTION(target, "Must have a target!");
 
-    if (!xhr::UpdateXHRState(aCx, target, state) ||
+    if (!xhr::UpdateXHRState(aCx, target, true, state) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_abort, true) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_loadend, true)) {
       return false;
     }
 
     mProxy->mSeenUploadLoadStart = false;
   }
 
   if (mProxy->mSeenLoadStart) {
     JSObject* target = mProxy->mXMLHttpRequestPrivate->GetJSObject();
     NS_ASSERTION(target, "Must have a target!");
 
-    if (!xhr::UpdateXHRState(aCx, target, state) ||
+    if (!xhr::UpdateXHRState(aCx, target, false, state) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_readystatechange,
                                      false)) {
       return false;
     }
 
     if (aFromOpen) {
       if (!DispatchPrematureAbortEvent(aCx, target, STRING_abort, false) ||
           !DispatchPrematureAbortEvent(aCx, target, STRING_loadend, false)) {