Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/presentation/ipc/PresentationIPCService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/ContentChild.h"
8
#include "mozilla/dom/PermissionMessageUtils.h"
9
#include "mozilla/dom/PPresentation.h"
10
#include "mozilla/dom/TabParent.h"
11
#include "mozilla/ipc/InputStreamUtils.h"
12
#include "mozilla/ipc/URIUtils.h"
13
#include "nsGlobalWindow.h"
14
#include "nsIPresentationListener.h"
15
#include "PresentationCallbacks.h"
16
#include "PresentationChild.h"
17
#include "PresentationContentSessionInfo.h"
18
#include "PresentationIPCService.h"
19
#include "PresentationLog.h"
20
21
using namespace mozilla;
22
using namespace mozilla::dom;
23
using namespace mozilla::ipc;
24
25
namespace {
26
27
PresentationChild* sPresentationChild;
28
29
} // anonymous
30
31
NS_IMPL_ISUPPORTS(PresentationIPCService,
32
                  nsIPresentationService,
33
                  nsIPresentationAvailabilityListener)
34
35
PresentationIPCService::PresentationIPCService()
36
0
{
37
0
  ContentChild* contentChild = ContentChild::GetSingleton();
38
0
  if (NS_WARN_IF(!contentChild || contentChild->IsShuttingDown())) {
39
0
    return;
40
0
  }
41
0
  sPresentationChild = new PresentationChild(this);
42
0
  Unused <<
43
0
    NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
44
0
}
45
46
/* virtual */
47
PresentationIPCService::~PresentationIPCService()
48
0
{
49
0
  Shutdown();
50
0
51
0
  mSessionListeners.Clear();
52
0
  mSessionInfoAtController.Clear();
53
0
  mSessionInfoAtReceiver.Clear();
54
0
  sPresentationChild = nullptr;
55
0
}
56
57
NS_IMETHODIMP
58
PresentationIPCService::StartSession(
59
               const nsTArray<nsString>& aUrls,
60
               const nsAString& aSessionId,
61
               const nsAString& aOrigin,
62
               const nsAString& aDeviceId,
63
               uint64_t aWindowId,
64
               EventTarget* aEventTarget,
65
               nsIPrincipal* aPrincipal,
66
               nsIPresentationServiceCallback* aCallback,
67
               nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
68
0
{
69
0
  if (aWindowId != 0) {
70
0
    AddRespondingSessionId(aWindowId,
71
0
                           aSessionId,
72
0
                           nsIPresentationService::ROLE_CONTROLLER);
73
0
  }
74
0
75
0
  nsPIDOMWindowInner* window =
76
0
    nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
77
0
  TabId tabId = TabParent::GetTabIdFrom(window->GetDocShell());
78
0
79
0
  return SendRequest(aCallback, StartSessionRequest(aUrls,
80
0
                                                    nsString(aSessionId),
81
0
                                                    nsString(aOrigin),
82
0
                                                    nsString(aDeviceId),
83
0
                                                    aWindowId,
84
0
                                                    tabId,
85
0
                                                    IPC::Principal(aPrincipal)));
86
0
}
87
88
NS_IMETHODIMP
89
PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
90
                                           uint8_t aRole,
91
                                           const nsAString& aData)
92
0
{
93
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
94
0
  MOZ_ASSERT(!aData.IsEmpty());
95
0
96
0
  RefPtr<PresentationContentSessionInfo> info =
97
0
    GetSessionInfo(aSessionId, aRole);
98
0
  // data channel session transport is maintained by content process
99
0
  if (info) {
100
0
    return info->Send(aData);
101
0
  }
102
0
103
0
  return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
104
0
                                                        aRole,
105
0
                                                        nsString(aData)));
106
0
}
107
108
NS_IMETHODIMP
109
PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId,
110
                                             uint8_t aRole,
111
                                             const nsACString &aData)
112
0
{
113
0
  MOZ_ASSERT(NS_IsMainThread());
114
0
  MOZ_ASSERT(!aData.IsEmpty());
115
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
116
0
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
117
0
             aRole == nsIPresentationService::ROLE_RECEIVER);
118
0
119
0
  RefPtr<PresentationContentSessionInfo> info =
120
0
    GetSessionInfo(aSessionId, aRole);
121
0
  // data channel session transport is maintained by content process
122
0
  if (info) {
123
0
    return info->SendBinaryMsg(aData);
124
0
  }
125
0
126
0
  return NS_ERROR_NOT_AVAILABLE;
127
0
}
128
129
NS_IMETHODIMP
130
PresentationIPCService::SendSessionBlob(const nsAString& aSessionId,
131
                                        uint8_t aRole,
132
                                        Blob* aBlob)
