265 lines
9.6 KiB
C++
265 lines
9.6 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
#ifndef _mozilla_dom_FetchService_h
|
|
#define _mozilla_dom_FetchService_h
|
|
|
|
#include "nsIChannel.h"
|
|
#include "nsIObserver.h"
|
|
#include "nsTHashMap.h"
|
|
#include "mozilla/ErrorResult.h"
|
|
#include "mozilla/MozPromise.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/dom/FetchDriver.h"
|
|
#include "mozilla/dom/FetchTypes.h"
|
|
#include "mozilla/dom/PerformanceTimingTypes.h"
|
|
#include "mozilla/dom/SafeRefPtr.h"
|
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
|
#include "mozilla/net/NeckoChannelParams.h"
|
|
|
|
class nsILoadGroup;
|
|
class nsIPrincipal;
|
|
class nsICookieJarSettings;
|
|
class PerformanceStorage;
|
|
|
|
namespace mozilla::dom {
|
|
|
|
class InternalRequest;
|
|
class InternalResponse;
|
|
class ClientInfo;
|
|
class ServiceWorkerDescriptor;
|
|
|
|
using FetchServiceResponse = SafeRefPtr<InternalResponse>;
|
|
using FetchServiceResponseAvailablePromise =
|
|
MozPromise<FetchServiceResponse, CopyableErrorResult, true>;
|
|
using FetchServiceResponseTimingPromise =
|
|
MozPromise<ResponseTiming, CopyableErrorResult, true>;
|
|
using FetchServiceResponseEndPromise =
|
|
MozPromise<ResponseEndArgs, CopyableErrorResult, true>;
|
|
|
|
class FetchServicePromises final {
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchServicePromises);
|
|
|
|
public:
|
|
FetchServicePromises();
|
|
|
|
RefPtr<FetchServiceResponseAvailablePromise> GetResponseAvailablePromise();
|
|
RefPtr<FetchServiceResponseTimingPromise> GetResponseTimingPromise();
|
|
RefPtr<FetchServiceResponseEndPromise> GetResponseEndPromise();
|
|
|
|
bool IsResponseAvailablePromiseResolved() {
|
|
return mAvailablePromiseResolved;
|
|
}
|
|
bool IsResponseTimingPromiseResolved() { return mTimingPromiseResolved; }
|
|
bool IsResponseEndPromiseResolved() { return mEndPromiseResolved; }
|
|
|
|
void ResolveResponseAvailablePromise(FetchServiceResponse&& aResponse,
|
|
StaticString aMethodName);
|
|
void RejectResponseAvailablePromise(const CopyableErrorResult&& aError,
|
|
StaticString aMethodName);
|
|
void ResolveResponseTimingPromise(ResponseTiming&& aTiming,
|
|
StaticString aMethodName);
|
|
void RejectResponseTimingPromise(const CopyableErrorResult&& aError,
|
|
StaticString aMethodName);
|
|
void ResolveResponseEndPromise(ResponseEndArgs&& aArgs,
|
|
StaticString aMethodName);
|
|
void RejectResponseEndPromise(const CopyableErrorResult&& aError,
|
|
StaticString aMethodName);
|
|
|
|
private:
|
|
~FetchServicePromises() = default;
|
|
|
|
RefPtr<FetchServiceResponseAvailablePromise::Private> mAvailablePromise;
|
|
RefPtr<FetchServiceResponseTimingPromise::Private> mTimingPromise;
|
|
RefPtr<FetchServiceResponseEndPromise::Private> mEndPromise;
|
|
|
|
// The MozPromise interface intentionally does not expose synchronous access
|
|
// to the internal resolved/rejected state. Instead, we track whether or not
|
|
// we've called Resolve on the FetchServicePromises.
|
|
bool mAvailablePromiseResolved = false;
|
|
bool mTimingPromiseResolved = false;
|
|
bool mEndPromiseResolved = false;
|
|
};
|
|
|
|
/**
|
|
* FetchService is a singleton object which designed to be used in parent
|
|
* process main thread only. It is used to handle the special fetch requests
|
|
* from ServiceWorkers(by Navigation Preload) and PFetch.
|
|
*
|
|
* FetchService creates FetchInstance internally to represent each Fetch
|
|
* request. It supports an asynchronous fetching, FetchServicePromises is
|
|
* created when a Fetch starts, once the response is ready or any error happens,
|
|
* the FetchServicePromises would be resolved or rejected. The promises
|
|
* consumers can set callbacks to handle the Fetch result.
|
|
*/
|
|
class FetchService final : public nsIObserver {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
// Used for ServiceWorkerNavigationPreload
|
|
struct NavigationPreloadArgs {
|
|
SafeRefPtr<InternalRequest> mRequest;
|
|
nsCOMPtr<nsIChannel> mChannel;
|
|
};
|
|
|
|
// Used for content process worker thread fetch()
|
|
struct WorkerFetchArgs {
|
|
SafeRefPtr<InternalRequest> mRequest;
|
|
mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
|
nsCString mWorkerScript;
|
|
Maybe<ClientInfo> mClientInfo;
|
|
Maybe<ServiceWorkerDescriptor> mController;
|
|
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
|
|
bool mNeedOnDataAvailable;
|
|
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
|
|
uint64_t mAssociatedBrowsingContextID;
|
|
nsCOMPtr<nsISerialEventTarget> mEventTarget;
|
|
nsID mActorID;
|
|
bool mIsThirdPartyContext;
|
|
MozPromiseRequestHolder<FetchServiceResponseEndPromise>
|
|
mResponseEndPromiseHolder;
|
|
RefPtr<GenericPromise::Private> mFetchParentPromise;
|
|
bool mIsOn3PCBExceptionList;
|
|
};
|
|
|
|
// Used for content process main thread fetch()
|
|
// Currently this is just used for keepalive request
|
|
// This would be further used for sending all main thread fetch requests
|
|
// through PFetch
|
|
// See Bug 1897129.
|
|
struct MainThreadFetchArgs {
|
|
SafeRefPtr<InternalRequest> mRequest;
|
|
mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
|
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
|
|
bool mNeedOnDataAvailable;
|
|
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
|
|
uint64_t mAssociatedBrowsingContextID;
|
|
nsCOMPtr<nsISerialEventTarget> mEventTarget;
|
|
nsID mActorID;
|
|
bool mIsThirdPartyContext{false};
|
|
};
|
|
|
|
struct UnknownArgs {};
|
|
|
|
using FetchArgs = Variant<NavigationPreloadArgs, WorkerFetchArgs,
|
|
MainThreadFetchArgs, UnknownArgs>;
|
|
|
|
enum class FetchArgsType {
|
|
NavigationPreload,
|
|
WorkerFetch,
|
|
MainThreadFetch,
|
|
Unknown,
|
|
};
|
|
static already_AddRefed<FetchService> GetInstance();
|
|
|
|
static RefPtr<FetchServicePromises> NetworkErrorResponse(
|
|
nsresult aRv, const FetchArgs& aArgs = AsVariant(UnknownArgs{}));
|
|
|
|
FetchService();
|
|
|
|
// This method creates a FetchInstance to trigger fetch.
|
|
// The created FetchInstance is saved in mFetchInstanceTable
|
|
RefPtr<FetchServicePromises> Fetch(FetchArgs&& aArgs);
|
|
|
|
void CancelFetch(const RefPtr<FetchServicePromises>&& aPromises,
|
|
bool aForceAbort);
|
|
|
|
MozPromiseRequestHolder<FetchServiceResponseEndPromise>&
|
|
GetResponseEndPromiseHolder(const RefPtr<FetchServicePromises>& aPromises);
|
|
|
|
private:
|
|
/**
|
|
* FetchInstance is an internal representation for each Fetch created by
|
|
* FetchService.
|
|
* FetchInstance is also a FetchDriverObserver which has responsibility to
|
|
* resolve/reject the FetchServicePromises.
|
|
* FetchInstance triggers fetch by instancing a FetchDriver with proper
|
|
* initialization. The general usage flow of FetchInstance is as follows
|
|
*
|
|
* RefPtr<FetchInstance> fetch = MakeRefPtr<FetchInstance>();
|
|
* fetch->Initialize(FetchArgs args);
|
|
* RefPtr<FetchServicePromises> fetch->Fetch();
|
|
*/
|
|
class FetchInstance final : public FetchDriverObserver {
|
|
public:
|
|
FetchInstance() = default;
|
|
|
|
nsresult Initialize(FetchArgs&& aArgs);
|
|
|
|
const FetchArgs& Args() { return mArgs; }
|
|
MozPromiseRequestHolder<FetchServiceResponseEndPromise>&
|
|
GetResponseEndPromiseHolder() {
|
|
MOZ_ASSERT(mArgs.is<WorkerFetchArgs>());
|
|
return mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder;
|
|
}
|
|
|
|
RefPtr<FetchServicePromises> Fetch();
|
|
|
|
void Cancel(bool aForceAbort);
|
|
|
|
bool IsLocalHostFetch() const;
|
|
|
|
/* FetchDriverObserver interface */
|
|
void OnResponseEnd(FetchDriverObserver::EndReason aReason,
|
|
JS::Handle<JS::Value> aReasonDetails) override;
|
|
void OnResponseAvailableInternal(
|
|
SafeRefPtr<InternalResponse> aResponse) override;
|
|
bool NeedOnDataAvailable() override;
|
|
void OnDataAvailable() override;
|
|
void FlushConsoleReport() override;
|
|
void OnReportPerformanceTiming() override;
|
|
void OnNotifyNetworkMonitorAlternateStack(uint64_t aChannelID) override;
|
|
|
|
private:
|
|
~FetchInstance() = default;
|
|
nsCOMPtr<nsISerialEventTarget> GetBackgroundEventTarget();
|
|
nsID GetActorID();
|
|
|
|
SafeRefPtr<InternalRequest> mRequest;
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
|
nsCOMPtr<nsICookieJarSettings> mCookieJarSettings;
|
|
RefPtr<PerformanceStorage> mPerformanceStorage;
|
|
FetchArgs mArgs{AsVariant(FetchService::UnknownArgs())};
|
|
RefPtr<FetchDriver> mFetchDriver;
|
|
SafeRefPtr<InternalResponse> mResponse;
|
|
RefPtr<FetchServicePromises> mPromises;
|
|
FetchArgsType mArgsType;
|
|
Atomic<bool> mActorDying{false};
|
|
};
|
|
|
|
~FetchService();
|
|
|
|
nsresult RegisterNetworkObserver();
|
|
nsresult UnregisterNetworkObserver();
|
|
|
|
// Update pending keepalive fetch requests count
|
|
void IncrementKeepAliveRequestCount(const nsACString& aOrigin);
|
|
void DecrementKeepAliveRequestCount(const nsACString& aOrigin);
|
|
|
|
// Check if the number of pending keepalive fetch requests exceeds the
|
|
// configured limit
|
|
// We limit the number of pending keepalive requests on two levels:
|
|
// 1. per origin - controlled by pref
|
|
// dom.fetchKeepalive.request_limit_per_origin)
|
|
// 2. per browser instance - controlled by pref
|
|
// dom.fetchKeepalive.total_request_limit
|
|
bool DoesExceedsKeepaliveResourceLimits(const nsACString& aOrigin);
|
|
|
|
// This is a container to manage the generated fetches.
|
|
nsTHashMap<nsRefPtrHashKey<FetchServicePromises>, RefPtr<FetchInstance> >
|
|
mFetchInstanceTable;
|
|
bool mObservingNetwork{false};
|
|
bool mOffline{false};
|
|
|
|
// map to key origin to number of pending keepalive fetch requests
|
|
nsTHashMap<nsCStringHashKey, uint32_t> mPendingKeepAliveRequestsPerOrigin;
|
|
|
|
// total pending keepalive fetch requests per browser instance
|
|
uint32_t mTotalKeepAliveRequests{0};
|
|
};
|
|
|
|
} // namespace mozilla::dom
|
|
|
|
#endif // _mozilla_dom_FetchService_h
|