Bug 1090170 - WebSocketChannel must remove itself as observer when disconnected. r=bagder, a=lsblakk
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 28 Oct 2014 14:49:57 +0000
changeset 233543 569c893707446cd5009190b9cd06f278035aa2eb
parent 233542 bf0c996166662cd8c9ca6ba2ae2623d29ab26ae7
child 233544 6675f988b6c56879fda0113eef9135693d76db28
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)
reviewersbagder, lsblakk
bugs1090170
milestone35.0a2
Bug 1090170 - WebSocketChannel must remove itself as observer when disconnected. r=bagder, a=lsblakk
netwerk/protocol/websocket/WebSocketChannel.cpp
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1031,26 +1031,16 @@ WebSocketChannel::WebSocketChannel() :
   mFramePtr = mBuffer = static_cast<uint8_t *>(moz_xmalloc(mBufferSize));
 
   nsresult rv;
   mConnectionLogService = do_GetService("@mozilla.org/network/dashboard;1",&rv);
   if (NS_FAILED(rv))
     LOG(("Failed to initiate dashboard service."));
 
   mSerial = sSerialSeed++;
-
-  // Register for prefs change notifications
-  nsCOMPtr<nsIObserverService> observerService =
-    mozilla::services::GetObserverService();
-  if (observerService) {
-    observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
-  } else {
-    NS_WARNING("failed to get observer service");
-  }
-
 }
 
 WebSocketChannel::~WebSocketChannel()
 {
   LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this));
 
   if (mWasOpened) {
     MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called");
@@ -1967,16 +1957,43 @@ WebSocketChannel::EnsureHdrOut(uint32_t 
     mDynamicOutputSize = size;
     mDynamicOutput =
       (uint8_t *) moz_xrealloc(mDynamicOutput, mDynamicOutputSize);
   }
 
   mHdrOut = mDynamicOutput;
 }
 
+namespace {
+
+class RemoveObserverRunnable : public nsRunnable
+{
+  nsRefPtr<WebSocketChannel> mChannel;
+
+public:
+  RemoveObserverRunnable(WebSocketChannel* aChannel)
+    : mChannel(aChannel)
+  {}
+
+  NS_IMETHOD Run()
+  {
+    nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+    if (!observerService) {
+      NS_WARNING("failed to get observer service");
+      return NS_OK;
+    }
+
+    observerService->RemoveObserver(mChannel, NS_NETWORK_LINK_TOPIC);
+    return NS_OK;
+  }
+};
+
+} // anonymous namespace
+
 void
 WebSocketChannel::CleanupConnection()
 {
   LOG(("WebSocketChannel::CleanupConnection() %p", this));
 
   if (mLingeringCloseTimer) {
     mLingeringCloseTimer->Cancel();
     mLingeringCloseTimer = nullptr;
@@ -1998,16 +2015,20 @@ WebSocketChannel::CleanupConnection()
     mTransport->Close(NS_BASE_STREAM_CLOSED);
     mTransport = nullptr;
   }
 
   if (mConnectionLogService && !mPrivateBrowsing) {
     mConnectionLogService->RemoveHost(mHost, mSerial);
   }
 
+  // This method can run in any thread, but the observer has to be removed on
+  // the main-thread.
+  NS_DispatchToMainThread(new RemoveObserverRunnable(this));
+
   DecrementSessionCount();
 }
 
 void
 WebSocketChannel::StopSession(nsresult reason)
 {
   LOG(("WebSocketChannel::StopSession() %p [%x]\n", this, reason));
 
@@ -2105,18 +2126,16 @@ WebSocketChannel::StopSession(nsresult r
   delete mCompressor;
   mCompressor = nullptr;
 
   if (!mCalledOnStop) {
     mCalledOnStop = 1;
     mTargetThread->Dispatch(new CallOnStop(this, reason),
                             NS_DISPATCH_NORMAL);
   }
-
-  return;
 }
 
 void
 WebSocketChannel::AbortSession(nsresult reason)
 {
   LOG(("WebSocketChannel::AbortSession() %p [reason %x] stopped = %d\n",
        this, reason, mStopped));
 
@@ -2914,16 +2933,29 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI
     mConnectionLogService->AddHost(mHost, mSerial,
                                    BaseWebSocketChannel::mEncrypted);
   }
 
   rv = ApplyForAdmission();
   if (NS_FAILED(rv))
     return rv;
 
+  // Register for prefs change notifications
+  nsCOMPtr<nsIObserverService> observerService =
+    mozilla::services::GetObserverService();
+  if (!observerService) {
+    NS_WARNING("failed to get observer service");
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   // Only set these if the open was successful:
   //
   mWasOpened = 1;
   mListener = aListener;
   mContext = aContext;
   IncrementSessionCount();
 
   return rv;
@@ -3223,18 +3255,18 @@ WebSocketChannel::OnStartRequest(nsIRequ
   if (mRecvdHttpUpgradeTransport)
     return StartWebsocketData();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannel::OnStopRequest(nsIRequest *aRequest,
-                                  nsISupports *aContext,
-                                  nsresult aStatusCode)
+                                nsISupports *aContext,
+                                nsresult aStatusCode)
 {
   LOG(("WebSocketChannel::OnStopRequest() %p [%p %p %x]\n",
        this, aRequest, aContext, aStatusCode));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
   ReportConnectionTelemetry();
 
   // This is the end of the HTTP upgrade transaction, the