Bug 1090142 - WebSocketChannelChild should respect the order of the runnable to be dispatched. r=jduell, a=dveditz
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 07 Nov 2014 09:35:54 -0500
changeset 233698 a47736824ffdcbd3c753ab98097f89e48ca2d62e
parent 233697 c4b670cb5a6d4039e443879ae2dafd30a3e7feb4
child 233740 9a35e16bfa5510245ae961e898d5a76591205911
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, dveditz
bugs1090142
milestone35.0a2
Bug 1090142 - WebSocketChannelChild should respect the order of the runnable to be dispatched. r=jduell, a=dveditz
content/base/src/WebSocket.cpp
netwerk/protocol/websocket/WebSocketChannelChild.cpp
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -2256,16 +2256,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;
 }