133
0
{
134
0
  MOZ_ASSERT(NS_IsMainThread());
135
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
136
0
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
137
0
             aRole == nsIPresentationService::ROLE_RECEIVER);
138
0
  MOZ_ASSERT(aBlob);
139
0
140
0
  RefPtr<PresentationContentSessionInfo> info =
141
0
    GetSessionInfo(aSessionId, aRole);
142
0
  // data channel session transport is maintained by content process
143
0
  if (info) {
144
0
    return info->SendBlob(aBlob);
145
0
  }
146
0
147
0
  return NS_ERROR_NOT_AVAILABLE;
148
0
}
149
150
NS_IMETHODIMP
151
PresentationIPCService::CloseSession(const nsAString& aSessionId,
152
                                     uint8_t aRole,
153
                                     uint8_t aClosedReason)
154
0
{
155
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
156
0
157
0
  nsresult rv = SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId),
158
0
                                                         aRole,
159
0
                                                         aClosedReason));
160
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
161
0
    return rv;
162
0
  }
163
0
164
0
  RefPtr<PresentationContentSessionInfo> info =
165
0
    GetSessionInfo(aSessionId, aRole);
166
0
  if (info) {
167
0
    return info->Close(NS_OK);
168
0
  }
169
0
170
0
  return NS_OK;
171
0
}
172
173
NS_IMETHODIMP
174
PresentationIPCService::TerminateSession(const nsAString& aSessionId,
175
                                         uint8_t aRole)
176
0
{
177
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
178
0
179
0
  nsresult rv = SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId), aRole));
180
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
181
0
    return rv;
182
0
  }
183
0
184
0
  RefPtr<PresentationContentSessionInfo> info =
185
0
    GetSessionInfo(aSessionId, aRole);
186
0
  if (info) {
187
0
    return info->Close(NS_OK);
188
0
  }
189
0
190
0
  return NS_OK;
191
0
}
192
193
NS_IMETHODIMP
194
PresentationIPCService::ReconnectSession(const nsTArray<nsString>& aUrls,
195
                                         const nsAString& aSessionId,
196
                                         uint8_t aRole,
197
                                         nsIPresentationServiceCallback* aCallback)
198
0
{
199
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
200
0
201
0
  if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
202
0
    MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
203
0
    return NS_ERROR_INVALID_ARG;
204
0
  }
205
0
206
0
  return SendRequest(aCallback, ReconnectSessionRequest(aUrls,
207
0
                                                        nsString(aSessionId),
208
0
                                                        aRole));
209
0
}
210
211
NS_IMETHODIMP
212
PresentationIPCService::BuildTransport(const nsAString& aSessionId,
213
                                       uint8_t aRole)
214
0
{
215
0
  MOZ_ASSERT(!aSessionId.IsEmpty());
216
0
217
0
  if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
218
0
    MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
219
0
    return NS_ERROR_INVALID_ARG;
220
0
  }
221
0
222
0
  return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId),
223
0
                                                    aRole));
224
0
}
225
226
nsresult
227
PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
228
                                    const PresentationIPCRequest& aRequest)
229
0
{
230
0
  if (sPresentationChild) {
231
0
    PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
232
0
    Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
233
0
  }
234
0
  return NS_OK;
235
0
}
236
237
NS_IMETHODIMP
238
PresentationIPCService::RegisterAvailabilityListener(
239
                                const nsTArray<nsString>& aAvailabilityUrls,
240
                                nsIPresentationAvailabilityListener* aListener)
241
0
{
242
0
  MOZ_ASSERT(NS_IsMainThread());
243
0
  MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
244
0
  MOZ_ASSERT(aListener);
245
0
246
0
  nsTArray<nsString> addedUrls;
247
0
  mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls,
248
0
                                               aListener,
249
0
                                               addedUrls);
250
0
251
0
  if (sPresentationChild && !addedUrls.IsEmpty()) {
252
0
    Unused <<
253
0
      NS_WARN_IF(
254
0
        !sPresentationChild->SendRegisterAvailabilityHandler(addedUrls));
255
0
  }
256
0
  return NS_OK;
257
0
}
258
259
NS_IMETHODIMP
260
PresentationIPCService::UnregisterAvailabilityListener(
261
                                const nsTArray<nsString>& aAvailabilityUrls,
262
                                nsIPresentationAvailabilityListener* aListener)
263
0
{
264
0
  MOZ_ASSERT(NS_IsMainThread());
265
0
266
0
  nsTArray<nsString> removedUrls;
267
0
  mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls,
268
0
                                                  aListener,
269
0
                                                  removedUrls);
