tor-browser

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

SheetLoadData.h (11581B)


      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_css_SheetLoadData_h
      8 #define mozilla_css_SheetLoadData_h
      9 
     10 #include "mozilla/AlreadyAddRefed.h"
     11 #include "mozilla/Encoding.h"
     12 #include "mozilla/NotNull.h"
     13 #include "mozilla/PreloaderBase.h"
     14 #include "mozilla/RefPtr.h"
     15 #include "mozilla/SharedSubResourceCache.h"
     16 #include "mozilla/css/Loader.h"
     17 #include "mozilla/css/SheetParsingMode.h"
     18 #include "mozilla/dom/CacheExpirationTime.h"
     19 #include "nsProxyRelease.h"
     20 
     21 namespace mozilla {
     22 namespace dom {
     23 enum class FetchPriority : uint8_t;
     24 }  // namespace dom
     25 class AsyncEventDispatcher;
     26 class StyleSheet;
     27 }  // namespace mozilla
     28 class nsICSSLoaderObserver;
     29 class nsINode;
     30 class nsIPrincipal;
     31 class nsIURI;
     32 class nsIReferrerInfo;
     33 
     34 namespace mozilla::css {
     35 
     36 /*********************************************
     37 * Data needed to properly load a stylesheet *
     38 *********************************************/
     39 
     40 static_assert(eAuthorSheetFeatures == 0 && eUserSheetFeatures == 1 &&
     41                  eAgentSheetFeatures == 2,
     42              "sheet parsing mode constants won't fit "
     43              "in SheetLoadData::mParsingMode");
     44 
     45 enum class SyncLoad : bool { No, Yes };
     46 
     47 class SheetLoadData final
     48    : public PreloaderBase,
     49      public SharedSubResourceCacheLoadingValueBase<SheetLoadData> {
     50  using MediaMatched = dom::LinkStyle::MediaMatched;
     51  using IsAlternate = dom::LinkStyle::IsAlternate;
     52  using UseSystemPrincipal = css::Loader::UseSystemPrincipal;
     53 
     54 protected:
     55  virtual ~SheetLoadData();
     56 
     57 public:
     58  static void PrioritizeAsPreload(nsIChannel* aChannel);
     59 
     60  // If this is a deferred load, start it now.
     61  void StartPendingLoad();
     62 
     63  // Data for loading a sheet linked from a document
     64  SheetLoadData(
     65      css::Loader*, const nsAString& aTitle, nsIURI*, StyleSheet*, SyncLoad,
     66      nsINode* aOwningNode, IsAlternate, MediaMatched, StylePreloadKind,
     67      nsICSSLoaderObserver* aObserver, nsIPrincipal* aTriggeringPrincipal,
     68      nsIReferrerInfo*, const nsAString& aNonce,
     69      dom::FetchPriority aFetchPriority,
     70      already_AddRefed<SubResourceNetworkMetadataHolder>&& aNetworkMetadata);
     71 
     72  // Data for loading a sheet linked from an @import rule
     73  SheetLoadData(
     74      css::Loader*, nsIURI*, StyleSheet*, SheetLoadData* aParentData,
     75      nsICSSLoaderObserver* aObserver, nsIPrincipal* aTriggeringPrincipal,
     76      nsIReferrerInfo*,
     77      already_AddRefed<SubResourceNetworkMetadataHolder>&& aNetworkMetadata);
     78 
     79  // Data for loading a non-document sheet
     80  SheetLoadData(
     81      css::Loader*, nsIURI*, StyleSheet*, SyncLoad, UseSystemPrincipal,
     82      StylePreloadKind, const Encoding* aPreloadEncoding,
     83      nsICSSLoaderObserver* aObserver, nsIPrincipal* aTriggeringPrincipal,
     84      nsIReferrerInfo*, const nsAString& aNonce,
     85      dom::FetchPriority aFetchPriority,
     86      already_AddRefed<SubResourceNetworkMetadataHolder>&& aNetworkMetadata);
     87 
     88  nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
     89 
     90  const nsString& Nonce() const { return mNonce; }
     91 
     92  already_AddRefed<AsyncEventDispatcher> PrepareLoadEventIfNeeded();
     93 
     94  NotNull<const Encoding*> DetermineNonBOMEncoding(const nsACString& aSegment,
     95                                                   nsIChannel*) const;
     96 
     97  void OnStartRequest(nsIRequest*);
     98 
     99  // The caller may have the bytes for the stylesheet split across two strings,
    100  // so aBytes1 and aBytes2 refer to those pieces.
    101  nsresult VerifySheetReadyToParse(nsresult aStatus, const nsACString& aBytes1,
    102                                   const nsACString& aBytes2, nsIChannel*);
    103 
    104  NS_DECL_ISUPPORTS
    105 
    106  css::Loader& Loader() { return *mLoader; }
    107  const css::Loader& Loader() const { return *mLoader; }
    108 
    109  void DidCancelLoad() { mIsCancelled = true; }
    110 
    111  // Hold a ref to the CSSLoader so we can call back to it to let it
    112  // know the load finished
    113  const RefPtr<css::Loader> mLoader;
    114 
    115  // Title needed to pull datas out of the pending datas table when
    116  // the preferred title is changed
    117  const nsString mTitle;
    118 
    119  // The encoding we decided to use for the sheet
    120  const Encoding* mEncoding;
    121 
    122  // URI we're loading.  Null for inline or constructable sheets.
    123  nsCOMPtr<nsIURI> mURI;
    124 
    125  // The sheet we're loading data for
    126  const RefPtr<StyleSheet> mSheet;
    127 
    128  // Load data for the sheet that @import-ed us if we were @import-ed
    129  // during the parse
    130  const RefPtr<SheetLoadData> mParentData;
    131 
    132  // The expiration time of the channel that has loaded this data, if
    133  // applicable.
    134  CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
    135 
    136  // The load tainting of the request. Needed to be able to pass it around off
    137  // the main thread for SRI checks.
    138  LoadTainting mTainting{LoadTainting::Basic};
    139 
    140  // Number of sheets we @import-ed that are still loading
    141  uint32_t mPendingChildren;
    142 
    143  // mSyncLoad is true when the load needs to be synchronous.
    144  // For LoadSheetSync, <link> to chrome stylesheets in UA Widgets,
    145  // and children of sync loads.
    146  const bool mSyncLoad : 1;
    147 
    148  // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
    149  // LoadSheet or an @import from such a sheet.  Non-document sheet loads can
    150  // proceed even if we have no document.
    151  const bool mIsNonDocumentSheet : 1;
    152 
    153  // Whether this stylesheet is for a child sheet load. This is necessary
    154  // because the sheet could be detached mid-load by CSSOM.
    155  const bool mIsChildSheet : 1;
    156 
    157  // mIsBeingParsed is true if this stylesheet is currently being parsed.
    158  bool mIsBeingParsed : 1;
    159 
    160  // mIsLoading is set to true when a sheet load is initiated. This field is
    161  // also used by the SharedSubResourceCache to avoid having multiple loads for
    162  // the same resource.
    163  bool mIsLoading : 1;
    164 
    165  // mIsCancelled is set to true when a sheet load is stopped by
    166  // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
    167  // SheetLoadData::OnStreamComplete() checks this to avoid parsing
    168  // sheets that have been cancelled and such.
    169  bool mIsCancelled : 1;
    170 
    171  // mMustNotify is true if the load data is being loaded async and the original
    172  // function call that started the load has returned.
    173  //
    174  // This applies only to observer notifications; load/error events are fired
    175  // for any SheetLoadData that has a non-null owner node (though mMustNotify is
    176  // used to avoid an event loop round-trip in that case).
    177  bool mMustNotify : 1;
    178 
    179  // Whether we had an owner node at the point of creation. This allows
    180  // differentiating between "Link" header stylesheets and LinkStyle-owned
    181  // stylesheets.
    182  const bool mHadOwnerNode : 1;
    183 
    184  // mWasAlternate is true if the sheet was an alternate
    185  // (https://html.spec.whatwg.org/#rel-alternate) when the load data was
    186  // created.
    187  const bool mWasAlternate : 1;
    188 
    189  // mMediaMatched is true if the sheet matched its medialist when the load data
    190  // was created.
    191  const bool mMediaMatched : 1;
    192 
    193  // mUseSystemPrincipal is true if the system principal should be used for
    194  // this sheet, no matter what the channel principal is.  Only true for sync
    195  // loads.
    196  const bool mUseSystemPrincipal : 1;
    197 
    198  // If true, this SheetLoadData is being used as a way to handle
    199  // async observer notification for an already-complete sheet.
    200  bool mSheetAlreadyComplete : 1;
    201 
    202  // Boolean flag indicating whether the load has failed.  This will be set
    203  // to true if this load, or the load of any descendant import, fails.
    204  bool mLoadFailed : 1;
    205 
    206  // If this flag is true, this load uses a cached load, where the corresponding
    207  // notifications from the necko channel doesn't happen for the current
    208  // document.  The loader should emulate the equivalent once the load finishes.
    209  // See Loader::NotifyObservers.
    210  //
    211  // This becomes true in the following cases:
    212  //   * This load is coalesced to a pending or loading cache, where the load
    213  //     is performed by a different loader for the different document
    214  //   * This load uses a complete cache and no necko activity happens
    215  bool mShouldEmulateNotificationsForCachedLoad : 1;
    216 
    217  // Whether this is a preload, and which kind of preload it is.
    218  //
    219  // TODO(emilio): This can become a bitfield once we build with a GCC version
    220  // that has the fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414,
    221  // which causes a false positive warning here.
    222  const StylePreloadKind mPreloadKind;
    223 
    224  nsINode* GetRequestingNode() const;
    225 
    226  // The observer that wishes to be notified of load completion
    227  nsCOMPtr<nsICSSLoaderObserver> mObserver;
    228 
    229  // The principal that identifies who started loading us.
    230  const nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
    231 
    232  // Referrer info of the load.
    233  const nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
    234 
    235  // The cryptographic nonce of the load used for CSP checks.
    236  const nsString mNonce;
    237 
    238  const dom::FetchPriority mFetchPriority;
    239 
    240  // The encoding guessed from attributes and the document character set.
    241  const NotNull<const Encoding*> mGuessedEncoding;
    242 
    243  // The quirks mode of the loader at the time the load was triggered.
    244  const nsCompatibility mCompatMode;
    245 
    246  // Whether SheetComplete was called.
    247  bool mSheetCompleteCalled = false;
    248 
    249  // Whether we intentionally are not calling SheetComplete because nobody is
    250  // listening for the load.
    251  bool mIntentionallyDropped = false;
    252 
    253  // The start timestamp for the load, or the timestamp where this load is
    254  // coalesced into an existing load.
    255  TimeStamp mLoadStart;
    256 
    257  const bool mRecordErrors;
    258 
    259  RefPtr<SubResourceNetworkMetadataHolder> mNetworkMetadata;
    260 
    261  bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; }
    262 
    263  RefPtr<StyleSheet> ValueForCache() const;
    264  CacheExpirationTime ExpirationTime() const { return mExpirationTime; }
    265 
    266  // If there are no child sheets outstanding, mark us as complete.
    267  // Otherwise, the children are holding strong refs to the data
    268  // and will call SheetComplete() on it when they complete.
    269  void SheetFinishedParsingAsync() {
    270    MOZ_ASSERT(mIsBeingParsed);
    271    mIsBeingParsed = false;
    272    if (!mPendingChildren) {
    273      mLoader->SheetComplete(*this, NS_OK);
    274    }
    275  }
    276 
    277  bool IsPreload() const { return mPreloadKind != StylePreloadKind::None; }
    278  bool IsLinkRelPreloadOrEarlyHint() const {
    279    return css::IsLinkRelPreloadOrEarlyHint(mPreloadKind);
    280  }
    281 
    282  bool BlocksLoadEvent() const {
    283    const auto& root = RootLoadData();
    284    return !root.IsLinkRelPreloadOrEarlyHint() && !root.IsSyncLoad();
    285  }
    286 
    287  bool IsSyncLoad() const override { return mSyncLoad; }
    288  bool IsLoading() const override { return mIsLoading; }
    289  bool IsCancelled() const override { return mIsCancelled; }
    290 
    291  SubResourceNetworkMetadataHolder* GetNetworkMetadata() const override {
    292    return mNetworkMetadata.get();
    293  }
    294 
    295  void StartLoading() override;
    296  void SetLoadCompleted() override;
    297  void OnCoalescedTo(const SheetLoadData& aExistingLoad) override;
    298 
    299  void Cancel() override { mIsCancelled = true; }
    300 
    301  void SetMinimumExpirationTime(const CacheExpirationTime& aExpirationTime) {
    302    mExpirationTime.SetMinimum(aExpirationTime);
    303  }
    304 
    305  nsLiteralString InitiatorTypeString();
    306 
    307 private:
    308  const SheetLoadData& RootLoadData() const {
    309    const auto* top = this;
    310    while (top->mParentData) {
    311      top = top->mParentData;
    312    }
    313    return *top;
    314  }
    315 };
    316 
    317 using SheetLoadDataHolder = nsMainThreadPtrHolder<SheetLoadData>;
    318 
    319 }  // namespace mozilla::css
    320 
    321 #endif  // mozilla_css_SheetLoadData_h