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