Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/presentation/ipc/PresentationParent.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 "DCPresentationChannelDescription.h"
8
#include "mozilla/dom/ContentProcessManager.h"
9
#include "mozilla/dom/Element.h"
10
#include "mozilla/ipc/InputStreamUtils.h"
11
#include "mozilla/Unused.h"
12
#include "nsIPresentationDeviceManager.h"
13
#include "nsIPresentationSessionTransport.h"
14
#include "nsIPresentationSessionTransportBuilder.h"
15
#include "nsServiceManagerUtils.h"
16
#include "PresentationBuilderParent.h"
17
#include "PresentationParent.h"
18
#include "PresentationService.h"
19
#include "PresentationSessionInfo.h"
20
21
namespace mozilla {
22
namespace dom {
23
24
namespace {
25
26
class PresentationTransportBuilderConstructorIPC final :
27
  public nsIPresentationTransportBuilderConstructor
28
{
29
public:
30
  NS_DECL_ISUPPORTS
31
  NS_DECL_NSIPRESENTATIONTRANSPORTBUILDERCONSTRUCTOR
32
33
  explicit PresentationTransportBuilderConstructorIPC(PresentationParent* aParent)
34
    : mParent(aParent)
35
0
  {
36
0
  }
37
38
private:
39
0
  virtual ~PresentationTransportBuilderConstructorIPC() = default;
40
41
  RefPtr<PresentationParent> mParent;
42
};
43
44
NS_IMPL_ISUPPORTS(PresentationTransportBuilderConstructorIPC,
45
                  nsIPresentationTransportBuilderConstructor)
46
47
NS_IMETHODIMP
48
PresentationTransportBuilderConstructorIPC::CreateTransportBuilder(
49
                              uint8_t aType,
50
                              nsIPresentationSessionTransportBuilder** aRetval)
51
0
{
52
0
  if (NS_WARN_IF(!aRetval)) {
53
0
    return NS_ERROR_INVALID_ARG;
54
0
  }
55
0
56
0
  *aRetval = nullptr;
57
0
58
0
  if (NS_WARN_IF(aType != nsIPresentationChannelDescription::TYPE_TCP &&
59
0
                 aType != nsIPresentationChannelDescription::TYPE_DATACHANNEL)) {
60
0
    return NS_ERROR_INVALID_ARG;
61
0
  }
62
0
63
0
  if (XRE_IsContentProcess()) {
64
0
    MOZ_ASSERT(false,
65
0
               "CreateTransportBuilder can only be invoked in parent process.");
66
0
    return NS_ERROR_FAILURE;
67
0
  }
68
0
69
0
  nsCOMPtr<nsIPresentationSessionTransportBuilder> builder;
70
0
  if (aType == nsIPresentationChannelDescription::TYPE_TCP) {
71
0
    builder = do_CreateInstance(PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID);
72
0
  } else {
73
0
    builder = new PresentationBuilderParent(mParent);
74
0
  }
75
0
76
0
  if (NS_WARN_IF(!builder)) {
77
0
    return NS_ERROR_DOM_OPERATION_ERR;
78
0
  }
79
0
80
0
  builder.forget(aRetval);
81
0
  return NS_OK;
82
0
}
83
84
} // anonymous namespace
85
86
/*
87
 * Implementation of PresentationParent
88
 */
89
90
NS_IMPL_ISUPPORTS(PresentationParent,
91
                  nsIPresentationAvailabilityListener,
92
                  nsIPresentationSessionListener,
93
                  nsIPresentationRespondingListener)
94
95
PresentationParent::PresentationParent()
96
0
{
97
0
}
98
99
/* virtual */ PresentationParent::~PresentationParent()
100
0
{
101
0
}
102
103
bool
104
PresentationParent::Init(ContentParentId aContentParentId)
105
0
{
106
0
  MOZ_ASSERT(!mService);
107
0
  mService = do_GetService(PRESENTATION_SERVICE_CONTRACTID);
108
0
  mChildId = aContentParentId;
109
0
  return NS_WARN_IF(!mService) ? false : true;
110
0
}
111
112
void
113
PresentationParent::ActorDestroy(ActorDestroyReason aWhy)
114
0
{
115
0
  mActorDestroyed = true;
116
0
117
0
  for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) {
118
0
    Unused << NS_WARN_IF(NS_FAILED(mService->
119
0
      UnregisterSessionListener(mSessionIdsAtController[i],
120
0
                                nsIPresentationService::ROLE_CONTROLLER)));
121
0
  }
122
0
  mSessionIdsAtController.Clear();
123
0
124
0
  for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) {
125
0
    Unused << NS_WARN_IF(NS_FAILED(mService->
126
0
      UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER)));
127
0
  }
