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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "RemoteServiceWorkerContainerImpl.h"
8 
9 #include <utility>
10 
11 #include "mozilla/ipc/BackgroundChild.h"
12 #include "mozilla/ipc/PBackgroundChild.h"
13 #include "ServiceWorkerContainerChild.h"
14 
15 namespace mozilla {
16 namespace dom {
17 
18 using mozilla::ipc::BackgroundChild;
19 using mozilla::ipc::PBackgroundChild;
20 using mozilla::ipc::ResponseRejectReason;
21 
~RemoteServiceWorkerContainerImpl()22 RemoteServiceWorkerContainerImpl::~RemoteServiceWorkerContainerImpl() {
23   Shutdown();
24   MOZ_DIAGNOSTIC_ASSERT(!mOuter);
25 }
26 
Shutdown()27 void RemoteServiceWorkerContainerImpl::Shutdown() {
28   if (mShutdown) {
29     return;
30   }
31   mShutdown = true;
32 
33   if (mActor) {
34     mActor->RevokeOwner(this);
35     mActor->MaybeStartTeardown();
36     mActor = nullptr;
37   }
38 }
39 
AddContainer(ServiceWorkerContainer * aOuter)40 void RemoteServiceWorkerContainerImpl::AddContainer(
41     ServiceWorkerContainer* aOuter) {
42   MOZ_DIAGNOSTIC_ASSERT(aOuter);
43   MOZ_DIAGNOSTIC_ASSERT(!mOuter);
44   mOuter = aOuter;
45 }
46 
RemoveContainer(ServiceWorkerContainer * aOuter)47 void RemoteServiceWorkerContainerImpl::RemoveContainer(
48     ServiceWorkerContainer* aOuter) {
49   MOZ_DIAGNOSTIC_ASSERT(aOuter);
50   MOZ_DIAGNOSTIC_ASSERT(mOuter == aOuter);
51   mOuter = nullptr;
52 }
53 
Register(const ClientInfo & aClientInfo,const nsACString & aScopeURL,const nsACString & aScriptURL,ServiceWorkerUpdateViaCache aUpdateViaCache,ServiceWorkerRegistrationCallback && aSuccessCB,ServiceWorkerFailureCallback && aFailureCB) const54 void RemoteServiceWorkerContainerImpl::Register(
55     const ClientInfo& aClientInfo, const nsACString& aScopeURL,
56     const nsACString& aScriptURL, ServiceWorkerUpdateViaCache aUpdateViaCache,
57     ServiceWorkerRegistrationCallback&& aSuccessCB,
58     ServiceWorkerFailureCallback&& aFailureCB) const {
59   if (!mActor) {
60     CopyableErrorResult rv;
61     rv.ThrowInvalidStateError("Can't register service worker");
62     aFailureCB(std::move(rv));
63     return;
64   }
65 
66   mActor->SendRegister(
67       aClientInfo.ToIPC(), nsCString(aScopeURL), nsCString(aScriptURL),
68       aUpdateViaCache,
69       [successCB = std::move(aSuccessCB), aFailureCB](
70           const IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&
71               aResult) {
72         if (aResult.type() ==
73             IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult::
74                 TCopyableErrorResult) {
75           // application layer error
76           auto& rv = aResult.get_CopyableErrorResult();
77           MOZ_DIAGNOSTIC_ASSERT(rv.Failed());
78           aFailureCB(CopyableErrorResult(rv));
79           return;
80         }
81         // success
82         auto& ipcDesc = aResult.get_IPCServiceWorkerRegistrationDescriptor();
83         successCB(ServiceWorkerRegistrationDescriptor(ipcDesc));
84       },
85       [aFailureCB](ResponseRejectReason&& aReason) {
86         // IPC layer error
87         CopyableErrorResult rv;
88         rv.ThrowInvalidStateError("Failed to register service worker");
89         aFailureCB(std::move(rv));
90       });
91 }
92 
GetRegistration(const ClientInfo & aClientInfo,const nsACString & aURL,ServiceWorkerRegistrationCallback && aSuccessCB,ServiceWorkerFailureCallback && aFailureCB) const93 void RemoteServiceWorkerContainerImpl::GetRegistration(
94     const ClientInfo& aClientInfo, const nsACString& aURL,
95     ServiceWorkerRegistrationCallback&& aSuccessCB,
96     ServiceWorkerFailureCallback&& aFailureCB) const {
97   if (!mActor) {
98     aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
99     return;
100   }
101 
102   mActor->SendGetRegistration(
103       aClientInfo.ToIPC(), nsCString(aURL),
104       [successCB = std::move(aSuccessCB), aFailureCB](
105           const IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&
106               aResult) {
107         if (aResult.type() ==
108             IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult::
109                 TCopyableErrorResult) {
110           auto& rv = aResult.get_CopyableErrorResult();
111           // If rv is a failure then this is an application layer error.  Note,
112           // though, we also reject with NS_OK to indicate that we just didn't
113           // find a registration.
114           aFailureCB(CopyableErrorResult(rv));
115           return;
116         }
117         // success
118         auto& ipcDesc = aResult.get_IPCServiceWorkerRegistrationDescriptor();
119         successCB(ServiceWorkerRegistrationDescriptor(ipcDesc));
120       },
121       [aFailureCB](ResponseRejectReason&& aReason) {
122         // IPC layer error
123         aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
124       });
125 }
126 
GetRegistrations(const ClientInfo & aClientInfo,ServiceWorkerRegistrationListCallback && aSuccessCB,ServiceWorkerFailureCallback && aFailureCB) const127 void RemoteServiceWorkerContainerImpl::GetRegistrations(
128     const ClientInfo& aClientInfo,
129     ServiceWorkerRegistrationListCallback&& aSuccessCB,
130     ServiceWorkerFailureCallback&& aFailureCB) const {
131   if (!mActor) {
132     aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
133     return;
134   }
135 
136   mActor->SendGetRegistrations(
137       aClientInfo.ToIPC(),
138       [successCB = std::move(aSuccessCB), aFailureCB](
139           const IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult&
140               aResult) {
141         if (aResult.type() ==
142             IPCServiceWorkerRegistrationDescriptorListOrCopyableErrorResult::
143                 TCopyableErrorResult) {
144           // application layer error
145           auto& rv = aResult.get_CopyableErrorResult();
146           MOZ_DIAGNOSTIC_ASSERT(rv.Failed());
147           aFailureCB(CopyableErrorResult(rv));
148           return;
149         }
150         // success
151         auto& ipcList =
152             aResult.get_IPCServiceWorkerRegistrationDescriptorList();
153         nsTArray<ServiceWorkerRegistrationDescriptor> list(
154             ipcList.values().Length());
155         for (auto& ipcDesc : ipcList.values()) {
156           list.AppendElement(ServiceWorkerRegistrationDescriptor(ipcDesc));
157         }
158         successCB(std::move(list));
159       },
160       [aFailureCB](ResponseRejectReason&& aReason) {
161         // IPC layer error
162         aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
163       });
164 }
165 
GetReady(const ClientInfo & aClientInfo,ServiceWorkerRegistrationCallback && aSuccessCB,ServiceWorkerFailureCallback && aFailureCB) const166 void RemoteServiceWorkerContainerImpl::GetReady(
167     const ClientInfo& aClientInfo,
168     ServiceWorkerRegistrationCallback&& aSuccessCB,
169     ServiceWorkerFailureCallback&& aFailureCB) const {
170   if (!mActor) {
171     aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
172     return;
173   }
174 
175   mActor->SendGetReady(
176       aClientInfo.ToIPC(),
177       [successCB = std::move(aSuccessCB), aFailureCB](
178           const IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult&
179               aResult) {
180         if (aResult.type() ==
181             IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult::
182                 TCopyableErrorResult) {
183           // application layer error
184           auto& rv = aResult.get_CopyableErrorResult();
185           MOZ_DIAGNOSTIC_ASSERT(rv.Failed());
186           aFailureCB(CopyableErrorResult(rv));
187           return;
188         }
189         // success
190         auto& ipcDesc = aResult.get_IPCServiceWorkerRegistrationDescriptor();
191         successCB(ServiceWorkerRegistrationDescriptor(ipcDesc));
192       },
193       [aFailureCB](ResponseRejectReason&& aReason) {
194         // IPC layer error
195         aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
196       });
197 }
198 
RemoteServiceWorkerContainerImpl()199 RemoteServiceWorkerContainerImpl::RemoteServiceWorkerContainerImpl()
200     : mOuter(nullptr), mShutdown(false) {
201   PBackgroundChild* parentActor =
202       BackgroundChild::GetOrCreateForCurrentThread();
203   if (NS_WARN_IF(!parentActor)) {
204     Shutdown();
205     return;
206   }
207 
208   RefPtr<ServiceWorkerContainerChild> actor =
209       ServiceWorkerContainerChild::Create();
210   if (NS_WARN_IF(!actor)) {
211     Shutdown();
212     return;
213   }
214 
215   PServiceWorkerContainerChild* sentActor =
216       parentActor->SendPServiceWorkerContainerConstructor(actor);
217   if (NS_WARN_IF(!sentActor)) {
218     Shutdown();
219     return;
220   }
221   MOZ_DIAGNOSTIC_ASSERT(sentActor == actor);
222 
223   mActor = std::move(actor);
224   mActor->SetOwner(this);
225 }
226 
RevokeActor(ServiceWorkerContainerChild * aActor)227 void RemoteServiceWorkerContainerImpl::RevokeActor(
228     ServiceWorkerContainerChild* aActor) {
229   MOZ_DIAGNOSTIC_ASSERT(mActor);
230   MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
231   mActor->RevokeOwner(this);
232   mActor = nullptr;
233 
234   mShutdown = true;
235 }
236 
237 }  // namespace dom
238 }  // namespace mozilla
239