bug 667853: Missing close() event if websocket::init fails. r=mcmanus, jdm
authorPatrick McManus <mcmanus@ducksong.com>
Tue, 02 Aug 2011 16:55:17 -0700
changeset 73727 e337d0d2d7a92be8046b86a8587ff362db34285b
parent 73726 feda6619295c168a15f20a8d77f4e083297131f0
child 73728 52702d275995f508a0044f18b09f20f717afc23d
push id20911
push usermak77@bonardo.net
push dateWed, 03 Aug 2011 08:47:10 +0000
treeherdermozilla-central@c35c69e1ce99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, jdm
bugs667853
milestone8.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 667853: Missing close() event if websocket::init fails. r=mcmanus, jdm
content/base/src/nsWebSocket.cpp
netwerk/protocol/websocket/PWebSocket.ipdl
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelChild.h
netwerk/protocol/websocket/WebSocketChannelParent.cpp
netwerk/protocol/websocket/WebSocketChannelParent.h
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -370,17 +370,16 @@ nsWebSocketEstablishedConnection::Close(
   if (!mOwner)
     return NS_OK;
 
   // Disconnect() can release this object, so we keep a
   // reference until the end of the method
   nsRefPtr<nsWebSocketEstablishedConnection> kungfuDeathGrip = this;
 
   if (mOwner->mReadyState == nsIMozWebSocket::CONNECTING) {
-    mOwner->SetReadyState(nsIMozWebSocket::CLOSING);
     mOwner->SetReadyState(nsIMozWebSocket::CLOSED);
     Disconnect();
     return NS_OK;
   }
 
   mOwner->SetReadyState(nsIMozWebSocket::CLOSING);
 
   if (mStatus == CONN_CLOSED) {
@@ -412,17 +411,17 @@ nsWebSocketEstablishedConnection::Consol
                           NS_LITERAL_STRING("connectionFailure").get(),
                           formatStrings, NS_ARRAY_LENGTH(formatStrings));
     } else {
       PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                           NS_LITERAL_STRING("netInterrupt").get(),
                           formatStrings, NS_ARRAY_LENGTH(formatStrings));
     }
   }
-  /// todo some sepcific errors - like for message too large
+  /// todo some specific errors - like for message too large
   return rv;
 }
 
 
 nsresult
 nsWebSocketEstablishedConnection::FailConnection()
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
@@ -760,19 +759,22 @@ nsWebSocket::EstablishConnection()
   NS_ABORT_IF_FALSE(!mConnection, "mConnection should be null");
 
   nsresult rv;
 
   nsRefPtr<nsWebSocketEstablishedConnection> conn =
     new nsWebSocketEstablishedConnection();
 
   rv = conn->Init(this);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   mConnection = conn;
+  if (NS_FAILED(rv)) {
+    Close();
+    mConnection = nsnull;
+    return rv;
+  }
 
   return NS_OK;
 }
 
 class nsWSCloseEvent : public nsRunnable
 {
 public:
   nsWSCloseEvent(nsWebSocket *aWebSocket, PRBool aWasClean)
--- a/netwerk/protocol/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -65,17 +65,14 @@ child:
   // Forwarded notifications corresponding to the nsIWebSocketListener interface
   OnStart(nsCString aProtocol);
   OnStop(nsresult aStatusCode);
   OnMessageAvailable(nsCString aMsg);
   OnBinaryMessageAvailable(nsCString aMsg);
   OnAcknowledge(PRUint32 aSize);
   OnServerClose();
 
-  // Only sent in the event that AsyncOpen fails
-  AsyncOpenFailed();
-
   __delete__();
 
 };
 
 } //namespace net
 } //namespace mozilla
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1539,32 +1539,32 @@ WebSocketChannel::SetupRequest()
   char* b64 = PL_Base64Encode((const char *)secKey, 16, nsnull);
   NS_Free(secKey);
   if (!b64)
     return NS_ERROR_OUT_OF_MEMORY;
   secKeyString.Assign(b64);
   PR_Free(b64);
   mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Sec-WebSocket-Key"),
                                  secKeyString, PR_FALSE);
