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_serviceworkerop_h__ 8 #define mozilla_dom_serviceworkerop_h__ 9 10 #include <functional> 11 12 #include "nsISupportsImpl.h" 13 14 #include "ServiceWorkerEvents.h" 15 #include "ServiceWorkerOpPromise.h" 16 #include "mozilla/Attributes.h" 17 #include "mozilla/Maybe.h" 18 #include "mozilla/RefPtr.h" 19 #include "mozilla/dom/PromiseNativeHandler.h" 20 #include "mozilla/dom/RemoteWorkerChild.h" 21 #include "mozilla/dom/ServiceWorkerOpArgs.h" 22 #include "mozilla/dom/WorkerRunnable.h" 23 24 namespace mozilla { 25 namespace dom { 26 27 class FetchEventOpProxyChild; 28 29 class ServiceWorkerOp : public RemoteWorkerChild::Op { 30 public: 31 // `aCallback` will be called when the operation completes or is canceled. 32 static already_AddRefed<ServiceWorkerOp> Create( 33 ServiceWorkerOpArgs&& aArgs, 34 std::function<void(const ServiceWorkerOpResult&)>&& aCallback); 35 36 ServiceWorkerOp( 37 ServiceWorkerOpArgs&& aArgs, 38 std::function<void(const ServiceWorkerOpResult&)>&& aCallback); 39 40 ServiceWorkerOp(const ServiceWorkerOp&) = delete; 41 42 ServiceWorkerOp& operator=(const ServiceWorkerOp&) = delete; 43 44 ServiceWorkerOp(ServiceWorkerOp&&) = default; 45 46 ServiceWorkerOp& operator=(ServiceWorkerOp&&) = default; 47 48 // Returns `true` if the operation has started and `false` otherwise. 49 bool MaybeStart(RemoteWorkerChild* aOwner, 50 RemoteWorkerChild::State& aState) final; 51 52 void Cancel() final; 53 54 protected: 55 ~ServiceWorkerOp(); 56 57 bool Started() const; 58 59 bool IsTerminationOp() const; 60 61 // Override to provide a runnable that's not a `ServiceWorkerOpRunnable.` 62 virtual RefPtr<WorkerRunnable> GetRunnable(WorkerPrivate* aWorkerPrivate); 63 64 // Overridden by ServiceWorkerOp subclasses, it should return true when 65 // the ServiceWorkerOp was executed successfully (and false if it did fail). 66 // Content throwing an exception during event dispatch is still considered 67 // success. 68 virtual bool Exec(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; 69 70 // Override to reject any additional MozPromises that subclasses may contain. 71 virtual void RejectAll(nsresult aStatus); 72 73 ServiceWorkerOpArgs mArgs; 74 75 // Subclasses must settle this promise when appropriate. 76 MozPromiseHolder<ServiceWorkerOpPromise> mPromiseHolder; 77 78 private: 79 class ServiceWorkerOpRunnable; 80 81 bool mStarted = false; 82 }; 83 84 class ExtendableEventOp : public ServiceWorkerOp, 85 public ExtendableEventCallback { 86 using ServiceWorkerOp::ServiceWorkerOp; 87 88 protected: 89 ~ExtendableEventOp() = default; 90 91 void FinishedWithResult(ExtendableEventResult aResult) override; 92 }; 93 94 class FetchEventOp final : public ExtendableEventOp, 95 public PromiseNativeHandler { 96 using ExtendableEventOp::ExtendableEventOp; 97 98 public: 99 NS_DECL_THREADSAFE_ISUPPORTS 100 101 /** 102 * This must be called once and only once before the first call to 103 * `MaybeStart()`; `aActor` will be used for `AsyncLog()` and 104 * `ReportCanceled().` 105 */ 106 void SetActor(RefPtr<FetchEventOpProxyChild> aActor); 107 108 void RevokeActor(FetchEventOpProxyChild* aActor); 109 110 // This must be called at most once before the first call to `MaybeStart().` 111 RefPtr<FetchEventRespondWithPromise> GetRespondWithPromise(); 112 113 // This must be called when `FetchEvent::RespondWith()` is called. 114 void RespondWithCalledAt(const nsCString& aRespondWithScriptSpec, 115 uint32_t aRespondWithLineNumber, 116 uint32_t aRespondWithColumnNumber); 117 118 void ReportCanceled(const nsCString& aPreventDefaultScriptSpec, 119 uint32_t aPreventDefaultLineNumber, 120 uint32_t aPreventDefaultColumnNumber); 121 122 private: 123 class AutoCancel; 124 125 ~FetchEventOp(); 126 127 bool Exec(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; 128 129 void RejectAll(nsresult aStatus) override; 130 131 void FinishedWithResult(ExtendableEventResult aResult) override; 132 133 /** 134 * `{Resolved,Reject}Callback()` are use to handle the 135 * `FetchEvent::RespondWith()` promise. 136 */ 137 void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override; 138 139 void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override; 140 141 void MaybeFinished(); 142 143 // Requires mRespondWithClosure to be non-empty. 144 void AsyncLog(const nsCString& aMessageName, nsTArray<nsString> aParams); 145 146 void AsyncLog(const nsCString& aScriptSpec, uint32_t aLineNumber, 147 uint32_t aColumnNumber, const nsCString& aMessageName, 148 nsTArray<nsString> aParams); 149 150 void GetRequestURL(nsAString& aOutRequestURL); 151 152 // A failure code means that the dispatch failed. 153 nsresult DispatchFetchEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate); 154 155 // Worker Launcher thread only. Used for `AsyncLog().` 156 RefPtr<FetchEventOpProxyChild> mActor; 157 158 /** 159 * Created on the Worker Launcher thread and settled on the worker thread. 160 * If this isn't settled before `mPromiseHolder` (which it should be), 161 * `FetchEventOpChild` will cancel the intercepted network request. 162 */ 163 MozPromiseHolder<FetchEventRespondWithPromise> mRespondWithPromiseHolder; 164 165 // Worker thread only. 166 Maybe<ExtendableEventResult> mResult; 167 bool mPostDispatchChecksDone = false; 168 169 // Worker thread only; set when `FetchEvent::RespondWith()` is called. 170 Maybe<FetchEventRespondWithClosure> mRespondWithClosure; 171 172 // Must be set to `nullptr` on the worker thread because `Promise`'s 173 // destructor must be called on the worker thread. 174 RefPtr<Promise> mHandled; 175 }; 176 177 } // namespace dom 178 } // namespace mozilla 179 180 #endif // mozilla_dom_serviceworkerop_h__ 181