Bug 786666 - workaround __exposedProps__ typed array issue in mozTCPSocket. r=fabrice
authorAndrew Sutherland <asutherland@asutherland.org>
Wed, 29 Aug 2012 12:47:24 -0300
changeset 105823 b739aa9d9ede6bd90794eabdacdb46fca8a011fd
parent 105822 c05251c5a7e3e96d7cd507e27db09f802a1f8a53
child 105824 58b937c070d67cde0e3e3da19264f8ea018d0b42
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersfabrice
bugs786666
milestone18.0a1
Bug 786666 - workaround __exposedProps__ typed array issue in mozTCPSocket. r=fabrice
dom/network/src/TCPSocket.js
--- a/dom/network/src/TCPSocket.js
+++ b/dom/network/src/TCPSocket.js
@@ -83,16 +83,25 @@ function TCPSocket() {
   this._onerror = null;
   this._onclose = null;
 
   this._binaryType = "string";
 
   this._host = "";
   this._port = 0;
   this._ssl = false;
+
+  // As a workaround for bug https://bugzilla.mozilla.org/show_bug.cgi?id=786639
+  // we want to create any Uint8Array's off of the owning window so that there
+  // is no need for a wrapper to exist around the typed array from the
+  // perspective of content.  (The wrapper is bad because it only lets content
+  // see length, and forbids access to the array indices unless we excplicitly
+  // list them all.)  We will then access the array through a wrapper, but
+  // since we are chrome-privileged, this does not pose a problem.
+  this.useWin = null;
 }
 
 TCPSocket.prototype = {
   __exposedProps__: {
     open: 'r',
     host: 'r',
     port: 'r',
     ssl: 'r',
@@ -267,16 +276,17 @@ TCPSocket.prototype = {
                  : Services.perms.testExactPermissionFromPrincipal(principal, "tcp-socket");
 
     this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
 
     let util = aWindow.QueryInterface(
       Ci.nsIInterfaceRequestor
     ).getInterface(Ci.nsIDOMWindowUtils);
 
+    this.useWin = XPCNativeWrapper.unwrap(aWindow);
     this.innerWindowID = util.currentInnerWindowID;
     LOG("window init: " + this.innerWindowID);
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic == "inner-window-destroyed") {
       let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
       if (wId == this.innerWindowID) {
@@ -286,31 +296,34 @@ TCPSocket.prototype = {
         // so that we don't get a "can't access dead object" when the
         // underlying stream goes to tell us that we are closed
         this.onopen = null;
         this.ondrain = null;
         this.ondata = null;
         this.onerror = null;
         this.onclose = null;
 
+        this.useWin = null;
+
         // Clean up our socket
         this.close();
       }
     }
   },
 
   // nsIDOMTCPSocket
   open: function ts_open(host, port, options) {
     // in the testing case, init won't be called and
     // hasPrivileges will be null. We want to proceed to test.
     if (this._hasPrivileges !== true && this._hasPrivileges !== null) {
       throw new Error("TCPSocket does not have permission in this context.\n");
     }
     let that = new TCPSocket();
 
+    that.useWin = this.useWin;
     that.innerWindowID = this.innerWindowID;
 
     LOG("window init: " + that.innerWindowID);
     Services.obs.addObserver(that, "inner-window-destroyed", true);
 
     LOG("startup called\n");
     LOG("Host info: " + host + ":" + port + "\n");
 
@@ -471,17 +484,17 @@ TCPSocket.prototype = {
   // nsIRequestObserver (Triggered by _inputStreamPump.asyncRead)
   onStopRequest: function ts_onStopRequest(request, context, status) {
     let buffered_output = this._multiplexStream.count !== 0;
 
     this._inputStreamPump = null;
 
     if (buffered_output && !status) {
       // If we have some buffered output still, and status is not an
-      // error, the other side has done a half-close, but we don't 
+      // error, the other side has done a half-close, but we don't
       // want to be in the close state until we are done sending
       // everything that was buffered. We also don't want to call onclose
       // yet.
       return;
     }
 
     this._readyState = kCLOSED;
 
@@ -492,17 +505,18 @@ TCPSocket.prototype = {
     }
 
     this.callListener("onclose");
   },
 
   // nsIStreamListener (Triggered by _inputStreamPump.asyncRead)
   onDataAvailable: function ts_onDataAvailable(request, context, inputStream, offset, count) {
     if (this._binaryType === "arraybuffer") {
-      let ua = new Uint8Array(count);
+      let ua = this.useWin ? new this.useWin.Uint8Array(count)
+                           : new Uint8Array(count);
       ua.set(this._inputStreamBinary.readByteArray(count));
       this.callListener("ondata", ua);
     } else {
       this.callListener("ondata", this._inputStreamScriptable.read(count));
     }
   },
 
   classID: Components.ID("{cda91b22-6472-11e1-aa11-834fec09cd0a}"),