content/base/src/nsDOMDataChannel.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 "nsDOMDataChannel.h"
     9 #ifdef MOZ_LOGGING
    10 #define FORCE_PR_LOG
    11 #endif
    13 #include "base/basictypes.h"
    14 #include "prlog.h"
    16 #ifdef PR_LOGGING
    17 extern PRLogModuleInfo* GetDataChannelLog();
    18 #endif
    19 #undef LOG
    20 #define LOG(args) PR_LOG(GetDataChannelLog(), PR_LOG_DEBUG, args)
    23 #include "nsDOMDataChannelDeclarations.h"
    24 #include "nsDOMDataChannel.h"
    25 #include "nsIDOMFile.h"
    26 #include "nsIDOMDataChannel.h"
    27 #include "nsIDOMMessageEvent.h"
    28 #include "mozilla/DOMEventTargetHelper.h"
    30 #include "nsError.h"
    31 #include "nsAutoPtr.h"
    32 #include "nsContentUtils.h"
    33 #include "nsCxPusher.h"
    34 #include "nsCycleCollectionParticipant.h"
    35 #include "nsIScriptObjectPrincipal.h"
    36 #include "nsNetUtil.h"
    37 #include "nsDOMFile.h"
    39 #include "DataChannel.h"
    41 // Since we've moved the windows.h include down here, we have to explicitly
    42 // undef GetBinaryType, otherwise we'll get really odd conflicts
    43 #ifdef GetBinaryType
    44 #undef GetBinaryType
    45 #endif
    47 using namespace mozilla;
    48 using namespace mozilla::dom;
    50 nsDOMDataChannel::~nsDOMDataChannel()
    51 {
    52   // Don't call us anymore!  Likely isn't an issue (or maybe just less of
    53   // one) once we block GC until all the (appropriate) onXxxx handlers
    54   // are dropped. (See WebRTC spec)
    55   LOG(("Close()ing %p", mDataChannel.get()));
    56   mDataChannel->SetListener(nullptr, nullptr);
    57   mDataChannel->Close();
    58 }
    60 /* virtual */ JSObject*
    61 nsDOMDataChannel::WrapObject(JSContext* aCx)
    62 {
    63   return DataChannelBinding::Wrap(aCx, this);
    64 }
    66 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDataChannel)
    68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMDataChannel,
    69                                                   DOMEventTargetHelper)
    70 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    72 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMDataChannel,
    73                                                 DOMEventTargetHelper)
    74 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    76 NS_IMPL_ADDREF_INHERITED(nsDOMDataChannel, DOMEventTargetHelper)
    77 NS_IMPL_RELEASE_INHERITED(nsDOMDataChannel, DOMEventTargetHelper)
    79 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDataChannel)
    80   NS_INTERFACE_MAP_ENTRY(nsIDOMDataChannel)
    81 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
    83 nsDOMDataChannel::nsDOMDataChannel(already_AddRefed<mozilla::DataChannel>& aDataChannel,
    84                                    nsPIDOMWindow* aWindow)
    85   : DOMEventTargetHelper(aWindow && aWindow->IsOuterWindow() ?
    86                            aWindow->GetCurrentInnerWindow() : aWindow)
    87   , mDataChannel(aDataChannel)
    88   , mBinaryType(DC_BINARY_TYPE_BLOB)
    89 {
    90 }
    92 nsresult
    93 nsDOMDataChannel::Init(nsPIDOMWindow* aDOMWindow)
    94 {
    95   nsresult rv;
    96   nsAutoString urlParam;
    98   MOZ_ASSERT(mDataChannel);
    99   mDataChannel->SetListener(this, nullptr);
   101   // Now grovel through the objects to get a usable origin for onMessage
   102   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDOMWindow);
   103   NS_ENSURE_STATE(sgo);
   104   nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
   105   NS_ENSURE_STATE(scriptContext);
   107   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal(do_QueryInterface(aDOMWindow));
   108   NS_ENSURE_STATE(scriptPrincipal);
   109   nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
   110   NS_ENSURE_STATE(principal);
   112   // Attempt to kill "ghost" DataChannel (if one can happen): but usually too early for check to fail
   113   rv = CheckInnerWindowCorrectness();
   114   NS_ENSURE_SUCCESS(rv,rv);
   116   rv = nsContentUtils::GetUTFOrigin(principal,mOrigin);
   117   LOG(("%s: origin = %s\n",__FUNCTION__,NS_LossyConvertUTF16toASCII(mOrigin).get()));
   118   return rv;
   119 }
   121 NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, open)
   122 NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, error)
   123 NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, close)
   124 NS_IMPL_EVENT_HANDLER(nsDOMDataChannel, message)
   126 NS_IMETHODIMP
   127 nsDOMDataChannel::GetLabel(nsAString& aLabel)
   128 {
   129   mDataChannel->GetLabel(aLabel);
   130   return NS_OK;
   131 }
   133 NS_IMETHODIMP
   134 nsDOMDataChannel::GetProtocol(nsAString& aProtocol)
   135 {
   136   mDataChannel->GetProtocol(aProtocol);
   137   return NS_OK;
   138 }
   140 uint16_t
   141 nsDOMDataChannel::Id() const
   142 {
   143   return mDataChannel->GetStream();
   144 }
   146 NS_IMETHODIMP
   147 nsDOMDataChannel::GetId(uint16_t *aId)
   148 {
   149   *aId = Id();
   150   return NS_OK;
   151 }
   153 uint16_t
   154 nsDOMDataChannel::Stream() const
   155 {
   156   return mDataChannel->GetStream();
   157 }
   159 NS_IMETHODIMP
   160 nsDOMDataChannel::GetStream(uint16_t *aStream)
   161 {
   162   *aStream = Stream();
   163   return NS_OK;
   164 }
   166 // XXX should be GetType()?  Open question for the spec
   167 bool
   168 nsDOMDataChannel::Reliable() const
   169 {
   170   return mDataChannel->GetType() == mozilla::DataChannelConnection::RELIABLE;
   171 }
   173 NS_IMETHODIMP
   174 nsDOMDataChannel::GetReliable(bool* aReliable)
   175 {
   176   *aReliable = Reliable();
   177   return NS_OK;
   178 }
   180 bool
   181 nsDOMDataChannel::Ordered() const
   182 {
   183   return mDataChannel->GetOrdered();
   184 }
   186 NS_IMETHODIMP
   187 nsDOMDataChannel::GetOrdered(bool* aOrdered)
   188 {
   189   *aOrdered = Ordered();
   190   return NS_OK;
   191 }
   193 RTCDataChannelState
   194 nsDOMDataChannel::ReadyState() const
   195 {
   196   return static_cast<RTCDataChannelState>(mDataChannel->GetReadyState());
   197 }
   200 NS_IMETHODIMP
   201 nsDOMDataChannel::GetReadyState(nsAString& aReadyState)
   202 {
   203   uint16_t readyState = mDataChannel->GetReadyState();
   204   // From the WebRTC spec
   205   const char * stateName[] = {
   206     "connecting",
   207     "open",
   208     "closing",
   209     "closed"
   210   };
   211   MOZ_ASSERT(/*readyState >= mozilla::DataChannel::CONNECTING && */ // Always true due to datatypes
   212              readyState <= mozilla::DataChannel::CLOSED);
   213   aReadyState.AssignASCII(stateName[readyState]);
   215   return NS_OK;
   216 }
   218 uint32_t
   219 nsDOMDataChannel::BufferedAmount() const
   220 {
   221   return mDataChannel->GetBufferedAmount();
   222 }
   224 NS_IMETHODIMP
   225 nsDOMDataChannel::GetBufferedAmount(uint32_t* aBufferedAmount)
   226 {
   227   *aBufferedAmount = BufferedAmount();
   228   return NS_OK;
   229 }
   231 NS_IMETHODIMP nsDOMDataChannel::GetBinaryType(nsAString & aBinaryType)
   232 {
   233   switch (mBinaryType) {
   234   case DC_BINARY_TYPE_ARRAYBUFFER:
   235     aBinaryType.AssignLiteral("arraybuffer");
   236     break;
   237   case DC_BINARY_TYPE_BLOB:
   238     aBinaryType.AssignLiteral("blob");
   239     break;
   240   default:
   241     NS_ERROR("Should not happen");
   242   }
   243   return NS_OK;
   244 }
   246 NS_IMETHODIMP
   247 nsDOMDataChannel::SetBinaryType(const nsAString& aBinaryType)
   248 {
   249   if (aBinaryType.EqualsLiteral("arraybuffer")) {
   250     mBinaryType = DC_BINARY_TYPE_ARRAYBUFFER;
   251   } else if (aBinaryType.EqualsLiteral("blob")) {
   252     mBinaryType = DC_BINARY_TYPE_BLOB;
   253   } else  {
   254     return NS_ERROR_INVALID_ARG;
   255   }
   256   return NS_OK;
   257 }
   259 NS_IMETHODIMP
   260 nsDOMDataChannel::Close()
   261 {
   262   mDataChannel->Close();
   263   return NS_OK;
   264 }
   266 // All of the following is copy/pasted from WebSocket.cpp.
   267 void
   268 nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
   269 {
   270   NS_ConvertUTF16toUTF8 msgString(aData);
   271   Send(nullptr, msgString, msgString.Length(), false, aRv);
   272 }
   274 void
   275 nsDOMDataChannel::Send(nsIDOMBlob* aData, ErrorResult& aRv)
   276 {
   277   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   279   nsCOMPtr<nsIInputStream> msgStream;
   280   nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
   281   if (NS_FAILED(rv)) {
   282     aRv.Throw(rv);
   283     return;
   284   }
   286   uint64_t msgLength;
   287   rv = aData->GetSize(&msgLength);
   288   if (NS_FAILED(rv)) {
   289     aRv.Throw(rv);
   290     return;
   291   }
   293   if (msgLength > UINT32_MAX) {
   294     aRv.Throw(NS_ERROR_FILE_TOO_BIG);
   295     return;
   296   }
   298   Send(msgStream, EmptyCString(), msgLength, true, aRv);
   299 }
   301 void
   302 nsDOMDataChannel::Send(const ArrayBuffer& aData, ErrorResult& aRv)
   303 {
   304   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   306   aData.ComputeLengthAndData();
   308   static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
   310   uint32_t len = aData.Length();
   311   char* data = reinterpret_cast<char*>(aData.Data());
   313   nsDependentCSubstring msgString(data, len);
   314   Send(nullptr, msgString, len, true, aRv);
   315 }
   317 void
   318 nsDOMDataChannel::Send(const ArrayBufferView& aData, ErrorResult& aRv)
   319 {
   320   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   322   aData.ComputeLengthAndData();
   324   static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
   326   uint32_t len = aData.Length();
   327   char* data = reinterpret_cast<char*>(aData.Data());
   329   nsDependentCSubstring msgString(data, len);
   330   Send(nullptr, msgString, len, true, aRv);
   331 }
   333 void
   334 nsDOMDataChannel::Send(nsIInputStream* aMsgStream,
   335                        const nsACString& aMsgString,
   336                        uint32_t aMsgLength,
   337                        bool aIsBinary,
   338                        ErrorResult& aRv)
   339 {
   340   MOZ_ASSERT(NS_IsMainThread());
   341   uint16_t state = mDataChannel->GetReadyState();
   343   // In reality, the DataChannel protocol allows this, but we want it to
   344   // look like WebSockets
   345   if (state == mozilla::DataChannel::CONNECTING) {
   346     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   347     return;
   348   }
   350   if (state == mozilla::DataChannel::CLOSING ||
   351       state == mozilla::DataChannel::CLOSED) {
   352     return;
   353   }
   355   MOZ_ASSERT(state == mozilla::DataChannel::OPEN,
   356              "Unknown state in nsDOMDataChannel::Send");
   358   int32_t sent;
   359   if (aMsgStream) {
   360     sent = mDataChannel->SendBinaryStream(aMsgStream, aMsgLength);
   361   } else {
   362     if (aIsBinary) {
   363       sent = mDataChannel->SendBinaryMsg(aMsgString);
   364     } else {
   365       sent = mDataChannel->SendMsg(aMsgString);
   366     }
   367   }
   368   if (sent < 0) {
   369     aRv.Throw(NS_ERROR_FAILURE);
   370   }
   371 }
   373 nsresult
   374 nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
   375                                        bool aBinary)
   376 {
   377   MOZ_ASSERT(NS_IsMainThread());
   379   LOG(("DoOnMessageAvailable%s\n",aBinary ? ((mBinaryType == DC_BINARY_TYPE_BLOB) ? " (blob)" : " (binary)") : ""));
   381   nsresult rv = CheckInnerWindowCorrectness();
   382   if (NS_FAILED(rv)) {
   383     return NS_OK;
   384   }
   385   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
   386   NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
   388   nsIScriptContext* sc = sgo->GetContext();
   389   NS_ENSURE_TRUE(sc, NS_ERROR_FAILURE);
   391   AutoPushJSContext cx(sc->GetNativeContext());
   392   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
   394   JS::Rooted<JS::Value> jsData(cx);
   396   if (aBinary) {
   397     if (mBinaryType == DC_BINARY_TYPE_BLOB) {
   398       rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
   399       NS_ENSURE_SUCCESS(rv, rv);
   400     } else if (mBinaryType == DC_BINARY_TYPE_ARRAYBUFFER) {
   401       JS::Rooted<JSObject*> arrayBuf(cx);
   402       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
   403       NS_ENSURE_SUCCESS(rv, rv);
   404       jsData = OBJECT_TO_JSVAL(arrayBuf);
   405     } else {
   406       NS_RUNTIMEABORT("Unknown binary type!");
   407       return NS_ERROR_UNEXPECTED;
   408     }
   409   } else {
   410     NS_ConvertUTF8toUTF16 utf16data(aData);
   411     JSString* jsString = JS_NewUCStringCopyN(cx, utf16data.get(), utf16data.Length());
   412     NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
   414     jsData = STRING_TO_JSVAL(jsString);
   415   }
   417   nsCOMPtr<nsIDOMEvent> event;
   418   rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
   419   NS_ENSURE_SUCCESS(rv,rv);
   421   nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
   422   rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
   423                                       false, false,
   424                                       jsData, mOrigin, EmptyString(),
   425                                       nullptr);
   426   NS_ENSURE_SUCCESS(rv,rv);
   427   event->SetTrusted(true);
   429   LOG(("%p(%p): %s - Dispatching\n",this,(void*)mDataChannel,__FUNCTION__));
   430   rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
   431   if (NS_FAILED(rv)) {
   432     NS_WARNING("Failed to dispatch the message event!!!");
   433   }
   434   return rv;
   435 }
   437 nsresult
   438 nsDOMDataChannel::OnMessageAvailable(nsISupports* aContext,
   439                                      const nsACString& aMessage)
   440 {
   441   MOZ_ASSERT(NS_IsMainThread());
   442   return DoOnMessageAvailable(aMessage, false);
   443 }
   445 nsresult
   446 nsDOMDataChannel::OnBinaryMessageAvailable(nsISupports* aContext,
   447                                            const nsACString& aMessage)
   448 {
   449   MOZ_ASSERT(NS_IsMainThread());
   450   return DoOnMessageAvailable(aMessage, true);
   451 }
   453 nsresult
   454 nsDOMDataChannel::OnSimpleEvent(nsISupports* aContext, const nsAString& aName)
   455 {
   456   MOZ_ASSERT(NS_IsMainThread());
   458   nsresult rv = CheckInnerWindowCorrectness();
   459   if (NS_FAILED(rv)) {
   460     return NS_OK;
   461   }
   463   nsCOMPtr<nsIDOMEvent> event;
   464   rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
   465   NS_ENSURE_SUCCESS(rv,rv);
   467   rv = event->InitEvent(aName, false, false);
   468   NS_ENSURE_SUCCESS(rv,rv);
   470   event->SetTrusted(true);
   472   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
   473 }
   475 nsresult
   476 nsDOMDataChannel::OnChannelConnected(nsISupports* aContext)
   477 {
   478   LOG(("%p(%p): %s - Dispatching\n",this,(void*)mDataChannel,__FUNCTION__));
   480   return OnSimpleEvent(aContext, NS_LITERAL_STRING("open"));
   481 }
   483 nsresult
   484 nsDOMDataChannel::OnChannelClosed(nsISupports* aContext)
   485 {
   486   LOG(("%p(%p): %s - Dispatching\n",this,(void*)mDataChannel,__FUNCTION__));
   488   return OnSimpleEvent(aContext, NS_LITERAL_STRING("close"));
   489 }
   491 void
   492 nsDOMDataChannel::AppReady()
   493 {
   494   mDataChannel->AppReady();
   495 }
   497 /* static */
   498 nsresult
   499 NS_NewDOMDataChannel(already_AddRefed<mozilla::DataChannel>&& aDataChannel,
   500                      nsPIDOMWindow* aWindow,
   501                      nsIDOMDataChannel** aDomDataChannel)
   502 {
   503   nsRefPtr<nsDOMDataChannel> domdc =
   504     new nsDOMDataChannel(aDataChannel, aWindow);
   506   nsresult rv = domdc->Init(aWindow);
   507   NS_ENSURE_SUCCESS(rv,rv);
   509   return CallQueryInterface(domdc, aDomDataChannel);
   510 }
   512 /* static */
   513 void
   514 NS_DataChannelAppReady(nsIDOMDataChannel* aDomDataChannel)
   515 {
   516   ((nsDOMDataChannel *)aDomDataChannel)->AppReady();
   517 }

mercurial