270
0
271
0
  if (sPresentationChild && !removedUrls.IsEmpty()) {
272
0
    Unused <<
273
0
      NS_WARN_IF(
274
0
        !sPresentationChild->SendUnregisterAvailabilityHandler(removedUrls));
275
0
  }
276
0
  return NS_OK;
277
0
}
278
279
NS_IMETHODIMP
280
PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
281
                                                uint8_t aRole,
282
                                                nsIPresentationSessionListener* aListener)
283
0
{
284
0
  MOZ_ASSERT(NS_IsMainThread());
285
0
  MOZ_ASSERT(aListener);
286
0
287
0
  nsCOMPtr<nsIPresentationSessionListener> listener;
288
0
  if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
289
0
    mSessionListeners.Put(aSessionId, aListener);
290
0
    return NS_OK;
291
0
  }
292
0
293
0
  mSessionListeners.Put(aSessionId, aListener);
294
0
  if (sPresentationChild) {
295
0
    Unused <<
296
0
      NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(
297
0
        nsString(aSessionId), aRole));
298
0
  }
299
0
  return NS_OK;
300
0
}
301
302
NS_IMETHODIMP
303
PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId,
304
                                                  uint8_t aRole)
305
0
{
306
0
  MOZ_ASSERT(NS_IsMainThread());
307
0
308
0
  UntrackSessionInfo(aSessionId, aRole);
309
0
310
0
  mSessionListeners.Remove(aSessionId);
311
0
  if (sPresentationChild) {
312
0
    Unused <<
313
0
      NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(
314
0
        nsString(aSessionId), aRole));
315
0
  }
316
0
  return NS_OK;
317
0
}
318
319
NS_IMETHODIMP
320
PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId,
321
                                                   nsIPresentationRespondingListener* aListener)
322
0
{
323
0
  MOZ_ASSERT(NS_IsMainThread());
324
0
325
0
  mRespondingListeners.Put(aWindowId, aListener);
326
0
  if (sPresentationChild) {
327
0
    Unused <<
328
0
      NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId));
329
0
  }
330
0
  return NS_OK;
331
0
}
332
333
NS_IMETHODIMP
334
PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
335
0
{
336
0
  MOZ_ASSERT(NS_IsMainThread());
337
0
338
0
  mRespondingListeners.Remove(aWindowId);
339
0
  if (sPresentationChild) {
340
0
    Unused <<
341
0
      NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(
342
0
        aWindowId));
343
0
  }
344
0
  return NS_OK;
345
0
}
346
347
nsresult
348
PresentationIPCService::NotifySessionTransport(const nsString& aSessionId,
349
                                               const uint8_t& aRole,
350
                                               nsIPresentationSessionTransport* aTransport)
351
0
{
352
0
  RefPtr<PresentationContentSessionInfo> info =
353
0
    new PresentationContentSessionInfo(aSessionId, aRole, aTransport);
354
0
355
0
  if (NS_WARN_IF(NS_FAILED(info->Init()))) {
356
0
    return NS_ERROR_NOT_AVAILABLE;
357
0
  }
358
0
359
0
  if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
360
0
    mSessionInfoAtController.Put(aSessionId, info);
361
0
  } else {
362
0
    mSessionInfoAtReceiver.Put(aSessionId, info);
363
0
  }
364
0
  return NS_OK;
365
0
}
366
367
NS_IMETHODIMP
368
PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
369
                                               uint8_t aRole,
370
                                               uint64_t* aWindowId)
371
0
{
372
0
  return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
373
0
}
374
375
NS_IMETHODIMP
376
PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
377
                                                  uint8_t aRole,
378
                                                  const uint64_t aWindowId)
379
0
{
380
0
  return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
381
0
}
382
383
nsresult
384
PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
385
                                                 uint16_t aState,
386
                                                 nsresult aReason)
387
0
{
388
0
  nsCOMPtr<nsIPresentationSessionListener> listener;
389
0
  if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
390
0
    return NS_OK;
391
0
  }
392
0
393
0
  return listener->NotifyStateChange(aSessionId, aState, aReason);
394
0
}
395
396
// Only used for OOP RTCDataChannel session transport case.
397
nsresult
398
PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
399
                                      const nsACString& aData,
400
                                      const bool& aIsBinary)
401
0
{
402
0
  nsCOMPtr<nsIPresentationSessionListener> listener;
403
0
  if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
404
0
    return NS_OK;
405
0
  }
406
0
407
0
  return listener->NotifyMessage(aSessionId, aData, aIsBinary);
408
0
}
409
410
// Only used for OOP RTCDataChannel session transport case.
411
nsresult
412
PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId,
413
                                              uint8_t aRole,
414
                                              nsresult aReason)