128
0
  mSessionIdsAtReceiver.Clear();
129
0
130
0
  for (uint32_t i = 0; i < mWindowIds.Length(); i++) {
131
0
    Unused << NS_WARN_IF(NS_FAILED(mService->
132
0
      UnregisterRespondingListener(mWindowIds[i])));
133
0
  }
134
0
  mWindowIds.Clear();
135
0
136
0
  if (!mContentAvailabilityUrls.IsEmpty()) {
137
0
    mService->UnregisterAvailabilityListener(mContentAvailabilityUrls, this);
138
0
  }
139
0
  mService = nullptr;
140
0
}
141
142
mozilla::ipc::IPCResult
143
PresentationParent::RecvPPresentationRequestConstructor(
144
  PPresentationRequestParent* aActor,
145
  const PresentationIPCRequest& aRequest)
146
0
{
147
0
  PresentationRequestParent* actor = static_cast<PresentationRequestParent*>(aActor);
148
0
149
0
  nsresult rv = NS_ERROR_FAILURE;
150
0
  switch (aRequest.type()) {
151
0
    case PresentationIPCRequest::TStartSessionRequest:
152
0
      rv = actor->DoRequest(aRequest.get_StartSessionRequest());
153
0
      break;
154
0
    case PresentationIPCRequest::TSendSessionMessageRequest:
155
0
      rv = actor->DoRequest(aRequest.get_SendSessionMessageRequest());
156
0
      break;
157
0
    case PresentationIPCRequest::TCloseSessionRequest:
158
0
      rv = actor->DoRequest(aRequest.get_CloseSessionRequest());
159
0
      break;
160
0
    case PresentationIPCRequest::TTerminateSessionRequest:
161
0
      rv = actor->DoRequest(aRequest.get_TerminateSessionRequest());
162
0
      break;
163
0
    case PresentationIPCRequest::TReconnectSessionRequest:
164
0
      rv = actor->DoRequest(aRequest.get_ReconnectSessionRequest());
165
0
      break;
166
0
    case PresentationIPCRequest::TBuildTransportRequest:
167
0
      rv = actor->DoRequest(aRequest.get_BuildTransportRequest());
168
0
      break;
169
0
    default:
170
0
      MOZ_CRASH("Unknown PresentationIPCRequest type");
171
0
  }
172
0
173
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
174
0
    return IPC_FAIL_NO_REASON(this);
175
0
  }
176
0
  return IPC_OK();
177
0
}
178
179
PPresentationRequestParent*
180
PresentationParent::AllocPPresentationRequestParent(
181
  const PresentationIPCRequest& aRequest)
182
0
{
183
0
  MOZ_ASSERT(mService);
184
0
  RefPtr<PresentationRequestParent> actor = new PresentationRequestParent(mService, mChildId);
185
0
  return actor.forget().take();
186
0
}
187
188
bool
189
PresentationParent::DeallocPPresentationRequestParent(
190
  PPresentationRequestParent* aActor)
191
0
{
192
0
  RefPtr<PresentationRequestParent> actor =
193
0
    dont_AddRef(static_cast<PresentationRequestParent*>(aActor));
194
0
  return true;
195
0
}
196
197
PPresentationBuilderParent*
198
PresentationParent::AllocPPresentationBuilderParent(const nsString& aSessionId,
199
                                                    const uint8_t& aRole)
