Fixed bug 678432: Sending arraybuffers using XMLHttpRequest.send. r=sicking
authorShawn Gong <sgong@mozilla.com>
Wed, 17 Aug 2011 18:44:56 -0700
changeset 76803 8e143ea435d9ad458f5ad72438723a82fcff53dd
parent 76802 edb32fa29bca558a5afc8c9afb363fbc98873fe0
child 76804 27c140d86b1b725e3ba5e0d032ab04c54333f0b9
push id21141
push usereakhgari@mozilla.com
push dateFri, 09 Sep 2011 14:06:30 +0000
treeherdermozilla-central@694520af9b18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs678432
milestone9.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
Fixed bug 678432: Sending arraybuffers using XMLHttpRequest.send. r=sicking
content/base/src/nsXMLHttpRequest.cpp
content/base/test/test_XHRSendData.html
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2078,16 +2078,38 @@ GetRequestBody(nsIVariant* aBody, nsIInp
       return NS_OK;
     }
 
     // nsIXHRSendable?
     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
     if (sendable) {
       return sendable->GetSendInfo(aResult, aContentType, aCharset);
     }
+
+    // ArrayBuffer?
+    jsval realVal;
+    JSObject* obj;
+    nsresult rv = aBody->GetAsJSVal(&realVal);
+    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
+        (obj = JSVAL_TO_OBJECT(realVal)) &&
+        (js_IsArrayBuffer(obj))) {
+
+      aContentType.SetIsVoid(PR_TRUE);
+      PRInt32 abLength = JS_GetArrayBufferByteLength(obj);
+      char* data = (char*)JS_GetArrayBufferData(obj);
+
+      nsCOMPtr<nsIInputStream> stream;
+      nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
+                                          abLength, NS_ASSIGNMENT_COPY);
+      NS_ENSURE_SUCCESS(rv, rv);
+      stream.forget(aResult);
+      aCharset.Truncate();
+
+      return NS_OK;
+    }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
            dataType == nsIDataType::VTYPE_EMPTY) {
     // Makes us act as if !aBody, don't upload anything
     return NS_OK;
   }
 
   PRUnichar* data = nsnull;
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -35,16 +35,27 @@ is(testDoc2.inputEncoding, null, "wrong 
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
 var testData = "blahblahblahblahblahblahblaaaaaaaah. blah.";
 var extensions = [".txt",".png",".jpg",".gif",".xml", "noext"];
 var fileTypes = ["text/plain", "image/png", "image/jpeg", "image/gif", "text/xml", null];
 var testFiles = new Array;
 var testDOMFiles = new Array;
 
+// arraybuffer test objects
+var shortArray = new ArrayBuffer(1);
+var shortInt8View = new Uint8Array(shortArray);
+shortInt8View[0] = 3;
+
+var longArray = new ArrayBuffer(512);
+var longInt8View = new Uint8Array(longArray);
+for (var i = 0; i < longInt8View.length; i++) {
+  longInt8View[i] = i % 255;
+}
+
 extensions.forEach(
     function (extension) {
       var testFile = createFileWithDataExt(testData, extension);
       testFiles.push(testFile);
 
       var fileList = document.getElementById('fileList');
       fileList.value = testFile.path;
       testDOMFiles.push(fileList.files[0]);
@@ -139,47 +150,60 @@ tests = [{ body: null,
            contentType: "foo/bar; charset=uTf-8",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { //will trigger a redirect test server-side
            body: ("TEST_REDIRECT_STR&url=" + window.location.host + window.location.pathname),
            redirect: true,
          },
+         { body: shortArray,
+           resBody: shortArray,
+           resType: "arraybuffer"
+         },
+         { body: longArray,
+           resBody: longArray,
+           resType: "arraybuffer"
+         },
          ];
 
 for (var i = 0; i < testDOMFiles.length; i++) {
   tests.push({ body: testDOMFiles[i],
                resBody: testData,
                resContentType: fileTypes[i],
                resContentLength: testData.length,
               });
 }
 
 try {
   for each(test in tests) {
     xhr = new XMLHttpRequest;
     xhr.open("POST", "file_XHRSendData.sjs", false);
     if (test.contentType)
       xhr.setRequestHeader("Content-Type", test.contentType);
+    if (test.resType)
+      xhr.responseType = test.resType;
     xhr.send(test.body);
 
     if (test.resContentType) {
       is(xhr.getResponseHeader("Result-Content-Type"), test.resContentType,
          "Wrong Content-Type sent");
     }
     else {
       is(xhr.getResponseHeader("Result-Content-Type"), null);
     }
 
     if (test.resContentLength) {
       is(xhr.getResponseHeader("Result-Content-Length"), test.resContentLength, "Wrong Content-Length sent");
     }
 
-    if (test.body instanceof Document) {
+    if (test.resType == "arraybuffer") {
+      is_identical_arraybuffer(xhr.response, test.resBody);
+    }
+    else if (test.body instanceof Document) {
       is(xhr.responseText.replace("\r\n", "\n"), test.resBody, "Wrong body");
     }
     else if (!test.redirect) {
       is(xhr.responseText, test.resBody, "Wrong body");
     }
     else {
       // If we're testing redirect, determine whether the body is
       // this document by looking for the relevant bug url
@@ -197,12 +221,20 @@ function cleanUpData() {
       function (testFile) {
         try {
           testFile.remove(false);
         } catch (e) {}
       }
   );
 }
 
+function is_identical_arraybuffer(ab1, ab2) {
+  is(ab1.byteLength, ab2.byteLength, "arraybuffer byteLengths not equal");
+  u8v1 = new Uint8Array(ab1);
+  u8v2 = new Uint8Array(ab2);
+  is(String.fromCharCode.apply(String, u8v1),
+     String.fromCharCode.apply(String, u8v2), "arraybuffer values not equal");
+}
+
 </script>
 </pre>
 </body>
 </html>