415
0
{
416
0
  RefPtr<PresentationContentSessionInfo> info =
417
0
    GetSessionInfo(aSessionId, aRole);
418
0
  if (NS_WARN_IF(!info)) {
419
0
    return NS_ERROR_NOT_AVAILABLE;
420
0
  }
421
0
  Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason));
422
0
  return NS_OK;
423
0
}
424
425
nsresult
426
PresentationIPCService::NotifySessionConnect(uint64_t aWindowId,
427
                                             const nsAString& aSessionId)
428
0
{
429
0
  nsCOMPtr<nsIPresentationRespondingListener> listener;
430
0
  if (NS_WARN_IF(!mRespondingListeners.Get(aWindowId, getter_AddRefs(listener)))) {
431
0
    return NS_OK;
432
0
  }
433
0
434
0
  return listener->NotifySessionConnect(aWindowId, aSessionId);
435
0
}
436
437
NS_IMETHODIMP
438
PresentationIPCService::NotifyAvailableChange(
439
                                   const nsTArray<nsString>& aAvailabilityUrls,
440
                                   bool aAvailable)
441
0
{
442
0
  return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
443
0
                                                      aAvailable);
444
0
}
445
446
NS_IMETHODIMP
447
PresentationIPCService::NotifyReceiverReady(
448
               const nsAString& aSessionId,
449
               uint64_t aWindowId,
450
               bool aIsLoading,
451
               nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
452
0
{
453
0
  MOZ_ASSERT(NS_IsMainThread());
454
0
455
0
  // No actual window uses 0 as its ID.
456
0
  if (NS_WARN_IF(aWindowId == 0)) {
457
0
    return NS_ERROR_NOT_AVAILABLE;
458
0
  }
459
0
460
0
  // Track the responding info for an OOP receiver page.
461
0
  AddRespondingSessionId(aWindowId,
462
0
                         aSessionId,
463
0
                         nsIPresentationService::ROLE_RECEIVER);
464
0
465
0
  Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
466
0
                                                                    aWindowId,
467
0
                                                                    aIsLoading));
468
0
469
0
  // Release mCallback after using aSessionId
470
0
  // because aSessionId is held by mCallback.
471
0
  mCallback = nullptr;
472
0
  return NS_OK;
473
0
}
474
475
NS_IMETHODIMP
476
PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId,
477
                                           uint8_t aRole)
478
0
{
479
0
  PRES_DEBUG("content %s:id[%s], role[%d]\n", __func__,
480
0
             NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
481
0
482
0
  if (nsIPresentationService::ROLE_RECEIVER == aRole) {
483
0
    // Terminate receiver page.
484
0
    uint64_t windowId;
485
0
    if (NS_SUCCEEDED(GetWindowIdBySessionIdInternal(aSessionId,
486
0
                                                    aRole,
487
0
                                                    &windowId))) {
488
0
      NS_DispatchToMainThread(NS_NewRunnableFunction(
489
0
        "dom::PresentationIPCService::UntrackSessionInfo",
490
0
        [windowId]() -> void {
491
0
          PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
492
0
493
0
          if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(windowId)) {
494
0
            window->Close();
495
0
          }
496
0
        }));
497
0
    }
498
0
  }
499
0
500
0
  // Remove the OOP responding info (if it has never been used).
501
0
  RemoveRespondingSessionId(aSessionId, aRole);
502
0
503
0
  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
504
0
    mSessionInfoAtController.Remove(aSessionId);
505
0
  } else {
506
0
    mSessionInfoAtReceiver.Remove(aSessionId);
507
0
  }
508
0
509
0
  return NS_OK;
510
0
}
511
512
void
513
PresentationIPCService::NotifyPresentationChildDestroyed()
514
0
{
515
0
  sPresentationChild = nullptr;
516
0
}
517
518
nsresult
519
PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId,
520
                                                nsIDocShell* aDocShell)
521
0
{
522
0
  MOZ_ASSERT(NS_IsMainThread());
523
0
524
0
  mCallback = new PresentationResponderLoadingCallback(aSessionId);
525
0
  return mCallback->Init(aDocShell);
526
0
}
527
528
nsresult
529
PresentationIPCService::CloseContentSessionTransport(const nsString& aSessionId,
530
                                                     uint8_t aRole,
531
                                                     nsresult aReason)
532
0
{
533
0
  RefPtr<PresentationContentSessionInfo> info =
534
0
    GetSessionInfo(aSessionId, aRole);
535
0
  if (NS_WARN_IF(!info)) {
536
0
    return NS_ERROR_NOT_AVAILABLE;
537
0
  }
538
0
539
0
  return info->Close(aReason);
540
0
}