Backout f142f32a98a3 (Bug 775317) and ef14686c31d0 (Bug 761278). r=bustage
authorJason Duell <jduell.mcbugs@gmail.com>
Sat, 21 Jul 2012 20:05:37 -0700
changeset 103179 ad5866c81a03d90889d2369ad83884e20c0be8c7
parent 103178 f142f32a98a3849089b235818a1ed359d633084c
child 103180 252f295c46645d8a1c315cc1448d00579557cfd3
push idunknown
push userunknown
push dateunknown
reviewersbustage
bugs775317, 761278
milestone17.0a1
backs outf142f32a98a3849089b235818a1ed359d633084c
Backout f142f32a98a3 (Bug 775317) and ef14686c31d0 (Bug 761278). r=bustage
content/base/public/nsDeprecatedOperationList.h
content/base/public/nsIXMLHttpRequest.idl
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
content/base/test/file_CrossSiteXHR_inner.html
content/base/test/file_CrossSiteXHR_inner_data.sjs
content/base/test/test_CrossSiteXHR.html
content/base/test/test_XHR_onuploadprogress.html
content/base/test/test_bug372964.html
content/base/test/test_bug435425.html
dom/locales/en-US/chrome/dom/dom.properties
dom/webidl/XMLHttpRequest.webidl
dom/workers/XMLHttpRequest.h
js/src/jsapi-tests/Makefile.in
js/src/jsapi-tests/testJSEvaluateScript.cpp
--- a/content/base/public/nsDeprecatedOperationList.h
+++ b/content/base/public/nsDeprecatedOperationList.h
@@ -43,8 +43,9 @@ DEPRECATED_OPERATION(Position)
 DEPRECATED_OPERATION(TotalSize)
 DEPRECATED_OPERATION(InputEncoding)
 DEPRECATED_OPERATION(MozBeforePaint)
 DEPRECATED_OPERATION(MozBlobBuilder)
 DEPRECATED_OPERATION(DOMExceptionCode)
 DEPRECATED_OPERATION(NoExposedProps)
 DEPRECATED_OPERATION(MutationEvent)
 DEPRECATED_OPERATION(MozSlice)
+DEPRECATED_OPERATION(Onuploadprogress)
--- a/content/base/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -390,18 +390,32 @@ interface nsIXHRSendable : nsISupports {
   void getSendInfo(out nsIInputStream body,
                    out ACString contentType,
                    out ACString charset);
 };
 
 /**
  * @deprecated
  */
