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