Bug 1215092 - WebSocketEventService and WebSocket discovering - part 4 - MessageAvailable event, r=michal
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 28 Oct 2015 19:11:25 +0000
changeset 305253 a6cd337118c4a10fc9bdceed0b41afd8f56162d7
parent 305252 3fe351a6269628e5b43bdcf981f3677ccabbf0cd
child 305254 086aa469aa8470dd14b2348db14be715b367718b
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1215092
milestone44.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
Bug 1215092 - WebSocketEventService and WebSocket discovering - part 4 - MessageAvailable event, r=michal
dom/base/WebSocket.cpp
dom/base/test/test_websocket_frame.html
netwerk/protocol/websocket/PWebSocketEventListener.ipdl
netwerk/protocol/websocket/WebSocketEventListenerChild.cpp
netwerk/protocol/websocket/WebSocketEventListenerChild.h
netwerk/protocol/websocket/WebSocketEventListenerParent.cpp
netwerk/protocol/websocket/WebSocketEventService.cpp
netwerk/protocol/websocket/WebSocketEventService.h
netwerk/protocol/websocket/nsIWebSocketEventService.idl
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1847,24 +1847,30 @@ WebSocket::CreateAndDispatchMessageEvent
   MOZ_ASSERT(mImpl);
   AssertIsOnTargetThread();
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
+  uint16_t messageType = nsIWebSocketEventListener::TYPE_STRING;
+
   // Create appropriate JS object for message
   JS::Rooted<JS::Value> jsData(aCx);
   if (aIsBinary) {
     if (mBinaryType == dom::BinaryType::Blob) {
+      messageType = nsIWebSocketEventListener::TYPE_BLOB;
+
       nsresult rv = nsContentUtils::CreateBlobBuffer(aCx, GetOwner(), aData,
                                                      &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
+      messageType = nsIWebSocketEventListener::TYPE_ARRAYBUFFER;
+
       JS::Rooted<JSObject*> arrayBuf(aCx);
       nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
                                                       arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData.setObject(*arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
       return NS_ERROR_UNEXPECTED;
@@ -1874,16 +1880,20 @@ WebSocket::CreateAndDispatchMessageEvent
     NS_ConvertUTF8toUTF16 utf16Data(aData);
     JSString* jsString;
     jsString = JS_NewUCStringCopyN(aCx, utf16Data.get(), utf16Data.Length());
     NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
 
     jsData.setString(jsString);
   }
 
+  mImpl->mService->WebSocketMessageAvailable(mImpl->mChannel->Serial(),
+                                             mImpl->mInnerWindowID,
+                                             aData, messageType);
+
   // create an event that uses the MessageEvent interface,
   // which does not bubble, is not cancelable, and has no default action
 
   RefPtr<MessageEvent> event = NS_NewDOMMessageEvent(this, nullptr, nullptr);
 
   rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false,
                                jsData, mImpl->mUTF16Origin, EmptyString(),
                                nullptr);
--- a/dom/base/test/test_websocket_frame.html
+++ b/dom/base/test/test_websocket_frame.html
@@ -13,24 +13,24 @@
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 const URI = "ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic";
 
 var frameReceivedCounter = 0;
 var frameSentCounter = 0;
 var webSocketCreatedCounter = 0;
 var webSocketOpenedCounter = 0;
+var webSocketMessageAvailableCounter = 0;
 var webSocketClosedCounter = 0;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var tests = [
   { payload: "Hello world!" },
   { payload: (function() { var buffer = ""; for (var i = 0; i < 120; ++i) buffer += i; return buffer; }()) },
-  { payload: "end" },
 ]
 
 var innerId =
   window.top.QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
 ok(innerId, "We have a valid innerWindowID: " + innerId);
 
 var service = Cc["@mozilla.org/websocketevent/service;1"]
@@ -54,16 +54,34 @@ var listener = {
 
     is(aEffectiveURI, URI, "EffectiveURI matches");
     is(aProtocols, "frame", "Protocol matches");
     is(aExtensions, "permessage-deflate", "No extensions");
 
     webSocketOpenedCounter++;
   },
 
+  webSocketMessageAvailable: function(aWebSocketSerialID, aData, aMessageType) {
+    info("WebSocketMessageAvailable");
+
+    if (tests.length) {
+      is(aData, tests[0].payload, "Message matches!");
+      is(aMessageType, Ci.nsIWebSocketEventListener.TYPE_STRING, "The type is 'string'");
+
+      webSocketMessageAvailableCounter++;
+
+      tests.shift();
+      if (tests.length) {
+        ws.send(tests[0].payload);
+      } else {
+        ws.send("end");
+      }
+    }
+  },
+
   webSocketClosed: function(aWebSocketSerialID, aWasClean,
                             aCode, aReason) {
     info("WebSocketClosed");
 
     ok(aWasClean, "The socket is closed in a clean state");
     is(aCode, 1000, "Exit code 1000");
     ok(!aReason.length, "No reason");
 
@@ -79,25 +97,16 @@ var listener = {
       is(aFrame.finBit, true, "Checking finBit");
       is(aFrame.rsvBit1, true, "Checking rsvBit1");
       is(aFrame.rsvBit2, false, "Checking rsvBit2");
       is(aFrame.rsvBit3, false, "Checking rsvBit3");
       is(aFrame.opCode, aFrame.OPCODE_TEXT, "Checking opCode");
       is(aFrame.maskBit, false, "Checking maskBit");
       is(aFrame.mask, 0, "Checking mask");
       is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
-    } else {
-      ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
-      is(aFrame.finBit, true, "Checking finBit");
-      is(aFrame.rsvBit1, false, "Checking rsvBit1");
-      is(aFrame.rsvBit2, false, "Checking rsvBit2");
-      is(aFrame.rsvBit3, false, "Checking rsvBit3");
-      is(aFrame.opCode, aFrame.OPCODE_CLOSE, "Checking opCode");
-      is(aFrame.maskBit, false, "Checking maskBit");
-      is(aFrame.mask, 0, "Checking mask");
     }
 
     frameReceivedCounter++;
   },
 
   frameSent: function(aWebSocketSerialID, aFrame) {
     ok(!!aFrame, "We have sent a frame");
 
@@ -106,41 +115,33 @@ var listener = {
       is(aFrame.finBit, true, "Checking finBit");
       is(aFrame.rsvBit1, true, "Checking rsvBit1");
       is(aFrame.rsvBit2, false, "Checking rsvBit2");
       is(aFrame.rsvBit3, false, "Checking rsvBit3");
       is(aFrame.opCode, aFrame.OPCODE_TEXT, "Checking opCode");
       is(aFrame.maskBit, true, "Checking maskBit");
       ok(!!aFrame.mask, "Checking mask: " + aFrame.mask);
       is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
-    } else {
-      ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
-      is(aFrame.finBit, true, "Checking finBit");
-      is(aFrame.rsvBit1, false, "Checking rsvBit1");
-      is(aFrame.rsvBit2, false, "Checking rsvBit2");
-      is(aFrame.rsvBit3, false, "Checking rsvBit3");
-      is(aFrame.opCode, aFrame.OPCODE_CLOSE, "Checking opCode");
-      is(aFrame.maskBit, true, "Checking maskBit");
-      ok(!!aFrame.mask, "Checking mask: " + aFrame.mask);
     }
 
     frameSentCounter++;
   }
 };
 
 service.addListener(innerId, listener);
 ok(true, "Listener added");
 
 function checkListener() {
   service.removeListener(innerId, listener);
 
   ok(frameReceivedCounter, "We received some frames!");
   ok(frameSentCounter, "We sent some frames!");
   ok(webSocketCreatedCounter, "We have a create notification");
   ok(webSocketOpenedCounter, "We have a open notification");
+  ok(webSocketMessageAvailableCounter, "We have a messageAvailable notification");
   ok(webSocketClosedCounter, "We have a close notification");
   SimpleTest.finish();
 }
 
 var ws = new WebSocket(URI, "frame");
 ws.onopen = function(e) {
   info("onopen");
 
@@ -148,21 +149,18 @@ ws.onopen = function(e) {
 }
 
 ws.onclose = function(e) {
   info("onclose");
 }
 
 ws.onmessage = function(e) {
   info("onmessage");
-
-  is(e.data, tests[0].payload, "Wrong data");
-  tests.shift();
   if (tests.length) {
-    ws.send(tests[0].payload);
+    is(e.data, tests[0].payload, "Wrong data");
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </body>
 </html>
--- a/netwerk/protocol/websocket/PWebSocketEventListener.ipdl
+++ b/netwerk/protocol/websocket/PWebSocketEventListener.ipdl
@@ -21,16 +21,20 @@ child:
                    nsString aURI,
                    nsCString aProtocols);
 
   WebSocketOpened(uint32_t awebSocketSerialID,
                   nsString aEffectiveURI,
                   nsCString aProtocols,
                   nsCString aExtensions);
 
+  WebSocketMessageAvailable(uint32_t awebSocketSerialID,
+                            nsCString aData,
+                            uint16_t aMessageType);
+
   WebSocketClosed(uint32_t awebSocketSerialID,
                   bool aWasClean,
                   uint16_t aCode,
                   nsString aReason);
 
   FrameReceived(uint32_t aWebSocketSerialID,
                 WebSocketFrameData aFrameData);
 
--- a/netwerk/protocol/websocket/WebSocketEventListenerChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketEventListenerChild.cpp
@@ -45,16 +45,29 @@ WebSocketEventListenerChild::RecvWebSock
     mService->WebSocketOpened(aWebSocketSerialID, mInnerWindowID,
                               aEffectiveURI, aProtocols, aExtensions);
   }
 
   return true;
 }
 
 bool
+WebSocketEventListenerChild::RecvWebSocketMessageAvailable(const uint32_t& aWebSocketSerialID,
+                                                           const nsCString& aData,
+                                                           const uint16_t& aMessageType)
+{
+  if (mService) {
+    mService->WebSocketMessageAvailable(aWebSocketSerialID, mInnerWindowID,
+                                        aData, aMessageType);
+  }
+
+  return true;
+}
+
+bool
 WebSocketEventListenerChild::RecvWebSocketClosed(const uint32_t& aWebSocketSerialID,
                                                  const bool& aWasClean,
                                                  const uint16_t& aCode,
                                                  const nsString& aReason)
 {
   if (mService) {
     mService->WebSocketClosed(aWebSocketSerialID, mInnerWindowID,
                               aWasClean, aCode, aReason);
--- a/netwerk/protocol/websocket/WebSocketEventListenerChild.h
+++ b/netwerk/protocol/websocket/WebSocketEventListenerChild.h
@@ -25,16 +25,20 @@ public:
                             const nsString& aURI,
                             const nsCString& aProtocols) override;
 
   bool RecvWebSocketOpened(const uint32_t& aWebSocketSerialID,
                            const nsString& aEffectiveURI,
                            const nsCString& aProtocols,
                            const nsCString& aExtensions) override;
 
+  bool RecvWebSocketMessageAvailable(const uint32_t& aWebSocketSerialID,
+                                     const nsCString& aData,
+                                     const uint16_t& aMessageType) override;
+
   bool RecvWebSocketClosed(const uint32_t& aWebSocketSerialID,
                           const bool& aWasClean,
                           const uint16_t& aCode,
                           const nsString& aReason) override;
 
   bool RecvFrameReceived(const uint32_t& aWebSocketSerialID,
                          const WebSocketFrameData& aFrameData) override;
 
--- a/netwerk/protocol/websocket/WebSocketEventListenerParent.cpp
+++ b/netwerk/protocol/websocket/WebSocketEventListenerParent.cpp
@@ -84,16 +84,26 @@ WebSocketEventListenerParent::WebSocketC
                                               const nsAString& aReason)
 {
   unused << SendWebSocketClosed(aWebSocketSerialID, aWasClean, aCode,
                                 nsString(aReason));
   return NS_OK;
 }
 
 NS_IMETHODIMP
+WebSocketEventListenerParent::WebSocketMessageAvailable(uint32_t aWebSocketSerialID,
+                                                        const nsACString& aData,
+                                                        uint16_t aMessageType)
+{
+  unused << SendWebSocketMessageAvailable(aWebSocketSerialID, nsCString(aData),
+                                          aMessageType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 WebSocketEventListenerParent::FrameReceived(uint32_t aWebSocketSerialID,
                                             nsIWebSocketFrame* aFrame)
 {
   if (!aFrame) {
     return NS_ERROR_FAILURE;
   }
 
   WebSocketFrame* frame = static_cast<WebSocketFrame*>(aFrame);
--- a/netwerk/protocol/websocket/WebSocketEventService.cpp
+++ b/netwerk/protocol/websocket/WebSocketEventService.cpp
@@ -144,16 +144,40 @@ private:
     NS_WARN_IF(NS_FAILED(rv));
   }
 
   const nsString mEffectiveURI;
   const nsCString mProtocols;
   const nsCString mExtensions;
 };
 
+class WebSocketMessageAvailableRunnable final : public WebSocketBaseRunnable
+{
+public:
+  WebSocketMessageAvailableRunnable(uint32_t aWebSocketSerialID,
+                          uint64_t aInnerWindowID,
+                          const nsACString& aData,
+                          uint16_t aMessageType)
+    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
+    , mData(aData)
+    , mMessageType(aMessageType)
+  {}
+
+private:
+  virtual void DoWork(nsIWebSocketEventListener* aListener) override
+  {
+    nsresult rv = aListener->WebSocketMessageAvailable(mWebSocketSerialID,
+                                                       mData, mMessageType);
+    NS_WARN_IF(NS_FAILED(rv));
+  }
+
+  const nsCString mData;
+  uint16_t mMessageType;
+};
+
 class WebSocketClosedRunnable final : public WebSocketBaseRunnable
 {
 public:
   WebSocketClosedRunnable(uint32_t aWebSocketSerialID,
                           uint64_t aInnerWindowID,
                           bool aWasClean,
                           uint16_t aCode,
                           const nsAString& aReason)
@@ -248,16 +272,34 @@ WebSocketEventService::WebSocketOpened(u
   RefPtr<WebSocketOpenedRunnable> runnable =
     new WebSocketOpenedRunnable(aWebSocketSerialID, aInnerWindowID,
                                 aEffectiveURI, aProtocols, aExtensions);
   nsresult rv = NS_DispatchToMainThread(runnable);
   NS_WARN_IF(NS_FAILED(rv));
 }
 
 void
+WebSocketEventService::WebSocketMessageAvailable(uint32_t aWebSocketSerialID,
+                                                 uint64_t aInnerWindowID,
+                                                 const nsACString& aData,
+                                                 uint16_t aMessageType)
+{
+  // Let's continue only if we have some listeners.
+  if (!HasListeners()) {
+    return;
+  }
+
+  RefPtr<WebSocketMessageAvailableRunnable> runnable =
+    new WebSocketMessageAvailableRunnable(aWebSocketSerialID, aInnerWindowID,
+                                          aData, aMessageType);
+  nsresult rv = NS_DispatchToMainThread(runnable);
+  NS_WARN_IF(NS_FAILED(rv));
+}
+
+void
 WebSocketEventService::WebSocketClosed(uint32_t aWebSocketSerialID,
                                        uint64_t aInnerWindowID,
                                        bool aWasClean,
                                        uint16_t aCode,
                                        const nsAString& aReason)
 {
   // Let's continue only if we have some listeners.
   if (!HasListeners()) {
--- a/netwerk/protocol/websocket/WebSocketEventService.h
+++ b/netwerk/protocol/websocket/WebSocketEventService.h
@@ -41,16 +41,21 @@ public:
                         const nsACString& aProtocols);
 
   void WebSocketOpened(uint32_t aWebSocketSerialID,
                        uint64_t aInnerWindowID,
                        const nsAString& aEffectiveURI,
                        const nsACString& aProtocols,
                        const nsACString& aExtensions);
 
+  void WebSocketMessageAvailable(uint32_t aWebSocketSerialID,
+                                 uint64_t aInnerWindowID,
+                                 const nsACString& aData,
+                                 uint16_t aMessageType);
+
   void WebSocketClosed(uint32_t aWebSocketSerialID,
                        uint64_t aInnerWindowID,
                        bool aWasClean,
                        uint16_t aCode,
                        const nsAString& aReason);
 
   void FrameReceived(uint32_t aWebSocketSerialID,
                      uint64_t aInnerWindowID,
--- a/netwerk/protocol/websocket/nsIWebSocketEventService.idl
+++ b/netwerk/protocol/websocket/nsIWebSocketEventService.idl
@@ -1,17 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 #include "nsISupports.idl"
 
-[scriptable, builtinclass, uuid(470133f3-a04f-48a9-82bd-8d1bc7eb6f9c)]
+[scriptable, builtinclass, uuid(6714a6be-2265-4f73-a988-d78a12416037)]
 interface nsIWebSocketFrame : nsISupports
 {
   readonly attribute DOMHighResTimeStamp timeStamp;
 
   readonly attribute boolean finBit;
 
   readonly attribute boolean rsvBit1;
   readonly attribute boolean rsvBit2;
@@ -21,38 +21,46 @@ interface nsIWebSocketFrame : nsISupport
 
   readonly attribute boolean maskBit;
 
   readonly attribute unsigned long mask;
 
   readonly attribute ACString payload;
 
   // Non-Control opCode values:
-  const long OPCODE_CONTINUATION = 0x0;
-  const long OPCODE_TEXT         = 0x1;
-  const long OPCODE_BINARY       = 0x2;
+  const unsigned short OPCODE_CONTINUATION = 0x0;
+  const unsigned short OPCODE_TEXT         = 0x1;
+  const unsigned short OPCODE_BINARY       = 0x2;
 
   // Control opCode values:
-  const long OPCODE_CLOSE        = 0x8;
-  const long OPCODE_PING         = 0x9;
-  const long OPCODE_PONG         = 0xA;
+  const unsigned short OPCODE_CLOSE        = 0x8;
+  const unsigned short OPCODE_PING         = 0x9;
+  const unsigned short OPCODE_PONG         = 0xA;
 };
 
-[scriptable, uuid(ccbd96ae-2b7d-42fc-9ee5-116fa8e1723a)]
+[scriptable, uuid(e7c005ab-e694-489b-b741-96db43ffb16f)]
 interface nsIWebSocketEventListener : nsISupports
 {
   void webSocketCreated(in unsigned long aWebSocketSerialID,
                         in AString aURI,
                         in ACString aProtocols);
 
   void webSocketOpened(in unsigned long aWebSocketSerialID,
                        in AString aEffectiveURI,
                        in ACString aProtocols,
                        in ACString aExtensions);
 
+  const unsigned short TYPE_STRING      = 0x0;
+  const unsigned short TYPE_BLOB        = 0x1;
+  const unsigned short TYPE_ARRAYBUFFER = 0x2;
+
+  void webSocketMessageAvailable(in unsigned long aWebSocketSerialID,
+                                 in ACString aMessage,
+                                 in unsigned short aType);
+
   void webSocketClosed(in unsigned long aWebSocketSerialID,
                        in boolean aWasClean,
                        in unsigned short aCode,
                        in AString aReason);
 
   void frameReceived(in unsigned long aWebSocketSerialID,
                      in nsIWebSocketFrame aFrame);