-[deprecated, scriptable, uuid(8ae70a39-edf1-40b4-a992-472d23421c25)]
+[deprecated, scriptable, uuid(423fdd3d-41c9-4149-8fe5-b14a1d3912a0)]
 interface nsIJSXMLHttpRequest : nsISupports {
+  /**
+   * Meant to be a script-only mechanism for setting an upload progress event
+   * listener.
+   * This attribute should not be used from native code!!
+   * This event listener may be called multiple times during the upload..
+   *
+   * After the initial response, all event listeners will be cleared.
+   * // XXXbz what does that mean, exactly?
+   *
+   * This event listener must be set BEFORE calling open().
+   *
+   * Mozilla only.
+   */
+  attribute nsIDOMEventListener onuploadprogress;
 };
 
 %{ C++
 #define NS_XMLHTTPREQUEST_CID                       \
  { /* d164e770-4157-11d4-9a42-000064657374 */       \
   0xd164e770, 0x4157, 0x11d4,                       \
  {0x9a, 0x42, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} }
 #define NS_XMLHTTPREQUEST_CONTRACTID \
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -85,16 +85,17 @@ using namespace mozilla;
 using namespace mozilla::dom;
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define TIMEOUT_STR "timeout"
 #define LOADSTART_STR "loadstart"
 #define PROGRESS_STR "progress"
+#define UPLOADPROGRESS_STR "uploadprogress"
 #define READYSTATE_STR "readystatechange"
 #define LOADEND_STR "loadend"
 
 // CIDs
 
 // State
 #define XML_HTTP_REQUEST_UNSENT           (1 << 0) // 0 UNSENT
 #define XML_HTTP_REQUEST_OPENED           (1 << 1) // 1 OPENED
@@ -613,16 +614,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(
     if (tmp->mListenerManager) {
       tmp->mListenerManager->UnmarkGrayJSListeners();
       NS_UNMARK_LISTENER_WRAPPER(Load)
       NS_UNMARK_LISTENER_WRAPPER(Error)
       NS_UNMARK_LISTENER_WRAPPER(Abort)
       NS_UNMARK_LISTENER_WRAPPER(LoadStart)
       NS_UNMARK_LISTENER_WRAPPER(Progress)
       NS_UNMARK_LISTENER_WRAPPER(Loadend)
+      NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
       NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
     }
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
@@ -638,16 +640,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_E
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
                                                   nsXHREventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCORSPreflightChannel)
 
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload,
@@ -659,16 +662,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   tmp->mResultArrayBuffer = nsnull;
   tmp->mResultJSON = JSVAL_VOID;
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCORSPreflightChannel)
 
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mUpload)
@@ -699,16 +703,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsXHREve
 
 NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 
 void
 nsXMLHttpRequest::DisconnectFromOwner()
 {
   nsXHREventTarget::DisconnectFromOwner();
+  NS_DISCONNECT_EVENT_HANDLER(UploadProgress)
   NS_DISCONNECT_EVENT_HANDLER(Readystatechange)
   Abort();
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechange)
 {
   return
@@ -720,16 +725,33 @@ NS_IMETHODIMP
 nsXMLHttpRequest::SetOnreadystatechange(nsIDOMEventListener * aOnreadystatechange)
 {
   return
     nsXHREventTarget::RemoveAddEventListener(NS_LITERAL_STRING(READYSTATE_STR),
                                              mOnReadystatechangeListener,
                                              aOnreadystatechange);
 }
 
+NS_IMETHODIMP
+nsXMLHttpRequest::GetOnuploadprogress(nsIDOMEventListener * *aOnuploadprogress)
+{
+  return
+    nsXHREventTarget::GetInnerEventListener(mOnUploadProgressListener,
+                                            aOnuploadprogress);
+}
+
+NS_IMETHODIMP
+nsXMLHttpRequest::SetOnuploadprogress(nsIDOMEventListener * aOnuploadprogress)
+{
+  return
+    nsXHREventTarget::RemoveAddEventListener(NS_LITERAL_STRING(UPLOADPROGRESS_STR),
+                                             mOnUploadProgressListener,
+                                             aOnuploadprogress);
+}
+
 /* readonly attribute nsIChannel channel; */
 NS_IMETHODIMP
 nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
 {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_IF_ADDREF(*aChannel = mChannel);
 
   return NS_OK;
@@ -1628,17 +1650,18 @@ nsXMLHttpRequest::DispatchProgressEvent(
                                         bool aLengthComputable,
                                         PRUint64 aLoaded, PRUint64 aTotal,
                                         PRUint64 aPosition, PRUint64 aTotalSize)
 {
   NS_ASSERTION(aTarget, "null target");
   NS_ASSERTION(!aType.IsEmpty(), "missing event type");
 
   if (NS_FAILED(CheckInnerWindowCorrectness()) ||
-      (!AllowUploadProgress() && aTarget == mUpload)) {
+      (!AllowUploadProgress() &&
+       (aTarget == mUpload || aType.EqualsLiteral(UPLOADPROGRESS_STR)))) {
     return;
   }
 
   bool dispatchLoadend = aType.EqualsLiteral(LOAD_STR) ||
                            aType.EqualsLiteral(ERROR_STR) ||
                            aType.EqualsLiteral(TIMEOUT_STR) ||
                            aType.EqualsLiteral(ABORT_STR);
   
@@ -1724,16 +1747,17 @@ nsXMLHttpRequest::CheckChannelForCrossSi
 
   // Check if we need to do a preflight request.
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI);
 
   nsCAutoString method;
   httpChannel->GetRequestMethod(method);
   if (!mCORSUnsafeHeaders.IsEmpty() ||
+      HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
       (mUpload && mUpload->HasListeners()) ||
       (!method.LowerCaseEqualsLiteral("get") &&
        !method.LowerCaseEqualsLiteral("post") &&
        !method.LowerCaseEqualsLiteral("head"))) {
     mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
   }
 
   return NS_OK;
@@ -2791,16 +2815,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   }
 
 
   // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
   // in turn keeps STOP button from becoming active.  If the consumer passed in
   // a progress event handler we must load with nsIRequest::LOAD_NORMAL or
   // necko won't generate any progress notifications.
   if (HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)) ||
