tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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