tor-browser

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

EarlyHintPreloader.h (7407B)


      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 
      5 #ifndef mozilla_net_EarlyHintPreloader_h
      6 #define mozilla_net_EarlyHintPreloader_h
      7 
      8 #include "mozilla/dom/ipc/IdType.h"
      9 #include "mozilla/Maybe.h"
     10 #include "mozilla/PreloadHashKey.h"
     11 #include "NeckoCommon.h"
     12 #include "mozilla/net/NeckoChannelParams.h"
     13 #include "nsHashtablesFwd.h"
     14 #include "nsIChannelEventSink.h"
     15 #include "nsIInterfaceRequestor.h"
     16 #include "nsIMultiPartChannel.h"
     17 #include "nsIRedirectResultListener.h"
     18 #include "nsIStreamListener.h"
     19 #include "nsITimer.h"
     20 #include "nsNetUtil.h"
     21 
     22 class nsAttrValue;
     23 class nsICookieJarSettings;
     24 class nsILoadContext;
     25 class nsIPrincipal;
     26 class nsIReferrerInfo;
     27 
     28 namespace mozilla::dom {
     29 class CanonicalBrowsingContext;
     30 }
     31 
     32 namespace mozilla::net {
     33 
     34 class EarlyHintPreloader;
     35 class EarlyHintConnectArgs;
     36 class ParentChannelListener;
     37 struct LinkHeader;
     38 
     39 // class keeping track of all ongoing early hints
     40 class OngoingEarlyHints final {
     41 public:
     42  NS_INLINE_DECL_REFCOUNTING(OngoingEarlyHints)
     43 
     44  OngoingEarlyHints() = default;
     45 
     46  // returns whether a preload with that key already existed
     47  bool Contains(const PreloadHashKey& aKey);
     48  bool Add(const PreloadHashKey& aKey, RefPtr<EarlyHintPreloader> aPreloader);
     49 
     50  void CancelAll(const nsACString& aReason);
     51 
     52  // registers all channels and returns the ids
     53  void RegisterLinksAndGetConnectArgs(
     54      dom::ContentParentId aCpId, nsTArray<EarlyHintConnectArgs>& aOutLinks);
     55 
     56 private:
     57  ~OngoingEarlyHints() = default;
     58 
     59  // We need to do two things requiring two separate variables to keep track of
     60  // preloads:
     61  //  - deduplicate Link headers when starting preloads, therefore we store them
     62  //    hashset with PreloadHashKey to look up whether we started the preload
     63  //    already
     64  //  - pass link headers in order they were received when passing all started
     65  //    preloads to the content process, therefore we store them in a nsTArray
     66  nsTHashSet<PreloadHashKey> mStartedPreloads;
     67  nsTArray<RefPtr<EarlyHintPreloader>> mPreloaders;
     68 };
     69 
     70 class EarlyHintPreloader final : public nsIStreamListener,
     71                                 public nsIChannelEventSink,
     72                                 public nsIRedirectResultListener,
     73                                 public nsIInterfaceRequestor,
     74                                 public nsIMultiPartChannelListener,
     75                                 public nsINamed,
     76                                 public nsITimerCallback {
     77 public:
     78  NS_DECL_ISUPPORTS
     79  NS_DECL_NSIREQUESTOBSERVER
     80  NS_DECL_NSISTREAMLISTENER
     81  NS_DECL_NSICHANNELEVENTSINK
     82  NS_DECL_NSIREDIRECTRESULTLISTENER
     83  NS_DECL_NSIINTERFACEREQUESTOR
     84  NS_DECL_NSIMULTIPARTCHANNELLISTENER
     85  // required by NS_DECL_NSITIMERCALLBACK
     86  NS_DECL_NSINAMED
     87  NS_DECL_NSITIMERCALLBACK
     88 
     89 public:
     90  // Create and insert a preload into OngoingEarlyHints if the same preload
     91  // wasn't already issued and the LinkHeader can be parsed correctly.
     92  static void MaybeCreateAndInsertPreload(
     93      OngoingEarlyHints* aOngoingEarlyHints, const LinkHeader& aHeader,
     94      nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
     95      nsICookieJarSettings* aCookieJarSettings,
     96      const nsACString& aReferrerPolicy, const nsACString& aCSPHeader,
     97      uint64_t aBrowsingContextID,
     98      dom::CanonicalBrowsingContext* aLoadingBrowsingContext,
     99      bool aIsModulepreload);
    100 
    101  // register Channel to EarlyHintRegistrar. Returns true and sets connect args
    102  // if successful
    103  bool Register(dom::ContentParentId aCpId, EarlyHintConnectArgs& aOut);
    104 
    105  // Allows EarlyHintRegistrar to check if the correct content process accesses
    106  // this preload. Preventing compromised content processes to access Early Hint
    107  // preloads from other origins
    108  bool IsFromContentParent(dom::ContentParentId aCpId) const;
    109 
    110  // Should be called by the preloader service when the preload is not
    111  // needed after all, because the final response returns a non-2xx status
    112  // code. If aDeleteEntry is false, the calling function MUST make sure that
    113  // the EarlyHintPreloader is not in the EarlyHintRegistrar anymore. Because
    114  // after this function, the EarlyHintPreloader can't connect back to the
    115  // parent anymore.
    116  nsresult CancelChannel(nsresult aStatus, const nsACString& aReason,
    117                         bool aDeleteEntry);
    118 
    119  void OnParentReady(nsIParentChannel* aParent);
    120 
    121 private:
    122  void SetParentChannel();
    123  void InvokeStreamListenerFunctions();
    124 
    125  EarlyHintPreloader();
    126  ~EarlyHintPreloader();
    127 
    128  static Maybe<PreloadHashKey> GenerateHashKey(ASDestination aAs, nsIURI* aURI,
    129                                               nsIPrincipal* aPrincipal,
    130                                               CORSMode corsMode,
    131                                               bool aIsModulepreload);
    132 
    133  static nsSecurityFlags ComputeSecurityFlags(CORSMode aCORSMode,
    134                                              ASDestination aAs);
    135 
    136  // call to start the preload
    137  nsresult OpenChannel(nsIURI* aURI, nsIPrincipal* aPrincipal,
    138                       nsSecurityFlags aSecurityFlags,
    139                       nsContentPolicyType aContentPolicyType,
    140                       nsIReferrerInfo* aReferrerInfo,
    141                       nsICookieJarSettings* aCookieJarSettings,
    142                       uint64_t aBrowsingContextID);
    143  void PriorizeAsPreload();
    144  void SetLinkHeader(const LinkHeader& aLinkHeader);
    145 
    146  nsCOMPtr<nsIChannel> mChannel;
    147  nsCOMPtr<nsIChannel> mRedirectChannel;
    148 
    149  dom::ContentParentId mCpId;
    150  EarlyHintConnectArgs mConnectArgs;
    151 
    152  // Copy behavior from DocumentLoadListener.h:
    153  // https://searchfox.org/mozilla-central/rev/c0bed29d643393af6ebe77aa31455f283f169202/netwerk/ipc/DocumentLoadListener.h#487-512
    154  // The set of nsIStreamListener functions that got called on this
    155  // listener, so that we can replay them onto the replacement channel's
    156  // listener. This should generally only be OnStartRequest, since we
    157  // Suspend() the channel at that point, but it can fail sometimes
    158  // so we have to support holding a list.
    159  nsTArray<StreamListenerFunction> mStreamListenerFunctions;
    160 
    161  // Set to true once OnStartRequest is called
    162  bool mOnStartRequestCalled = false;
    163  // Set to true if we suspended mChannel in the OnStartRequest call
    164  bool mSuspended = false;
    165  nsCOMPtr<nsIParentChannel> mParent;
    166  // Set to true after we've received the last OnStopRequest, and shouldn't
    167  // setup a reference from the ParentChannelListener to the replacement
    168  // channel.
    169  bool mIsFinished = false;
    170 
    171  RefPtr<ParentChannelListener> mParentListener;
    172  nsCOMPtr<nsITimer> mTimer;
    173 
    174  // Hold the load context to provide data to web extension and anti tracking.
    175  // See Bug 1836289 and Bug 1875268
    176  nsCOMPtr<nsILoadContext> mLoadContext;
    177 
    178 private:
    179  // IMPORTANT: when adding new values, always add them to the end, otherwise
    180  // it will mess up telemetry.
    181  enum EHPreloaderState : uint32_t {
    182    ePreloaderCreated = 0,
    183    ePreloaderOpened,
    184    ePreloaderUsed,
    185    ePreloaderCancelled,
    186    ePreloaderTimeout,
    187  };
    188  EHPreloaderState mState = ePreloaderCreated;
    189  void SetState(EHPreloaderState aState) { mState = aState; }
    190 };
    191 
    192 inline nsISupports* ToSupports(EarlyHintPreloader* aObj) {
    193  return static_cast<nsIInterfaceRequestor*>(aObj);
    194 }
    195 
    196 }  // namespace mozilla::net
    197 
    198 #endif  // mozilla_net_EarlyHintPreloader_h