LCOV - code coverage report
Current view: top level - dom/presentation - PresentationConnection.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 350 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 48 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       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/. */
       6             : 
       7             : #include "PresentationConnection.h"
       8             : 
       9             : #include "ControllerConnectionCollection.h"
      10             : #include "mozilla/AsyncEventDispatcher.h"
      11             : #include "mozilla/dom/DOMException.h"
      12             : #include "mozilla/dom/File.h"
      13             : #include "mozilla/dom/MessageEvent.h"
      14             : #include "mozilla/dom/MessageEventBinding.h"
      15             : #include "mozilla/dom/PresentationConnectionCloseEvent.h"
      16             : #include "mozilla/ErrorNames.h"
      17             : #include "mozilla/DebugOnly.h"
      18             : #include "mozilla/IntegerPrintfMacros.h"
      19             : #include "nsContentUtils.h"
      20             : #include "nsCycleCollectionParticipant.h"
      21             : #include "nsIPresentationService.h"
      22             : #include "nsServiceManagerUtils.h"
      23             : #include "nsStringStream.h"
      24             : #include "PresentationConnectionList.h"
      25             : #include "PresentationLog.h"
      26             : 
      27             : using namespace mozilla;
      28             : using namespace mozilla::dom;
      29             : 
      30             : NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationConnection)
      31             : 
      32           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
      33           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningConnectionList)
      34           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      35             : 
      36           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
      37           0 :   tmp->Shutdown();
      38           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningConnectionList)
      39           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      40             : 
      41           0 : NS_IMPL_ADDREF_INHERITED(PresentationConnection, DOMEventTargetHelper)
      42           0 : NS_IMPL_RELEASE_INHERITED(PresentationConnection, DOMEventTargetHelper)
      43             : 
      44           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationConnection)
      45           0 :   NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionListener)
      46           0 :   NS_INTERFACE_MAP_ENTRY(nsIRequest)
      47           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
      48             : 
      49           0 : PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
      50             :                                                const nsAString& aId,
      51             :                                                const nsAString& aUrl,
      52             :                                                const uint8_t aRole,
      53           0 :                                                PresentationConnectionList* aList)
      54             :   : DOMEventTargetHelper(aWindow)
      55             :   , mId(aId)
      56             :   , mUrl(aUrl)
      57             :   , mState(PresentationConnectionState::Connecting)
      58             :   , mOwningConnectionList(aList)
      59           0 :   , mBinaryType(PresentationConnectionBinaryType::Arraybuffer)
      60             : {
      61           0 :   MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
      62             :              aRole == nsIPresentationService::ROLE_RECEIVER);
      63           0 :   mRole = aRole;
      64           0 : }
      65             : 
      66           0 : /* virtual */ PresentationConnection::~PresentationConnection()
      67             : {
      68           0 : }
      69             : 
      70             : /* static */ already_AddRefed<PresentationConnection>
      71           0 : PresentationConnection::Create(nsPIDOMWindowInner* aWindow,
      72             :                                const nsAString& aId,
      73             :                                const nsAString& aUrl,
      74             :                                const uint8_t aRole,
      75             :                                PresentationConnectionList* aList)
      76             : {
      77           0 :   MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
      78             :              aRole == nsIPresentationService::ROLE_RECEIVER);
      79             :   RefPtr<PresentationConnection> connection =
      80           0 :     new PresentationConnection(aWindow, aId, aUrl, aRole, aList);
      81           0 :   if (NS_WARN_IF(!connection->Init())) {
      82           0 :     return nullptr;
      83             :   }
      84             : 
      85           0 :   if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
      86           0 :     ControllerConnectionCollection::GetSingleton()->AddConnection(connection,
      87           0 :                                                                   aRole);
      88             :   }
      89             : 
      90           0 :   return connection.forget();
      91             : }
      92             : 
      93             : bool
      94           0 : PresentationConnection::Init()
      95             : {
      96           0 :   if (NS_WARN_IF(mId.IsEmpty())) {
      97           0 :     return false;
      98             :   }
      99             : 
     100             :   nsCOMPtr<nsIPresentationService> service =
     101           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     102           0 :   if(NS_WARN_IF(!service)) {
     103           0 :     return false;
     104             :   }
     105             : 
     106           0 :   nsresult rv = service->RegisterSessionListener(mId, mRole, this);
     107           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     108           0 :     return false;
     109             :   }
     110             : 
     111           0 :   rv = AddIntoLoadGroup();
     112           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     113           0 :     return false;
     114             :   }
     115             : 
     116           0 :   return true;
     117             : }
     118             : 
     119             : void
     120           0 : PresentationConnection::Shutdown()
     121             : {
     122           0 :   PRES_DEBUG("connection shutdown:id[%s], role[%d]\n",
     123             :              NS_ConvertUTF16toUTF8(mId).get(), mRole);
     124             : 
     125             :   nsCOMPtr<nsIPresentationService> service =
     126           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     127           0 :   if (NS_WARN_IF(!service)) {
     128           0 :     return;
     129             :   }
     130             : 
     131           0 :   DebugOnly<nsresult> rv = service->UnregisterSessionListener(mId, mRole);
     132           0 :   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "UnregisterSessionListener failed");
     133             : 
     134           0 :   DebugOnly<nsresult> rv2 = RemoveFromLoadGroup();
     135           0 :   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv2), "RemoveFromLoadGroup failed");
     136             : 
     137           0 :   if (mRole == nsIPresentationService::ROLE_CONTROLLER) {
     138           0 :     ControllerConnectionCollection::GetSingleton()->RemoveConnection(this,
     139           0 :                                                                      mRole);
     140             :   }
     141             : }
     142             : 
     143             : /* virtual */ void
     144           0 : PresentationConnection::DisconnectFromOwner()
     145             : {
     146           0 :   Unused << NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway()));
     147           0 :   DOMEventTargetHelper::DisconnectFromOwner();
     148           0 : }
     149             : 
     150             : /* virtual */ JSObject*
     151           0 : PresentationConnection::WrapObject(JSContext* aCx,
     152             :                                    JS::Handle<JSObject*> aGivenProto)
     153             : {
     154           0 :   return PresentationConnectionBinding::Wrap(aCx, this, aGivenProto);
     155             : }
     156             : 
     157             : void
     158           0 : PresentationConnection::GetId(nsAString& aId) const
     159             : {
     160           0 :   aId = mId;
     161           0 : }
     162             : 
     163             : void
     164           0 : PresentationConnection::GetUrl(nsAString& aUrl) const
     165             : {
     166           0 :   aUrl = mUrl;
     167           0 : }
     168             : 
     169             : PresentationConnectionState
     170           0 : PresentationConnection::State() const
     171             : {
     172           0 :   return mState;
     173             : }
     174             : 
     175             : PresentationConnectionBinaryType
     176           0 : PresentationConnection::BinaryType() const
     177             : {
     178           0 :   return mBinaryType;
     179             : }
     180             : 
     181             : void
     182           0 : PresentationConnection::SetBinaryType(PresentationConnectionBinaryType aType)
     183             : {
     184           0 :   mBinaryType = aType;
     185           0 : }
     186             : 
     187             : void
     188           0 : PresentationConnection::Send(const nsAString& aData,
     189             :                              ErrorResult& aRv)
     190             : {
     191             :   // Sending is not allowed if the session is not connected.
     192           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     193           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     194           0 :     return;
     195             :   }
     196             : 
     197             :   nsCOMPtr<nsIPresentationService> service =
     198           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     199           0 :   if(NS_WARN_IF(!service)) {
     200           0 :     AsyncCloseConnectionWithErrorMsg(
     201           0 :       NS_LITERAL_STRING("Unable to send message due to an internal error."));
     202           0 :     return;
     203             :   }
     204             : 
     205           0 :   nsresult rv = service->SendSessionMessage(mId, mRole, aData);
     206           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     207           0 :     const uint32_t kMaxMessageLength = 256;
     208           0 :     nsAutoString data(Substring(aData, 0, kMaxMessageLength));
     209             : 
     210           0 :     AsyncCloseConnectionWithErrorMsg(
     211           0 :       NS_LITERAL_STRING("Unable to send message: \"") + data +
     212           0 :       NS_LITERAL_STRING("\""));
     213             :   }
     214             : }
     215             : 
     216             : void
     217           0 : PresentationConnection::Send(Blob& aData,
     218             :                              ErrorResult& aRv)
     219             : {
     220           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     221           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     222           0 :     return;
     223             :   }
     224             : 
     225             :   nsCOMPtr<nsIPresentationService> service =
     226           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     227           0 :   if(NS_WARN_IF(!service)) {
     228           0 :     AsyncCloseConnectionWithErrorMsg(
     229           0 :       NS_LITERAL_STRING("Unable to send message due to an internal error."));
     230           0 :     return;
     231             :   }
     232             : 
     233           0 :   nsresult rv = service->SendSessionBlob(mId, mRole, &aData);
     234           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     235           0 :     AsyncCloseConnectionWithErrorMsg(
     236           0 :       NS_LITERAL_STRING("Unable to send binary message for Blob message."));
     237             :   }
     238             : }
     239             : 
     240             : void
     241           0 : PresentationConnection::Send(const ArrayBuffer& aData,
     242             :                              ErrorResult& aRv)
     243             : {
     244           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     245           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     246           0 :     return;
     247             :   }
     248             : 
     249             :   nsCOMPtr<nsIPresentationService> service =
     250           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     251           0 :   if(NS_WARN_IF(!service)) {
     252           0 :     AsyncCloseConnectionWithErrorMsg(
     253           0 :       NS_LITERAL_STRING("Unable to send message due to an internal error."));
     254           0 :     return;
     255             :   }
     256             : 
     257           0 :   aData.ComputeLengthAndData();
     258             : 
     259             :   static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
     260             : 
     261           0 :   uint32_t length = aData.Length();
     262           0 :   char* data = reinterpret_cast<char*>(aData.Data());
     263           0 :   nsDependentCSubstring msgString(data, length);
     264             : 
     265           0 :   nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
     266           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     267           0 :     AsyncCloseConnectionWithErrorMsg(
     268           0 :       NS_LITERAL_STRING("Unable to send binary message for ArrayBuffer message."));
     269             :   }
     270             : }
     271             : 
     272             : void
     273           0 : PresentationConnection::Send(const ArrayBufferView& aData,
     274             :                              ErrorResult& aRv)
     275             : {
     276           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     277           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     278           0 :     return;
     279             :   }
     280             : 
     281             :   nsCOMPtr<nsIPresentationService> service =
     282           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     283           0 :   if(NS_WARN_IF(!service)) {
     284           0 :     AsyncCloseConnectionWithErrorMsg(
     285           0 :       NS_LITERAL_STRING("Unable to send message due to an internal error."));
     286           0 :     return;
     287             :   }
     288             : 
     289           0 :   aData.ComputeLengthAndData();
     290             : 
     291             :   static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
     292             : 
     293           0 :   uint32_t length = aData.Length();
     294           0 :   char* data = reinterpret_cast<char*>(aData.Data());
     295           0 :   nsDependentCSubstring msgString(data, length);
     296             : 
     297           0 :   nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
     298           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     299           0 :     AsyncCloseConnectionWithErrorMsg(
     300           0 :       NS_LITERAL_STRING("Unable to send binary message for ArrayBufferView message."));
     301             :   }
     302             : }
     303             : 
     304             : void
     305           0 : PresentationConnection::Close(ErrorResult& aRv)
     306             : {
     307             :   // It only works when the state is CONNECTED or CONNECTING.
     308           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
     309             :                  mState != PresentationConnectionState::Connecting)) {
     310           0 :     return;
     311             :   }
     312             : 
     313             :   nsCOMPtr<nsIPresentationService> service =
     314           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     315           0 :   if(NS_WARN_IF(!service)) {
     316           0 :     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     317           0 :     return;
     318             :   }
     319             : 
     320           0 :   Unused << NS_WARN_IF(NS_FAILED(
     321             :     service->CloseSession(mId,
     322             :                           mRole,
     323             :                           nsIPresentationService::CLOSED_REASON_CLOSED)));
     324             : }
     325             : 
     326             : void
     327           0 : PresentationConnection::Terminate(ErrorResult& aRv)
     328             : {
     329             :   // It only works when the state is CONNECTED.
     330           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     331           0 :     return;
     332             :   }
     333             : 
     334             :   nsCOMPtr<nsIPresentationService> service =
     335           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     336           0 :   if(NS_WARN_IF(!service)) {
     337           0 :     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     338           0 :     return;
     339             :   }
     340             : 
     341           0 :   Unused << NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
     342             : }
     343             : 
     344             : bool
     345           0 : PresentationConnection::Equals(uint64_t aWindowId,
     346             :                                const nsAString& aId)
     347             : {
     348           0 :   return GetOwner() &&
     349           0 :          aWindowId == GetOwner()->WindowID() &&
     350           0 :          mId.Equals(aId);
     351             : }
     352             : 
     353             : NS_IMETHODIMP
     354           0 : PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
     355             :                                           uint16_t aState,
     356             :                                           nsresult aReason)
     357             : {
     358           0 :   PRES_DEBUG("connection state change:id[%s], state[%" PRIx32
     359             :              "], reason[%" PRIx32 "], role[%d]\n",
     360             :              NS_ConvertUTF16toUTF8(aSessionId).get(), aState,
     361             :              static_cast<uint32_t>(aReason), mRole);
     362             : 
     363           0 :   if (!aSessionId.Equals(mId)) {
     364           0 :     return NS_ERROR_INVALID_ARG;
     365             :   }
     366             : 
     367             :   // A terminated connection should always remain in terminated.
     368           0 :   if (mState == PresentationConnectionState::Terminated) {
     369           0 :     return NS_OK;
     370             :   }
     371             : 
     372             :   PresentationConnectionState state;
     373           0 :   switch (aState) {
     374             :     case nsIPresentationSessionListener::STATE_CONNECTING:
     375           0 :       state = PresentationConnectionState::Connecting;
     376           0 :       break;
     377             :     case nsIPresentationSessionListener::STATE_CONNECTED:
     378           0 :       state = PresentationConnectionState::Connected;
     379           0 :       break;
     380             :     case nsIPresentationSessionListener::STATE_CLOSED:
     381           0 :       state = PresentationConnectionState::Closed;
     382           0 :       break;
     383             :     case nsIPresentationSessionListener::STATE_TERMINATED:
     384           0 :       state = PresentationConnectionState::Terminated;
     385           0 :       break;
     386             :     default:
     387           0 :       NS_WARNING("Unknown presentation session state.");
     388           0 :       return NS_ERROR_INVALID_ARG;
     389             :   }
     390             : 
     391           0 :   if (mState == state) {
     392           0 :     return NS_OK;
     393             :   }
     394           0 :   mState = state;
     395             : 
     396           0 :   nsresult rv = ProcessStateChanged(aReason);
     397           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     398           0 :       return rv;
     399             :   }
     400             : 
     401           0 :   if (mOwningConnectionList) {
     402           0 :     mOwningConnectionList->NotifyStateChange(aSessionId, this);
     403             :   }
     404             : 
     405           0 :   return NS_OK;
     406             : }
     407             : 
     408             : nsresult
     409           0 : PresentationConnection::ProcessStateChanged(nsresult aReason)
     410             : {
     411           0 :   switch (mState) {
     412             :     case PresentationConnectionState::Connecting:
     413           0 :       return NS_OK;
     414             :     case PresentationConnectionState::Connected: {
     415             :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
     416           0 :         new AsyncEventDispatcher(this, NS_LITERAL_STRING("connect"), false);
     417           0 :       return asyncDispatcher->PostDOMEvent();
     418             :     }
     419             :     case PresentationConnectionState::Closed: {
     420             :       PresentationConnectionClosedReason reason =
     421           0 :         PresentationConnectionClosedReason::Closed;
     422             : 
     423           0 :       nsString errorMsg;
     424           0 :       if (NS_FAILED(aReason)) {
     425           0 :         reason = PresentationConnectionClosedReason::Error;
     426           0 :         nsCString name, message;
     427             : 
     428             :         // If aReason is not a DOM error, use error name as message.
     429           0 :         if (NS_FAILED(NS_GetNameAndMessageForDOMNSResult(aReason,
     430             :                                                          name,
     431             :                                                          message))) {
     432           0 :           mozilla::GetErrorName(aReason, message);
     433           0 :           message.InsertLiteral("Internal error: ", 0);
     434             :         }
     435           0 :         CopyUTF8toUTF16(message, errorMsg);
     436             :       }
     437             : 
     438             :       Unused <<
     439           0 :         NS_WARN_IF(NS_FAILED(DispatchConnectionCloseEvent(reason, errorMsg)));
     440             : 
     441           0 :       return RemoveFromLoadGroup();
     442             :     }
     443             :     case PresentationConnectionState::Terminated: {
     444             :       // Ensure onterminate event is fired.
     445             :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
     446           0 :         new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
     447           0 :       Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
     448             : 
     449             :       nsCOMPtr<nsIPresentationService> service =
     450           0 :         do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     451           0 :       if (NS_WARN_IF(!service)) {
     452           0 :         return NS_ERROR_NOT_AVAILABLE;
     453             :       }
     454             : 
     455           0 :       nsresult rv = service->UnregisterSessionListener(mId, mRole);
     456           0 :       if(NS_WARN_IF(NS_FAILED(rv))) {
     457           0 :         return rv;
     458             :       }
     459             : 
     460           0 :       return RemoveFromLoadGroup();
     461             :     }
     462             :     default:
     463           0 :       MOZ_CRASH("Unknown presentation session state.");
     464             :       return NS_ERROR_INVALID_ARG;
     465             :   }
     466             : }
     467             : 
     468             : NS_IMETHODIMP
     469           0 : PresentationConnection::NotifyMessage(const nsAString& aSessionId,
     470             :                                       const nsACString& aData,
     471             :                                       bool aIsBinary)
     472             : {
     473           0 :   PRES_DEBUG("connection %s:id[%s], data[%s], role[%d]\n", __func__,
     474             :              NS_ConvertUTF16toUTF8(aSessionId).get(),
     475             :              nsPromiseFlatCString(aData).get(), mRole);
     476             : 
     477           0 :   if (!aSessionId.Equals(mId)) {
     478           0 :     return NS_ERROR_INVALID_ARG;
     479             :   }
     480             : 
     481             :   // No message should be expected when the session is not connected.
     482           0 :   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     483           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     484             :   }
     485             : 
     486           0 :   if (NS_WARN_IF(NS_FAILED(DoReceiveMessage(aData, aIsBinary)))) {
     487           0 :     AsyncCloseConnectionWithErrorMsg(
     488           0 :       NS_LITERAL_STRING("Unable to receive a message."));
     489           0 :     return NS_ERROR_FAILURE;
     490             :   }
     491             : 
     492           0 :   return NS_OK;
     493             : }
     494             : 
     495             : nsresult
     496           0 : PresentationConnection::DoReceiveMessage(const nsACString& aData, bool aIsBinary)
     497             : {
     498             :   // Transform the data.
     499           0 :   AutoJSAPI jsapi;
     500           0 :   if (!jsapi.Init(GetOwner())) {
     501           0 :     return NS_ERROR_FAILURE;
     502             :   }
     503           0 :   JSContext* cx = jsapi.cx();
     504           0 :   JS::Rooted<JS::Value> jsData(cx);
     505             : 
     506             :   nsresult rv;
     507           0 :   if (aIsBinary) {
     508           0 :     if (mBinaryType == PresentationConnectionBinaryType::Blob) {
     509             :       RefPtr<Blob> blob =
     510           0 :         Blob::CreateStringBlob(GetOwner(), aData, EmptyString());
     511           0 :       MOZ_ASSERT(blob);
     512             : 
     513           0 :       if (!ToJSValue(cx, blob, &jsData)) {
     514           0 :         return NS_ERROR_FAILURE;
     515             :       }
     516           0 :     } else if (mBinaryType == PresentationConnectionBinaryType::Arraybuffer) {
     517           0 :       JS::Rooted<JSObject*> arrayBuf(cx);
     518           0 :       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
     519           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     520           0 :         return rv;
     521             :       }
     522           0 :       jsData.setObject(*arrayBuf);
     523             :     } else {
     524           0 :       NS_RUNTIMEABORT("Unknown binary type!");
     525           0 :       return NS_ERROR_UNEXPECTED;
     526             :     }
     527             :   } else {
     528           0 :     NS_ConvertUTF8toUTF16 utf16Data(aData);
     529           0 :     if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
     530           0 :       return NS_ERROR_FAILURE;
     531             :     }
     532             :   }
     533             : 
     534           0 :   return DispatchMessageEvent(jsData);
     535             : }
     536             : 
     537             : nsresult
     538           0 : PresentationConnection::DispatchConnectionCloseEvent(
     539             :   PresentationConnectionClosedReason aReason,
     540             :   const nsAString& aMessage,
     541             :   bool aDispatchNow)
     542             : {
     543           0 :   if (mState != PresentationConnectionState::Closed) {
     544           0 :     MOZ_ASSERT(false, "The connection state should be closed.");
     545             :     return NS_ERROR_FAILURE;
     546             :   }
     547             : 
     548           0 :   PresentationConnectionCloseEventInit init;
     549           0 :   init.mReason = aReason;
     550           0 :   init.mMessage = aMessage;
     551             : 
     552             :   RefPtr<PresentationConnectionCloseEvent> closedEvent =
     553           0 :     PresentationConnectionCloseEvent::Constructor(this,
     554           0 :                                                    NS_LITERAL_STRING("close"),
     555           0 :                                                    init);
     556           0 :   closedEvent->SetTrusted(true);
     557             : 
     558           0 :   if (aDispatchNow) {
     559             :     bool ignore;
     560           0 :     return DOMEventTargetHelper::DispatchEvent(closedEvent, &ignore);
     561             :   }
     562             : 
     563             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     564           0 :     new AsyncEventDispatcher(this, static_cast<Event*>(closedEvent));
     565           0 :   return asyncDispatcher->PostDOMEvent();
     566             : }
     567             : 
     568             : nsresult
     569           0 : PresentationConnection::DispatchMessageEvent(JS::Handle<JS::Value> aData)
     570             : {
     571           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
     572           0 :   if (NS_WARN_IF(!global)) {
     573           0 :     return NS_ERROR_NOT_AVAILABLE;
     574             :   }
     575             : 
     576             :   // Get the origin.
     577           0 :   nsAutoString origin;
     578           0 :   nsresult rv = nsContentUtils::GetUTFOrigin(global->PrincipalOrNull(), origin);
     579           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     580           0 :     return rv;
     581             :   }
     582             : 
     583           0 :   RefPtr<MessageEvent> messageEvent = new MessageEvent(this, nullptr, nullptr);
     584             : 
     585           0 :   messageEvent->InitMessageEvent(nullptr,
     586           0 :                                  NS_LITERAL_STRING("message"),
     587             :                                  false, false, aData, origin,
     588           0 :                                  EmptyString(), nullptr,
     589           0 :                                  Sequence<OwningNonNull<MessagePort>>());
     590           0 :   messageEvent->SetTrusted(true);
     591             : 
     592             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     593           0 :     new AsyncEventDispatcher(this, static_cast<Event*>(messageEvent));
     594           0 :   return asyncDispatcher->PostDOMEvent();
     595             : }
     596             : 
     597             : nsresult
     598           0 : PresentationConnection::ProcessConnectionWentAway()
     599             : {
     600           0 :   if (mState != PresentationConnectionState::Connected &&
     601           0 :       mState != PresentationConnectionState::Connecting) {
     602             :     // If the state is not connected or connecting, do not need to
     603             :     // close the session.
     604           0 :     return NS_OK;
     605             :   }
     606             : 
     607           0 :   mState = PresentationConnectionState::Terminated;
     608             : 
     609             :   nsCOMPtr<nsIPresentationService> service =
     610           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     611           0 :   if (NS_WARN_IF(!service)) {
     612           0 :     return NS_ERROR_NOT_AVAILABLE;
     613             :   }
     614             : 
     615           0 :   return service->CloseSession(
     616           0 :     mId, mRole, nsIPresentationService::CLOSED_REASON_WENTAWAY);
     617             : }
     618             : 
     619             : NS_IMETHODIMP
     620           0 : PresentationConnection::GetName(nsACString &aResult)
     621             : {
     622           0 :   aResult.AssignLiteral("about:presentation-connection");
     623           0 :   return NS_OK;
     624             : }
     625             : 
     626             : NS_IMETHODIMP
     627           0 : PresentationConnection::IsPending(bool* aRetval)
     628             : {
     629           0 :   *aRetval = true;
     630           0 :   return NS_OK;
     631             : }
     632             : 
     633             : NS_IMETHODIMP
     634           0 : PresentationConnection::GetStatus(nsresult* aStatus)
     635             : {
     636           0 :   *aStatus = NS_OK;
     637           0 :   return NS_OK;
     638             : }
     639             : 
     640             : NS_IMETHODIMP
     641           0 : PresentationConnection::Cancel(nsresult aStatus)
     642             : {
     643             :   nsCOMPtr<nsIRunnable> event =
     644           0 :     NewRunnableMethod("dom::PresentationConnection::ProcessConnectionWentAway",
     645             :                       this,
     646           0 :                       &PresentationConnection::ProcessConnectionWentAway);
     647           0 :   return NS_DispatchToCurrentThread(event);
     648             : }
     649             : NS_IMETHODIMP
     650           0 : PresentationConnection::Suspend(void)
     651             : {
     652           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     653             : }
     654             : NS_IMETHODIMP
     655           0 : PresentationConnection::Resume(void)
     656             : {
     657           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     658             : }
     659             : 
     660             : NS_IMETHODIMP
     661           0 : PresentationConnection::GetLoadGroup(nsILoadGroup** aLoadGroup)
     662             : {
     663           0 :   *aLoadGroup = nullptr;
     664             : 
     665           0 :   nsCOMPtr<nsIDocument> doc = GetOwner() ? GetOwner()->GetExtantDoc() : nullptr;
     666           0 :   if (!doc) {
     667           0 :     return NS_ERROR_FAILURE;
     668             :   }
     669             : 
     670           0 :   *aLoadGroup = doc->GetDocumentLoadGroup().take();
     671           0 :   return NS_OK;
     672             : }
     673             : 
     674             : NS_IMETHODIMP
     675           0 : PresentationConnection::SetLoadGroup(nsILoadGroup * aLoadGroup)
     676             : {
     677           0 :   return NS_ERROR_UNEXPECTED;
     678             : }
     679             : 
     680             : NS_IMETHODIMP
     681           0 : PresentationConnection::GetLoadFlags(nsLoadFlags* aLoadFlags)
     682             : {
     683           0 :   *aLoadFlags = nsIRequest::LOAD_BACKGROUND;
     684           0 :   return NS_OK;
     685             : }
     686             : 
     687             : NS_IMETHODIMP
     688           0 : PresentationConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
     689             : {
     690           0 :   return NS_OK;
     691             : }
     692             : 
     693             : nsresult
     694           0 : PresentationConnection::AddIntoLoadGroup()
     695             : {
     696             :   // Avoid adding to loadgroup multiple times
     697           0 :   if (mWeakLoadGroup) {
     698           0 :     return NS_OK;
     699             :   }
     700             : 
     701           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     702           0 :   nsresult rv = GetLoadGroup(getter_AddRefs(loadGroup));
     703           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     704           0 :     return rv;
     705             :   }
     706             : 
     707           0 :   rv = loadGroup->AddRequest(this, nullptr);
     708           0 :   if(NS_WARN_IF(NS_FAILED(rv))) {
     709           0 :     return rv;
     710             :   }
     711             : 
     712           0 :   mWeakLoadGroup = do_GetWeakReference(loadGroup);
     713           0 :   return NS_OK;
     714             : }
     715             : 
     716             : nsresult
     717           0 : PresentationConnection::RemoveFromLoadGroup()
     718             : {
     719           0 :   if (!mWeakLoadGroup) {
     720           0 :     return NS_OK;
     721             :   }
     722             : 
     723           0 :   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
     724           0 :   if (loadGroup) {
     725           0 :     mWeakLoadGroup = nullptr;
     726           0 :     return loadGroup->RemoveRequest(this, nullptr, NS_OK);
     727             :   }
     728             : 
     729           0 :   return NS_OK;
     730             : }
     731             : 
     732             : void
     733           0 : PresentationConnection::AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage)
     734             : {
     735           0 :   if (mState == PresentationConnectionState::Terminated) {
     736           0 :     return;
     737             :   }
     738             : 
     739           0 :   nsString message = nsString(aMessage);
     740           0 :   RefPtr<PresentationConnection> self = this;
     741           0 :   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
     742             :     "dom::PresentationConnection::AsyncCloseConnectionWithErrorMsg",
     743           0 :     [self, message]() -> void {
     744             :       // Set |mState| to |PresentationConnectionState::Closed| here to avoid
     745             :       // calling |ProcessStateChanged|.
     746           0 :       self->mState = PresentationConnectionState::Closed;
     747             : 
     748             :       // Make sure dispatching the event and closing the connection are invoked
     749             :       // at the same time by setting |aDispatchNow| to true.
     750           0 :       Unused << NS_WARN_IF(NS_FAILED(
     751             :         self->DispatchConnectionCloseEvent(PresentationConnectionClosedReason::Error,
     752             :                                            message,
     753             :                                            true)));
     754             : 
     755             :       nsCOMPtr<nsIPresentationService> service =
     756           0 :         do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     757           0 :       if(NS_WARN_IF(!service)) {
     758           0 :         return;
     759             :       }
     760             : 
     761           0 :       Unused << NS_WARN_IF(NS_FAILED(
     762             :         service->CloseSession(self->mId,
     763             :                               self->mRole,
     764             :                               nsIPresentationService::CLOSED_REASON_ERROR)));
     765           0 :     });
     766             : 
     767           0 :   Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)));
     768             : }

Generated by: LCOV version 1.13