Loader.cpp 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. * vim: ft=cpp tw=78 sw=2 et ts=2
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. *
  8. * This Original Code has been modified by IBM Corporation.
  9. * Modifications made by IBM described herein are Copyright (c)
  10. * International Business Machines Corporation, 2000. Modifications
  11. * to Mozilla code or documentation identified per MPL Section 3.3
  12. *
  13. * Date Modified by Description of modification
  14. * 04/20/2000 IBM Corp. OS/2 VisualAge build.
  15. */
  16. /* loading of CSS style sheets using the network APIs */
  17. #include "mozilla/ArrayUtils.h"
  18. #include "mozilla/LoadInfo.h"
  19. #include "mozilla/MemoryReporting.h"
  20. #include "mozilla/css/Loader.h"
  21. #include "mozilla/StyleSheetInlines.h"
  22. #include "nsIRunnable.h"
  23. #include "nsIUnicharStreamLoader.h"
  24. #include "nsSyncLoadService.h"
  25. #include "nsCOMPtr.h"
  26. #include "nsString.h"
  27. #include "nsIContent.h"
  28. #include "nsIDocument.h"
  29. #include "nsIDOMNode.h"
  30. #include "nsIDOMDocument.h"
  31. #include "nsIURI.h"
  32. #include "nsNetUtil.h"
  33. #include "nsIProtocolHandler.h"
  34. #include "nsContentUtils.h"
  35. #include "nsIScriptSecurityManager.h"
  36. #include "nsContentPolicyUtils.h"
  37. #include "nsIHttpChannel.h"
  38. #include "nsIHttpChannelInternal.h"
  39. #include "nsIClassOfService.h"
  40. #include "nsIScriptError.h"
  41. #include "nsMimeTypes.h"
  42. #include "nsIStyleSheetLinkingElement.h"
  43. #include "nsICSSLoaderObserver.h"
  44. #include "nsCSSParser.h"
  45. #include "mozilla/css/ImportRule.h"
  46. #include "nsThreadUtils.h"
  47. #include "nsGkAtoms.h"
  48. #include "nsIThreadInternal.h"
  49. #include "nsINetworkPredictor.h"
  50. #include "nsITimedChannel.h"
  51. #include "mozilla/dom/ShadowRoot.h"
  52. #include "mozilla/dom/URL.h"
  53. #include "mozilla/AsyncEventDispatcher.h"
  54. #include "mozilla/StyleSheet.h"
  55. #include "mozilla/StyleSheetInlines.h"
  56. #include "mozilla/ConsoleReportCollector.h"
  57. #ifdef MOZ_XUL
  58. #include "nsXULPrototypeCache.h"
  59. #endif
  60. #include "nsIMediaList.h"
  61. #include "nsIDOMStyleSheet.h"
  62. #include "nsError.h"
  63. #include "nsIContentSecurityPolicy.h"
  64. #include "mozilla/dom/SRICheck.h"
  65. #include "mozilla/dom/EncodingUtils.h"
  66. using mozilla::dom::EncodingUtils;
  67. using namespace mozilla::dom;
  68. /**
  69. * OVERALL ARCHITECTURE
  70. *
  71. * The CSS Loader gets requests to load various sorts of style sheets:
  72. * inline style from <style> elements, linked style, @import-ed child
  73. * sheets, non-document sheets. The loader handles the following tasks:
  74. * 1) Creation of the actual style sheet objects: CreateSheet()
  75. * 2) setting of the right media, title, enabled state, etc on the
  76. * sheet: PrepareSheet()
  77. * 3) Insertion of the sheet in the proper cascade order:
  78. * InsertSheetInDoc() and InsertChildSheet()
  79. * 4) Load of the sheet: LoadSheet() including security checks
  80. * 5) Parsing of the sheet: ParseSheet()
  81. * 6) Cleanup: SheetComplete()
  82. *
  83. * The detailed documentation for these functions is found with the
  84. * function implementations.
  85. *
  86. * The following helper object is used:
  87. * SheetLoadData -- a small class that is used to store all the
  88. * information needed for the loading of a sheet;
  89. * this class handles listening for the stream
  90. * loader completion and also handles charset
  91. * determination.
  92. */
  93. namespace mozilla {
  94. namespace css {
  95. /*********************************************
  96. * Data needed to properly load a stylesheet *
  97. *********************************************/
  98. static_assert(eAuthorSheetFeatures == 0 &&
  99. eUserSheetFeatures == 1 &&
  100. eAgentSheetFeatures == 2,
  101. "sheet parsing mode constants won't fit "
  102. "in SheetLoadData::mParsingMode");
  103. class SheetLoadData final : public nsIRunnable,
  104. public nsIUnicharStreamLoaderObserver,
  105. public nsIThreadObserver
  106. {
  107. protected:
  108. virtual ~SheetLoadData(void);
  109. public:
  110. // Data for loading a sheet linked from a document
  111. SheetLoadData(Loader* aLoader,
  112. const nsSubstring& aTitle,
  113. nsIURI* aURI,
  114. StyleSheet* aSheet,
  115. nsIStyleSheetLinkingElement* aOwningElement,
  116. bool aIsAlternate,
  117. nsICSSLoaderObserver* aObserver,
  118. nsIPrincipal* aLoaderPrincipal,
  119. nsINode* aRequestingNode);
  120. // Data for loading a sheet linked from an @import rule
  121. SheetLoadData(Loader* aLoader,
  122. nsIURI* aURI,
  123. StyleSheet* aSheet,
  124. SheetLoadData* aParentData,
  125. nsICSSLoaderObserver* aObserver,
  126. nsIPrincipal* aLoaderPrincipal,
  127. nsINode* aRequestingNode);
  128. // Data for loading a non-document sheet
  129. SheetLoadData(Loader* aLoader,
  130. nsIURI* aURI,
  131. StyleSheet* aSheet,
  132. bool aSyncLoad,
  133. bool aUseSystemPrincipal,
  134. const nsCString& aCharset,
  135. nsICSSLoaderObserver* aObserver,
  136. nsIPrincipal* aLoaderPrincipal,
  137. nsINode* aRequestingNode);
  138. already_AddRefed<nsIURI> GetReferrerURI();
  139. void ScheduleLoadEventIfNeeded(nsresult aStatus);
  140. NS_DECL_ISUPPORTS
  141. NS_DECL_NSIRUNNABLE
  142. NS_DECL_NSITHREADOBSERVER
  143. NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
  144. // Hold a ref to the CSSLoader so we can call back to it to let it
  145. // know the load finished
  146. RefPtr<Loader> mLoader;
  147. // Title needed to pull datas out of the pending datas table when
  148. // the preferred title is changed
  149. nsString mTitle;
  150. // Charset we decided to use for the sheet
  151. nsCString mCharset;
  152. // URI we're loading. Null for inline sheets
  153. nsCOMPtr<nsIURI> mURI;
  154. // Should be 1 for non-inline sheets.
  155. uint32_t mLineNumber;
  156. // The sheet we're loading data for
  157. RefPtr<StyleSheet> mSheet;
  158. // Linked list of datas for the same URI as us
  159. SheetLoadData* mNext; // strong ref
  160. // Load data for the sheet that @import-ed us if we were @import-ed
  161. // during the parse
  162. RefPtr<SheetLoadData> mParentData;
  163. // Number of sheets we @import-ed that are still loading
  164. uint32_t mPendingChildren;
  165. // mSyncLoad is true when the load needs to be synchronous -- right
  166. // now only for LoadSheetSync and children of sync loads.
  167. bool mSyncLoad : 1;
  168. // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
  169. // LoadSheet or an @import from such a sheet. Non-document sheet loads can
  170. // proceed even if we have no document.
  171. bool mIsNonDocumentSheet : 1;
  172. // mIsLoading is true from the moment we are placed in the loader's
  173. // "loading datas" table (right after the async channel is opened)
  174. // to the moment we are removed from said table (due to the load
  175. // completing or being cancelled).
  176. bool mIsLoading : 1;
  177. // mIsCancelled is set to true when a sheet load is stopped by
  178. // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
  179. // SheetLoadData::OnStreamComplete() checks this to avoid parsing
  180. // sheets that have been cancelled and such.
  181. bool mIsCancelled : 1;
  182. // mMustNotify is true if the load data is being loaded async and
  183. // the original function call that started the load has returned.
  184. // This applies only to observer notifications; load/error events
  185. // are fired for any SheetLoadData that has a non-null
  186. // mOwningElement.
  187. bool mMustNotify : 1;
  188. // mWasAlternate is true if the sheet was an alternate when the load data was
  189. // created.
  190. bool mWasAlternate : 1;
  191. // mUseSystemPrincipal is true if the system principal should be used for
  192. // this sheet, no matter what the channel principal is. Only true for sync
  193. // loads.
  194. bool mUseSystemPrincipal : 1;
  195. // If true, this SheetLoadData is being used as a way to handle
  196. // async observer notification for an already-complete sheet.
  197. bool mSheetAlreadyComplete : 1;
  198. // This is the element that imported the sheet. Needed to get the
  199. // charset set on it and to fire load/error events.
  200. nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
  201. // The observer that wishes to be notified of load completion
  202. nsCOMPtr<nsICSSLoaderObserver> mObserver;
  203. // The principal that identifies who started loading us.
  204. nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
  205. // The node that identifies who started loading us.
  206. nsCOMPtr<nsINode> mRequestingNode;
  207. // The charset to use if the transport and sheet don't indicate one.
  208. // May be empty. Must be empty if mOwningElement is non-null.
  209. nsCString mCharsetHint;
  210. // The status our load ended up with; this determines whether we
  211. // should fire error events or load events. This gets initialized
  212. // by ScheduleLoadEventIfNeeded, and is only used after that has
  213. // been called.
  214. MOZ_INIT_OUTSIDE_CTOR nsresult mStatus;
  215. private:
  216. void FireLoadEvent(nsIThreadInternal* aThread);
  217. };
  218. #include "mozilla/Logging.h"
  219. static mozilla::LazyLogModule sCssLoaderLog("nsCSSLoader");
  220. static mozilla::LazyLogModule gSriPRLog("SRI");
  221. #define LOG_ERROR(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Error, args)
  222. #define LOG_WARN(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Warning, args)
  223. #define LOG_DEBUG(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Debug, args)
  224. #define LOG(args) LOG_DEBUG(args)
  225. #define LOG_ERROR_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Error)
  226. #define LOG_WARN_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Warning)
  227. #define LOG_DEBUG_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Debug)
  228. #define LOG_ENABLED() LOG_DEBUG_ENABLED()
  229. #define LOG_URI(format, uri) \
  230. PR_BEGIN_MACRO \
  231. NS_ASSERTION(uri, "Logging null uri"); \
  232. if (LOG_ENABLED()) { \
  233. LOG((format, uri->GetSpecOrDefault().get())); \
  234. } \
  235. PR_END_MACRO
  236. // And some convenience strings...
  237. static const char* const gStateStrings[] = {
  238. "eSheetStateUnknown",
  239. "eSheetNeedsParser",
  240. "eSheetPending",
  241. "eSheetLoading",
  242. "eSheetComplete"
  243. };
  244. /********************************
  245. * SheetLoadData implementation *
  246. ********************************/
  247. NS_IMPL_ISUPPORTS(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable,
  248. nsIThreadObserver)
  249. SheetLoadData::SheetLoadData(Loader* aLoader,
  250. const nsSubstring& aTitle,
  251. nsIURI* aURI,
  252. StyleSheet* aSheet,
  253. nsIStyleSheetLinkingElement* aOwningElement,
  254. bool aIsAlternate,
  255. nsICSSLoaderObserver* aObserver,
  256. nsIPrincipal* aLoaderPrincipal,
  257. nsINode* aRequestingNode)
  258. : mLoader(aLoader),
  259. mTitle(aTitle),
  260. mURI(aURI),
  261. mLineNumber(1),
  262. mSheet(aSheet),
  263. mNext(nullptr),
  264. mPendingChildren(0),
  265. mSyncLoad(false),
  266. mIsNonDocumentSheet(false),
  267. mIsLoading(false),
  268. mIsCancelled(false),
  269. mMustNotify(false),
  270. mWasAlternate(aIsAlternate),
  271. mUseSystemPrincipal(false),
  272. mSheetAlreadyComplete(false),
  273. mOwningElement(aOwningElement),
  274. mObserver(aObserver),
  275. mLoaderPrincipal(aLoaderPrincipal),
  276. mRequestingNode(aRequestingNode)
  277. {
  278. NS_PRECONDITION(mLoader, "Must have a loader!");
  279. }
  280. SheetLoadData::SheetLoadData(Loader* aLoader,
  281. nsIURI* aURI,
  282. StyleSheet* aSheet,
  283. SheetLoadData* aParentData,
  284. nsICSSLoaderObserver* aObserver,
  285. nsIPrincipal* aLoaderPrincipal,
  286. nsINode* aRequestingNode)
  287. : mLoader(aLoader),
  288. mURI(aURI),
  289. mLineNumber(1),
  290. mSheet(aSheet),
  291. mNext(nullptr),
  292. mParentData(aParentData),
  293. mPendingChildren(0),
  294. mSyncLoad(false),
  295. mIsNonDocumentSheet(false),
  296. mIsLoading(false),
  297. mIsCancelled(false),
  298. mMustNotify(false),
  299. mWasAlternate(false),
  300. mUseSystemPrincipal(false),
  301. mSheetAlreadyComplete(false),
  302. mOwningElement(nullptr),
  303. mObserver(aObserver),
  304. mLoaderPrincipal(aLoaderPrincipal),
  305. mRequestingNode(aRequestingNode)
  306. {
  307. NS_PRECONDITION(mLoader, "Must have a loader!");
  308. if (mParentData) {
  309. mSyncLoad = mParentData->mSyncLoad;
  310. mIsNonDocumentSheet = mParentData->mIsNonDocumentSheet;
  311. mUseSystemPrincipal = mParentData->mUseSystemPrincipal;
  312. ++(mParentData->mPendingChildren);
  313. }
  314. NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
  315. "Shouldn't use system principal for async loads");
  316. }
  317. SheetLoadData::SheetLoadData(Loader* aLoader,
  318. nsIURI* aURI,
  319. StyleSheet* aSheet,
  320. bool aSyncLoad,
  321. bool aUseSystemPrincipal,
  322. const nsCString& aCharset,
  323. nsICSSLoaderObserver* aObserver,
  324. nsIPrincipal* aLoaderPrincipal,
  325. nsINode* aRequestingNode)
  326. : mLoader(aLoader),
  327. mURI(aURI),
  328. mLineNumber(1),
  329. mSheet(aSheet),
  330. mNext(nullptr),
  331. mPendingChildren(0),
  332. mSyncLoad(aSyncLoad),
  333. mIsNonDocumentSheet(true),
  334. mIsLoading(false),
  335. mIsCancelled(false),
  336. mMustNotify(false),
  337. mWasAlternate(false),
  338. mUseSystemPrincipal(aUseSystemPrincipal),
  339. mSheetAlreadyComplete(false),
  340. mOwningElement(nullptr),
  341. mObserver(aObserver),
  342. mLoaderPrincipal(aLoaderPrincipal),
  343. mRequestingNode(aRequestingNode),
  344. mCharsetHint(aCharset)
  345. {
  346. NS_PRECONDITION(mLoader, "Must have a loader!");
  347. NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
  348. "Shouldn't use system principal for async loads");
  349. }
  350. SheetLoadData::~SheetLoadData()
  351. {
  352. NS_CSS_NS_RELEASE_LIST_MEMBER(SheetLoadData, this, mNext);
  353. }
  354. NS_IMETHODIMP
  355. SheetLoadData::Run()
  356. {
  357. mLoader->HandleLoadEvent(this);
  358. return NS_OK;
  359. }
  360. NS_IMETHODIMP
  361. SheetLoadData::OnDispatchedEvent(nsIThreadInternal* aThread)
  362. {
  363. return NS_OK;
  364. }
  365. NS_IMETHODIMP
  366. SheetLoadData::OnProcessNextEvent(nsIThreadInternal* aThread,
  367. bool aMayWait)
  368. {
  369. // XXXkhuey this is insane!
  370. // We want to fire our load even before or after event processing,
  371. // whichever comes first.
  372. FireLoadEvent(aThread);
  373. return NS_OK;
  374. }
  375. NS_IMETHODIMP
  376. SheetLoadData::AfterProcessNextEvent(nsIThreadInternal* aThread,
  377. bool aEventWasProcessed)
  378. {
  379. // XXXkhuey this too!
  380. // We want to fire our load even before or after event processing,
  381. // whichever comes first.
  382. FireLoadEvent(aThread);
  383. return NS_OK;
  384. }
  385. void
  386. SheetLoadData::FireLoadEvent(nsIThreadInternal* aThread)
  387. {
  388. // First remove ourselves as a thread observer. But we need to keep
  389. // ourselves alive while doing that!
  390. RefPtr<SheetLoadData> kungFuDeathGrip(this);
  391. aThread->RemoveObserver(this);
  392. // Now fire the event
  393. nsCOMPtr<nsINode> node = do_QueryInterface(mOwningElement);
  394. NS_ASSERTION(node, "How did that happen???");
  395. nsContentUtils::DispatchTrustedEvent(node->OwnerDoc(),
  396. node,
  397. NS_SUCCEEDED(mStatus) ?
  398. NS_LITERAL_STRING("load") :
  399. NS_LITERAL_STRING("error"),
  400. false, false);
  401. // And unblock onload
  402. if (mLoader->mDocument) {
  403. mLoader->mDocument->UnblockOnload(true);
  404. }
  405. }
  406. void
  407. SheetLoadData::ScheduleLoadEventIfNeeded(nsresult aStatus)
  408. {
  409. if (!mOwningElement) {
  410. return;
  411. }
  412. mStatus = aStatus;
  413. nsCOMPtr<nsIThread> thread = do_GetMainThread();
  414. nsCOMPtr<nsIThreadInternal> internalThread = do_QueryInterface(thread);
  415. if (NS_SUCCEEDED(internalThread->AddObserver(this))) {
  416. // Make sure to block onload here
  417. if (mLoader->mDocument) {
  418. mLoader->mDocument->BlockOnload();
  419. }
  420. }
  421. }
  422. /*********************
  423. * Style sheet reuse *
  424. *********************/
  425. bool
  426. LoaderReusableStyleSheets::FindReusableStyleSheet(nsIURI* aURL,
  427. RefPtr<CSSStyleSheet>& aResult)
  428. {
  429. MOZ_ASSERT(aURL);
  430. for (size_t i = mReusableSheets.Length(); i > 0; --i) {
  431. size_t index = i - 1;
  432. bool sameURI;
  433. MOZ_ASSERT(mReusableSheets[index]->GetOriginalURI());
  434. nsresult rv = aURL->Equals(mReusableSheets[index]->GetOriginalURI(),
  435. &sameURI);
  436. if (!NS_FAILED(rv) && sameURI) {
  437. aResult = mReusableSheets[index];
  438. mReusableSheets.RemoveElementAt(index);
  439. return true;
  440. }
  441. }
  442. return false;
  443. }
  444. /*************************
  445. * Loader Implementation *
  446. *************************/
  447. Loader::Loader(StyleBackendType aType)
  448. : mDocument(nullptr)
  449. , mDatasToNotifyOn(0)
  450. , mCompatMode(eCompatibility_FullStandards)
  451. , mStyleBackendType(Some(aType))
  452. , mEnabled(true)
  453. , mReporter(new ConsoleReportCollector())
  454. #ifdef DEBUG
  455. , mSyncCallback(false)
  456. #endif
  457. {
  458. }
  459. Loader::Loader(nsIDocument* aDocument)
  460. : mDocument(aDocument)
  461. , mDatasToNotifyOn(0)
  462. , mCompatMode(eCompatibility_FullStandards)
  463. , mEnabled(true)
  464. , mReporter(new ConsoleReportCollector())
  465. #ifdef DEBUG
  466. , mSyncCallback(false)
  467. #endif
  468. {
  469. // We can just use the preferred set, since there are no sheets in the
  470. // document yet (if there are, how did they get there? _we_ load the sheets!)
  471. // and hence the selected set makes no sense at this time.
  472. nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
  473. if (domDoc) {
  474. domDoc->GetPreferredStyleSheetSet(mPreferredSheet);
  475. }
  476. }
  477. Loader::~Loader()
  478. {
  479. NS_ASSERTION(!mSheets || mSheets->mLoadingDatas.Count() == 0,
  480. "How did we get destroyed when there are loading data?");
  481. NS_ASSERTION(!mSheets || mSheets->mPendingDatas.Count() == 0,
  482. "How did we get destroyed when there are pending data?");
  483. // Note: no real need to revoke our stylesheet loaded events -- they
  484. // hold strong references to us, so if we're going away that means
  485. // they're all done.
  486. }
  487. void
  488. Loader::DropDocumentReference(void)
  489. {
  490. mDocument = nullptr;
  491. // Flush out pending datas just so we don't leak by accident. These
  492. // loads should short-circuit through the mDocument check in
  493. // LoadSheet and just end up in SheetComplete immediately
  494. if (mSheets) {
  495. StartAlternateLoads();
  496. }
  497. }
  498. nsresult
  499. Loader::SetPreferredSheet(const nsAString& aTitle)
  500. {
  501. #ifdef DEBUG
  502. nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
  503. if (doc) {
  504. nsAutoString currentPreferred;
  505. doc->GetLastStyleSheetSet(currentPreferred);
  506. if (DOMStringIsNull(currentPreferred)) {
  507. doc->GetPreferredStyleSheetSet(currentPreferred);
  508. }
  509. NS_ASSERTION(currentPreferred.Equals(aTitle),
  510. "Unexpected argument to SetPreferredSheet");
  511. }
  512. #endif
  513. mPreferredSheet = aTitle;
  514. // start any pending alternates that aren't alternates anymore
  515. if (mSheets) {
  516. LoadDataArray arr(mSheets->mPendingDatas.Count());
  517. for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
  518. SheetLoadData* data = iter.Data();
  519. MOZ_ASSERT(data, "Must have a data");
  520. // Note that we don't want to affect what the selected style set is, so
  521. // use true for aHasAlternateRel.
  522. if (!data->mLoader->IsAlternate(data->mTitle, true)) {
  523. arr.AppendElement(data);
  524. iter.Remove();
  525. }
  526. }
  527. mDatasToNotifyOn += arr.Length();
  528. for (uint32_t i = 0; i < arr.Length(); ++i) {
  529. --mDatasToNotifyOn;
  530. LoadSheet(arr[i], eSheetNeedsParser, false);
  531. }
  532. }
  533. return NS_OK;
  534. }
  535. static const char kCharsetSym[] = "@charset \"";
  536. static bool GetCharsetFromData(const char* aStyleSheetData,
  537. uint32_t aDataLength,
  538. nsACString& aCharset)
  539. {
  540. aCharset.Truncate();
  541. if (aDataLength <= sizeof(kCharsetSym) - 1)
  542. return false;
  543. if (strncmp(aStyleSheetData,
  544. kCharsetSym,
  545. sizeof(kCharsetSym) - 1)) {
  546. return false;
  547. }
  548. for (uint32_t i = sizeof(kCharsetSym) - 1; i < aDataLength; ++i) {
  549. char c = aStyleSheetData[i];
  550. if (c == '"') {
  551. ++i;
  552. if (i < aDataLength && aStyleSheetData[i] == ';') {
  553. return true;
  554. }
  555. // fail
  556. break;
  557. }
  558. aCharset.Append(c);
  559. }
  560. // Did not see end quote or semicolon
  561. aCharset.Truncate();
  562. return false;
  563. }
  564. NS_IMETHODIMP
  565. SheetLoadData::OnDetermineCharset(nsIUnicharStreamLoader* aLoader,
  566. nsISupports* aContext,
  567. nsACString const& aSegment,
  568. nsACString& aCharset)
  569. {
  570. NS_PRECONDITION(!mOwningElement || mCharsetHint.IsEmpty(),
  571. "Can't have element _and_ charset hint");
  572. LOG_URI("SheetLoadData::OnDetermineCharset for '%s'", mURI);
  573. // The precedence is (per CSS3 Syntax 2012-11-08 ED):
  574. // BOM
  575. // Channel
  576. // @charset rule
  577. // charset attribute on the referrer
  578. // encoding of the referrer
  579. // UTF-8
  580. aCharset.Truncate();
  581. if (nsContentUtils::CheckForBOM((const unsigned char*)aSegment.BeginReading(),
  582. aSegment.Length(),
  583. aCharset)) {
  584. // aCharset is now either "UTF-16BE", "UTF-16BE" or "UTF-8"
  585. // which will swallow the BOM.
  586. mCharset.Assign(aCharset);
  587. LOG((" Setting from BOM to: %s", PromiseFlatCString(aCharset).get()));
  588. return NS_OK;
  589. }
  590. nsCOMPtr<nsIChannel> channel;
  591. nsAutoCString specified;
  592. aLoader->GetChannel(getter_AddRefs(channel));
  593. if (channel) {
  594. channel->GetContentCharset(specified);
  595. if (EncodingUtils::FindEncodingForLabel(specified, aCharset)) {
  596. mCharset.Assign(aCharset);
  597. LOG((" Setting from HTTP to: %s", PromiseFlatCString(aCharset).get()));
  598. return NS_OK;
  599. }
  600. }
  601. if (GetCharsetFromData(aSegment.BeginReading(),
  602. aSegment.Length(),
  603. specified)) {
  604. if (EncodingUtils::FindEncodingForLabel(specified, aCharset)) {
  605. // FindEncodingForLabel currently never returns UTF-16LE but will
  606. // probably change to never return UTF-16 instead, so check both here
  607. // to avoid relying on the exact behavior.
  608. if (aCharset.EqualsLiteral("UTF-16") ||
  609. aCharset.EqualsLiteral("UTF-16BE") ||
  610. aCharset.EqualsLiteral("UTF-16LE")) {
  611. // Be consistent with HTML <meta> handling in face of impossibility.
  612. // When the @charset rule itself evidently was not UTF-16-encoded,
  613. // it saying UTF-16 has to be a lie.
  614. aCharset.AssignLiteral("UTF-8");
  615. }
  616. mCharset.Assign(aCharset);
  617. LOG((" Setting from @charset rule to: %s",
  618. PromiseFlatCString(aCharset).get()));
  619. return NS_OK;
  620. }
  621. }
  622. // Now try the charset on the <link> or processing instruction
  623. // that loaded us
  624. if (mOwningElement) {
  625. nsAutoString specified16;
  626. mOwningElement->GetCharset(specified16);
  627. if (EncodingUtils::FindEncodingForLabel(specified16, aCharset)) {
  628. mCharset.Assign(aCharset);
  629. LOG((" Setting from charset attribute to: %s",
  630. PromiseFlatCString(aCharset).get()));
  631. return NS_OK;
  632. }
  633. }
  634. // In the preload case, the value of the charset attribute on <link> comes
  635. // in via mCharsetHint instead.
  636. if (EncodingUtils::FindEncodingForLabel(mCharsetHint, aCharset)) {
  637. mCharset.Assign(aCharset);
  638. LOG((" Setting from charset attribute (preload case) to: %s",
  639. PromiseFlatCString(aCharset).get()));
  640. return NS_OK;
  641. }
  642. // Try charset from the parent stylesheet.
  643. if (mParentData) {
  644. aCharset = mParentData->mCharset;
  645. if (!aCharset.IsEmpty()) {
  646. mCharset.Assign(aCharset);
  647. LOG((" Setting from parent sheet to: %s",
  648. PromiseFlatCString(aCharset).get()));
  649. return NS_OK;
  650. }
  651. }
  652. if (mLoader->mDocument) {
  653. // no useful data on charset. Try the document charset.
  654. aCharset = mLoader->mDocument->GetDocumentCharacterSet();
  655. MOZ_ASSERT(!aCharset.IsEmpty());
  656. mCharset.Assign(aCharset);
  657. LOG((" Setting from document to: %s", PromiseFlatCString(aCharset).get()));
  658. return NS_OK;
  659. }
  660. aCharset.AssignLiteral("UTF-8");
  661. mCharset = aCharset;
  662. LOG((" Setting from default to: %s", PromiseFlatCString(aCharset).get()));
  663. return NS_OK;
  664. }
  665. already_AddRefed<nsIURI>
  666. SheetLoadData::GetReferrerURI()
  667. {
  668. nsCOMPtr<nsIURI> uri;
  669. if (mParentData)
  670. uri = mParentData->mSheet->GetSheetURI();
  671. if (!uri && mLoader->mDocument)
  672. uri = mLoader->mDocument->GetDocumentURI();
  673. return uri.forget();
  674. }
  675. /*
  676. * Here we need to check that the load did not give us an http error
  677. * page and check the mimetype on the channel to make sure we're not
  678. * loading non-text/css data in standards mode.
  679. */
  680. NS_IMETHODIMP
  681. SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
  682. nsISupports* aContext,
  683. nsresult aStatus,
  684. const nsAString& aBuffer)
  685. {
  686. LOG(("SheetLoadData::OnStreamComplete"));
  687. NS_ASSERTION(!mLoader->mSyncCallback, "Synchronous callback from necko");
  688. if (mIsCancelled) {
  689. // Just return. Don't call SheetComplete -- it's already been
  690. // called and calling it again will lead to an extra NS_RELEASE on
  691. // this data and a likely crash.
  692. return NS_OK;
  693. }
  694. if (!mLoader->mDocument && !mIsNonDocumentSheet) {
  695. // Sorry, we don't care about this load anymore
  696. LOG_WARN((" No document and not non-document sheet; dropping load"));
  697. mLoader->SheetComplete(this, NS_BINDING_ABORTED);
  698. return NS_OK;
  699. }
  700. if (NS_FAILED(aStatus)) {
  701. LOG_WARN((" Load failed: status 0x%x", aStatus));
  702. // Handle sheet not loading error because source was a tracking URL.
  703. // We make a note of this sheet node by including it in a dedicated
  704. // array of blocked tracking nodes under its parent document.
  705. //
  706. // Multiple sheet load instances might be tied to this request,
  707. // we annotate each one linked to a valid owning element (node).
  708. if (aStatus == NS_ERROR_TRACKING_URI) {
  709. nsIDocument* doc = mLoader->GetDocument();
  710. if (doc) {
  711. for (SheetLoadData* data = this; data; data = data->mNext) {
  712. // mOwningElement may be null but AddBlockTrackingNode can cope
  713. nsCOMPtr<nsIContent> content = do_QueryInterface(data->mOwningElement);
  714. doc->AddBlockedTrackingNode(content);
  715. }
  716. }
  717. }
  718. mLoader->SheetComplete(this, aStatus);
  719. return NS_OK;
  720. }
  721. nsCOMPtr<nsIChannel> channel;
  722. nsresult result = aLoader->GetChannel(getter_AddRefs(channel));
  723. if (NS_FAILED(result)) {
  724. LOG_WARN((" No channel from loader"));
  725. mLoader->SheetComplete(this, result);
  726. return NS_OK;
  727. }
  728. nsCOMPtr<nsIURI> originalURI;
  729. channel->GetOriginalURI(getter_AddRefs(originalURI));
  730. // If the channel's original URI is "chrome:", we want that, since
  731. // the observer code in nsXULPrototypeCache depends on chrome stylesheets
  732. // having a chrome URI. (Whether or not chrome stylesheets come through
  733. // this codepath seems nondeterministic.)
  734. // Otherwise we want the potentially-HTTP-redirected URI.
  735. nsCOMPtr<nsIURI> channelURI;
  736. NS_GetFinalChannelURI(channel, getter_AddRefs(channelURI));
  737. if (!channelURI || !originalURI) {
  738. NS_ERROR("Someone just violated the nsIRequest contract");
  739. LOG_WARN((" Channel without a URI. Bad!"));
  740. mLoader->SheetComplete(this, NS_ERROR_UNEXPECTED);
  741. return NS_OK;
  742. }
  743. nsCOMPtr<nsIPrincipal> principal;
  744. nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
  745. result = NS_ERROR_NOT_AVAILABLE;
  746. if (secMan) { // Could be null if we already shut down
  747. if (mUseSystemPrincipal) {
  748. result = secMan->GetSystemPrincipal(getter_AddRefs(principal));
  749. } else {
  750. result = secMan->GetChannelResultPrincipal(channel, getter_AddRefs(principal));
  751. }
  752. }
  753. if (NS_FAILED(result)) {
  754. LOG_WARN((" Couldn't get principal"));
  755. mLoader->SheetComplete(this, result);
  756. return NS_OK;
  757. }
  758. mSheet->SetPrincipal(principal);
  759. // If it's an HTTP channel, we want to make sure this is not an
  760. // error document we got.
  761. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  762. if (httpChannel) {
  763. bool requestSucceeded;
  764. result = httpChannel->GetRequestSucceeded(&requestSucceeded);
  765. if (NS_SUCCEEDED(result) && !requestSucceeded) {
  766. LOG((" Load returned an error page"));
  767. mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
  768. return NS_OK;
  769. }
  770. }
  771. nsAutoCString contentType;
  772. if (channel) {
  773. channel->GetContentType(contentType);
  774. }
  775. // In standards mode, a style sheet must have one of these MIME
  776. // types to be processed at all. In quirks mode, we accept any
  777. // MIME type, but only if the style sheet is same-origin with the
  778. // requesting document or parent sheet. See bug 524223.
  779. bool validType = contentType.EqualsLiteral("text/css") ||
  780. contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
  781. contentType.IsEmpty();
  782. if (!validType) {
  783. const char *errorMessage;
  784. uint32_t errorFlag;
  785. bool sameOrigin = true;
  786. if (mLoaderPrincipal) {
  787. bool subsumed;
  788. result = mLoaderPrincipal->Subsumes(principal, &subsumed);
  789. if (NS_FAILED(result) || !subsumed) {
  790. sameOrigin = false;
  791. }
  792. }
  793. if (sameOrigin && mLoader->mCompatMode == eCompatibility_NavQuirks) {
  794. errorMessage = "MimeNotCssWarn";
  795. errorFlag = nsIScriptError::warningFlag;
  796. } else {
  797. errorMessage = "MimeNotCss";
  798. errorFlag = nsIScriptError::errorFlag;
  799. }
  800. const nsAFlatString& specUTF16 =
  801. NS_ConvertUTF8toUTF16(channelURI->GetSpecOrDefault());
  802. const nsAFlatString& ctypeUTF16 = NS_ConvertASCIItoUTF16(contentType);
  803. const char16_t *strings[] = { specUTF16.get(), ctypeUTF16.get() };
  804. nsCOMPtr<nsIURI> referrer = GetReferrerURI();
  805. nsContentUtils::ReportToConsole(errorFlag,
  806. NS_LITERAL_CSTRING("CSS Loader"),
  807. mLoader->mDocument,
  808. nsContentUtils::eCSS_PROPERTIES,
  809. errorMessage,
  810. strings, ArrayLength(strings),
  811. referrer);
  812. if (errorFlag == nsIScriptError::errorFlag) {
  813. LOG_WARN((" Ignoring sheet with improper MIME type %s",
  814. contentType.get()));
  815. mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
  816. return NS_OK;
  817. }
  818. }
  819. SRIMetadata sriMetadata;
  820. mSheet->GetIntegrity(sriMetadata);
  821. if (sriMetadata.IsEmpty()) {
  822. nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
  823. if (loadInfo->GetEnforceSRI()) {
  824. LOG((" Load was blocked by SRI"));
  825. MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
  826. ("css::Loader::OnStreamComplete, required SRI not found"));
  827. mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
  828. // log the failed load to web console
  829. nsCOMPtr<nsIContentSecurityPolicy> csp;
  830. loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
  831. nsAutoCString spec;
  832. mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(spec);
  833. // line number unknown. mRequestingNode doesn't bear this info.
  834. csp->LogViolationDetails(
  835. nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE,
  836. NS_ConvertUTF8toUTF16(spec), EmptyString(),
  837. 0, EmptyString(), EmptyString());
  838. return NS_OK;
  839. }
  840. } else {
  841. nsAutoCString sourceUri;
  842. if (mLoader->mDocument && mLoader->mDocument->GetDocumentURI()) {
  843. mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
  844. }
  845. nsresult rv = SRICheck::VerifyIntegrity(sriMetadata, aLoader, aBuffer,
  846. sourceUri, mLoader->mReporter);
  847. mLoader->mReporter->FlushConsoleReports(mLoader->mDocument);
  848. if (NS_FAILED(rv)) {
  849. LOG((" Load was blocked by SRI"));
  850. MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
  851. ("css::Loader::OnStreamComplete, bad metadata"));
  852. mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
  853. return NS_OK;
  854. }
  855. }
  856. // Enough to set the URIs on mSheet, since any sibling datas we have share
  857. // the same mInner as mSheet and will thus get the same URI.
  858. mSheet->SetURIs(channelURI, originalURI, channelURI);
  859. bool completed;
  860. result = mLoader->ParseSheet(aBuffer, this, completed);
  861. NS_ASSERTION(completed || !mSyncLoad, "sync load did not complete");
  862. return result;
  863. }
  864. bool
  865. Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
  866. {
  867. // A sheet is alternate if it has a nonempty title that doesn't match the
  868. // currently selected style set. But if there _is_ no currently selected
  869. // style set, the sheet wasn't marked as an alternate explicitly, and aTitle
  870. // is nonempty, we should select the style set corresponding to aTitle, since
  871. // that's a preferred sheet.
  872. if (aTitle.IsEmpty()) {
  873. return false;
  874. }
  875. if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) {
  876. // There's no preferred set yet, and we now have a sheet with a title.
  877. // Make that be the preferred set.
  878. mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle);
  879. // We're definitely not an alternate
  880. return false;
  881. }
  882. return !aTitle.Equals(mPreferredSheet);
  883. }
  884. nsresult
  885. Loader::ObsoleteSheet(nsIURI* aURI)
  886. {
  887. if (!mSheets) {
  888. return NS_OK;
  889. }
  890. if (!aURI) {
  891. return NS_ERROR_INVALID_ARG;
  892. }
  893. for (auto iter = mSheets->mCompleteSheets.Iter(); !iter.Done(); iter.Next()) {
  894. nsIURI* sheetURI = iter.Key()->GetURI();
  895. bool areEqual;
  896. nsresult rv = sheetURI->Equals(aURI, &areEqual);
  897. if (NS_SUCCEEDED(rv) && areEqual) {
  898. iter.Remove();
  899. }
  900. }
  901. return NS_OK;
  902. }
  903. nsresult
  904. Loader::CheckContentPolicy(nsIPrincipal* aSourcePrincipal,
  905. nsIURI* aTargetURI,
  906. nsISupports* aContext,
  907. bool aIsPreload)
  908. {
  909. // When performing a system load (e.g. aUseSystemPrincipal = true)
  910. // then aSourcePrincipal == null; don't consult content policies.
  911. if (!aSourcePrincipal) {
  912. return NS_OK;
  913. }
  914. nsContentPolicyType contentPolicyType =
  915. aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
  916. : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
  917. int16_t shouldLoad = nsIContentPolicy::ACCEPT;
  918. nsresult rv = NS_CheckContentLoadPolicy(contentPolicyType,
  919. aTargetURI,
  920. aSourcePrincipal,
  921. aContext,
  922. NS_LITERAL_CSTRING("text/css"),
  923. nullptr, //extra param
  924. &shouldLoad,
  925. nsContentUtils::GetContentPolicy(),
  926. nsContentUtils::GetSecurityManager());
  927. if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
  928. return NS_ERROR_CONTENT_BLOCKED;
  929. }
  930. return NS_OK;
  931. }
  932. /**
  933. * CreateSheet() creates a CSSStyleSheet object for the given URI,
  934. * if any. If there is no URI given, we just create a new style sheet
  935. * object. Otherwise, we check for an existing style sheet object for
  936. * that uri in various caches and clone it if we find it. Cloned
  937. * sheets will have the title/media/enabled state of the sheet they
  938. * are clones off; make sure to call PrepareSheet() on the result of
  939. * CreateSheet().
  940. */
  941. nsresult
  942. Loader::CreateSheet(nsIURI* aURI,
  943. nsIContent* aLinkingContent,
  944. nsIPrincipal* aLoaderPrincipal,
  945. css::SheetParsingMode aParsingMode,
  946. CORSMode aCORSMode,
  947. ReferrerPolicy aReferrerPolicy,
  948. const nsAString& aIntegrity,
  949. bool aSyncLoad,
  950. bool aHasAlternateRel,
  951. const nsAString& aTitle,
  952. StyleSheetState& aSheetState,
  953. bool *aIsAlternate,
  954. RefPtr<StyleSheet>* aSheet)
  955. {
  956. LOG(("css::Loader::CreateSheet"));
  957. NS_PRECONDITION(aSheet, "Null out param!");
  958. if (!mSheets) {
  959. mSheets = new Sheets();
  960. }
  961. *aSheet = nullptr;
  962. aSheetState = eSheetStateUnknown;
  963. // Check the alternate state before doing anything else, because it
  964. // can mess with our hashtables.
  965. *aIsAlternate = IsAlternate(aTitle, aHasAlternateRel);
  966. // XXXheycam Cached sheets currently must be CSSStyleSheets.
  967. if (aURI && GetStyleBackendType() == StyleBackendType::Gecko) {
  968. aSheetState = eSheetComplete;
  969. RefPtr<StyleSheet> sheet;
  970. // First, the XUL cache
  971. #ifdef MOZ_XUL
  972. if (IsChromeURI(aURI)) {
  973. nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
  974. if (cache) {
  975. if (cache->IsEnabled()) {
  976. sheet = cache->GetStyleSheet(aURI);
  977. LOG((" From XUL cache: %p", sheet.get()));
  978. }
  979. }
  980. }
  981. #endif
  982. bool fromCompleteSheets = false;
  983. if (!sheet) {
  984. // Then our per-document complete sheets.
  985. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
  986. StyleSheet* completeSheet = nullptr;
  987. mSheets->mCompleteSheets.Get(&key, &completeSheet);
  988. sheet = completeSheet;
  989. LOG((" From completed: %p", sheet.get()));
  990. fromCompleteSheets = !!sheet;
  991. }
  992. if (sheet) {
  993. if (sheet->IsServo()) {
  994. MOZ_CRASH("stylo: can't clone ServoStyleSheets yet");
  995. }
  996. // This sheet came from the XUL cache or our per-document hashtable; it
  997. // better be a complete sheet.
  998. NS_ASSERTION(sheet->AsGecko()->IsComplete(),
  999. "Sheet thinks it's not complete while we think it is");
  1000. // Make sure it hasn't been modified; if it has, we can't use it
  1001. if (sheet->AsGecko()->IsModified()) {
  1002. LOG((" Not cloning completed sheet %p because it's been modified",
  1003. sheet.get()));
  1004. sheet = nullptr;
  1005. fromCompleteSheets = false;
  1006. }
  1007. }
  1008. // Then loading sheets
  1009. if (!sheet && !aSyncLoad) {
  1010. aSheetState = eSheetLoading;
  1011. SheetLoadData* loadData = nullptr;
  1012. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
  1013. mSheets->mLoadingDatas.Get(&key, &loadData);
  1014. if (loadData) {
  1015. sheet = loadData->mSheet;
  1016. LOG((" From loading: %p", sheet.get()));
  1017. #ifdef DEBUG
  1018. bool debugEqual;
  1019. NS_ASSERTION((!aLoaderPrincipal && !loadData->mLoaderPrincipal) ||
  1020. (aLoaderPrincipal && loadData->mLoaderPrincipal &&
  1021. NS_SUCCEEDED(aLoaderPrincipal->
  1022. Equals(loadData->mLoaderPrincipal,
  1023. &debugEqual)) && debugEqual),
  1024. "Principals should be the same");
  1025. #endif
  1026. }
  1027. // Then alternate sheets
  1028. if (!sheet) {
  1029. aSheetState = eSheetPending;
  1030. loadData = nullptr;
  1031. mSheets->mPendingDatas.Get(&key, &loadData);
  1032. if (loadData) {
  1033. sheet = loadData->mSheet;
  1034. LOG((" From pending: %p", sheet.get()));
  1035. #ifdef DEBUG
  1036. bool debugEqual;
  1037. NS_ASSERTION((!aLoaderPrincipal && !loadData->mLoaderPrincipal) ||
  1038. (aLoaderPrincipal && loadData->mLoaderPrincipal &&
  1039. NS_SUCCEEDED(aLoaderPrincipal->
  1040. Equals(loadData->mLoaderPrincipal,
  1041. &debugEqual)) && debugEqual),
  1042. "Principals should be the same");
  1043. #endif
  1044. }
  1045. }
  1046. }
  1047. if (sheet) {
  1048. // The sheet we have now should be either incomplete or unmodified
  1049. if (sheet->IsServo()) {
  1050. MOZ_CRASH("stylo: can't clone ServoStyleSheets yet");
  1051. }
  1052. NS_ASSERTION(!sheet->AsGecko()->IsModified() ||
  1053. !sheet->AsGecko()->IsComplete(),
  1054. "Unexpected modified complete sheet");
  1055. NS_ASSERTION(sheet->AsGecko()->IsComplete() ||
  1056. aSheetState != eSheetComplete,
  1057. "Sheet thinks it's not complete while we think it is");
  1058. RefPtr<CSSStyleSheet> clonedSheet =
  1059. sheet->AsGecko()->Clone(nullptr, nullptr, nullptr, nullptr);
  1060. *aSheet = Move(clonedSheet);
  1061. if (*aSheet && fromCompleteSheets &&
  1062. !sheet->AsGecko()->GetOwnerNode() &&
  1063. !sheet->AsGecko()->GetParentSheet()) {
  1064. // The sheet we're cloning isn't actually referenced by
  1065. // anyone. Replace it in the cache, so that if our CSSOM is
  1066. // later modified we don't end up with two copies of our inner
  1067. // hanging around.
  1068. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
  1069. NS_ASSERTION((*aSheet)->AsGecko()->IsComplete(),
  1070. "Should only be caching complete sheets");
  1071. mSheets->mCompleteSheets.Put(&key, *aSheet);
  1072. }
  1073. }
  1074. }
  1075. if (!*aSheet) {
  1076. aSheetState = eSheetNeedsParser;
  1077. nsIURI *sheetURI;
  1078. nsCOMPtr<nsIURI> baseURI;
  1079. nsIURI* originalURI;
  1080. if (!aURI) {
  1081. // Inline style. Use the document's base URL so that @import in
  1082. // the inline sheet picks up the right base.
  1083. NS_ASSERTION(aLinkingContent, "Inline stylesheet without linking content?");
  1084. baseURI = aLinkingContent->GetBaseURI();
  1085. sheetURI = aLinkingContent->OwnerDoc()->GetDocumentURI();
  1086. originalURI = nullptr;
  1087. } else {
  1088. baseURI = aURI;
  1089. sheetURI = aURI;
  1090. originalURI = aURI;
  1091. }
  1092. SRIMetadata sriMetadata;
  1093. if (!aIntegrity.IsEmpty()) {
  1094. MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
  1095. ("css::Loader::CreateSheet, integrity=%s",
  1096. NS_ConvertUTF16toUTF8(aIntegrity).get()));
  1097. nsAutoCString sourceUri;
  1098. if (mDocument && mDocument->GetDocumentURI()) {
  1099. mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
  1100. }
  1101. SRICheck::IntegrityMetadata(aIntegrity, sourceUri, mReporter,
  1102. &sriMetadata);
  1103. }
  1104. if (GetStyleBackendType() == StyleBackendType::Gecko) {
  1105. *aSheet = new CSSStyleSheet(aParsingMode, aCORSMode, aReferrerPolicy, sriMetadata);
  1106. } else {
  1107. *aSheet = new ServoStyleSheet(aParsingMode, aCORSMode, aReferrerPolicy, sriMetadata);
  1108. }
  1109. (*aSheet)->SetURIs(sheetURI, originalURI, baseURI);
  1110. }
  1111. NS_ASSERTION(*aSheet, "We should have a sheet by now!");
  1112. NS_ASSERTION(aSheetState != eSheetStateUnknown, "Have to set a state!");
  1113. LOG((" State: %s", gStateStrings[aSheetState]));
  1114. return NS_OK;
  1115. }
  1116. /**
  1117. * PrepareSheet() handles setting the media and title on the sheet, as
  1118. * well as setting the enabled state based on the title and whether
  1119. * the sheet had "alternate" in its rel.
  1120. */
  1121. void
  1122. Loader::PrepareSheet(StyleSheet* aSheet,
  1123. const nsSubstring& aTitle,
  1124. const nsSubstring& aMediaString,
  1125. nsMediaList* aMediaList,
  1126. Element* aScopeElement,
  1127. bool isAlternate,
  1128. bool isExplicitlyEnabled)
  1129. {
  1130. NS_PRECONDITION(aSheet, "Must have a sheet!");
  1131. // XXXheycam Need to set media, title, etc. on ServoStyleSheets.
  1132. if (aSheet->IsServo()) {
  1133. NS_WARNING("stylo: should set metadata on ServoStyleSheets. See bug 1290209.");
  1134. return;
  1135. }
  1136. CSSStyleSheet* sheet = aSheet->AsGecko();
  1137. RefPtr<nsMediaList> mediaList(aMediaList);
  1138. if (!aMediaString.IsEmpty()) {
  1139. NS_ASSERTION(!aMediaList,
  1140. "must not provide both aMediaString and aMediaList");
  1141. mediaList = new nsMediaList();
  1142. nsCSSParser mediumParser(this);
  1143. // We have aMediaString only when linked from link elements, style
  1144. // elements, or PIs, so pass true.
  1145. mediumParser.ParseMediaList(aMediaString, nullptr, 0, mediaList, true);
  1146. }
  1147. sheet->SetMedia(mediaList);
  1148. sheet->SetTitle(aTitle);
  1149. sheet->SetEnabled(!isAlternate || isExplicitlyEnabled);
  1150. sheet->SetScopeElement(aScopeElement);
  1151. }
  1152. /**
  1153. * InsertSheetInDoc handles ordering of sheets in the document. Here
  1154. * we have two types of sheets -- those with linking elements and
  1155. * those without. The latter are loaded by Link: headers.
  1156. * The following constraints are observed:
  1157. * 1) Any sheet with a linking element comes after all sheets without
  1158. * linking elements
  1159. * 2) Sheets without linking elements are inserted in the order in
  1160. * which the inserting requests come in, since all of these are
  1161. * inserted during header data processing in the content sink
  1162. * 3) Sheets with linking elements are ordered based on document order
  1163. * as determined by CompareDocumentPosition.
  1164. */
  1165. nsresult
  1166. Loader::InsertSheetInDoc(StyleSheet* aSheet,
  1167. nsIContent* aLinkingContent,
  1168. nsIDocument* aDocument)
  1169. {
  1170. LOG(("css::Loader::InsertSheetInDoc"));
  1171. NS_PRECONDITION(aSheet, "Nothing to insert");
  1172. NS_PRECONDITION(aDocument, "Must have a document to insert into");
  1173. // XXX Need to cancel pending sheet loads for this element, if any
  1174. int32_t sheetCount = aDocument->SheetCount();
  1175. /*
  1176. * Start the walk at the _end_ of the list, since in the typical
  1177. * case we'll just want to append anyway. We want to break out of
  1178. * the loop when insertionPoint points to just before the index we
  1179. * want to insert at. In other words, when we leave the loop
  1180. * insertionPoint is the index of the stylesheet that immediately
  1181. * precedes the one we're inserting.
  1182. */
  1183. int32_t insertionPoint;
  1184. for (insertionPoint = sheetCount - 1; insertionPoint >= 0; --insertionPoint) {
  1185. StyleSheet* curSheet = aDocument->SheetAt(insertionPoint);
  1186. NS_ASSERTION(curSheet, "There must be a sheet here!");
  1187. nsCOMPtr<nsINode> sheetOwner = curSheet->GetOwnerNode();
  1188. if (sheetOwner && !aLinkingContent) {
  1189. // Keep moving; all sheets with a sheetOwner come after all
  1190. // sheets without a linkingNode
  1191. continue;
  1192. }
  1193. if (!sheetOwner) {
  1194. // Aha! The current sheet has no sheet owner, so we want to
  1195. // insert after it no matter whether we have a linkingNode
  1196. break;
  1197. }
  1198. NS_ASSERTION(aLinkingContent != sheetOwner,
  1199. "Why do we still have our old sheet?");
  1200. // Have to compare
  1201. if (nsContentUtils::PositionIsBefore(sheetOwner, aLinkingContent)) {
  1202. // The current sheet comes before us, and it better be the first
  1203. // such, because now we break
  1204. break;
  1205. }
  1206. }
  1207. ++insertionPoint; // adjust the index to the spot we want to insert in
  1208. // XXX <meta> elements do not implement nsIStyleSheetLinkingElement;
  1209. // need to fix this for them to be ordered correctly.
  1210. nsCOMPtr<nsIStyleSheetLinkingElement>
  1211. linkingElement = do_QueryInterface(aLinkingContent);
  1212. if (linkingElement) {
  1213. linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
  1214. }
  1215. aDocument->BeginUpdate(UPDATE_STYLE);
  1216. aDocument->InsertStyleSheetAt(aSheet, insertionPoint);
  1217. aDocument->EndUpdate(UPDATE_STYLE);
  1218. LOG((" Inserting into document at position %d", insertionPoint));
  1219. return NS_OK;
  1220. }
  1221. /**
  1222. * InsertChildSheet handles ordering of @import-ed sheet in their
  1223. * parent sheets. Here we want to just insert based on order of the
  1224. * @import rules that imported the sheets. In theory we can't just
  1225. * append to the end because the CSSOM can insert @import rules. In
  1226. * practice, we get the call to load the child sheet before the CSSOM
  1227. * has finished inserting the @import rule, so we have no idea where
  1228. * to put it anyway. So just append for now. (In the future if we
  1229. * want to insert the sheet at the correct position, we'll need to
  1230. * restore CSSStyleSheet::InsertStyleSheetAt, which was removed in
  1231. * bug 1220506.)
  1232. */
  1233. nsresult
  1234. Loader::InsertChildSheet(StyleSheet* aSheet,
  1235. StyleSheet* aParentSheet,
  1236. ImportRule* aParentRule)
  1237. {
  1238. LOG(("css::Loader::InsertChildSheet"));
  1239. NS_PRECONDITION(aSheet, "Nothing to insert");
  1240. NS_PRECONDITION(aParentSheet, "Need a parent to insert into");
  1241. NS_PRECONDITION(aParentSheet, "How did we get imported?");
  1242. // XXXheycam The InsertChildSheet API doesn't work with ServoStyleSheets,
  1243. // since they won't have Gecko ImportRules in them.
  1244. if (aSheet->IsServo()) {
  1245. return NS_ERROR_FAILURE;
  1246. }
  1247. // child sheets should always start out enabled, even if they got
  1248. // cloned off of top-level sheets which were disabled
  1249. aSheet->AsGecko()->SetEnabled(true);
  1250. aParentSheet->AppendStyleSheet(aSheet);
  1251. aParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
  1252. LOG((" Inserting into parent sheet"));
  1253. // LOG((" Inserting into parent sheet at position %d", insertionPoint));
  1254. return NS_OK;
  1255. }
  1256. /**
  1257. * LoadSheet handles the actual load of a sheet. If the load is
  1258. * supposed to be synchronous it just opens a channel synchronously
  1259. * using the given uri, wraps the resulting stream in a converter
  1260. * stream and calls ParseSheet. Otherwise it tries to look for an
  1261. * existing load for this URI and piggyback on it. Failing all that,
  1262. * a new load is kicked off asynchronously.
  1263. */
  1264. nsresult
  1265. Loader::LoadSheet(SheetLoadData* aLoadData,
  1266. StyleSheetState aSheetState,
  1267. bool aIsPreload)
  1268. {
  1269. LOG(("css::Loader::LoadSheet"));
  1270. NS_PRECONDITION(aLoadData, "Need a load data");
  1271. NS_PRECONDITION(aLoadData->mURI, "Need a URI to load");
  1272. NS_PRECONDITION(aLoadData->mSheet, "Need a sheet to load into");
  1273. NS_PRECONDITION(aSheetState != eSheetComplete, "Why bother?");
  1274. NS_PRECONDITION(!aLoadData->mUseSystemPrincipal || aLoadData->mSyncLoad,
  1275. "Shouldn't use system principal for async loads");
  1276. NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
  1277. LOG_URI(" Load from: '%s'", aLoadData->mURI);
  1278. nsresult rv = NS_OK;
  1279. if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
  1280. // No point starting the load; just release all the data and such.
  1281. LOG_WARN((" No document and not non-document sheet; pre-dropping load"));
  1282. SheetComplete(aLoadData, NS_BINDING_ABORTED);
  1283. return NS_BINDING_ABORTED;
  1284. }
  1285. SRIMetadata sriMetadata;
  1286. aLoadData->mSheet->GetIntegrity(sriMetadata);
  1287. if (aLoadData->mSyncLoad) {
  1288. LOG((" Synchronous load"));
  1289. NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
  1290. NS_ASSERTION(aSheetState == eSheetNeedsParser,
  1291. "Sync loads can't reuse existing async loads");
  1292. // Create a nsIUnicharStreamLoader instance to which we will feed
  1293. // the data from the sync load. Do this before creating the
  1294. // channel to make error recovery simpler.
  1295. nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
  1296. rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
  1297. if (NS_FAILED(rv)) {
  1298. LOG_ERROR((" Failed to create stream loader for sync load"));
  1299. SheetComplete(aLoadData, rv);
  1300. return rv;
  1301. }
  1302. if (mDocument) {
  1303. mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
  1304. nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
  1305. mDocument);
  1306. }
  1307. nsSecurityFlags securityFlags =
  1308. nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
  1309. nsILoadInfo::SEC_ALLOW_CHROME;
  1310. nsContentPolicyType contentPolicyType =
  1311. aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
  1312. : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
  1313. // Just load it
  1314. nsCOMPtr<nsIChannel> channel;
  1315. // Note that we are calling NS_NewChannelWithTriggeringPrincipal() with both
  1316. // a node and a principal.
  1317. // This is because of a case where the node is the document being styled and
  1318. // the principal is the stylesheet (perhaps from a different origin) that is
  1319. // applying the styles.
  1320. if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
  1321. rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
  1322. aLoadData->mURI,
  1323. aLoadData->mRequestingNode,
  1324. aLoadData->mLoaderPrincipal,
  1325. securityFlags,
  1326. contentPolicyType);
  1327. }
  1328. else {
  1329. // either we are loading something inside a document, in which case
  1330. // we should always have a requestingNode, or we are loading something
  1331. // outside a document, in which case the loadingPrincipal and the
  1332. // triggeringPrincipal should always be the systemPrincipal.
  1333. rv = NS_NewChannel(getter_AddRefs(channel),
  1334. aLoadData->mURI,
  1335. nsContentUtils::GetSystemPrincipal(),
  1336. securityFlags,
  1337. contentPolicyType);
  1338. }
  1339. if (NS_FAILED(rv)) {
  1340. LOG_ERROR((" Failed to create channel"));
  1341. SheetComplete(aLoadData, rv);
  1342. return rv;
  1343. }
  1344. nsCOMPtr<nsIInputStream> stream;
  1345. rv = channel->Open2(getter_AddRefs(stream));
  1346. if (NS_FAILED(rv)) {
  1347. LOG_ERROR((" Failed to open URI synchronously"));
  1348. SheetComplete(aLoadData, rv);
  1349. return rv;
  1350. }
  1351. // Force UA sheets to be UTF-8.
  1352. // XXX this is only necessary because the default in
  1353. // SheetLoadData::OnDetermineCharset is wrong (bug 521039).
  1354. channel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
  1355. // Manually feed the streamloader the contents of the stream.
  1356. // This will call back into OnStreamComplete
  1357. // and thence to ParseSheet. Regardless of whether this fails,
  1358. // SheetComplete has been called.
  1359. return nsSyncLoadService::PushSyncStreamToListener(stream,
  1360. streamLoader,
  1361. channel);
  1362. }
  1363. SheetLoadData* existingData = nullptr;
  1364. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
  1365. aLoadData->mLoaderPrincipal,
  1366. aLoadData->mSheet->GetCORSMode(),
  1367. aLoadData->mSheet->GetReferrerPolicy());
  1368. if (aSheetState == eSheetLoading) {
  1369. mSheets->mLoadingDatas.Get(&key, &existingData);
  1370. NS_ASSERTION(existingData, "CreateSheet lied about the state");
  1371. }
  1372. else if (aSheetState == eSheetPending){
  1373. mSheets->mPendingDatas.Get(&key, &existingData);
  1374. NS_ASSERTION(existingData, "CreateSheet lied about the state");
  1375. }
  1376. if (existingData) {
  1377. LOG((" Glomming on to existing load"));
  1378. SheetLoadData* data = existingData;
  1379. while (data->mNext) {
  1380. data = data->mNext;
  1381. }
  1382. data->mNext = aLoadData; // transfer ownership
  1383. if (aSheetState == eSheetPending && !aLoadData->mWasAlternate) {
  1384. // Kick the load off; someone cares about it right away
  1385. #ifdef DEBUG
  1386. SheetLoadData* removedData;
  1387. NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
  1388. removedData == existingData,
  1389. "Bad pending table.");
  1390. #endif
  1391. mSheets->mPendingDatas.Remove(&key);
  1392. LOG((" Forcing load of pending data"));
  1393. return LoadSheet(existingData, eSheetNeedsParser, aIsPreload);
  1394. }
  1395. // All done here; once the load completes we'll be marked complete
  1396. // automatically
  1397. return NS_OK;
  1398. }
  1399. nsCOMPtr<nsILoadGroup> loadGroup;
  1400. if (mDocument) {
  1401. loadGroup = mDocument->GetDocumentLoadGroup();
  1402. // load for a document with no loadgrup indicates that something is
  1403. // completely bogus, let's bail out early.
  1404. if (!loadGroup) {
  1405. LOG_ERROR((" Failed to query loadGroup from document"));
  1406. SheetComplete(aLoadData, NS_ERROR_UNEXPECTED);
  1407. return NS_ERROR_UNEXPECTED;
  1408. }
  1409. }
  1410. #ifdef DEBUG
  1411. mSyncCallback = true;
  1412. #endif
  1413. CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
  1414. nsSecurityFlags securityFlags =
  1415. ourCORSMode == CORS_NONE
  1416. ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
  1417. : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
  1418. if (ourCORSMode == CORS_ANONYMOUS) {
  1419. securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
  1420. } else if (ourCORSMode == CORS_USE_CREDENTIALS) {
  1421. securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
  1422. }
  1423. securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
  1424. nsContentPolicyType contentPolicyType =
  1425. aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
  1426. : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
  1427. nsCOMPtr<nsIChannel> channel;
  1428. // Note we are calling NS_NewChannelWithTriggeringPrincipal here with a node
  1429. // and a principal. This is because of a case where the node is the document
  1430. // being styled and the principal is the stylesheet (perhaps from a different
  1431. // origin) that is applying the styles.
  1432. if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
  1433. rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
  1434. aLoadData->mURI,
  1435. aLoadData->mRequestingNode,
  1436. aLoadData->mLoaderPrincipal,
  1437. securityFlags,
  1438. contentPolicyType,
  1439. loadGroup,
  1440. nullptr, // aCallbacks
  1441. nsIChannel::LOAD_NORMAL |
  1442. nsIChannel::LOAD_CLASSIFY_URI);
  1443. }
  1444. else {
  1445. // either we are loading something inside a document, in which case
  1446. // we should always have a requestingNode, or we are loading something
  1447. // outside a document, in which case the loadingPrincipal and the
  1448. // triggeringPrincipal should always be the systemPrincipal.
  1449. rv = NS_NewChannel(getter_AddRefs(channel),
  1450. aLoadData->mURI,
  1451. nsContentUtils::GetSystemPrincipal(),
  1452. securityFlags,
  1453. contentPolicyType,
  1454. loadGroup,
  1455. nullptr, // aCallbacks
  1456. nsIChannel::LOAD_NORMAL |
  1457. nsIChannel::LOAD_CLASSIFY_URI);
  1458. }
  1459. if (NS_FAILED(rv)) {
  1460. #ifdef DEBUG
  1461. mSyncCallback = false;
  1462. #endif
  1463. LOG_ERROR((" Failed to create channel"));
  1464. SheetComplete(aLoadData, rv);
  1465. return rv;
  1466. }
  1467. if (!aLoadData->mWasAlternate) {
  1468. nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
  1469. if (cos) {
  1470. cos->AddClassFlags(nsIClassOfService::Leader);
  1471. }
  1472. }
  1473. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  1474. if (httpChannel) {
  1475. nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
  1476. if (referrerURI)
  1477. httpChannel->SetReferrerWithPolicy(referrerURI,
  1478. aLoadData->mSheet->GetReferrerPolicy());
  1479. nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
  1480. if (internalChannel) {
  1481. internalChannel->SetIntegrityMetadata(sriMetadata.GetIntegrityString());
  1482. }
  1483. // Set the initiator type
  1484. nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
  1485. if (timedChannel) {
  1486. if (aLoadData->mParentData) {
  1487. timedChannel->SetInitiatorType(NS_LITERAL_STRING("css"));
  1488. } else {
  1489. timedChannel->SetInitiatorType(NS_LITERAL_STRING("link"));
  1490. }
  1491. }
  1492. }
  1493. // Now tell the channel we expect text/css data back.... We do
  1494. // this before opening it, so it's only treated as a hint.
  1495. channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
  1496. // We don't have to hold on to the stream loader. The ownership
  1497. // model is: Necko owns the stream loader, which owns the load data,
  1498. // which owns us
  1499. nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
  1500. rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
  1501. if (NS_FAILED(rv)) {
  1502. #ifdef DEBUG
  1503. mSyncCallback = false;
  1504. #endif
  1505. LOG_ERROR((" Failed to create stream loader"));
  1506. SheetComplete(aLoadData, rv);
  1507. return rv;
  1508. }
  1509. if (mDocument) {
  1510. mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
  1511. nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
  1512. mDocument);
  1513. }
  1514. rv = channel->AsyncOpen2(streamLoader);
  1515. #ifdef DEBUG
  1516. mSyncCallback = false;
  1517. #endif
  1518. if (NS_FAILED(rv)) {
  1519. LOG_ERROR((" Failed to create stream loader"));
  1520. SheetComplete(aLoadData, rv);
  1521. return rv;
  1522. }
  1523. mSheets->mLoadingDatas.Put(&key, aLoadData);
  1524. aLoadData->mIsLoading = true;
  1525. return NS_OK;
  1526. }
  1527. /**
  1528. * ParseSheet handles parsing the data stream. The main idea here is
  1529. * to push the current load data onto the parse stack before letting
  1530. * the CSS parser at the data stream. That lets us handle @import
  1531. * correctly.
  1532. */
  1533. nsresult
  1534. Loader::ParseSheet(const nsAString& aInput,
  1535. SheetLoadData* aLoadData,
  1536. bool& aCompleted)
  1537. {
  1538. LOG(("css::Loader::ParseSheet"));
  1539. NS_PRECONDITION(aLoadData, "Must have load data");
  1540. NS_PRECONDITION(aLoadData->mSheet, "Must have sheet to parse into");
  1541. aCompleted = false;
  1542. // Push our load data on the stack so any kids can pick it up
  1543. mParsingDatas.AppendElement(aLoadData);
  1544. nsIURI* sheetURI = aLoadData->mSheet->GetSheetURI();
  1545. nsIURI* baseURI = aLoadData->mSheet->GetBaseURI();
  1546. nsresult rv;
  1547. if (aLoadData->mSheet->IsGecko()) {
  1548. nsCSSParser parser(this, aLoadData->mSheet->AsGecko());
  1549. rv = parser.ParseSheet(aInput, sheetURI, baseURI,
  1550. aLoadData->mSheet->Principal(),
  1551. aLoadData->mLineNumber);
  1552. } else {
  1553. rv =
  1554. aLoadData->mSheet->AsServo()->ParseSheet(aInput, sheetURI, baseURI,
  1555. aLoadData->mSheet->Principal(),
  1556. aLoadData->mLineNumber);
  1557. }
  1558. mParsingDatas.RemoveElementAt(mParsingDatas.Length() - 1);
  1559. if (NS_FAILED(rv)) {
  1560. LOG_ERROR((" Low-level error in parser!"));
  1561. SheetComplete(aLoadData, rv);
  1562. return rv;
  1563. }
  1564. NS_ASSERTION(aLoadData->mPendingChildren == 0 || !aLoadData->mSyncLoad,
  1565. "Sync load has leftover pending children!");
  1566. if (aLoadData->mPendingChildren == 0) {
  1567. LOG((" No pending kids from parse"));
  1568. aCompleted = true;
  1569. SheetComplete(aLoadData, NS_OK);
  1570. }
  1571. // Otherwise, the children are holding strong refs to the data and
  1572. // will call SheetComplete() on it when they complete.
  1573. return NS_OK;
  1574. }
  1575. /**
  1576. * SheetComplete is the do-it-all cleanup function. It removes the
  1577. * load data from the "loading" hashtable, adds the sheet to the
  1578. * "completed" hashtable, massages the XUL cache, handles siblings of
  1579. * the load data (other loads for the same URI), handles unblocking
  1580. * blocked parent loads as needed, and most importantly calls
  1581. * NS_RELEASE on the load data to destroy the whole mess.
  1582. */
  1583. void
  1584. Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus)
  1585. {
  1586. LOG(("css::Loader::SheetComplete"));
  1587. if (aLoadData->mSheet->IsServo() && NS_FAILED(aStatus)) {
  1588. aLoadData->mSheet->AsServo()->LoadFailed();
  1589. }
  1590. // 8 is probably big enough for all our common cases. It's not likely that
  1591. // imports will nest more than 8 deep, and multiple sheets with the same URI
  1592. // are rare.
  1593. AutoTArray<RefPtr<SheetLoadData>, 8> datasToNotify;
  1594. DoSheetComplete(aLoadData, aStatus, datasToNotify);
  1595. // Now it's safe to go ahead and notify observers
  1596. uint32_t count = datasToNotify.Length();
  1597. mDatasToNotifyOn += count;
  1598. for (uint32_t i = 0; i < count; ++i) {
  1599. --mDatasToNotifyOn;
  1600. SheetLoadData* data = datasToNotify[i];
  1601. NS_ASSERTION(data && data->mMustNotify, "How did this data get here?");
  1602. if (data->mObserver) {
  1603. LOG((" Notifying observer %p for data %p. wasAlternate: %d",
  1604. data->mObserver.get(), data, data->mWasAlternate));
  1605. data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
  1606. aStatus);
  1607. }
  1608. nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> >::ForwardIterator iter(mObservers);
  1609. nsCOMPtr<nsICSSLoaderObserver> obs;
  1610. while (iter.HasMore()) {
  1611. obs = iter.GetNext();
  1612. LOG((" Notifying global observer %p for data %p. wasAlternate: %d",
  1613. obs.get(), data, data->mWasAlternate));
  1614. obs->StyleSheetLoaded(data->mSheet, data->mWasAlternate, aStatus);
  1615. }
  1616. }
  1617. if (mSheets->mLoadingDatas.Count() == 0 && mSheets->mPendingDatas.Count() > 0) {
  1618. LOG((" No more loading sheets; starting alternates"));
  1619. StartAlternateLoads();
  1620. }
  1621. }
  1622. void
  1623. Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
  1624. LoadDataArray& aDatasToNotify)
  1625. {
  1626. LOG(("css::Loader::DoSheetComplete"));
  1627. NS_PRECONDITION(aLoadData, "Must have a load data!");
  1628. NS_PRECONDITION(aLoadData->mSheet, "Must have a sheet");
  1629. NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
  1630. LOG(("Load completed, status: 0x%x", aStatus));
  1631. // Twiddle the hashtables
  1632. if (aLoadData->mURI) {
  1633. LOG_URI(" Finished loading: '%s'", aLoadData->mURI);
  1634. // Remove the data from the list of loading datas
  1635. if (aLoadData->mIsLoading) {
  1636. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
  1637. aLoadData->mLoaderPrincipal,
  1638. aLoadData->mSheet->GetCORSMode(),
  1639. aLoadData->mSheet->GetReferrerPolicy());
  1640. #ifdef DEBUG
  1641. SheetLoadData *loadingData;
  1642. NS_ASSERTION(mSheets->mLoadingDatas.Get(&key, &loadingData) &&
  1643. loadingData == aLoadData,
  1644. "Bad loading table");
  1645. #endif
  1646. mSheets->mLoadingDatas.Remove(&key);
  1647. aLoadData->mIsLoading = false;
  1648. }
  1649. }
  1650. // Go through and deal with the whole linked list.
  1651. SheetLoadData* data = aLoadData;
  1652. while (data) {
  1653. if (!data->mSheetAlreadyComplete) {
  1654. // If mSheetAlreadyComplete, then the sheet could well be modified between
  1655. // when we posted the async call to SheetComplete and now, since the sheet
  1656. // was page-accessible during that whole time.
  1657. MOZ_ASSERT(!(data->mSheet->IsGecko() &&
  1658. data->mSheet->AsGecko()->IsModified()),
  1659. "should not get marked modified during parsing");
  1660. data->mSheet->SetComplete();
  1661. data->ScheduleLoadEventIfNeeded(aStatus);
  1662. }
  1663. if (data->mMustNotify && (data->mObserver || !mObservers.IsEmpty())) {
  1664. // Don't notify here so we don't trigger script. Remember the
  1665. // info we need to notify, then do it later when it's safe.
  1666. aDatasToNotify.AppendElement(data);
  1667. // On append failure, just press on. We'll fail to notify the observer,
  1668. // but not much we can do about that....
  1669. }
  1670. NS_ASSERTION(!data->mParentData ||
  1671. data->mParentData->mPendingChildren != 0,
  1672. "Broken pending child count on our parent");
  1673. // If we have a parent, our parent is no longer being parsed, and
  1674. // we are the last pending child, then our load completion
  1675. // completes the parent too. Note that the parent _can_ still be
  1676. // being parsed (eg if the child (us) failed to open the channel
  1677. // or some such).
  1678. if (data->mParentData &&
  1679. --(data->mParentData->mPendingChildren) == 0 &&
  1680. !mParsingDatas.Contains(data->mParentData)) {
  1681. DoSheetComplete(data->mParentData, aStatus, aDatasToNotify);
  1682. }
  1683. data = data->mNext;
  1684. }
  1685. // Now that it's marked complete, put the sheet in our cache.
  1686. // If we ever start doing this for failure aStatus, we'll need to
  1687. // adjust the PostLoadEvent code that thinks anything already
  1688. // complete must have loaded succesfully.
  1689. if (NS_SUCCEEDED(aStatus) && aLoadData->mURI) {
  1690. // Pick our sheet to cache carefully. Ideally, we want to cache
  1691. // one of the sheets that will be kept alive by a document or
  1692. // parent sheet anyway, so that if someone then accesses it via
  1693. // CSSOM we won't have extra clones of the inner lying around.
  1694. if (aLoadData->mSheet->IsGecko()) {
  1695. data = aLoadData;
  1696. CSSStyleSheet* sheet = aLoadData->mSheet->AsGecko();
  1697. while (data) {
  1698. if (data->mSheet->GetParentSheet() || data->mSheet->GetOwnerNode()) {
  1699. sheet = data->mSheet->AsGecko();
  1700. break;
  1701. }
  1702. data = data->mNext;
  1703. }
  1704. #ifdef MOZ_XUL
  1705. if (IsChromeURI(aLoadData->mURI)) {
  1706. nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
  1707. if (cache && cache->IsEnabled()) {
  1708. if (!cache->GetStyleSheet(aLoadData->mURI)) {
  1709. LOG((" Putting sheet in XUL prototype cache"));
  1710. NS_ASSERTION(sheet->IsComplete(),
  1711. "Should only be caching complete sheets");
  1712. cache->PutStyleSheet(sheet);
  1713. }
  1714. }
  1715. }
  1716. else {
  1717. #endif
  1718. URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
  1719. aLoadData->mLoaderPrincipal,
  1720. aLoadData->mSheet->GetCORSMode(),
  1721. aLoadData->mSheet->GetReferrerPolicy());
  1722. NS_ASSERTION(sheet->IsComplete(),
  1723. "Should only be caching complete sheets");
  1724. mSheets->mCompleteSheets.Put(&key, sheet);
  1725. #ifdef MOZ_XUL
  1726. }
  1727. #endif
  1728. } else {
  1729. NS_WARNING("stylo: Stylesheet caching not yet supported - see bug 1290218.");
  1730. }
  1731. }
  1732. NS_RELEASE(aLoadData); // this will release parents and siblings and all that
  1733. }
  1734. nsresult
  1735. Loader::LoadInlineStyle(nsIContent* aElement,
  1736. const nsAString& aBuffer,
  1737. uint32_t aLineNumber,
  1738. const nsAString& aTitle,
  1739. const nsAString& aMedia,
  1740. Element* aScopeElement,
  1741. nsICSSLoaderObserver* aObserver,
  1742. bool* aCompleted,
  1743. bool* aIsAlternate,
  1744. bool* aIsExplicitlyEnabled)
  1745. {
  1746. LOG(("css::Loader::LoadInlineStyle"));
  1747. NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
  1748. *aCompleted = true;
  1749. if (!mEnabled) {
  1750. LOG_WARN((" Not enabled"));
  1751. return NS_ERROR_NOT_AVAILABLE;
  1752. }
  1753. NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
  1754. nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
  1755. NS_ASSERTION(owningElement, "Element is not a style linking element!");
  1756. // Since we're not planning to load a URI, no need to hand a principal to the
  1757. // load data or to CreateSheet(). Also, OK to use CORS_NONE for the CORS
  1758. // mode and mDocument's ReferrerPolicy.
  1759. StyleSheetState state;
  1760. RefPtr<StyleSheet> sheet;
  1761. nsresult rv = CreateSheet(nullptr, aElement, nullptr, eAuthorSheetFeatures,
  1762. CORS_NONE, mDocument->GetReferrerPolicy(),
  1763. EmptyString(), // no inline integrity checks
  1764. false, false, aTitle, state, aIsAlternate,
  1765. &sheet);
  1766. NS_ENSURE_SUCCESS(rv, rv);
  1767. NS_ASSERTION(state == eSheetNeedsParser,
  1768. "Inline sheets should not be cached");
  1769. LOG((" Sheet is alternate: %d", *aIsAlternate));
  1770. LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled));
  1771. PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate, *aIsExplicitlyEnabled);
  1772. if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  1773. ShadowRoot* containingShadow = aElement->GetContainingShadow();
  1774. MOZ_ASSERT(containingShadow);
  1775. containingShadow->InsertSheet(sheet, aElement);
  1776. } else {
  1777. rv = InsertSheetInDoc(sheet, aElement, mDocument);
  1778. NS_ENSURE_SUCCESS(rv, rv);
  1779. }
  1780. SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
  1781. owningElement, *aIsAlternate,
  1782. aObserver, nullptr, static_cast<nsINode*>(aElement));
  1783. // We never actually load this, so just set its principal directly
  1784. sheet->SetPrincipal(aElement->NodePrincipal());
  1785. NS_ADDREF(data);
  1786. data->mLineNumber = aLineNumber;
  1787. // Parse completion releases the load data
  1788. rv = ParseSheet(aBuffer, data, *aCompleted);
  1789. NS_ENSURE_SUCCESS(rv, rv);
  1790. // If aCompleted is true, |data| may well be deleted by now.
  1791. if (!*aCompleted) {
  1792. data->mMustNotify = true;
  1793. }
  1794. return rv;
  1795. }
  1796. nsresult
  1797. Loader::LoadStyleLink(nsIContent* aElement,
  1798. nsIURI* aURL,
  1799. const nsAString& aTitle,
  1800. const nsAString& aMedia,
  1801. bool aHasAlternateRel,
  1802. CORSMode aCORSMode,
  1803. ReferrerPolicy aReferrerPolicy,
  1804. const nsAString& aIntegrity,
  1805. nsICSSLoaderObserver* aObserver,
  1806. bool* aIsAlternate,
  1807. bool* aIsExplicitlyEnabled)
  1808. {
  1809. LOG(("css::Loader::LoadStyleLink"));
  1810. NS_PRECONDITION(aURL, "Must have URL to load");
  1811. NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
  1812. LOG_URI(" Link uri: '%s'", aURL);
  1813. LOG((" Link title: '%s'", NS_ConvertUTF16toUTF8(aTitle).get()));
  1814. LOG((" Link media: '%s'", NS_ConvertUTF16toUTF8(aMedia).get()));
  1815. LOG((" Link alternate rel: %d", aHasAlternateRel));
  1816. if (!mEnabled) {
  1817. LOG_WARN((" Not enabled"));
  1818. return NS_ERROR_NOT_AVAILABLE;
  1819. }
  1820. NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
  1821. nsIPrincipal* principal =
  1822. aElement ? aElement->NodePrincipal() : mDocument->NodePrincipal();
  1823. nsISupports* context = aElement;
  1824. if (!context) {
  1825. context = mDocument;
  1826. }
  1827. nsresult rv = CheckContentPolicy(principal, aURL, context, false);
  1828. if (NS_WARN_IF(NS_FAILED(rv))) {
  1829. // Don't fire the error event if our document is loaded as data. We're
  1830. // supposed to not even try to do loads in that case... Unfortunately, we
  1831. // implement that via nsDataDocumentContentPolicy, which doesn't have a good
  1832. // way to communicate back to us that _it_ is the thing that blocked the
  1833. // load.
  1834. if (aElement && !mDocument->IsLoadedAsData()) {
  1835. // Fire an async error event on it.
  1836. RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
  1837. new LoadBlockingAsyncEventDispatcher(aElement,
  1838. NS_LITERAL_STRING("error"),
  1839. false, false);
  1840. loadBlockingAsyncDispatcher->PostDOMEvent();
  1841. }
  1842. return rv;
  1843. }
  1844. StyleSheetState state;
  1845. RefPtr<StyleSheet> sheet;
  1846. rv = CreateSheet(aURL, aElement, principal, eAuthorSheetFeatures,
  1847. aCORSMode, aReferrerPolicy, aIntegrity, false,
  1848. aHasAlternateRel, aTitle, state, aIsAlternate,
  1849. &sheet);
  1850. NS_ENSURE_SUCCESS(rv, rv);
  1851. LOG((" Sheet is alternate: %d", *aIsAlternate));
  1852. LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled));
  1853. PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate, *aIsExplicitlyEnabled);
  1854. rv = InsertSheetInDoc(sheet, aElement, mDocument);
  1855. NS_ENSURE_SUCCESS(rv, rv);
  1856. nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
  1857. if (state == eSheetComplete) {
  1858. LOG((" Sheet already complete: 0x%p", sheet.get()));
  1859. if (aObserver || !mObservers.IsEmpty() || owningElement) {
  1860. rv = PostLoadEvent(aURL, sheet, aObserver, *aIsAlternate,
  1861. owningElement);
  1862. return rv;
  1863. }
  1864. return NS_OK;
  1865. }
  1866. // Now we need to actually load it
  1867. nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
  1868. SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
  1869. owningElement, *aIsAlternate,
  1870. aObserver, principal, requestingNode);
  1871. NS_ADDREF(data);
  1872. // If we have to parse and it's an alternate non-inline, defer it unless
  1873. // it's explicitly enabled.
  1874. if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 &&
  1875. *aIsAlternate && !*aIsExplicitlyEnabled) {
  1876. LOG((" Deferring alternate sheet load"));
  1877. URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI,
  1878. data->mLoaderPrincipal,
  1879. data->mSheet->GetCORSMode(),
  1880. data->mSheet->GetReferrerPolicy());
  1881. mSheets->mPendingDatas.Put(&key, data);
  1882. data->mMustNotify = true;
  1883. return NS_OK;
  1884. }
  1885. // Load completion will free the data
  1886. rv = LoadSheet(data, state, false);
  1887. NS_ENSURE_SUCCESS(rv, rv);
  1888. data->mMustNotify = true;
  1889. return rv;
  1890. }
  1891. static bool
  1892. HaveAncestorDataWithURI(SheetLoadData *aData, nsIURI *aURI)
  1893. {
  1894. if (!aData->mURI) {
  1895. // Inline style; this won't have any ancestors
  1896. MOZ_ASSERT(!aData->mParentData,
  1897. "How does inline style have a parent?");
  1898. return false;
  1899. }
  1900. bool equal;
  1901. if (NS_FAILED(aData->mURI->Equals(aURI, &equal)) || equal) {
  1902. return true;
  1903. }
  1904. // Datas down the mNext chain have the same URI as aData, so we
  1905. // don't have to compare to them. But they might have different
  1906. // parents, and we have to check all of those.
  1907. while (aData) {
  1908. if (aData->mParentData &&
  1909. HaveAncestorDataWithURI(aData->mParentData, aURI)) {
  1910. return true;
  1911. }
  1912. aData = aData->mNext;
  1913. }
  1914. return false;
  1915. }
  1916. nsresult
  1917. Loader::LoadChildSheet(StyleSheet* aParentSheet,
  1918. nsIURI* aURL,
  1919. nsMediaList* aMedia,
  1920. ImportRule* aParentRule,
  1921. LoaderReusableStyleSheets* aReusableSheets)
  1922. {
  1923. LOG(("css::Loader::LoadChildSheet"));
  1924. NS_PRECONDITION(aURL, "Must have a URI to load");
  1925. NS_PRECONDITION(aParentSheet, "Must have a parent sheet");
  1926. if (!mEnabled) {
  1927. LOG_WARN((" Not enabled"));
  1928. return NS_ERROR_NOT_AVAILABLE;
  1929. }
  1930. LOG_URI(" Child uri: '%s'", aURL);
  1931. nsCOMPtr<nsINode> owningNode;
  1932. // check for an associated document: if none, don't bother walking up the
  1933. // parent sheets
  1934. if (aParentSheet->GetAssociatedDocument()) {
  1935. StyleSheet* topSheet = aParentSheet;
  1936. while (StyleSheet* parent = topSheet->GetParentSheet()) {
  1937. topSheet = parent;
  1938. }
  1939. owningNode = topSheet->GetOwnerNode();
  1940. }
  1941. nsISupports* context = owningNode;
  1942. if (!context) {
  1943. context = mDocument;
  1944. }
  1945. nsIPrincipal* principal = aParentSheet->Principal();
  1946. nsresult rv = CheckContentPolicy(principal, aURL, context, false);
  1947. NS_ENSURE_SUCCESS(rv, rv);
  1948. SheetLoadData* parentData = nullptr;
  1949. nsCOMPtr<nsICSSLoaderObserver> observer;
  1950. int32_t count = mParsingDatas.Length();
  1951. if (count > 0) {
  1952. LOG((" Have a parent load"));
  1953. parentData = mParsingDatas.ElementAt(count - 1);
  1954. // Check for cycles
  1955. if (HaveAncestorDataWithURI(parentData, aURL)) {
  1956. // Houston, we have a loop, blow off this child and pretend this never
  1957. // happened
  1958. LOG_ERROR((" @import cycle detected, dropping load"));
  1959. return NS_OK;
  1960. }
  1961. NS_ASSERTION(parentData->mSheet == aParentSheet,
  1962. "Unexpected call to LoadChildSheet");
  1963. } else {
  1964. LOG((" No parent load; must be CSSOM"));
  1965. // No parent load data, so the sheet will need to be notified when
  1966. // we finish, if it can be, if we do the load asynchronously.
  1967. // XXXheycam ServoStyleSheet doesn't implement nsICSSLoaderObserver yet.
  1968. MOZ_ASSERT(aParentSheet->IsGecko(),
  1969. "stylo: ServoStyleSheets don't support child sheet loading yet");
  1970. observer = aParentSheet->AsGecko();
  1971. }
  1972. // Now that we know it's safe to load this (passes security check and not a
  1973. // loop) do so.
  1974. RefPtr<StyleSheet> sheet;
  1975. RefPtr<CSSStyleSheet> reusableSheet;
  1976. StyleSheetState state;
  1977. if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, reusableSheet)) {
  1978. sheet = reusableSheet;
  1979. aParentRule->SetSheet(reusableSheet);
  1980. state = eSheetComplete;
  1981. } else {
  1982. bool isAlternate;
  1983. const nsSubstring& empty = EmptyString();
  1984. // For now, use CORS_NONE for child sheets
  1985. rv = CreateSheet(aURL, nullptr, principal,
  1986. aParentSheet->ParsingMode(),
  1987. CORS_NONE, aParentSheet->GetReferrerPolicy(),
  1988. EmptyString(), // integrity is only checked on main sheet
  1989. parentData ? parentData->mSyncLoad : false,
  1990. false, empty, state, &isAlternate, &sheet);
  1991. NS_ENSURE_SUCCESS(rv, rv);
  1992. // For now, child sheets are not explicitly enabled (seventh argument is
  1993. // always false here).
  1994. PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate, false);
  1995. }
  1996. rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
  1997. NS_ENSURE_SUCCESS(rv, rv);
  1998. if (state == eSheetComplete) {
  1999. LOG((" Sheet already complete"));
  2000. // We're completely done. No need to notify, even, since the
  2001. // @import rule addition/modification will trigger the right style
  2002. // changes automatically.
  2003. return NS_OK;
  2004. }
  2005. nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
  2006. SheetLoadData* data = new SheetLoadData(this, aURL, sheet, parentData,
  2007. observer, principal, requestingNode);
  2008. NS_ADDREF(data);
  2009. bool syncLoad = data->mSyncLoad;
  2010. // Load completion will release the data
  2011. rv = LoadSheet(data, state, false);
  2012. NS_ENSURE_SUCCESS(rv, rv);
  2013. // If syncLoad is true, |data| will be deleted by now.
  2014. if (!syncLoad) {
  2015. data->mMustNotify = true;
  2016. }
  2017. return rv;
  2018. }
  2019. nsresult
  2020. Loader::LoadSheetSync(nsIURI* aURL,
  2021. SheetParsingMode aParsingMode,
  2022. bool aUseSystemPrincipal,
  2023. RefPtr<StyleSheet>* aSheet)
  2024. {
  2025. LOG(("css::Loader::LoadSheetSync"));
  2026. return InternalLoadNonDocumentSheet(aURL,
  2027. false, aParsingMode, aUseSystemPrincipal,
  2028. nullptr, EmptyCString(),
  2029. aSheet, nullptr);
  2030. }
  2031. nsresult
  2032. Loader::LoadSheet(nsIURI* aURL,
  2033. nsIPrincipal* aOriginPrincipal,
  2034. const nsCString& aCharset,
  2035. nsICSSLoaderObserver* aObserver,
  2036. RefPtr<StyleSheet>* aSheet)
  2037. {
  2038. LOG(("css::Loader::LoadSheet(aURL, aObserver, aSheet) api call"));
  2039. NS_PRECONDITION(aSheet, "aSheet is null");
  2040. return InternalLoadNonDocumentSheet(aURL,
  2041. false, eAuthorSheetFeatures, false,
  2042. aOriginPrincipal, aCharset,
  2043. aSheet, aObserver);
  2044. }
  2045. nsresult
  2046. Loader::LoadSheet(nsIURI* aURL,
  2047. bool aIsPreload,
  2048. nsIPrincipal* aOriginPrincipal,
  2049. const nsCString& aCharset,
  2050. nsICSSLoaderObserver* aObserver,
  2051. CORSMode aCORSMode,
  2052. ReferrerPolicy aReferrerPolicy,
  2053. const nsAString& aIntegrity)
  2054. {
  2055. LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
  2056. return InternalLoadNonDocumentSheet(aURL,
  2057. aIsPreload, eAuthorSheetFeatures, false,
  2058. aOriginPrincipal, aCharset,
  2059. nullptr, aObserver,
  2060. aCORSMode, aReferrerPolicy, aIntegrity);
  2061. }
  2062. nsresult
  2063. Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
  2064. bool aIsPreload,
  2065. SheetParsingMode aParsingMode,
  2066. bool aUseSystemPrincipal,
  2067. nsIPrincipal* aOriginPrincipal,
  2068. const nsCString& aCharset,
  2069. RefPtr<StyleSheet>* aSheet,
  2070. nsICSSLoaderObserver* aObserver,
  2071. CORSMode aCORSMode,
  2072. ReferrerPolicy aReferrerPolicy,
  2073. const nsAString& aIntegrity)
  2074. {
  2075. NS_PRECONDITION(aURL, "Must have a URI to load");
  2076. NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
  2077. NS_PRECONDITION(!aUseSystemPrincipal || !aObserver,
  2078. "Shouldn't load system-principal sheets async");
  2079. NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
  2080. LOG_URI(" Non-document sheet uri: '%s'", aURL);
  2081. if (aSheet) {
  2082. *aSheet = nullptr;
  2083. }
  2084. if (!mEnabled) {
  2085. LOG_WARN((" Not enabled"));
  2086. return NS_ERROR_NOT_AVAILABLE;
  2087. }
  2088. nsresult rv = CheckContentPolicy(aOriginPrincipal, aURL, mDocument, aIsPreload);
  2089. NS_ENSURE_SUCCESS(rv, rv);
  2090. StyleSheetState state;
  2091. bool isAlternate;
  2092. RefPtr<StyleSheet> sheet;
  2093. bool syncLoad = (aObserver == nullptr);
  2094. const nsSubstring& empty = EmptyString();
  2095. rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aParsingMode,
  2096. aCORSMode, aReferrerPolicy, aIntegrity, syncLoad,
  2097. false, empty, state, &isAlternate, &sheet);
  2098. NS_ENSURE_SUCCESS(rv, rv);
  2099. // Sheets can only be explicitly enabled after creation and preparation, so
  2100. // we always pass false for the initial value of the explicitly enabled flag
  2101. // when calling PrepareSheet.
  2102. PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate, false);
  2103. if (state == eSheetComplete) {
  2104. LOG((" Sheet already complete"));
  2105. if (aObserver || !mObservers.IsEmpty()) {
  2106. rv = PostLoadEvent(aURL, sheet, aObserver, false, nullptr);
  2107. }
  2108. if (aSheet) {
  2109. sheet.swap(*aSheet);
  2110. }
  2111. return rv;
  2112. }
  2113. SheetLoadData* data =
  2114. new SheetLoadData(this, aURL, sheet, syncLoad,
  2115. aUseSystemPrincipal, aCharset, aObserver,
  2116. aOriginPrincipal, mDocument);
  2117. NS_ADDREF(data);
  2118. rv = LoadSheet(data, state, aIsPreload);
  2119. NS_ENSURE_SUCCESS(rv, rv);
  2120. if (aSheet) {
  2121. sheet.swap(*aSheet);
  2122. }
  2123. if (aObserver) {
  2124. data->mMustNotify = true;
  2125. }
  2126. return rv;
  2127. }
  2128. nsresult
  2129. Loader::PostLoadEvent(nsIURI* aURI,
  2130. StyleSheet* aSheet,
  2131. nsICSSLoaderObserver* aObserver,
  2132. bool aWasAlternate,
  2133. nsIStyleSheetLinkingElement* aElement)
  2134. {
  2135. LOG(("css::Loader::PostLoadEvent"));
  2136. NS_PRECONDITION(aSheet, "Must have sheet");
  2137. NS_PRECONDITION(aObserver || !mObservers.IsEmpty() || aElement,
  2138. "Must have observer or element");
  2139. RefPtr<SheetLoadData> evt =
  2140. new SheetLoadData(this, EmptyString(), // title doesn't matter here
  2141. aURI,
  2142. aSheet,
  2143. aElement,
  2144. aWasAlternate,
  2145. aObserver,
  2146. nullptr,
  2147. mDocument);
  2148. NS_ENSURE_TRUE(evt, NS_ERROR_OUT_OF_MEMORY);
  2149. if (!mPostedEvents.AppendElement(evt)) {
  2150. return NS_ERROR_OUT_OF_MEMORY;
  2151. }
  2152. nsresult rv = NS_DispatchToCurrentThread(evt);
  2153. if (NS_FAILED(rv)) {
  2154. NS_WARNING("failed to dispatch stylesheet load event");
  2155. mPostedEvents.RemoveElement(evt);
  2156. } else {
  2157. // We'll unblock onload when we handle the event.
  2158. if (mDocument) {
  2159. mDocument->BlockOnload();
  2160. }
  2161. // We want to notify the observer for this data.
  2162. evt->mMustNotify = true;
  2163. evt->mSheetAlreadyComplete = true;
  2164. // If we get to this code, aSheet loaded correctly at some point, so
  2165. // we can just use NS_OK for the status. Note that we do this here
  2166. // and not from inside our SheetComplete so that we don't end up
  2167. // running the load event async.
  2168. evt->ScheduleLoadEventIfNeeded(NS_OK);
  2169. }
  2170. return rv;
  2171. }
  2172. void
  2173. Loader::HandleLoadEvent(SheetLoadData* aEvent)
  2174. {
  2175. // XXXbz can't assert this yet.... May not have an observer because
  2176. // we're unblocking the parser
  2177. // NS_ASSERTION(aEvent->mObserver, "Must have observer");
  2178. NS_ASSERTION(aEvent->mSheet, "Must have sheet");
  2179. // Very important: this needs to come before the SheetComplete call
  2180. // below, so that HasPendingLoads() will test true as needed under
  2181. // notifications we send from that SheetComplete call.
  2182. mPostedEvents.RemoveElement(aEvent);
  2183. if (!aEvent->mIsCancelled) {
  2184. // SheetComplete will call Release(), so give it a reference to do
  2185. // that with.
  2186. NS_ADDREF(aEvent);
  2187. SheetComplete(aEvent, NS_OK);
  2188. }
  2189. if (mDocument) {
  2190. mDocument->UnblockOnload(true);
  2191. }
  2192. }
  2193. static void
  2194. StopLoadingSheets(
  2195. nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>& aDatas,
  2196. Loader::LoadDataArray& aArr)
  2197. {
  2198. for (auto iter = aDatas.Iter(); !iter.Done(); iter.Next()) {
  2199. SheetLoadData* data = iter.Data();
  2200. MOZ_ASSERT(data, "Must have a data!");
  2201. data->mIsLoading = false; // we will handle the removal right here
  2202. data->mIsCancelled = true;
  2203. aArr.AppendElement(data);
  2204. iter.Remove();
  2205. }
  2206. }
  2207. nsresult
  2208. Loader::Stop()
  2209. {
  2210. uint32_t pendingCount = mSheets ? mSheets->mPendingDatas.Count() : 0;
  2211. uint32_t loadingCount = mSheets ? mSheets->mLoadingDatas.Count() : 0;
  2212. LoadDataArray arr(pendingCount + loadingCount + mPostedEvents.Length());
  2213. if (pendingCount) {
  2214. StopLoadingSheets(mSheets->mPendingDatas, arr);
  2215. }
  2216. if (loadingCount) {
  2217. StopLoadingSheets(mSheets->mLoadingDatas, arr);
  2218. }
  2219. uint32_t i;
  2220. for (i = 0; i < mPostedEvents.Length(); ++i) {
  2221. SheetLoadData* data = mPostedEvents[i];
  2222. data->mIsCancelled = true;
  2223. if (arr.AppendElement(data)) {
  2224. // SheetComplete() calls Release(), so give this an extra ref.
  2225. NS_ADDREF(data);
  2226. }
  2227. #ifdef DEBUG
  2228. else {
  2229. NS_NOTREACHED("We preallocated this memory... shouldn't really fail, "
  2230. "except we never check that preallocation succeeds.");
  2231. }
  2232. #endif
  2233. }
  2234. mPostedEvents.Clear();
  2235. mDatasToNotifyOn += arr.Length();
  2236. for (i = 0; i < arr.Length(); ++i) {
  2237. --mDatasToNotifyOn;
  2238. SheetComplete(arr[i], NS_BINDING_ABORTED);
  2239. }
  2240. return NS_OK;
  2241. }
  2242. bool
  2243. Loader::HasPendingLoads()
  2244. {
  2245. return
  2246. (mSheets && mSheets->mLoadingDatas.Count() != 0) ||
  2247. (mSheets && mSheets->mPendingDatas.Count() != 0) ||
  2248. mPostedEvents.Length() != 0 ||
  2249. mDatasToNotifyOn != 0;
  2250. }
  2251. nsresult
  2252. Loader::AddObserver(nsICSSLoaderObserver* aObserver)
  2253. {
  2254. NS_PRECONDITION(aObserver, "Must have observer");
  2255. if (mObservers.AppendElementUnlessExists(aObserver)) {
  2256. return NS_OK;
  2257. }
  2258. return NS_ERROR_OUT_OF_MEMORY;
  2259. }
  2260. void
  2261. Loader::RemoveObserver(nsICSSLoaderObserver* aObserver)
  2262. {
  2263. mObservers.RemoveElement(aObserver);
  2264. }
  2265. void
  2266. Loader::StartAlternateLoads()
  2267. {
  2268. NS_PRECONDITION(mSheets, "Don't call me!");
  2269. LoadDataArray arr(mSheets->mPendingDatas.Count());
  2270. for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
  2271. arr.AppendElement(iter.Data());
  2272. iter.Remove();
  2273. }
  2274. mDatasToNotifyOn += arr.Length();
  2275. for (uint32_t i = 0; i < arr.Length(); ++i) {
  2276. --mDatasToNotifyOn;
  2277. LoadSheet(arr[i], eSheetNeedsParser, false);
  2278. }
  2279. }
  2280. NS_IMPL_CYCLE_COLLECTION_CLASS(Loader)
  2281. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Loader)
  2282. if (tmp->mSheets) {
  2283. for (auto iter = tmp->mSheets->mCompleteSheets.Iter();
  2284. !iter.Done();
  2285. iter.Next()) {
  2286. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "Sheet cache nsCSSLoader");
  2287. if (iter.UserData()->IsGecko()) {
  2288. CSSStyleSheet* sheet = iter.UserData()->AsGecko();
  2289. cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, sheet));
  2290. }
  2291. }
  2292. }
  2293. nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver>>::ForwardIterator
  2294. it(tmp->mObservers);
  2295. while (it.HasMore()) {
  2296. ImplCycleCollectionTraverse(cb, it.GetNext(),
  2297. "mozilla::css::Loader.mObservers");
  2298. }
  2299. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  2300. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Loader)
  2301. if (tmp->mSheets) {
  2302. tmp->mSheets->mCompleteSheets.Clear();
  2303. }
  2304. tmp->mObservers.Clear();
  2305. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  2306. NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Loader, AddRef)
  2307. NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Loader, Release)
  2308. size_t
  2309. Loader::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
  2310. {
  2311. size_t n = aMallocSizeOf(this);
  2312. if (mSheets) {
  2313. n += mSheets->mCompleteSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
  2314. for (auto iter = mSheets->mCompleteSheets.ConstIter();
  2315. !iter.Done();
  2316. iter.Next()) {
  2317. // If aSheet has a parent, then its parent will report it so we don't
  2318. // have to worry about it here. Likewise, if aSheet has an owning node,
  2319. // then the document that node is in will report it.
  2320. const StyleSheet* sheet = iter.UserData();
  2321. n += (sheet->GetOwnerNode() || sheet->GetParentSheet())
  2322. ? 0
  2323. : sheet->SizeOfIncludingThis(aMallocSizeOf);
  2324. }
  2325. }
  2326. n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
  2327. // Measurement of the following members may be added later if DMD finds it is
  2328. // worthwhile:
  2329. // - mLoadingDatas: transient, and should be small
  2330. // - mPendingDatas: transient, and should be small
  2331. // - mParsingDatas: transient, and should be small
  2332. // - mPostedEvents: transient, and should be small
  2333. //
  2334. // The following members aren't measured:
  2335. // - mDocument, because it's a weak backpointer
  2336. // - mPreferredSheet, because it can be a shared string
  2337. return n;
  2338. }
  2339. StyleBackendType
  2340. Loader::GetStyleBackendType() const
  2341. {
  2342. MOZ_ASSERT(mStyleBackendType || mDocument,
  2343. "you must construct a Loader with a document or set a "
  2344. "StyleBackendType on it before calling GetStyleBackendType");
  2345. if (mStyleBackendType) {
  2346. return *mStyleBackendType;
  2347. }
  2348. return mDocument->GetStyleBackendType();
  2349. }
  2350. } // namespace css
  2351. } // namespace mozilla