-  LOG(("WebSocketChannel::AsyncOpen(): client key %s\n", secKeyString.get()));
+  LOG(("WebSocketChannel::SetupRequest: client key %s\n", secKeyString.get()));
 
   // prepare the value we expect to see in
   // the sec-websocket-accept response header
   secKeyString.AppendLiteral("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
   nsCOMPtr<nsICryptoHash> hasher =
     do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = hasher->Init(nsICryptoHash::SHA1);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = hasher->Update((const PRUint8 *) secKeyString.BeginWriting(),
                       secKeyString.Length());
   NS_ENSURE_SUCCESS(rv, rv);
   rv = hasher->Finish(PR_TRUE, mHashedSecret);
   NS_ENSURE_SUCCESS(rv, rv);
-  LOG(("WebSocketChannel::AsyncOpen(): expected server key %s\n",
+  LOG(("WebSocketChannel::SetupRequest: expected server key %s\n",
        mHashedSecret.get()));
 
   return NS_OK;
 }
 
 nsresult
 WebSocketChannel::ApplyForAdmission()
 {
@@ -1578,17 +1578,17 @@ WebSocketChannel::ApplyForAdmission()
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString hostName;
   rv = mURI->GetHost(hostName);
   NS_ENSURE_SUCCESS(rv, rv);
   mAddress = hostName;
 
   // expect the callback in ::OnLookupComplete
-  LOG(("WebSocketChannel::AsyncOpen(): checking for concurrent open\n"));
+  LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
   nsCOMPtr<nsIThread> mainThread;
   NS_GetMainThread(getter_AddRefs(mainThread));
   dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mDNSRequest));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -1983,16 +1983,23 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI
   return ApplyForAdmission();
 }
 
 NS_IMETHODIMP
 WebSocketChannel::Close()
 {
   LOG(("WebSocketChannel::Close() %p\n", this));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
+
+  if (!mTransport) {
+    LOG(("WebSocketChannel::Close() without transport - aborting."));
+    AbortSession(NS_ERROR_NOT_CONNECTED);
+    return NS_ERROR_NOT_CONNECTED;
+  }
+
   if (mRequestedClose) {
     LOG(("WebSocketChannel:: Double close error\n"));
     return NS_ERROR_UNEXPECTED;
   }
 
   mRequestedClose = 1;
 
   return mSocketThread->Dispatch(new nsPostMessage(this, kFinMessage, -1),
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -72,17 +72,16 @@ NS_INTERFACE_MAP_BEGIN(WebSocketChannelC
   NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel)
   NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel)
 NS_INTERFACE_MAP_END
 
 WebSocketChannelChild::WebSocketChannelChild(bool aSecure)
 : mEventQ(static_cast<nsIWebSocketChannel*>(this))
 , mIPCOpen(false)
-, mCancelled(false)
 {
   LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
   BaseWebSocketChannel::mEncrypted = aSecure;
 }
 
 WebSocketChannelChild::~WebSocketChannelChild()
 {
   LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
@@ -320,51 +319,16 @@ WebSocketChannelChild::OnServerClose()
 {
   LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
   if (mListener) {
     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
     mListener->OnServerClose(mContext);
   }
 }
 
-class AsyncOpenFailedEvent : public ChannelEvent
-{
- public:
-  AsyncOpenFailedEvent(WebSocketChannelChild* aChild)
-  : mChild(aChild)
-  {}
-
-  void Run()
-  {
-    mChild->AsyncOpenFailed();
-  }
- private:
-  WebSocketChannelChild* mChild;
-};
-
-bool
-WebSocketChannelChild::RecvAsyncOpenFailed()
-{
-  if (mEventQ.ShouldEnqueue()) {
-    mEventQ.Enqueue(new AsyncOpenFailedEvent(this));
-  } else {
-    AsyncOpenFailed();
-  }
-  return true;
-}
-
-void
-WebSocketChannelChild::AsyncOpenFailed()
-{
-  LOG(("WebSocketChannelChild::RecvAsyncOpenFailed() %p\n", this));
-  mCancelled = true;
-  if (mIPCOpen)
-    SendDeleteSelf();
-}
-
 NS_IMETHODIMP
 WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
                                  const nsACString &aOrigin,
                                  nsIWebSocketListener *aListener,
                                  nsISupports *aContext)
 {
   LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
 
@@ -396,45 +360,36 @@ WebSocketChannelChild::AsyncOpen(nsIURI 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannelChild::Close()
 {
   LOG(("WebSocketChannelChild::Close() %p\n", this));
 
-  if (mCancelled)
-    return NS_ERROR_UNEXPECTED;
-
   if (!mIPCOpen || !SendClose())
     return NS_ERROR_UNEXPECTED;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannelChild::SendMsg(const nsACString &aMsg)
 {
   LOG(("WebSocketChannelChild::SendMsg() %p\n", this));
 
-  if (mCancelled)
-    return NS_ERROR_UNEXPECTED;
-
   if (!mIPCOpen || !SendSendMsg(nsCString(aMsg)))
     return NS_ERROR_UNEXPECTED;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg)
 {
   LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this));
 
-  if (mCancelled)
-    return NS_ERROR_UNEXPECTED;
-
   if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg)))
     return NS_ERROR_UNEXPECTED;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
 {
--- a/netwerk/protocol/websocket/WebSocketChannelChild.h
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.h
@@ -86,17 +86,16 @@ class WebSocketChannelChild : public Bas
   void OnMessageAvailable(const nsCString& aMsg);
   void OnBinaryMessageAvailable(const nsCString& aMsg);
   void OnAcknowledge(const PRUint32& aSize);
   void OnServerClose();
   void AsyncOpenFailed();  
 
   ChannelEventQueue mEventQ;
   bool mIPCOpen;
-  bool mCancelled;
 
   friend class StartEvent;
   friend class StopEvent;
   friend class MessageEvent;
   friend class AcknowledgeEvent;
   friend class ServerCloseEvent;
   friend class AsyncOpenFailedEvent;
 };
--- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp
@@ -78,31 +78,35 @@ WebSocketChannelParent::RecvAsyncOpen(co
   if (aSecure) {
     mChannel =
       do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
   } else {
     mChannel =
       do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
   }
   if (NS_FAILED(rv))
-    return CancelEarly();
+    goto fail;
 
   rv = mChannel->SetNotificationCallbacks(this);
   if (NS_FAILED(rv))
-    return CancelEarly();
+    goto fail;
 
   rv = mChannel->SetProtocol(aProtocol);
   if (NS_FAILED(rv))
-    return CancelEarly();
+    goto fail;
 
   rv = mChannel->AsyncOpen(aURI, aOrigin, this, nsnull);
   if (NS_FAILED(rv))
-    return CancelEarly();
+    goto fail;
 
   return true;
+
+fail:
+  mChannel = nsnull;
+  return SendOnStop(rv);
 }
 
 bool
 WebSocketChannelParent::RecvClose()
 {
   LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
   if (mChannel) {
     nsresult rv = mChannel->Close();
@@ -128,23 +132,16 @@ WebSocketChannelParent::RecvSendBinaryMs
   LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this));
   if (mChannel) {
     nsresult rv = mChannel->SendBinaryMsg(aMsg);
     NS_ENSURE_SUCCESS(rv, true);
   }
   return true;
 }
 
-bool
-WebSocketChannelParent::CancelEarly()
-{
-  LOG(("WebSocketChannelParent::CancelEarly() %p\n", this));
-  return mIPCOpen ? SendAsyncOpenFailed() : true;
-}
-
 NS_IMETHODIMP
 WebSocketChannelParent::GetInterface(const nsIID & iid, void **result NS_OUTPARAM)
 {
   LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
   if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
     return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
                                         iid, result);
 
--- a/netwerk/protocol/websocket/WebSocketChannelParent.h
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.h
@@ -66,17 +66,16 @@ class WebSocketChannelParent : public PW
   bool RecvAsyncOpen(const IPC::URI& aURI,
                      const nsCString& aOrigin,
                      const nsCString& aProtocol,
                      const bool& aSecure);
   bool RecvClose();
   bool RecvSendMsg(const nsCString& aMsg);
   bool RecvSendBinaryMsg(const nsCString& aMsg);
   bool RecvDeleteSelf();
-  bool CancelEarly();
 
   void ActorDestroy(ActorDestroyReason why);
 
   nsCOMPtr<nsIAuthPromptProvider> mAuthProvider;
   nsCOMPtr<nsIWebSocketChannel> mChannel;
   bool mIPCOpen;
 };