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 id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewerssicking
bugs678432
milestone9.0a1
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>