+      HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
       (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
     nsLoadFlags loadFlags;
     mChannel->GetLoadFlags(&loadFlags);
     loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
     loadFlags |= nsIRequest::LOAD_NORMAL;
     mChannel->SetLoadFlags(loadFlags);
   }
 
@@ -3149,17 +3174,19 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
       NS_DispatchToCurrentThread(resumeTimeoutRunnable);
     }
   } else {
     // Now that we've successfully opened the channel, we can change state.  Note
     // that this needs to come after the AsyncOpen() and rv check, because this
     // can run script that would try to restart this request, and that could end
     // up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
     ChangeState(XML_HTTP_REQUEST_SENT);
-    if (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR))) {
+    if ((!mUploadComplete &&
+         HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR))) ||
+        (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
       StartProgressEventTimer();
     }
     DispatchProgressEvent(this, NS_LITERAL_STRING(LOADSTART_STR), false,
                           0, 0);
     if (mUpload && !mUploadComplete) {
       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOADSTART_STR), true,
                             0, mUploadTotal);
     }
@@ -3690,16 +3717,20 @@ nsXMLHttpRequest::MaybeDispatchProgressE
   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
   // XML_HTTP_REQUEST_SENT
   if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
     if (aFinalProgress) {
       mUploadTotal = mUploadTransferred;
       mUploadProgressMax = mUploadProgress;
       mUploadLengthComputable = true;
     }
