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_serviceworkerevents_h__
8 #define mozilla_dom_serviceworkerevents_h__
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/Event.h"
12 #include "mozilla/dom/ExtendableEventBinding.h"
13 #include "mozilla/dom/ExtendableMessageEventBinding.h"
14 #include "mozilla/dom/FetchEventBinding.h"
15 #include "mozilla/dom/File.h"
16 #include "mozilla/dom/Promise.h"
17 #include "mozilla/dom/Response.h"
18 #include "mozilla/dom/WorkerCommon.h"
19 
20 #include "nsProxyRelease.h"
21 #include "nsContentUtils.h"
22 
23 class nsIInterceptedChannel;
24 
25 namespace mozilla {
26 namespace dom {
27 
28 class Blob;
29 class Client;
30 class FetchEventOp;
31 class MessagePort;
32 struct PushEventInit;
33 class Request;
34 class ResponseOrPromise;
35 class ServiceWorker;
36 class ServiceWorkerRegistrationInfo;
37 
38 // Defined in ServiceWorker.cpp
39 bool ServiceWorkerVisible(JSContext* aCx, JSObject* aObj);
40 
41 class CancelChannelRunnable final : public Runnable {
42   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
43   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
44   const nsresult mStatus;
45 
46  public:
47   CancelChannelRunnable(
48       nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
49       nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
50       nsresult aStatus);
51 
52   NS_IMETHOD Run() override;
53 };
54 
55 enum ExtendableEventResult { Rejected = 0, Resolved };
56 
57 class ExtendableEventCallback {
58  public:
59   virtual void FinishedWithResult(ExtendableEventResult aResult) = 0;
60 
61   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
62 };
63 
64 class ExtendableEvent : public Event {
65  public:
66   class ExtensionsHandler {
67     friend class ExtendableEvent;
68 
69    public:
70     virtual bool WaitOnPromise(Promise& aPromise) = 0;
71 
72     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
73 
74    protected:
75     virtual ~ExtensionsHandler();
76 
77     // Also returns false if the owning ExtendableEvent is destroyed.
78     bool GetDispatchFlag() const;
79 
80    private:
81     // Only the owning ExtendableEvent is allowed to set this data.
82     void SetExtendableEvent(const ExtendableEvent* const aExtendableEvent);
83 
84     MOZ_NON_OWNING_REF const ExtendableEvent* mExtendableEvent = nullptr;
85   };
86 
87  private:
88   RefPtr<ExtensionsHandler> mExtensionsHandler;
89 
90  protected:
GetDispatchFlag()91   bool GetDispatchFlag() const { return mEvent->mFlags.mIsBeingDispatched; }
92 
93   bool WaitOnPromise(Promise& aPromise);
94 
95   explicit ExtendableEvent(mozilla::dom::EventTarget* aOwner);
96 
~ExtendableEvent()97   ~ExtendableEvent() {
98     if (mExtensionsHandler) {
99       mExtensionsHandler->SetExtendableEvent(nullptr);
100     }
101   };
102 
103  public:
104   NS_DECL_ISUPPORTS_INHERITED
105 
106   void SetKeepAliveHandler(ExtensionsHandler* aExtensionsHandler);
107 
WrapObjectInternal(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)108   virtual JSObject* WrapObjectInternal(
109       JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override {
110     return mozilla::dom::ExtendableEvent_Binding::Wrap(aCx, this, aGivenProto);
111   }
112 
Constructor(mozilla::dom::EventTarget * aOwner,const nsAString & aType,const EventInit & aOptions)113   static already_AddRefed<ExtendableEvent> Constructor(
114       mozilla::dom::EventTarget* aOwner, const nsAString& aType,
115       const EventInit& aOptions) {
116     RefPtr<ExtendableEvent> e = new ExtendableEvent(aOwner);
117     bool trusted = e->Init(aOwner);
118     e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
119     e->SetTrusted(trusted);
120     e->SetComposed(aOptions.mComposed);
121     return e.forget();
122   }
123 
Constructor(const GlobalObject & aGlobal,const nsAString & aType,const EventInit & aOptions)124   static already_AddRefed<ExtendableEvent> Constructor(
125       const GlobalObject& aGlobal, const nsAString& aType,
126       const EventInit& aOptions) {
127     nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
128     return Constructor(target, aType, aOptions);
129   }
130 
131   void WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv);
132 
AsExtendableEvent()133   virtual ExtendableEvent* AsExtendableEvent() override { return this; }
134 };
135 
136 class FetchEvent final : public ExtendableEvent {
137   RefPtr<FetchEventOp> mRespondWithHandler;
138   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
139   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
140   RefPtr<Request> mRequest;
141   RefPtr<Promise> mHandled;
142   nsCString mScriptSpec;
143   nsCString mPreventDefaultScriptSpec;
144   nsString mClientId;
145   nsString mResultingClientId;
146   uint32_t mPreventDefaultLineNumber;
147   uint32_t mPreventDefaultColumnNumber;
148   bool mWaitToRespond;
149 
150  protected:
151   explicit FetchEvent(EventTarget* aOwner);
152   ~FetchEvent();
153 
154  public:
155   NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent,ExtendableEvent)156   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, ExtendableEvent)
157 
158   virtual JSObject* WrapObjectInternal(
159       JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override {
160     return FetchEvent_Binding::Wrap(aCx, this, aGivenProto);
161   }
162 
163   void PostInit(
164       nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
165       nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
166       const nsACString& aScriptSpec);
167 
168   void PostInit(const nsACString& aScriptSpec,
169                 RefPtr<FetchEventOp> aRespondWithHandler);
170 
171   static already_AddRefed<FetchEvent> Constructor(
172       const GlobalObject& aGlobal, const nsAString& aType,
173       const FetchEventInit& aOptions);
174 
WaitToRespond()175   bool WaitToRespond() const { return mWaitToRespond; }
176 
Request_()177   Request* Request_() const {
178     MOZ_ASSERT(mRequest);
179     return mRequest;
180   }
181 
GetClientId(nsAString & aClientId)182   void GetClientId(nsAString& aClientId) const { aClientId = mClientId; }
183 
GetResultingClientId(nsAString & aResultingClientId)184   void GetResultingClientId(nsAString& aResultingClientId) const {
185     aResultingClientId = mResultingClientId;
186   }
187 
Handled()188   Promise* Handled() const { return mHandled; }
189 
190   void RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv);
191 
192   // Pull in the Event version of PreventDefault so we don't get
193   // shadowing warnings.
194   using Event::PreventDefault;
195   void PreventDefault(JSContext* aCx, CallerType aCallerType) override;
196 
197   void ReportCanceled();
198 };
199 
200 class PushMessageData final : public nsISupports, public nsWrapperCache {
201  public:
202   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
203   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushMessageData)
204 
205   virtual JSObject* WrapObject(JSContext* aCx,
206                                JS::Handle<JSObject*> aGivenProto) override;
207 
GetParentObject()208   nsIGlobalObject* GetParentObject() const { return mOwner; }
209 
210   void Json(JSContext* cx, JS::MutableHandle<JS::Value> aRetval,
211             ErrorResult& aRv);
212   void Text(nsAString& aData);
213   void ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval,
214                    ErrorResult& aRv);
215   already_AddRefed<mozilla::dom::Blob> Blob(ErrorResult& aRv);
216 
217   PushMessageData(nsIGlobalObject* aOwner, nsTArray<uint8_t>&& aBytes);
218 
219  private:
220   nsCOMPtr<nsIGlobalObject> mOwner;
221   nsTArray<uint8_t> mBytes;
222   nsString mDecodedText;
223   ~PushMessageData();
224 
225   nsresult EnsureDecodedText();
226   uint8_t* GetContentsCopy();
227 };
228 
229 class PushEvent final : public ExtendableEvent {
230   RefPtr<PushMessageData> mData;
231 
232  protected:
233   explicit PushEvent(mozilla::dom::EventTarget* aOwner);
234   ~PushEvent() = default;
235 
236  public:
237   NS_DECL_ISUPPORTS_INHERITED
238   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PushEvent, ExtendableEvent)
239 
240   virtual JSObject* WrapObjectInternal(
241       JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
242 
243   static already_AddRefed<PushEvent> Constructor(
244       mozilla::dom::EventTarget* aOwner, const nsAString& aType,
245       const PushEventInit& aOptions, ErrorResult& aRv);
246 
Constructor(const GlobalObject & aGlobal,const nsAString & aType,const PushEventInit & aOptions,ErrorResult & aRv)247   static already_AddRefed<PushEvent> Constructor(const GlobalObject& aGlobal,
248                                                  const nsAString& aType,
249                                                  const PushEventInit& aOptions,
250                                                  ErrorResult& aRv) {
251     nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
252     return Constructor(owner, aType, aOptions, aRv);
253   }
254 
GetData()255   PushMessageData* GetData() const { return mData; }
256 };
257 
258 class ExtendableMessageEvent final : public ExtendableEvent {
259   JS::Heap<JS::Value> mData;
260   nsString mOrigin;
261   nsString mLastEventId;
262   RefPtr<Client> mClient;
263   RefPtr<ServiceWorker> mServiceWorker;
264   RefPtr<MessagePort> mMessagePort;
265   nsTArray<RefPtr<MessagePort>> mPorts;
266 
267  protected:
268   explicit ExtendableMessageEvent(EventTarget* aOwner);
269   ~ExtendableMessageEvent();
270 
271  public:
272   NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ExtendableMessageEvent,ExtendableEvent)273   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ExtendableMessageEvent,
274                                                          ExtendableEvent)
275 
276   virtual JSObject* WrapObjectInternal(
277       JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override {
278     return mozilla::dom::ExtendableMessageEvent_Binding::Wrap(aCx, this,
279                                                               aGivenProto);
280   }
281 
282   static already_AddRefed<ExtendableMessageEvent> Constructor(
283       mozilla::dom::EventTarget* aOwner, const nsAString& aType,
284       const ExtendableMessageEventInit& aOptions);
285 
286   static already_AddRefed<ExtendableMessageEvent> Constructor(
287       const GlobalObject& aGlobal, const nsAString& aType,
288       const ExtendableMessageEventInit& aOptions);
289 
290   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
291                ErrorResult& aRv);
292 
293   void GetSource(
294       Nullable<OwningClientOrServiceWorkerOrMessagePort>& aValue) const;
295 
GetOrigin(nsAString & aOrigin)296   void GetOrigin(nsAString& aOrigin) const { aOrigin = mOrigin; }
297 
GetLastEventId(nsAString & aLastEventId)298   void GetLastEventId(nsAString& aLastEventId) const {
299     aLastEventId = mLastEventId;
300   }
301 
302   void GetPorts(nsTArray<RefPtr<MessagePort>>& aPorts);
303 };
304 
305 }  // namespace dom
306 }  // namespace mozilla
307 
308 #endif /* mozilla_dom_serviceworkerevents_h__ */
309