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 #ifndef mozilla_dom_serviceworkercontainer_h__
8 #define mozilla_dom_serviceworkercontainer_h__
9 
10 #include "mozilla/DOMEventTargetHelper.h"
11 #include "mozilla/dom/ServiceWorkerUtils.h"
12 
13 class nsIGlobalWindow;
14 
15 namespace mozilla {
16 namespace dom {
17 
18 class ClientPostMessageArgs;
19 struct MessageEventInit;
20 class Promise;
21 struct RegistrationOptions;
22 class ServiceWorker;
23 
24 // Lightweight serviceWorker APIs collection.
25 class ServiceWorkerContainer final : public DOMEventTargetHelper {
26  public:
27   class Inner {
28    public:
29     virtual void AddContainer(ServiceWorkerContainer* aOuter) = 0;
30 
31     virtual void RemoveContainer(ServiceWorkerContainer* aOuter) = 0;
32 
33     virtual void Register(const ClientInfo& aClientInfo,
34                           const nsACString& aScopeURL,
35                           const nsACString& aScriptURL,
36                           ServiceWorkerUpdateViaCache aUpdateViaCache,
37                           ServiceWorkerRegistrationCallback&& aSuccessCB,
38                           ServiceWorkerFailureCallback&& aFailureCB) const = 0;
39 
40     virtual void GetRegistration(
41         const ClientInfo& aClientInfo, const nsACString& aURL,
42         ServiceWorkerRegistrationCallback&& aSuccessCB,
43         ServiceWorkerFailureCallback&& aFailureCB) const = 0;
44 
45     virtual void GetRegistrations(
46         const ClientInfo& aClientInfo,
47         ServiceWorkerRegistrationListCallback&& aSuccessCB,
48         ServiceWorkerFailureCallback&& aFailureCB) const = 0;
49 
50     virtual void GetReady(const ClientInfo& aClientInfo,
51                           ServiceWorkerRegistrationCallback&& aSuccessCB,
52                           ServiceWorkerFailureCallback&& aFailureCB) const = 0;
53 
54     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
55   };
56 
57   NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerContainer,DOMEventTargetHelper)58   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerContainer,
59                                            DOMEventTargetHelper)
60 
61   IMPL_EVENT_HANDLER(controllerchange)
62   IMPL_EVENT_HANDLER(error)
63   IMPL_EVENT_HANDLER(messageerror)
64 
65   // Almost a manual expansion of IMPL_EVENT_HANDLER(message), but
66   // with the additional StartMessages() when setting the handler, as
67   // required by the spec.
68   inline mozilla::dom::EventHandlerNonNull* GetOnmessage() {
69     return GetEventHandler(nsGkAtoms::onmessage);
70   }
SetOnmessage(mozilla::dom::EventHandlerNonNull * aCallback)71   inline void SetOnmessage(mozilla::dom::EventHandlerNonNull* aCallback) {
72     SetEventHandler(nsGkAtoms::onmessage, aCallback);
73     StartMessages();
74   }
75 
76   static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
77 
78   static already_AddRefed<ServiceWorkerContainer> Create(
79       nsIGlobalObject* aGlobal);
80 
81   virtual JSObject* WrapObject(JSContext* aCx,
82                                JS::Handle<JSObject*> aGivenProto) override;
83 
84   already_AddRefed<Promise> Register(const nsAString& aScriptURL,
85                                      const RegistrationOptions& aOptions,
86                                      ErrorResult& aRv);
87 
88   already_AddRefed<ServiceWorker> GetController();
89 
90   already_AddRefed<Promise> GetRegistration(const nsAString& aDocumentURL,
91                                             ErrorResult& aRv);
92 
93   already_AddRefed<Promise> GetRegistrations(ErrorResult& aRv);
94 
95   void StartMessages();
96 
97   Promise* GetReady(ErrorResult& aRv);
98 
99   // Testing only.
100   void GetScopeForUrl(const nsAString& aUrl, nsString& aScope,
101                       ErrorResult& aRv);
102 
103   // DOMEventTargetHelper
104   void DisconnectFromOwner() override;
105 
106   // Invalidates |mControllerWorker| and dispatches a "controllerchange"
107   // event.
108   void ControllerChanged(ErrorResult& aRv);
109 
110   void ReceiveMessage(const ClientPostMessageArgs& aArgs);
111 
112  private:
113   ServiceWorkerContainer(
114       nsIGlobalObject* aGlobal,
115       already_AddRefed<ServiceWorkerContainer::Inner> aInner);
116 
117   ~ServiceWorkerContainer();
118 
119   // Utility method to get the global if its present and if certain
120   // additional validaty checks pass.  One of these additional checks
121   // verifies the global can access storage.  Since storage access can
122   // vary based on user settings we want to often provide some error
123   // message if the storage check fails.  This method takes an optional
124   // callback that can be used to report the storage failure to the
125   // devtools console.
126   nsIGlobalObject* GetGlobalIfValid(
127       ErrorResult& aRv,
128       const std::function<void(Document*)>&& aStorageFailureCB = nullptr) const;
129 
130   struct ReceivedMessage;
131 
132   // Dispatch a Runnable that dispatches the given message on this
133   // object. When the owner of this object is a Window, the Runnable
134   // is dispatched on the corresponding TabGroup.
135   void EnqueueReceivedMessageDispatch(RefPtr<ReceivedMessage> aMessage);
136 
137   template <typename F>
138   void RunWithJSContext(F&& aCallable);
139 
140   void DispatchMessage(RefPtr<ReceivedMessage> aMessage);
141 
142   // When it fails, returning boolean means whether it's because deserailization
143   // failed or not.
144   static Result<Ok, bool> FillInMessageEventInit(JSContext* aCx,
145                                                  nsIGlobalObject* aGlobal,
146                                                  ReceivedMessage& aMessage,
147                                                  MessageEventInit& aInit,
148                                                  ErrorResult& aRv);
149 
150   RefPtr<Inner> mInner;
151 
152   // This only changes when a worker hijacks everything in its scope by calling
153   // claim.
154   RefPtr<ServiceWorker> mControllerWorker;
155 
156   RefPtr<Promise> mReadyPromise;
157   MozPromiseRequestHolder<ServiceWorkerRegistrationPromise> mReadyPromiseHolder;
158 
159   // Set after StartMessages() has been called.
160   bool mMessagesStarted = false;
161 
162   // Queue holding messages posted from service worker as long as
163   // StartMessages() hasn't been called.
164   nsTArray<RefPtr<ReceivedMessage>> mPendingMessages;
165 };
166 
167 }  // namespace dom
168 }  // namespace mozilla
169 
170 #endif /* mozilla_dom_serviceworkercontainer_h__ */
171