200
0
{
201
0
  MOZ_ASSERT_UNREACHABLE("We should never be manually allocating "
202
0
                         "AllocPPresentationBuilderParent actors");
203
0
  return nullptr;
204
0
}
205
206
bool
207
PresentationParent::DeallocPPresentationBuilderParent(
208
  PPresentationBuilderParent* aActor)
209
0
{
210
0
  return true;
211
0
}
212
213
mozilla::ipc::IPCResult
214
PresentationParent::Recv__delete__()
215
0
{
216
0
  return IPC_OK();
217
0
}
218
219
mozilla::ipc::IPCResult
220
PresentationParent::RecvRegisterAvailabilityHandler(
221
                                       nsTArray<nsString>&& aAvailabilityUrls)
222
0
{
223
0
  MOZ_ASSERT(mService);
224
0
225
0
  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(
226
0
                                                             aAvailabilityUrls,
227
0
                                                             this)));
228
0
  mContentAvailabilityUrls.AppendElements(aAvailabilityUrls);
229
0
  return IPC_OK();
230
0
}
231
232
mozilla::ipc::IPCResult
233
PresentationParent::RecvUnregisterAvailabilityHandler(
234
                                        nsTArray<nsString>&& aAvailabilityUrls)
235
0
{
236
0
  MOZ_ASSERT(mService);
237
0
238
0
  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(
239
0
                                                             aAvailabilityUrls,
240
0
                                                             this)));
241
0
  for (const auto& url : aAvailabilityUrls) {
242
0
    mContentAvailabilityUrls.RemoveElement(url);
243
0
  }
244
0
  return IPC_OK();
245
0
}
246
247
/* virtual */ mozilla::ipc::IPCResult
248
PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId,
249
                                               const uint8_t& aRole)
250
0
{
251
0
  MOZ_ASSERT(mService);
252
0
253
0
  // Validate the accessibility (primarily for receiver side) so that a
254
0
  // compromised child process can't fake the ID.
255
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
256
0
                  IsSessionAccessible(aSessionId, aRole, OtherPid()))) {
257
0
    return IPC_OK();
258
0
  }
259
0
260
0
  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
261
0
    mSessionIdsAtController.AppendElement(aSessionId);
262
0
  } else {
263
0
    mSessionIdsAtReceiver.AppendElement(aSessionId);
264
0
  }
265
0
  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
266
0
  return IPC_OK();
267
0
}
268
269
/* virtual */ mozilla::ipc::IPCResult
270
PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId,
271
                                                 const uint8_t& aRole)
272
0
{
273
0
  MOZ_ASSERT(mService);
274
0
  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
275
0
    mSessionIdsAtController.RemoveElement(aSessionId);
276
0
  } else {
277
0
    mSessionIdsAtReceiver.RemoveElement(aSessionId);
278
0
  }
279
0
  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole)));
280
0
  return IPC_OK();
281
0
}
282
283
/* virtual */ mozilla::ipc::IPCResult
284
PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId)
285
0
{
286
0
  MOZ_ASSERT(mService);
287
0
288
0
  mWindowIds.AppendElement(aWindowId);
289
0
  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this)));
290
0
  return IPC_OK();
291
0
}
292
293
/* virtual */ mozilla::ipc::IPCResult
294
PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId)
295
0
{
296
0
  MOZ_ASSERT(mService);
297
0
  mWindowIds.RemoveElement(aWindowId);
298
0
  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId)));
299
0
  return IPC_OK();
300
0
}
301
302
NS_IMETHODIMP
303
PresentationParent::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
304
                                          bool aAvailable)