+    DispatchProgressEvent(this, NS_LITERAL_STRING(UPLOADPROGRESS_STR),
+                          true, mUploadLengthComputable, mUploadTransferred,
+                          mUploadTotal, mUploadProgress,
+                          mUploadProgressMax);
     if (mUpload && !mUploadComplete) {
       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
                             true, mUploadLengthComputable, mUploadTransferred,
                             mUploadTotal, mUploadProgress,
                             mUploadProgressMax);
     }
   } else {
     if (aFinalProgress) {
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -212,16 +212,20 @@ public:
   nsresult InitParameters(JSContext* aCx, const jsval* aParams);
   void InitParameters(bool aAnon, bool aSystem);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIXMLHttpRequest
   NS_DECL_NSIXMLHTTPREQUEST
 
+  // nsIJSXMLHttpRequest
+  NS_IMETHOD GetOnuploadprogress(nsIDOMEventListener** aOnuploadprogress);
+  NS_IMETHOD SetOnuploadprogress(nsIDOMEventListener* aOnuploadprogress);
+
   NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
 
   // nsIStreamListener
   NS_DECL_NSISTREAMLISTENER
 
   // nsIRequestObserver
   NS_DECL_NSIREQUESTOBSERVER
 
@@ -244,16 +248,34 @@ public:
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
 
 #ifdef DEBUG
   void StaticAssertions();
 #endif
 
   // event handler
   IMPL_EVENT_HANDLER(readystatechange, Readystatechange)
+  JSObject* GetOnuploadprogress(JSContext* /* unused */)
+  {
+    nsIDocument* doc = GetOwner() ? GetOwner()->GetExtantDoc() : NULL;
+    if (doc) {
+      doc->WarnOnceAbout(nsIDocument::eOnuploadprogress);
+    }
+    return GetListenerAsJSObject(mOnUploadProgressListener);
+  }
+  void SetOnuploadprogress(JSContext* aCx, JSObject* aCallback,
+                           ErrorResult& aRv)
+  {
+    nsIDocument* doc = GetOwner() ? GetOwner()->GetExtantDoc() : NULL;
+    if (doc) {
+      doc->WarnOnceAbout(nsIDocument::eOnuploadprogress);
+    }
+    aRv = SetJSObjectListener(aCx, NS_LITERAL_STRING("uploadprogress"),
+                              mOnUploadProgressListener, aCallback);
+  }
 
   // states
   uint16_t GetReadyState();
 
   // request
   void Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync,
             const mozilla::dom::Optional<nsAString>& aUser,
             const mozilla::dom::Optional<nsAString>& aPassword,
@@ -550,16 +572,17 @@ protected:
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIChannel> mChannel;
   // mReadRequest is different from mChannel for multipart requests
   nsCOMPtr<nsIRequest> mReadRequest;
   nsCOMPtr<nsIDocument> mResponseXML;
   nsCOMPtr<nsIChannel> mCORSPreflightChannel;
   nsTArray<nsCString> mCORSUnsafeHeaders;
 
+  nsRefPtr<nsDOMEventListenerWrapper> mOnUploadProgressListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnReadystatechangeListener;
 
   nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
 
   // used to implement getAllResponseHeaders()
   class nsHeaderVisitor : public nsIHttpHeaderVisitor {
   public:
     NS_DECL_ISUPPORTS
--- a/content/base/test/file_CrossSiteXHR_inner.html
+++ b/content/base/test/file_CrossSiteXHR_inner.html
@@ -32,19 +32,26 @@ window.addEventListener("message", funct
   }
   xhr.addEventListener("readystatechange", function(e) {
     res.events.push("rs" + xhr.readyState);
   }, false);
   xhr.addEventListener("progress", function(e) {
     res.progressEvents++;
   }, false);
   if (req.uploadProgress) {
-    xhr.upload.addEventListener(req.uploadProgress, function(e) {
-      res.progressEvents++;
-    }, false);
+    if (req.uploadProgress == "uploadProgress") {
+      xhr.addEventListener("uploadProgress", function(e) {
+        res.progressEvents++;
+      }, false);
+    }
+    else {
+      xhr.upload.addEventListener(req.uploadProgress, function(e) {
+        res.progressEvents++;
+      }, false);
+    }
   }
   xhr.onerror = function(e) {
     res.didFail = true;
   };
   xhr.onloadend = function (event) {
     res.status = xhr.status;
     try {
       res.statusText = xhr.statusText;
--- a/content/base/test/file_CrossSiteXHR_inner_data.sjs
+++ b/content/base/test/file_CrossSiteXHR_inner_data.sjs
@@ -21,19 +21,26 @@ window.addEventListener("message", funct
   }\n\
   xhr.addEventListener("readystatechange", function(e) {\n\
     res.events.push("rs" + xhr.readyState);\n\
   }, false);\n\
   xhr.addEventListener("progress", function(e) {\n\
     res.progressEvents++;\n\
   }, false);\n\
   if (req.uploadProgress) {\n\
-    xhr.upload.addEventListener(req.uploadProgress, function(e) {\n\
-      res.progressEvents++;\n\
-    }, false);\n\
+    if (req.uploadProgress == "uploadProgress") {\n\
+      xhr.addEventListener("uploadProgress", function(e) {\n\
+        res.progressEvents++;\n\
+      }, false);\n\
+    }\n\
+    else {\n\
+      xhr.upload.addEventListener(req.uploadProgress, function(e) {\n\
+        res.progressEvents++;\n\
+      }, false);\n\
+    }\n\
   }\n\
   xhr.onerror = function(e) {\n\
     res.didFail = true;\n\
   };\n\
   xhr.onloadend = function (event) {\n\
     res.status = xhr.status;\n\
     try {\n\
       res.statusText = xhr.statusText;\n\
--- a/content/base/test/test_CrossSiteXHR.html
+++ b/content/base/test/test_CrossSiteXHR.html
@@ -448,22 +448,35 @@ function runTest() {
                  allowMethods: "put",
                },
 
                // Progress events
                { pass: 1,
                  method: "POST",
                  body: "hi there",
                  headers: { "Content-Type": "text/plain" },
+                 uploadProgress: "uploadprogress",
+               },
+               { pass: 1,
+                 method: "POST",
+                 body: "hi there",
+                 headers: { "Content-Type": "text/plain" },
                  uploadProgress: "progress",
                },
                { pass: 0,
                  method: "POST",
                  body: "hi there",
                  headers: { "Content-Type": "text/plain" },
+                 uploadProgress: "uploadprogress",
+                 noAllowPreflight: 1,
+               },
+               { pass: 0,
+                 method: "POST",
+                 body: "hi there",
+                 headers: { "Content-Type": "text/plain" },
                  uploadProgress: "progress",
                  noAllowPreflight: 1,
                },
 
                // Status messages
                { pass: 1,
                  method: "GET",
                  noAllowPreflight: 1,
--- a/content/base/test/test_XHR_onuploadprogress.html
+++ b/content/base/test/test_XHR_onuploadprogress.html
@@ -22,20 +22,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 var called = false;
 function uploadprogress()
 {
   called = true;
 }
 
 var xhr = new XMLHttpRequest();
-xhr.upload.onprogress = uploadprogress;
+xhr.onuploadprogress = uploadprogress;
 var event = document.createEvent("ProgressEvent");
-event.initProgressEvent("progress", false, false, false, false, 0);
-xhr.upload.dispatchEvent(event);
+event.initProgressEvent("uploadprogress", false, false, false, false, 0);
+xhr.dispatchEvent(event);
 ok(called,
-   "XMLHttpRequest.upload.onprogress sets upload progress event listener");
+   "XMLHttpRequest.onuploadprogress sets uploadprogress event listener");
 
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug372964.html
+++ b/content/base/test/test_bug372964.html
@@ -100,17 +100,17 @@ function test(trusted, type, removeAdded
   ecc = eventHandlerCallCount;
   shouldBeTrusted = trusted;
   x1.dispatchEvent(e1);
   is(eventHandlerCallCount, ecc + handlerCount,
      "Wrong number event handler calls. (3)");
 }
 
 var events =
-  ["load", "error", "progress", "readystatechange", "foo"];
+  ["load", "error", "progress", "uploadprogress", "readystatechange", "foo"];
 
 do {
   var e = events.shift();
   test(false, e, false, false);
   test(false, e, false, true);
   test(false, e, true,  false);
   test(false, e, true,  true);
   test(true,  e, false, false);
--- a/content/base/test/test_bug435425.html
+++ b/content/base/test/test_bug435425.html
@@ -99,16 +99,20 @@ function start(obj) {
   xhr.onloadstart =
     function (evt) {
       logEvent(evt);
     }
   xhr.onprogress =
     function (evt) {
       logEvent(evt);
     }
+  xhr.onuploadprogress =
+    function (evt) {
+      logEvent(evt);
+    }
 
   if ("upload" in xhr) {
     xhr.upload.onloadstart =
       function (evt) {
         logEvent(evt);
       }
     xhr.upload.onprogress =
       function (evt) {
@@ -268,106 +272,115 @@ var tests =
     { method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: true,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false}]},
 
     { method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: UPLOAD, type: "load", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false},
                        {target: XHR, type: "progress", optional: true},
                        {target: XHR, type: "load", optional: false},
                        {target: XHR, type: "loadend", optional: false}]},
     { method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
                        {target: XHR, type: "abort", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "abort", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: true,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
 
     { method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: UPLOAD, type: "load", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false},
                        {target: XHR, type: "progress", optional: true},
                        {target: XHR, type: "load", optional: false},
                        {target: XHR, type: "loadend", optional: false}]},
     { method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
                        {target: XHR, type: "abort", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "abort", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: true,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
 
     { method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: UPLOAD, type: "load", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false},
                        {target: XHR, type: "progress", optional: true},
                        {target: XHR, type: "load", optional: false},
                        {target: XHR, type: "loadend", optional: false}]},
     { method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
                        {target: XHR, type: "abort", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "abort", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
     { method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: true,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: UPLOAD, type: "loadstart", optional: false},
+                       {target: XHR, type: "uploadprogress", optional: true},
                        {target: UPLOAD, type: "progress", optional: true},
                        {target: XHR, type: "error", optional: false},
                        {target: XHR, type: "loadend", optional: false},
                        {target: UPLOAD, type: "error", optional: false},
                        {target: UPLOAD, type: "loadend", optional: false}]},
 ];
 
 function runTest() {
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -128,8 +128,9 @@ MozBlobBuilderWarning=Use of MozBlobBuil
 # LOCALIZATION NOTE: Do not translate "DOMException", "code" and "name"
 DOMExceptionCodeWarning=Use of DOMException's code attribute is deprecated. Use name instead.
 # LOCALIZATION NOTE: Do not translate "__exposedProps__"
 NoExposedPropsWarning=Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
 # LOCALIZATION NOTE: Do not translate "Mutation Event" and "MutationObserver"
 MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead.
 # LOCALIZATION NOTE: Do not translate "Blob", "mozSlice", or "slice"
 MozSliceWarning=Use of mozSlice on the Blob object is deprecated.  Use slice instead.
+OnuploadprogressWarning=Use of XMLHttpRequest's onuploadprogress attribute is deprecated.
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -122,14 +122,17 @@ interface XMLHttpRequest : XMLHttpReques
   attribute boolean mozBackgroundRequest;
 
   [ChromeOnly, GetterInfallible, SetterInfallible=MainThread]
   readonly attribute MozChannel channel;
 
   void sendAsBinary(DOMString body);
   any getInterface(IID iid);
 
+  [TreatNonCallableAsNull, GetterInfallible=MainThread]
+  attribute Function? onuploadprogress;
+
   [Infallible]
   readonly attribute boolean mozAnon;
 
   [Infallible]
   readonly attribute boolean mozSystem;
 };
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -92,16 +92,28 @@ public:
   {                                                                            \
     SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv);               \
   }
 
   IMPL_GETTER_AND_SETTER(readystatechange)
 
 #undef IMPL_GETTER_AND_SETTER
 
+  JSObject*
+  GetOnuploadprogress(JSContext* /* unused */, ErrorResult& aRv)
+  {
+    aRv = NS_ERROR_NOT_IMPLEMENTED;
+    return NULL;
+  }
+  void
+  SetOnuploadprogress(JSContext* /* unused */, JSObject* aListener, ErrorResult& aRv)
+  {
+    aRv = NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   uint16_t
   GetReadyState() const
   {
     return mStateData.mReadyState;
   }
 
   void
   Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync,
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -59,17 +59,16 @@ CPPSRCS = \
   testStringBuffer.cpp \
   testTrap.cpp \
   testTypedArrays.cpp \
   testUTF8.cpp \
   testValueABI.cpp \
   testVersion.cpp \
   testXDR.cpp \
   testProfileStrings.cpp \
-  testJSEvaluateScript.cpp \
   $(NULL)
 
 CSRCS = \
   valueABI.c
 
 # Disabled: an entirely unrelated test seems to cause this to fail.  Moreover,
 # given the test's dependence on interactions between the compiler, the GC, and
 # conservative stack scanning, the fix isn't obvious: more investigation
deleted file mode 100644
--- a/js/src/jsapi-tests/testJSEvaluateScript.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=99:
- */
-
-#include "tests.h"
-
-BEGIN_TEST(testJSEvaluateScript)
-{
-    jsvalRoot proto(cx);
-    JSObject *obj = JS_NewObject(cx, NULL, NULL, global);
-    CHECK(obj);
-
-    uint32_t options = JS_GetOptions(cx);
-    CHECK(options & JSOPTION_VAROBJFIX);
-
-    static const char src[] = "var x = 5;";
-
-    JS::Value retval;
-    CHECK(JS_EvaluateScript(cx, obj, src, sizeof(src) - 1, __FILE__, __LINE__,
-                            &retval));
-
-    JSBool hasProp = JS_TRUE;
-    CHECK(JS_AlreadyHasOwnProperty(cx, obj, "x", &hasProp));
-    CHECK(!hasProp);
-
-    hasProp = JS_FALSE;
-    CHECK(JS_HasProperty(cx, global, "x", &hasProp));
-    CHECK(hasProp);
-
-    // Now do the same thing, but without JSOPTION_VAROBJFIX
-    JS_SetOptions(cx, options & ~JSOPTION_VAROBJFIX);
-
-    static const char src2[] = "var y = 5;";
-
-    CHECK(JS_EvaluateScript(cx, obj, src2, sizeof(src2) - 1, __FILE__, __LINE__,
-                            &retval));
-
-    hasProp = JS_FALSE;
-    CHECK(JS_AlreadyHasOwnProperty(cx, obj, "y", &hasProp));
-    CHECK(hasProp);
-
-    hasProp = JS_TRUE;
-    CHECK(JS_AlreadyHasOwnProperty(cx, global, "y", &hasProp));
-    CHECK(!hasProp);
-
-    return true;
-}
-END_TEST(testJSEvaluateScript)
-
-