Bug 1090142 - WebSocketChannelChild should respect the order of the runnable to be dispatched. r=jduell
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 07 Nov 2014 09:35:54 -0500
changeset 238916 dcac8f919b6e8ba21eaf3dca2bab1f329f2d508b
parent 238915 73af59ec42d918d6d110e775727b29125d0ae2ee
child 238917 c39ff12ad6eb2e20d22554f1a95c2c3cab806760
child 238994 527d5142b7c5887de752d6223f0f8052117a9de2
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1090142
milestone36.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 1090142 - WebSocketChannelChild should respect the order of the runnable to be dispatched. r=jduell
dom/base/WebSocket.cpp
netwerk/protocol/websocket/WebSocketChannelChild.cpp
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -2291,16 +2291,22 @@ WebSocketImpl::Cancel(nsresult aStatus)
   return CancelInternal();
 }
 
 nsresult
 WebSocketImpl::CancelInternal()
 {
   AssertIsOnTargetThread();
 
+   // If CancelInternal is called by a runnable, we may already be disconnected
+   // by the time it runs.
+  if (mDisconnected) {
+    return NS_OK;
+  }
+
   int64_t readyState = mWebSocket->ReadyState();
   if (readyState == WebSocket::CLOSING || readyState == WebSocket::CLOSED) {
     return NS_OK;
   }
 
   ConsoleError();
 
   return CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -115,16 +115,41 @@ WebSocketChannelChild::DispatchToTargetT
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(mTargetThread);
   MOZ_RELEASE_ASSERT(aChannelEvent);
 
   mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent),
                           NS_DISPATCH_NORMAL);
 }
 
+class EventTargetDispatcher : public ChannelEvent
+{
+public:
+  EventTargetDispatcher(ChannelEvent* aChannelEvent,
+                        nsIEventTarget* aEventTarget)
+    : mChannelEvent(aChannelEvent)
+    , mEventTarget(aEventTarget)
+  {}
+
+  void Run()
+  {
+    if (mEventTarget) {
+      mEventTarget->Dispatch(new WrappedChannelEvent(mChannelEvent.forget()),
+                             NS_DISPATCH_NORMAL);
+      return;
+    }
+
+    mChannelEvent->Run();
+  }
+
+private:
+  nsAutoPtr<ChannelEvent> mChannelEvent;
+  nsCOMPtr<nsIEventTarget> mEventTarget;
+};
+
 class StartEvent : public ChannelEvent
 {
  public:
   StartEvent(WebSocketChannelChild* aChild,
              const nsCString& aProtocol,
              const nsCString& aExtensions,
              const nsString& aEffectiveURL,
              bool aEncrypted)
@@ -149,18 +174,20 @@ class StartEvent : public ChannelEvent
 
 bool
 WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol,
                                    const nsCString& aExtensions,
                                    const nsString& aEffectiveURL,
                                    const bool& aEncrypted)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions,
-                                    aEffectiveURL, aEncrypted));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new StartEvent(this, aProtocol, aExtensions,
+                                      aEffectiveURL, aEncrypted),
+                       mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions,
                                           aEffectiveURL, aEncrypted));
   } else {
     OnStart(aProtocol, aExtensions, aEffectiveURL, aEncrypted);
   }
   return true;
 }
@@ -200,17 +227,18 @@ class StopEvent : public ChannelEvent
   WebSocketChannelChild* mChild;
   nsresult mStatusCode;
 };
 
 bool
 WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new StopEvent(this, aStatusCode));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new StopEvent(this, aStatusCode), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new StopEvent(this, aStatusCode));
   } else {
     OnStop(aStatusCode);
   }
   return true;
 }
 
@@ -248,17 +276,18 @@ class MessageEvent : public ChannelEvent
   nsCString mMessage;
   bool mBinary;
 };
 
 bool
 WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new MessageEvent(this, aMsg, false));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new MessageEvent(this, aMsg, false), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new MessageEvent(this, aMsg, false));
    } else {
     OnMessageAvailable(aMsg);
   }
   return true;
 }
 
@@ -271,17 +300,18 @@ WebSocketChannelChild::OnMessageAvailabl
     mListener->OnMessageAvailable(mContext, aMsg);
   }
 }
 
 bool
 WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new MessageEvent(this, aMsg, true));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new MessageEvent(this, aMsg, true), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new MessageEvent(this, aMsg, true));
   } else {
     OnBinaryMessageAvailable(aMsg);
   }
   return true;
 }
 
@@ -312,17 +342,18 @@ class AcknowledgeEvent : public ChannelE
   WebSocketChannelChild* mChild;
   uint32_t mSize;
 };
 
 bool
 WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new AcknowledgeEvent(this, aSize));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new AcknowledgeEvent(this, aSize), mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new AcknowledgeEvent(this, aSize));
   } else {
     OnAcknowledge(aSize);
   }
   return true;
 }
 
@@ -357,17 +388,19 @@ class ServerCloseEvent : public ChannelE
   nsCString              mReason;
 };
 
 bool
 WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode,
                                          const nsCString& aReason)
 {
   if (mEventQ->ShouldEnqueue()) {
-    mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason));
+    mEventQ->Enqueue(new EventTargetDispatcher(
+                       new ServerCloseEvent(this, aCode, aReason),
+                       mTargetThread));
   } else if (mTargetThread) {
     DispatchToTargetThread(new ServerCloseEvent(this, aCode, aReason));
   } else {
     OnServerClose(aCode, aReason);
   }
   return true;
 }