netwerk/protocol/websocket/WebSocketChannelChild.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set sw=2 ts=8 et tw=80 : */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "WebSocketLog.h"
     8 #include "base/compiler_specific.h"
     9 #include "mozilla/dom/TabChild.h"
    10 #include "mozilla/net/NeckoChild.h"
    11 #include "WebSocketChannelChild.h"
    12 #include "nsITabChild.h"
    13 #include "nsNetUtil.h"
    14 #include "mozilla/ipc/InputStreamUtils.h"
    15 #include "mozilla/ipc/URIUtils.h"
    16 #include "mozilla/net/ChannelEventQueue.h"
    17 #include "SerializedLoadContext.h"
    19 using namespace mozilla::ipc;
    21 namespace mozilla {
    22 namespace net {
    24 NS_IMPL_ADDREF(WebSocketChannelChild)
    26 NS_IMETHODIMP_(MozExternalRefCountType) WebSocketChannelChild::Release()
    27 {
    28   NS_PRECONDITION(0 != mRefCnt, "dup release");
    29   NS_ASSERT_OWNINGTHREAD(WebSocketChannelChild);
    30   --mRefCnt;
    31   NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild");
    33   if (mRefCnt == 1 && mIPCOpen) {
    34     SendDeleteSelf();
    35     return mRefCnt;
    36   }
    38   if (mRefCnt == 0) {
    39     mRefCnt = 1; /* stabilize */
    40     delete this;
    41     return 0;
    42   }
    43   return mRefCnt;
    44 }
    46 NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild)
    47   NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel)
    48   NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
    49   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel)
    50   NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
    51 NS_INTERFACE_MAP_END
    53 WebSocketChannelChild::WebSocketChannelChild(bool aSecure)
    54  : mIPCOpen(false)
    55 {
    56   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
    58   LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
    59   BaseWebSocketChannel::mEncrypted = aSecure;
    60   mEventQ = new ChannelEventQueue(static_cast<nsIWebSocketChannel*>(this));
    61 }
    63 WebSocketChannelChild::~WebSocketChannelChild()
    64 {
    65   LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
    66 }
    68 void
    69 WebSocketChannelChild::AddIPDLReference()
    70 {
    71   NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
    72   mIPCOpen = true;
    73   AddRef();
    74 }
    76 void
    77 WebSocketChannelChild::ReleaseIPDLReference()
    78 {
    79   NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
    80   mIPCOpen = false;
    81   Release();
    82 }
    84 class WrappedChannelEvent : public nsRunnable
    85 {
    86 public:
    87   WrappedChannelEvent(ChannelEvent *aChannelEvent)
    88     : mChannelEvent(aChannelEvent)
    89   {
    90     MOZ_RELEASE_ASSERT(aChannelEvent);
    91   }
    92   NS_IMETHOD Run()
    93   {
    94     mChannelEvent->Run();
    95     return NS_OK;
    96   }
    97 private:
    98   nsAutoPtr<ChannelEvent> mChannelEvent;
    99 };
   101 void
   102 WebSocketChannelChild::DispatchToTargetThread(ChannelEvent *aChannelEvent)
   103 {
   104   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   105   MOZ_RELEASE_ASSERT(mTargetThread);
   106   MOZ_RELEASE_ASSERT(aChannelEvent);
   108   mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent),
   109                           NS_DISPATCH_NORMAL);
   110 }
   112 class StartEvent : public ChannelEvent
   113 {
   114  public:
   115   StartEvent(WebSocketChannelChild* aChild,
   116              const nsCString& aProtocol,
   117              const nsCString& aExtensions)
   118   : mChild(aChild)
   119   , mProtocol(aProtocol)
   120   , mExtensions(aExtensions)
   121   {}
   123   void Run()
   124   {
   125     mChild->OnStart(mProtocol, mExtensions);
   126   }
   127  private:
   128   WebSocketChannelChild* mChild;
   129   nsCString mProtocol;
   130   nsCString mExtensions;
   131 };
   133 bool
   134 WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol,
   135                                    const nsCString& aExtensions)
   136 {
   137   if (mEventQ->ShouldEnqueue()) {
   138     mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions));
   139   } else if (mTargetThread) {
   140     DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions));
   141   } else {
   142     OnStart(aProtocol, aExtensions);
   143   }
   144   return true;
   145 }
   147 void
   148 WebSocketChannelChild::OnStart(const nsCString& aProtocol,
   149                                const nsCString& aExtensions)
   150 {
   151   LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this));
   152   SetProtocol(aProtocol);
   153   mNegotiatedExtensions = aExtensions;
   155   if (mListener) {
   156     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   157     mListener->OnStart(mContext);
   158   }
   159 }
   161 class StopEvent : public ChannelEvent
   162 {
   163  public:
   164   StopEvent(WebSocketChannelChild* aChild,
   165             const nsresult& aStatusCode)
   166   : mChild(aChild)
   167   , mStatusCode(aStatusCode)
   168   {}
   170   void Run()
   171   {
   172     mChild->OnStop(mStatusCode);
   173   }
   174  private:
   175   WebSocketChannelChild* mChild;
   176   nsresult mStatusCode;
   177 };
   179 bool
   180 WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
   181 {
   182   if (mEventQ->ShouldEnqueue()) {
   183     mEventQ->Enqueue(new StopEvent(this, aStatusCode));
   184   } else if (mTargetThread) {
   185     DispatchToTargetThread(new StopEvent(this, aStatusCode));
   186   } else {
   187     OnStop(aStatusCode);
   188   }
   189   return true;
   190 }
   192 void
   193 WebSocketChannelChild::OnStop(const nsresult& aStatusCode)
   194 {
   195   LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this));
   196   if (mListener) {
   197     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   198     mListener->OnStop(mContext, aStatusCode);
   199   }
   200 }
   202 class MessageEvent : public ChannelEvent
   203 {
   204  public:
   205   MessageEvent(WebSocketChannelChild* aChild,
   206                const nsCString& aMessage,
   207                bool aBinary)
   208   : mChild(aChild)
   209   , mMessage(aMessage)
   210   , mBinary(aBinary)
   211   {}
   213   void Run()
   214   {
   215     if (!mBinary) {
   216       mChild->OnMessageAvailable(mMessage);
   217     } else {
   218       mChild->OnBinaryMessageAvailable(mMessage);
   219     }
   220   }
   221  private:
   222   WebSocketChannelChild* mChild;
   223   nsCString mMessage;
   224   bool mBinary;
   225 };
   227 bool
   228 WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
   229 {
   230   if (mEventQ->ShouldEnqueue()) {
   231     mEventQ->Enqueue(new MessageEvent(this, aMsg, false));
   232   } else if (mTargetThread) {
   233     DispatchToTargetThread(new MessageEvent(this, aMsg, false));
   234    } else {
   235     OnMessageAvailable(aMsg);
   236   }
   237   return true;
   238 }
   240 void
   241 WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg)
   242 {
   243   LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this));
   244   if (mListener) {
   245     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   246     mListener->OnMessageAvailable(mContext, aMsg);
   247   }
   248 }
   250 bool
   251 WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
   252 {
   253   if (mEventQ->ShouldEnqueue()) {
   254     mEventQ->Enqueue(new MessageEvent(this, aMsg, true));
   255   } else if (mTargetThread) {
   256     DispatchToTargetThread(new MessageEvent(this, aMsg, true));
   257   } else {
   258     OnBinaryMessageAvailable(aMsg);
   259   }
   260   return true;
   261 }
   263 void
   264 WebSocketChannelChild::OnBinaryMessageAvailable(const nsCString& aMsg)
   265 {
   266   LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this));
   267   if (mListener) {
   268     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   269     mListener->OnBinaryMessageAvailable(mContext, aMsg);
   270   }
   271 }
   273 class AcknowledgeEvent : public ChannelEvent
   274 {
   275  public:
   276   AcknowledgeEvent(WebSocketChannelChild* aChild,
   277                    const uint32_t& aSize)
   278   : mChild(aChild)
   279   , mSize(aSize)
   280   {}
   282   void Run()
   283   {
   284     mChild->OnAcknowledge(mSize);
   285   }
   286  private:
   287   WebSocketChannelChild* mChild;
   288   uint32_t mSize;
   289 };
   291 bool
   292 WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize)
   293 {
   294   if (mEventQ->ShouldEnqueue()) {
   295     mEventQ->Enqueue(new AcknowledgeEvent(this, aSize));
   296   } else if (mTargetThread) {
   297     DispatchToTargetThread(new AcknowledgeEvent(this, aSize));
   298   } else {
   299     OnAcknowledge(aSize);
   300   }
   301   return true;
   302 }
   304 void
   305 WebSocketChannelChild::OnAcknowledge(const uint32_t& aSize)
   306 {
   307   LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this));
   308   if (mListener) {
   309     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   310     mListener->OnAcknowledge(mContext, aSize);
   311   }
   312 }
   314 class ServerCloseEvent : public ChannelEvent
   315 {
   316  public:
   317   ServerCloseEvent(WebSocketChannelChild* aChild,
   318                    const uint16_t aCode,
   319                    const nsCString &aReason)
   320   : mChild(aChild)
   321   , mCode(aCode)
   322   , mReason(aReason)
   323   {}
   325   void Run()
   326   {
   327     mChild->OnServerClose(mCode, mReason);
   328   }
   329  private:
   330   WebSocketChannelChild* mChild;
   331   uint16_t               mCode;
   332   nsCString              mReason;
   333 };
   335 bool
   336 WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode,
   337                                          const nsCString& aReason)
   338 {
   339   if (mEventQ->ShouldEnqueue()) {
   340     mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason));
   341   } else if (mTargetThread) {
   342     DispatchToTargetThread(new ServerCloseEvent(this, aCode, aReason));
   343   } else {
   344     OnServerClose(aCode, aReason);
   345   }
   346   return true;
   347 }
   349 void
   350 WebSocketChannelChild::OnServerClose(const uint16_t& aCode,
   351                                      const nsCString& aReason)
   352 {
   353   LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
   354   if (mListener) {
   355     AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
   356     mListener->OnServerClose(mContext, aCode, aReason);
   357   }
   358 }
   360 NS_IMETHODIMP
   361 WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
   362                                  const nsACString &aOrigin,
   363                                  nsIWebSocketListener *aListener,
   364                                  nsISupports *aContext)
   365 {
   366   LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
   368   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
   369   NS_ABORT_IF_FALSE(aURI && aListener && !mListener, 
   370                     "Invalid state for WebSocketChannelChild::AsyncOpen");
   372   mozilla::dom::TabChild* tabChild = nullptr;
   373   nsCOMPtr<nsITabChild> iTabChild;
   374   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
   375                                 NS_GET_IID(nsITabChild),
   376                                 getter_AddRefs(iTabChild));
   377   if (iTabChild) {
   378     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   379   }
   380   if (MissingRequiredTabChild(tabChild, "websocket")) {
   381     return NS_ERROR_ILLEGAL_VALUE;
   382   }
   384   URIParams uri;
   385   SerializeURI(aURI, uri);
   387   // Corresponding release in DeallocPWebSocket
   388   AddIPDLReference();
   390   gNeckoChild->SendPWebSocketConstructor(this, tabChild,
   391                                          IPC::SerializedLoadContext(this));
   392   if (!SendAsyncOpen(uri, nsCString(aOrigin), mProtocol, mEncrypted,
   393                      mPingInterval, mClientSetPingInterval,
   394                      mPingResponseTimeout, mClientSetPingTimeout))
   395     return NS_ERROR_UNEXPECTED;
   397   mOriginalURI = aURI;
   398   mURI = mOriginalURI;
   399   mListener = aListener;
   400   mContext = aContext;
   401   mOrigin = aOrigin;
   402   mWasOpened = 1;
   404   return NS_OK;
   405 }
   407 class CloseEvent : public nsRunnable
   408 {
   409 public:
   410   CloseEvent(WebSocketChannelChild *aChild,
   411              uint16_t aCode,
   412              const nsACString& aReason)
   413     : mChild(aChild)
   414     , mCode(aCode)
   415     , mReason(aReason)
   416   {
   417     MOZ_RELEASE_ASSERT(!NS_IsMainThread());
   418     MOZ_ASSERT(aChild);
   419   }
   420   NS_IMETHOD Run()
   421   {
   422     MOZ_RELEASE_ASSERT(NS_IsMainThread());
   423     mChild->Close(mCode, mReason);
   424     return NS_OK;
   425   }
   426 private:
   427   nsRefPtr<WebSocketChannelChild> mChild;
   428   uint16_t                        mCode;
   429   nsCString                       mReason;
   430 };
   432 NS_IMETHODIMP
   433 WebSocketChannelChild::Close(uint16_t code, const nsACString & reason)
   434 {
   435   if (!NS_IsMainThread()) {
   436     MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread);
   437     return NS_DispatchToMainThread(new CloseEvent(this, code, reason));
   438   }
   439   LOG(("WebSocketChannelChild::Close() %p\n", this));
   441   if (!mIPCOpen || !SendClose(code, nsCString(reason)))
   442     return NS_ERROR_UNEXPECTED;
   443   return NS_OK;
   444 }
   446 class MsgEvent : public nsRunnable
   447 {
   448 public:
   449   MsgEvent(WebSocketChannelChild *aChild,
   450            const nsACString &aMsg,
   451            bool aBinaryMsg)
   452     : mChild(aChild)
   453     , mMsg(aMsg)
   454     , mBinaryMsg(aBinaryMsg)
   455   {
   456     MOZ_RELEASE_ASSERT(!NS_IsMainThread());
   457     MOZ_ASSERT(aChild);
   458   }
   459   NS_IMETHOD Run()
   460   {
   461     MOZ_RELEASE_ASSERT(NS_IsMainThread());
   462     if (mBinaryMsg) {
   463       mChild->SendBinaryMsg(mMsg);
   464     } else {
   465       mChild->SendMsg(mMsg);
   466     }
   467     return NS_OK;
   468   }
   469 private:
   470   nsRefPtr<WebSocketChannelChild> mChild;
   471   nsCString                       mMsg;
   472   bool                            mBinaryMsg;
   473 };
   475 NS_IMETHODIMP
   476 WebSocketChannelChild::SendMsg(const nsACString &aMsg)
   477 {
   478   if (!NS_IsMainThread()) {
   479     MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread);
   480     return NS_DispatchToMainThread(new MsgEvent(this, aMsg, false));
   481   }
   482   LOG(("WebSocketChannelChild::SendMsg() %p\n", this));
   484   if (!mIPCOpen || !SendSendMsg(nsCString(aMsg)))
   485     return NS_ERROR_UNEXPECTED;
   486   return NS_OK;
   487 }
   489 NS_IMETHODIMP
   490 WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg)
   491 {
   492   if (!NS_IsMainThread()) {
   493     MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread);
   494     return NS_DispatchToMainThread(new MsgEvent(this, aMsg, true));
   495   }
   496   LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this));
   498   if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg)))
   499     return NS_ERROR_UNEXPECTED;
   500   return NS_OK;
   501 }
   503 class BinaryStreamEvent : public nsRunnable
   504 {
   505 public:
   506   BinaryStreamEvent(WebSocketChannelChild *aChild,
   507                     OptionalInputStreamParams *aStream,
   508                     uint32_t aLength)
   509     : mChild(aChild)
   510     , mStream(aStream)
   511     , mLength(aLength)
   512   {
   513     MOZ_RELEASE_ASSERT(!NS_IsMainThread());
   514     MOZ_ASSERT(aChild);
   515   }
   516   NS_IMETHOD Run()
   517   {
   518     MOZ_ASSERT(NS_IsMainThread());
   519     mChild->SendBinaryStream(mStream, mLength);
   520     return NS_OK;
   521   }
   522 private:
   523   nsRefPtr<WebSocketChannelChild>      mChild;
   524   nsAutoPtr<OptionalInputStreamParams> mStream;
   525   uint32_t                             mLength;
   526 };
   528 NS_IMETHODIMP
   529 WebSocketChannelChild::SendBinaryStream(nsIInputStream *aStream,
   530                                         uint32_t aLength)
   531 {
   532   OptionalInputStreamParams *stream = new OptionalInputStreamParams();
   533   nsTArray<mozilla::ipc::FileDescriptor> fds;
   534   SerializeInputStream(aStream, *stream, fds);
   536   MOZ_ASSERT(fds.IsEmpty());
   538   if (!NS_IsMainThread()) {
   539     MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread);
   540     return NS_DispatchToMainThread(new BinaryStreamEvent(this, stream, aLength),
   541                                    NS_DISPATCH_NORMAL);
   542   }
   543   return SendBinaryStream(stream, aLength);
   544 }
   546 nsresult
   547 WebSocketChannelChild::SendBinaryStream(OptionalInputStreamParams *aStream,
   548                                         uint32_t aLength)
   549 {
   550   LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this));
   552   nsAutoPtr<OptionalInputStreamParams> stream(aStream);
   554   if (!mIPCOpen || !SendSendBinaryStream(*stream, aLength))
   555     return NS_ERROR_UNEXPECTED;
   556   return NS_OK;
   557 }
   559 NS_IMETHODIMP
   560 WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
   561 {
   562   LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this));
   563   return NS_ERROR_NOT_AVAILABLE;
   564 }
   566 //-----------------------------------------------------------------------------
   567 // WebSocketChannelChild::nsIThreadRetargetableRequest
   568 //-----------------------------------------------------------------------------
   570 NS_IMETHODIMP
   571 WebSocketChannelChild::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
   572 {
   573   nsresult rv = BaseWebSocketChannel::RetargetDeliveryTo(aTargetThread);
   574   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   576   return mEventQ->RetargetDeliveryTo(aTargetThread);
   577 }
   579 } // namespace net
   580 } // namespace mozilla

mercurial