FetchService.h (9825B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #ifndef _mozilla_dom_FetchService_h 5 #define _mozilla_dom_FetchService_h 6 7 #include "mozilla/ErrorResult.h" 8 #include "mozilla/MozPromise.h" 9 #include "mozilla/RefPtr.h" 10 #include "mozilla/dom/FetchDriver.h" 11 #include "mozilla/dom/FetchTypes.h" 12 #include "mozilla/dom/PerformanceTimingTypes.h" 13 #include "mozilla/dom/SafeRefPtr.h" 14 #include "mozilla/ipc/PBackgroundSharedTypes.h" 15 #include "mozilla/net/NeckoChannelParams.h" 16 #include "nsIChannel.h" 17 #include "nsIObserver.h" 18 #include "nsTHashMap.h" 19 20 class nsILoadGroup; 21 class nsIPrincipal; 22 class nsICookieJarSettings; 23 class PerformanceStorage; 24 25 namespace mozilla::dom { 26 27 class InternalRequest; 28 class InternalResponse; 29 class ClientInfo; 30 class ServiceWorkerDescriptor; 31 32 using FetchServiceResponse = SafeRefPtr<InternalResponse>; 33 using FetchServiceResponseAvailablePromise = 34 MozPromise<FetchServiceResponse, CopyableErrorResult, true>; 35 using FetchServiceResponseTimingPromise = 36 MozPromise<ResponseTiming, CopyableErrorResult, true>; 37 using FetchServiceResponseEndPromise = 38 MozPromise<ResponseEndArgs, CopyableErrorResult, true>; 39 40 class FetchServicePromises final { 41 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchServicePromises); 42 43 public: 44 FetchServicePromises(); 45 46 RefPtr<FetchServiceResponseAvailablePromise> GetResponseAvailablePromise(); 47 RefPtr<FetchServiceResponseTimingPromise> GetResponseTimingPromise(); 48 RefPtr<FetchServiceResponseEndPromise> GetResponseEndPromise(); 49 50 bool IsResponseAvailablePromiseResolved() { 51 return mAvailablePromiseResolved; 52 } 53 bool IsResponseTimingPromiseResolved() { return mTimingPromiseResolved; } 54 bool IsResponseEndPromiseResolved() { return mEndPromiseResolved; } 55 56 void ResolveResponseAvailablePromise(FetchServiceResponse&& aResponse, 57 StaticString aMethodName); 58 void RejectResponseAvailablePromise(const CopyableErrorResult&& aError, 59 StaticString aMethodName); 60 void ResolveResponseTimingPromise(ResponseTiming&& aTiming, 61 StaticString aMethodName); 62 void RejectResponseTimingPromise(const CopyableErrorResult&& aError, 63 StaticString aMethodName); 64 void ResolveResponseEndPromise(ResponseEndArgs&& aArgs, 65 StaticString aMethodName); 66 void RejectResponseEndPromise(const CopyableErrorResult&& aError, 67 StaticString aMethodName); 68 69 private: 70 ~FetchServicePromises() = default; 71 72 RefPtr<FetchServiceResponseAvailablePromise::Private> mAvailablePromise; 73 RefPtr<FetchServiceResponseTimingPromise::Private> mTimingPromise; 74 RefPtr<FetchServiceResponseEndPromise::Private> mEndPromise; 75 76 // The MozPromise interface intentionally does not expose synchronous access 77 // to the internal resolved/rejected state. Instead, we track whether or not 78 // we've called Resolve on the FetchServicePromises. 79 bool mAvailablePromiseResolved = false; 80 bool mTimingPromiseResolved = false; 81 bool mEndPromiseResolved = false; 82 }; 83 84 /** 85 * FetchService is a singleton object which designed to be used in parent 86 * process main thread only. It is used to handle the special fetch requests 87 * from ServiceWorkers(by Navigation Preload) and PFetch. 88 * 89 * FetchService creates FetchInstance internally to represent each Fetch 90 * request. It supports an asynchronous fetching, FetchServicePromises is 91 * created when a Fetch starts, once the response is ready or any error happens, 92 * the FetchServicePromises would be resolved or rejected. The promises 93 * consumers can set callbacks to handle the Fetch result. 94 */ 95 class FetchService final : public nsIObserver { 96 public: 97 NS_DECL_ISUPPORTS 98 NS_DECL_NSIOBSERVER 99 100 // Used for ServiceWorkerNavigationPreload 101 struct NavigationPreloadArgs { 102 SafeRefPtr<InternalRequest> mRequest; 103 nsCOMPtr<nsIChannel> mChannel; 104 }; 105 106 // Used for content process worker thread fetch() 107 struct WorkerFetchArgs { 108 SafeRefPtr<InternalRequest> mRequest; 109 mozilla::ipc::PrincipalInfo mPrincipalInfo; 110 nsCString mWorkerScript; 111 Maybe<ClientInfo> mClientInfo; 112 Maybe<ServiceWorkerDescriptor> mController; 113 Maybe<net::CookieJarSettingsArgs> mCookieJarSettings; 114 bool mNeedOnDataAvailable; 115 nsCOMPtr<nsICSPEventListener> mCSPEventListener; 116 uint64_t mAssociatedBrowsingContextID; 117 nsCOMPtr<nsISerialEventTarget> mEventTarget; 118 nsID mActorID; 119 bool mIsThirdPartyContext; 120 MozPromiseRequestHolder<FetchServiceResponseEndPromise> 121 mResponseEndPromiseHolder; 122 RefPtr<GenericPromise::Private> mFetchParentPromise; 123 bool mIsOn3PCBExceptionList; 124 }; 125 126 // Used for content process main thread fetch() 127 // Currently this is just used for keepalive request 128 // This would be further used for sending all main thread fetch requests 129 // through PFetch 130 // See Bug 1897129. 131 struct MainThreadFetchArgs { 132 SafeRefPtr<InternalRequest> mRequest; 133 mozilla::ipc::PrincipalInfo mPrincipalInfo; 134 Maybe<net::CookieJarSettingsArgs> mCookieJarSettings; 135 bool mNeedOnDataAvailable; 136 nsCOMPtr<nsICSPEventListener> mCSPEventListener; 137 uint64_t mAssociatedBrowsingContextID; 138 nsCOMPtr<nsISerialEventTarget> mEventTarget; 139 nsID mActorID; 140 bool mIsThirdPartyContext{false}; 141 }; 142 143 struct UnknownArgs {}; 144 145 using FetchArgs = Variant<NavigationPreloadArgs, WorkerFetchArgs, 146 MainThreadFetchArgs, UnknownArgs>; 147 148 enum class FetchArgsType { 149 NavigationPreload, 150 WorkerFetch, 151 MainThreadFetch, 152 Unknown, 153 }; 154 static already_AddRefed<FetchService> GetInstance(); 155 156 static RefPtr<FetchServicePromises> NetworkErrorResponse( 157 nsresult aRv, const FetchArgs& aArgs = AsVariant(UnknownArgs{})); 158 159 FetchService(); 160 161 // This method creates a FetchInstance to trigger fetch. 162 // The created FetchInstance is saved in mFetchInstanceTable 163 RefPtr<FetchServicePromises> Fetch(FetchArgs&& aArgs); 164 165 void CancelFetch(const RefPtr<FetchServicePromises>&& aPromises, 166 bool aForceAbort); 167 168 MozPromiseRequestHolder<FetchServiceResponseEndPromise>& 169 GetResponseEndPromiseHolder(const RefPtr<FetchServicePromises>& aPromises); 170 171 private: 172 /** 173 * FetchInstance is an internal representation for each Fetch created by 174 * FetchService. 175 * FetchInstance is also a FetchDriverObserver which has responsibility to 176 * resolve/reject the FetchServicePromises. 177 * FetchInstance triggers fetch by instancing a FetchDriver with proper 178 * initialization. The general usage flow of FetchInstance is as follows 179 * 180 * RefPtr<FetchInstance> fetch = MakeRefPtr<FetchInstance>(); 181 * fetch->Initialize(FetchArgs args); 182 * RefPtr<FetchServicePromises> fetch->Fetch(); 183 */ 184 class FetchInstance final : public FetchDriverObserver { 185 public: 186 FetchInstance() = default; 187 188 nsresult Initialize(FetchArgs&& aArgs); 189 190 const FetchArgs& Args() { return mArgs; } 191 MozPromiseRequestHolder<FetchServiceResponseEndPromise>& 192 GetResponseEndPromiseHolder() { 193 MOZ_ASSERT(mArgs.is<WorkerFetchArgs>()); 194 return mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder; 195 } 196 197 RefPtr<FetchServicePromises> Fetch(); 198 199 void Cancel(bool aForceAbort); 200 201 bool IsLocalHostFetch() const; 202 203 /* FetchDriverObserver interface */ 204 void OnResponseEnd(FetchDriverObserver::EndReason aReason, 205 JS::Handle<JS::Value> aReasonDetails) override; 206 void OnResponseAvailableInternal( 207 SafeRefPtr<InternalResponse> aResponse) override; 208 bool NeedOnDataAvailable() override; 209 void OnDataAvailable() override; 210 void FlushConsoleReport() override; 211 void OnReportPerformanceTiming() override; 212 void OnNotifyNetworkMonitorAlternateStack(uint64_t aChannelID) override; 213 214 private: 215 ~FetchInstance() = default; 216 nsCOMPtr<nsISerialEventTarget> GetBackgroundEventTarget(); 217 nsID GetActorID(); 218 219 SafeRefPtr<InternalRequest> mRequest; 220 nsCOMPtr<nsIPrincipal> mPrincipal; 221 nsCOMPtr<nsILoadGroup> mLoadGroup; 222 nsCOMPtr<nsICookieJarSettings> mCookieJarSettings; 223 RefPtr<PerformanceStorage> mPerformanceStorage; 224 FetchArgs mArgs{AsVariant(FetchService::UnknownArgs())}; 225 RefPtr<FetchDriver> mFetchDriver; 226 SafeRefPtr<InternalResponse> mResponse; 227 RefPtr<FetchServicePromises> mPromises; 228 FetchArgsType mArgsType; 229 Atomic<bool> mActorDying{false}; 230 }; 231 232 ~FetchService(); 233 234 nsresult RegisterNetworkObserver(); 235 nsresult UnregisterNetworkObserver(); 236 237 // Update pending keepalive fetch requests count 238 void IncrementKeepAliveRequestCount(const nsACString& aOrigin); 239 void DecrementKeepAliveRequestCount(const nsACString& aOrigin); 240 241 // Check if the number of pending keepalive fetch requests exceeds the 242 // configured limit 243 // We limit the number of pending keepalive requests on two levels: 244 // 1. per origin - controlled by pref 245 // dom.fetchKeepalive.request_limit_per_origin) 246 // 2. per browser instance - controlled by pref 247 // dom.fetchKeepalive.total_request_limit 248 bool DoesExceedsKeepaliveResourceLimits(const nsACString& aOrigin); 249 250 // This is a container to manage the generated fetches. 251 nsTHashMap<nsRefPtrHashKey<FetchServicePromises>, RefPtr<FetchInstance> > 252 mFetchInstanceTable; 253 bool mObservingNetwork{false}; 254 bool mOffline{false}; 255 256 // map to key origin to number of pending keepalive fetch requests 257 nsTHashMap<nsCStringHashKey, uint32_t> mPendingKeepAliveRequestsPerOrigin; 258 259 // total pending keepalive fetch requests per browser instance 260 uint32_t mTotalKeepAliveRequests{0}; 261 }; 262 263 } // namespace mozilla::dom 264 265 #endif // _mozilla_dom_FetchService_h