305
0
{
306
0
  if (NS_WARN_IF(mActorDestroyed ||
307
0
                 !SendNotifyAvailableChange(aAvailabilityUrls,
308
0
                                            aAvailable))) {
309
0
    return NS_ERROR_FAILURE;
310
0
  }
311
0
  return NS_OK;
312
0
}
313
314
NS_IMETHODIMP
315
PresentationParent::NotifyStateChange(const nsAString& aSessionId,
316
                                      uint16_t aState,
317
                                      nsresult aReason)
318
0
{
319
0
  if (NS_WARN_IF(mActorDestroyed ||
320
0
                 !SendNotifySessionStateChange(nsString(aSessionId),
321
0
                                               aState,
322
0
                                               aReason))) {
323
0
    return NS_ERROR_FAILURE;
324
0
  }
325
0
  return NS_OK;
326
0
}
327
328
NS_IMETHODIMP
329
PresentationParent::NotifyMessage(const nsAString& aSessionId,
330
                                  const nsACString& aData,
331
                                  bool aIsBinary)
332
0
{
333
0
  if (NS_WARN_IF(mActorDestroyed ||
334
0
                 !SendNotifyMessage(nsString(aSessionId),
335
0
                                    nsCString(aData),
336
0
                                    aIsBinary))) {
337
0
    return NS_ERROR_FAILURE;
338
0
  }
339
0
  return NS_OK;
340
0
}
341
342
NS_IMETHODIMP
343
PresentationParent::NotifySessionConnect(uint64_t aWindowId,
344
                                         const nsAString& aSessionId)
345
0
{
346
0
  if (NS_WARN_IF(mActorDestroyed ||
347
0
                 !SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) {
348
0
    return NS_ERROR_FAILURE;
349
0
  }
350
0
  return NS_OK;
351
0
}
352
353
mozilla::ipc::IPCResult
354
PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId,
355
                                            const uint64_t& aWindowId,
356
                                            const bool& aIsLoading)
357
0
{
358
0
  MOZ_ASSERT(mService);
359
0
360
0
  nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
361
0
    new PresentationTransportBuilderConstructorIPC(this);
362
0
  Unused << NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId,
363
0
                                                               aWindowId,
364
0
                                                               aIsLoading,
365
0
                                                               constructor)));
366
0
  return IPC_OK();
367
0
}
368
369
mozilla::ipc::IPCResult
370
PresentationParent::RecvNotifyTransportClosed(const nsString& aSessionId,
371
                                              const uint8_t& aRole,
372
                                              const nsresult& aReason)
373
0
{
374
0
  MOZ_ASSERT(mService);
375
0
376
0
  Unused << NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason)));
377
0
  return IPC_OK();
378
0
}
379
380
/*
381
 * Implementation of PresentationRequestParent
382
 */
383
384
NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
385
386
PresentationRequestParent::PresentationRequestParent(nsIPresentationService* aService,
387
                                                     ContentParentId aContentParentId)
388
  : mService(aService)
389
  , mChildId(aContentParentId)
390
0
{
391
0
}
392
393
PresentationRequestParent::~PresentationRequestParent()
394
0
{
395
0
}
396
397
void
398
PresentationRequestParent::ActorDestroy(ActorDestroyReason aWhy)
399
0
{
400
0
  mActorDestroyed = true;
401
0
  mService = nullptr;
402
0
}
403
404
nsresult
405
PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
406
0
{
407
0
  MOZ_ASSERT(mService);
408
0
409
0
  mSessionId = aRequest.sessionId();
410
0
411
0
  RefPtr<EventTarget> eventTarget;
412
0
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
413
0
  RefPtr<TabParent> tp =
414
0
    cpm->GetTopLevelTabParentByProcessAndTabId(mChildId, aRequest.tabId());
415
0
  if (tp) {
416
0
    eventTarget = tp->GetOwnerElement();
417
0
  }
418
0
419
0
  RefPtr<PresentationParent> parent = static_cast<PresentationParent*>(Manager());
420
0
  nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
421
0
    new PresentationTransportBuilderConstructorIPC(parent);
422
0
  return mService->StartSession(aRequest.urls(), aRequest.sessionId(),
423
0
                                aRequest.origin(), aRequest.deviceId(),
424
0
                                aRequest.windowId(), eventTarget,
425
0
                                aRequest.principal(), this, constructor);
426
0
}
427
428
nsresult
429
PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
430
0
{
431
0
  MOZ_ASSERT(mService);
432
0
433
0
  // Validate the accessibility (primarily for receiver side) so that a
434
0
  // compromised child process can't fake the ID.
435
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
436
0
                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
437
0
    return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
438
0
  }
