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 : }
|