439
0
440
0
  nsresult rv = mService->SendSessionMessage(aRequest.sessionId(),
441
0
                                             aRequest.role(),
442
0
                                             aRequest.data());
443
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
444
0
    return SendResponse(rv);
445
0
  }
446
0
  return SendResponse(NS_OK);
447
0
}
448
449
nsresult
450
PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest)
451
0
{
452
0
  MOZ_ASSERT(mService);
453
0
454
0
  // Validate the accessibility (primarily for receiver side) so that a
455
0
  // compromised child process can't fake the ID.
456
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
457
0
                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
458
0
    return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
459
0
  }
460
0
461
0
  nsresult rv = mService->CloseSession(aRequest.sessionId(),
462
0
                                       aRequest.role(),
463
0
                                       aRequest.closedReason());
464
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
465
0
    return SendResponse(rv);
466
0
  }
467
0
  return SendResponse(NS_OK);
468
0
}
469
470
nsresult
471
PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
472
0
{
473
0
  MOZ_ASSERT(mService);
474
0
475
0
  // Validate the accessibility (primarily for receiver side) so that a
476
0
  // compromised child process can't fake the ID.
477
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
478
0
                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
479
0
    return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
480
0
  }
481
0
482
0
  nsresult rv = mService->TerminateSession(aRequest.sessionId(), aRequest.role());
483
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
484
0
    return SendResponse(rv);
485
0
  }
486
0
  return SendResponse(NS_OK);
487
0
}
488
489
nsresult
490
PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest)
491
0
{
492
0
  MOZ_ASSERT(mService);
493
0
494
0
  // Validate the accessibility (primarily for receiver side) so that a
495
0
  // compromised child process can't fake the ID.
496
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
497
0
    IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
498
0
499
0
    // NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec.
500
0
    // https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation
501
0
    return SendResponse(NS_ERROR_DOM_NOT_FOUND_ERR);
502
0
  }
503
0
504
0
  mSessionId = aRequest.sessionId();
505
0
  return mService->ReconnectSession(aRequest.urls(),
506
0
                                    aRequest.sessionId(),
507
0
                                    aRequest.role(),
508
0
                                    this);
509
0
}
510
511
nsresult
512
PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest)
513
0
{
514
0
  MOZ_ASSERT(mService);
515
0
516
0
  // Validate the accessibility (primarily for receiver side) so that a
517
0
  // compromised child process can't fake the ID.
518
0
  if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
519
0
                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
520
0
    return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
521
0
  }
522
0
523
0
  nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role());
524
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
525
0
    return SendResponse(rv);
526
0
  }
527
0
  return SendResponse(NS_OK);
528
0
}
529
530
NS_IMETHODIMP
531
PresentationRequestParent::NotifySuccess(const nsAString& aUrl)
532
0
{
533
0
  Unused << SendNotifyRequestUrlSelected(nsString(aUrl));
534
0
  return SendResponse(NS_OK);
535
0
}
536
537
NS_IMETHODIMP
538
PresentationRequestParent::NotifyError(nsresult aError)
539
0
{
540
0
  return SendResponse(aError);
541
0
}
542
543
nsresult
544
PresentationRequestParent::SendResponse(nsresult aResult)
545
0
{
546
0
  if (NS_WARN_IF(mActorDestroyed || !Send__delete__(this, aResult))) {
547
0
    return NS_ERROR_FAILURE;
548
0
  }
549
0
550
0
  return NS_OK;
551
0
}
552
553
} // namespace dom
554
} // namespace mozilla