LCOV - code coverage report
Current view: top level - parser/html - nsHtml5TreeOpExecutor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 199 468 42.5 %
Date: 2017-07-14 16:53:18 Functions: 30 54 55.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set sw=2 ts=2 et tw=79: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/DebugOnly.h"
       8             : #include "mozilla/Likely.h"
       9             : #include "mozilla/dom/nsCSPService.h"
      10             : #include "mozilla/dom/ScriptLoader.h"
      11             : 
      12             : #include "nsError.h"
      13             : #include "nsHtml5TreeOpExecutor.h"
      14             : #include "nsIContentViewer.h"
      15             : #include "nsIContentSecurityPolicy.h"
      16             : #include "nsIDocShellTreeItem.h"
      17             : #include "nsIDocShell.h"
      18             : #include "nsIDOMDocument.h"
      19             : #include "nsIScriptGlobalObject.h"
      20             : #include "nsIWebShellServices.h"
      21             : #include "nsContentUtils.h"
      22             : #include "mozAutoDocUpdate.h"
      23             : #include "nsNetUtil.h"
      24             : #include "nsHtml5Parser.h"
      25             : #include "nsHtml5Tokenizer.h"
      26             : #include "nsHtml5TreeBuilder.h"
      27             : #include "nsHtml5StreamParser.h"
      28             : #include "mozilla/css/Loader.h"
      29             : #include "GeckoProfiler.h"
      30             : #include "nsIScriptError.h"
      31             : #include "nsIScriptContext.h"
      32             : #include "mozilla/Preferences.h"
      33             : #include "nsIHTMLDocument.h"
      34             : #include "nsIViewSourceChannel.h"
      35             : #include "xpcpublic.h"
      36             : 
      37             : using namespace mozilla;
      38             : 
      39           9 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHtml5TreeOpExecutor)
      40           7 :   NS_INTERFACE_TABLE_INHERITED(nsHtml5TreeOpExecutor,
      41             :                                nsIContentSink)
      42           7 : NS_INTERFACE_TABLE_TAIL_INHERITING(nsHtml5DocumentBuilder)
      43             : 
      44          66 : NS_IMPL_ADDREF_INHERITED(nsHtml5TreeOpExecutor, nsContentSink)
      45             : 
      46          62 : NS_IMPL_RELEASE_INHERITED(nsHtml5TreeOpExecutor, nsContentSink)
      47             : 
      48          24 : class nsHtml5ExecutorReflusher : public Runnable
      49             : {
      50             :   private:
      51             :     RefPtr<nsHtml5TreeOpExecutor> mExecutor;
      52             :   public:
      53           8 :     explicit nsHtml5ExecutorReflusher(nsHtml5TreeOpExecutor* aExecutor)
      54           8 :       : mozilla::Runnable("nsHtml5ExecutorReflusher")
      55           8 :       , mExecutor(aExecutor)
      56           8 :     {}
      57           8 :     NS_IMETHOD Run() override
      58             :     {
      59           8 :       mExecutor->RunFlushLoop();
      60           8 :       return NS_OK;
      61             :     }
      62             : };
      63             : 
      64             : static mozilla::LinkedList<nsHtml5TreeOpExecutor>* gBackgroundFlushList = nullptr;
      65             : static nsITimer* gFlushTimer = nullptr;
      66             : 
      67           2 : nsHtml5TreeOpExecutor::nsHtml5TreeOpExecutor()
      68             :   : nsHtml5DocumentBuilder(false)
      69             :   , mSuppressEOF(false)
      70             :   , mReadingFromStage(false)
      71             :   , mStreamParser(nullptr)
      72             :   , mPreloadedURLs(23)  // Mean # of preloadable resources per page on dmoz
      73             :   , mSpeculationReferrerPolicy(mozilla::net::RP_Unset)
      74             :   , mStarted(false)
      75             :   , mRunFlushLoopOnStack(false)
      76             :   , mCallContinueInterruptedParsingIfEnabled(false)
      77           2 :   , mAlreadyComplainedAboutCharset(false)
      78             : {
      79           2 : }
      80             : 
      81           0 : nsHtml5TreeOpExecutor::~nsHtml5TreeOpExecutor()
      82             : {
      83           0 :   if (gBackgroundFlushList && isInList()) {
      84           0 :     mOpQueue.Clear();
      85           0 :     removeFrom(*gBackgroundFlushList);
      86           0 :     if (gBackgroundFlushList->isEmpty()) {
      87           0 :       delete gBackgroundFlushList;
      88           0 :       gBackgroundFlushList = nullptr;
      89           0 :       if (gFlushTimer) {
      90           0 :         gFlushTimer->Cancel();
      91           0 :         NS_RELEASE(gFlushTimer);
      92             :       }
      93             :     }
      94             :   }
      95           0 :   NS_ASSERTION(mOpQueue.IsEmpty(), "Somehow there's stuff in the op queue.");
      96           0 : }
      97             : 
      98             : // nsIContentSink
      99             : NS_IMETHODIMP
     100           0 : nsHtml5TreeOpExecutor::WillParse()
     101             : {
     102           0 :   NS_NOTREACHED("No one should call this");
     103           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     104             : }
     105             : 
     106             : NS_IMETHODIMP
     107           2 : nsHtml5TreeOpExecutor::WillBuildModel(nsDTDMode aDTDMode)
     108             : {
     109           2 :   mDocument->AddObserver(this);
     110           2 :   WillBuildModelImpl();
     111           2 :   GetDocument()->BeginLoad();
     112           2 :   if (mDocShell && !GetDocument()->GetWindow() &&
     113           0 :       !IsExternalViewSource()) {
     114             :     // Not loading as data but script global object not ready
     115           0 :     return MarkAsBroken(NS_ERROR_DOM_INVALID_STATE_ERR);
     116             :   }
     117           2 :   return NS_OK;
     118             : }
     119             : 
     120             : 
     121             : // This is called when the tree construction has ended
     122             : NS_IMETHODIMP
     123           2 : nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated)
     124             : {
     125           2 :   if (!aTerminated) {
     126             :     // This is needed to avoid unblocking loads too many times on one hand
     127             :     // and on the other hand to avoid destroying the frame constructor from
     128             :     // within an update batch. See bug 537683.
     129           2 :     EndDocUpdate();
     130             :     
     131             :     // If the above caused a call to nsIParser::Terminate(), let that call
     132             :     // win.
     133           2 :     if (!mParser) {
     134           0 :       return NS_OK;
     135             :     }
     136             :   }
     137             :   
     138           2 :   if (mRunsToCompletion) {
     139           0 :     return NS_OK;
     140             :   }
     141             : 
     142           2 :   GetParser()->DropStreamParser();
     143             : 
     144             :   // This comes from nsXMLContentSink and nsHTMLContentSink
     145             :   // If this parser has been marked as broken, treat the end of parse as
     146             :   // forced termination.
     147           2 :   DidBuildModelImpl(aTerminated || NS_FAILED(IsBroken()));
     148             : 
     149           2 :   if (!mLayoutStarted) {
     150             :     // We never saw the body, and layout never got started. Force
     151             :     // layout *now*, to get an initial reflow.
     152             : 
     153             :     // NOTE: only force the layout if we are NOT destroying the
     154             :     // docshell. If we are destroying it, then starting layout will
     155             :     // likely cause us to crash, or at best waste a lot of time as we
     156             :     // are just going to tear it down anyway.
     157           0 :     bool destroying = true;
     158           0 :     if (mDocShell) {
     159           0 :       mDocShell->IsBeingDestroyed(&destroying);
     160             :     }
     161             : 
     162           0 :     if (!destroying) {
     163           0 :       nsContentSink::StartLayout(false);
     164             :     }
     165             :   }
     166             : 
     167           2 :   ScrollToRef();
     168           2 :   mDocument->RemoveObserver(this);
     169           2 :   if (!mParser) {
     170             :     // DidBuildModelImpl may cause mParser to be nulled out
     171             :     // Return early to avoid unblocking the onload event too many times.
     172           0 :     return NS_OK;
     173             :   }
     174             : 
     175             :   // We may not have called BeginLoad() if loading is terminated before
     176             :   // OnStartRequest call.
     177           2 :   if (mStarted) {
     178           2 :     mDocument->EndLoad();
     179             :   }
     180           2 :   DropParserAndPerfHint();
     181             : #ifdef GATHER_DOCWRITE_STATISTICS
     182             :   printf("UNSAFE SCRIPTS: %d\n", sUnsafeDocWrites);
     183             :   printf("TOKENIZER-SAFE SCRIPTS: %d\n", sTokenSafeDocWrites);
     184             :   printf("TREEBUILDER-SAFE SCRIPTS: %d\n", sTreeSafeDocWrites);
     185             : #endif
     186             : #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     187             :   printf("MAX NOTIFICATION BATCH LEN: %d\n", sAppendBatchMaxSize);
     188             :   if (sAppendBatchExaminations != 0) {
     189             :     printf("AVERAGE SLOTS EXAMINED: %d\n", sAppendBatchSlotsExamined / sAppendBatchExaminations);
     190             :   }
     191             : #endif
     192           2 :   return NS_OK;
     193             : }
     194             : 
     195             : NS_IMETHODIMP
     196           0 : nsHtml5TreeOpExecutor::WillInterrupt()
     197             : {
     198           0 :   NS_NOTREACHED("Don't call. For interface compat only.");
     199           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     200             : }
     201             : 
     202             : NS_IMETHODIMP
     203           0 : nsHtml5TreeOpExecutor::WillResume()
     204             : {
     205           0 :   NS_NOTREACHED("Don't call. For interface compat only.");
     206           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     207             : }
     208             : 
     209             : NS_IMETHODIMP
     210           2 : nsHtml5TreeOpExecutor::SetParser(nsParserBase* aParser)
     211             : {
     212           2 :   mParser = aParser;
     213           2 :   return NS_OK;
     214             : }
     215             : 
     216             : void
     217           0 : nsHtml5TreeOpExecutor::FlushPendingNotifications(FlushType aType)
     218             : {
     219           0 :   if (aType >= FlushType::EnsurePresShellInitAndFrames) {
     220             :     // Bug 577508 / 253951
     221           0 :     nsContentSink::StartLayout(true);
     222             :   }
     223           0 : }
     224             : 
     225             : nsISupports*
     226           5 : nsHtml5TreeOpExecutor::GetTarget()
     227             : {
     228           5 :   return mDocument;
     229             : }
     230             : 
     231             : nsresult
     232           0 : nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
     233             : {
     234           0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     235           0 :   mBroken = aReason;
     236           0 :   if (mStreamParser) {
     237           0 :     mStreamParser->Terminate();
     238             :   }
     239             :   // We are under memory pressure, but let's hope the following allocation
     240             :   // works out so that we get to terminate and clean up the parser from
     241             :   // a safer point.
     242           0 :   if (mParser && mDocument) { // can mParser ever be null here?
     243             :     nsCOMPtr<nsIRunnable> terminator =
     244           0 :       NewRunnableMethod("nsHtml5Parser::Terminate", GetParser(), &nsHtml5Parser::Terminate);
     245           0 :     if (NS_FAILED(mDocument->Dispatch("nsHtml5Parser::Terminate",
     246             :                                       TaskCategory::Network,
     247             :                                       terminator.forget()))) {
     248           0 :       NS_WARNING("failed to dispatch executor flush event");
     249             :     }
     250             :   }
     251           0 :   return aReason;
     252             : }
     253             : 
     254             : void
     255           0 : FlushTimerCallback(nsITimer* aTimer, void* aClosure)
     256             : {
     257           0 :   RefPtr<nsHtml5TreeOpExecutor> ex = gBackgroundFlushList->popFirst();
     258           0 :   if (ex) {
     259           0 :     ex->RunFlushLoop();
     260             :   }
     261           0 :   if (gBackgroundFlushList && gBackgroundFlushList->isEmpty()) {
     262           0 :     delete gBackgroundFlushList;
     263           0 :     gBackgroundFlushList = nullptr;
     264           0 :     gFlushTimer->Cancel();
     265           0 :     NS_RELEASE(gFlushTimer);
     266             :   }
     267           0 : }
     268             : 
     269             : void
     270           8 : nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
     271             : {
     272           8 :   if (!mDocument || !mDocument->IsInBackgroundWindow()) {
     273          16 :     nsCOMPtr<nsIRunnable> flusher = new nsHtml5ExecutorReflusher(this);
     274           8 :     if (NS_FAILED(mDocument->Dispatch("nsHtml5ExecutorReflusher",
     275             :                                       TaskCategory::Network,
     276             :                                       flusher.forget()))) {
     277           0 :       NS_WARNING("failed to dispatch executor flush event");
     278             :     }
     279             :   } else {
     280           0 :     if (!gBackgroundFlushList) {
     281           0 :       gBackgroundFlushList = new mozilla::LinkedList<nsHtml5TreeOpExecutor>();
     282             :     }
     283           0 :     if (!isInList()) {
     284           0 :       gBackgroundFlushList->insertBack(this);
     285             :     }
     286           0 :     if (!gFlushTimer) {
     287           0 :       nsCOMPtr<nsITimer> t = do_CreateInstance("@mozilla.org/timer;1");
     288           0 :       t.swap(gFlushTimer);
     289             :       // The timer value 50 should not hopefully slow down background pages too
     290             :       // much, yet lets event loop to process enough between ticks.
     291             :       // See bug 734015.
     292           0 :       gFlushTimer->InitWithNamedFuncCallback(FlushTimerCallback, nullptr,
     293             :                                              50, nsITimer::TYPE_REPEATING_SLACK,
     294           0 :                                              "FlushTimerCallback");
     295             :     }
     296             :   }
     297           8 : }
     298             : 
     299             : void
     300           7 : nsHtml5TreeOpExecutor::FlushSpeculativeLoads()
     301             : {
     302          14 :   nsTArray<nsHtml5SpeculativeLoad> speculativeLoadQueue;
     303           7 :   mStage.MoveSpeculativeLoadsTo(speculativeLoadQueue);
     304           7 :   const nsHtml5SpeculativeLoad* start = speculativeLoadQueue.Elements();
     305           7 :   const nsHtml5SpeculativeLoad* end = start + speculativeLoadQueue.Length();
     306          10 :   for (nsHtml5SpeculativeLoad* iter = const_cast<nsHtml5SpeculativeLoad*>(start);
     307          10 :        iter < end;
     308             :        ++iter) {
     309           3 :     if (MOZ_UNLIKELY(!mParser)) {
     310             :       // An extension terminated the parser from a HTTP observer.
     311           0 :       return;
     312             :     }
     313           3 :     iter->Perform(this);
     314             :   }
     315             : }
     316             : 
     317             : class nsHtml5FlushLoopGuard
     318             : {
     319             :   private:
     320             :     RefPtr<nsHtml5TreeOpExecutor> mExecutor;
     321             :     #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     322             :     uint32_t mStartTime;
     323             :     #endif
     324             :   public:
     325          16 :     explicit nsHtml5FlushLoopGuard(nsHtml5TreeOpExecutor* aExecutor)
     326          16 :       : mExecutor(aExecutor)
     327             :     #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     328             :       , mStartTime(PR_IntervalToMilliseconds(PR_IntervalNow()))
     329             :     #endif
     330             :     {
     331          16 :       mExecutor->mRunFlushLoopOnStack = true;
     332          16 :     }
     333          16 :     ~nsHtml5FlushLoopGuard()
     334          16 :     {
     335             :       #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     336             :         uint32_t timeOffTheEventLoop = 
     337             :           PR_IntervalToMilliseconds(PR_IntervalNow()) - mStartTime;
     338             :         if (timeOffTheEventLoop > 
     339             :             nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop) {
     340             :           nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop = 
     341             :             timeOffTheEventLoop;
     342             :         }
     343             :         printf("Longest time off the event loop: %d\n", 
     344             :           nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop);
     345             :       #endif
     346             : 
     347          16 :       mExecutor->mRunFlushLoopOnStack = false;
     348          16 :     }
     349             : };
     350             : 
     351             : /**
     352             :  * The purpose of the loop here is to avoid returning to the main event loop
     353             :  */
     354             : void
     355          16 : nsHtml5TreeOpExecutor::RunFlushLoop()
     356             : {
     357          32 :   AUTO_PROFILER_LABEL("nsHtml5TreeOpExecutor::RunFlushLoop", OTHER);
     358             : 
     359          16 :   if (mRunFlushLoopOnStack) {
     360             :     // There's already a RunFlushLoop() on the call stack.
     361           0 :     return;
     362             :   }
     363             :   
     364          32 :   nsHtml5FlushLoopGuard guard(this); // this is also the self-kungfu!
     365             :   
     366          32 :   RefPtr<nsParserBase> parserKungFuDeathGrip(mParser);
     367             : 
     368             :   // Remember the entry time
     369          16 :   (void) nsContentSink::WillParseImpl();
     370             : 
     371             :   for (;;) {
     372          21 :     if (!mParser) {
     373             :       // Parse has terminated.
     374           4 :       mOpQueue.Clear(); // clear in order to be able to assert in destructor
     375           4 :       return;
     376             :     }
     377             : 
     378          17 :     if (NS_FAILED(IsBroken())) {
     379           0 :       return;
     380             :     }
     381             : 
     382          17 :     if (!parserKungFuDeathGrip->IsParserEnabled()) {
     383             :       // The parser is blocked.
     384          10 :       return;
     385             :     }
     386             :   
     387           7 :     if (mFlushState != eNotFlushing) {
     388             :       // XXX Can this happen? In case it can, let's avoid crashing.
     389           0 :       return;
     390             :     }
     391             :     
     392             :     // If there are scripts executing, then the content sink is jumping the gun
     393             :     // (probably due to a synchronous XMLHttpRequest) and will re-enable us
     394             :     // later, see bug 460706.
     395           7 :     if (IsScriptExecuting()) {
     396           0 :       return;
     397             :     }
     398             : 
     399           7 :     if (mReadingFromStage) {
     400           4 :       nsTArray<nsHtml5SpeculativeLoad> speculativeLoadQueue;
     401           2 :       mStage.MoveOpsAndSpeculativeLoadsTo(mOpQueue, speculativeLoadQueue);
     402             :       // Make sure speculative loads never start after the corresponding
     403             :       // normal loads for the same URLs.
     404           2 :       const nsHtml5SpeculativeLoad* start = speculativeLoadQueue.Elements();
     405           2 :       const nsHtml5SpeculativeLoad* end = start + speculativeLoadQueue.Length();
     406           9 :       for (nsHtml5SpeculativeLoad* iter = (nsHtml5SpeculativeLoad*)start;
     407           9 :            iter < end;
     408             :            ++iter) {
     409           7 :         iter->Perform(this);
     410           7 :         if (MOZ_UNLIKELY(!mParser)) {
     411             :           // An extension terminated the parser from a HTTP observer.
     412           0 :           mOpQueue.Clear(); // clear in order to be able to assert in destructor
     413           0 :           return;
     414             :         }
     415             :       }
     416             :     } else {
     417           5 :       FlushSpeculativeLoads(); // Make sure speculative loads never start after
     418             :                                // the corresponding normal loads for the same
     419             :                                // URLs.
     420           5 :       if (MOZ_UNLIKELY(!mParser)) {
     421             :         // An extension terminated the parser from a HTTP observer.
     422           0 :         mOpQueue.Clear(); // clear in order to be able to assert in destructor
     423           0 :         return;
     424             :       }
     425             :       // Not sure if this grip is still needed, but previously, the code
     426             :       // gripped before calling ParseUntilBlocked();
     427             :       RefPtr<nsHtml5StreamParser> streamKungFuDeathGrip = 
     428          10 :         GetParser()->GetStreamParser();
     429             :       mozilla::Unused << streamKungFuDeathGrip; // Not used within function
     430             :       // Now parse content left in the document.write() buffer queue if any.
     431             :       // This may generate tree ops on its own or dequeue a speculation.
     432           5 :       nsresult rv = GetParser()->ParseUntilBlocked();
     433           5 :       if (NS_FAILED(rv)) {
     434           0 :         MarkAsBroken(rv);
     435           0 :         return;
     436             :       }
     437             :     }
     438             : 
     439           7 :     if (mOpQueue.IsEmpty()) {
     440             :       // Avoid bothering the rest of the engine with a doc update if there's 
     441             :       // nothing to do.
     442           0 :       return;
     443             :     }
     444             : 
     445           7 :     mFlushState = eInFlush;
     446             : 
     447           7 :     nsIContent* scriptElement = nullptr;
     448           7 :     bool interrupted = false;
     449             :     
     450           7 :     BeginDocUpdate();
     451             : 
     452           7 :     uint32_t numberOfOpsToFlush = mOpQueue.Length();
     453             : 
     454           7 :     const nsHtml5TreeOperation* first = mOpQueue.Elements();
     455           7 :     const nsHtml5TreeOperation* last = first + numberOfOpsToFlush - 1;
     456           7 :     for (nsHtml5TreeOperation* iter = const_cast<nsHtml5TreeOperation*>(first);;) {
     457          67 :       if (MOZ_UNLIKELY(!mParser)) {
     458             :         // The previous tree op caused a call to nsIParser::Terminate().
     459           0 :         break;
     460             :       }
     461          67 :       NS_ASSERTION(mFlushState == eInDocUpdate, 
     462             :         "Tried to perform tree op outside update batch.");
     463          67 :       nsresult rv = iter->Perform(this, &scriptElement, &interrupted);
     464          67 :       if (NS_FAILED(rv)) {
     465           0 :         MarkAsBroken(rv);
     466           0 :         break;
     467             :       }
     468             : 
     469             :       // Be sure not to check the deadline if the last op was just performed.
     470          67 :       if (MOZ_UNLIKELY(iter == last)) {
     471           7 :         break;
     472         120 :       } else if (MOZ_UNLIKELY(interrupted) ||
     473          60 :                  MOZ_UNLIKELY(nsContentSink::DidProcessATokenImpl() ==
     474             :                               NS_ERROR_HTMLPARSER_INTERRUPTED)) {
     475           0 :         mOpQueue.RemoveElementsAt(0, (iter - first) + 1);
     476             :         
     477           0 :         EndDocUpdate();
     478             : 
     479           0 :         mFlushState = eNotFlushing;
     480             : 
     481             :         #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     482             :           printf("REFLUSH SCHEDULED (executing ops): %d\n", 
     483             :             ++sTimesFlushLoopInterrupted);
     484             :         #endif
     485           0 :         nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
     486           0 :         return;
     487             :       }
     488          60 :       ++iter;
     489          60 :     }
     490             :     
     491           7 :     mOpQueue.Clear();
     492             :     
     493           7 :     EndDocUpdate();
     494             : 
     495           7 :     mFlushState = eNotFlushing;
     496             : 
     497           7 :     if (MOZ_UNLIKELY(!mParser)) {
     498             :       // The parse ended already.
     499           2 :       return;
     500             :     }
     501             : 
     502           5 :     if (scriptElement) {
     503             :       // must be tail call when mFlushState is eNotFlushing
     504           5 :       RunScript(scriptElement);
     505             :       
     506             :       // Always check the clock in nsContentSink right after a script
     507           5 :       StopDeflecting();
     508           5 :       if (nsContentSink::DidProcessATokenImpl() == 
     509             :           NS_ERROR_HTMLPARSER_INTERRUPTED) {
     510             :         #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
     511             :           printf("REFLUSH SCHEDULED (after script): %d\n", 
     512             :             ++sTimesFlushLoopInterrupted);
     513             :         #endif
     514           0 :         nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
     515           0 :         return;      
     516             :       }
     517             :     }
     518           5 :   }
     519             : }
     520             : 
     521             : nsresult
     522           0 : nsHtml5TreeOpExecutor::FlushDocumentWrite()
     523             : {
     524           0 :   nsresult rv = IsBroken();
     525           0 :   NS_ENSURE_SUCCESS(rv, rv);
     526             : 
     527           0 :   FlushSpeculativeLoads(); // Make sure speculative loads never start after the
     528             :                 // corresponding normal loads for the same URLs.
     529             : 
     530           0 :   if (MOZ_UNLIKELY(!mParser)) {
     531             :     // The parse has ended.
     532           0 :     mOpQueue.Clear(); // clear in order to be able to assert in destructor
     533           0 :     return rv;
     534             :   }
     535             :   
     536           0 :   if (mFlushState != eNotFlushing) {
     537             :     // XXX Can this happen? In case it can, let's avoid crashing.
     538           0 :     return rv;
     539             :   }
     540             : 
     541           0 :   mFlushState = eInFlush;
     542             : 
     543             :   // avoid crashing near EOF
     544           0 :   RefPtr<nsHtml5TreeOpExecutor> kungFuDeathGrip(this);
     545           0 :   RefPtr<nsParserBase> parserKungFuDeathGrip(mParser);
     546             :   mozilla::Unused << parserKungFuDeathGrip; // Intentionally not used within function
     547             : 
     548           0 :   NS_ASSERTION(!mReadingFromStage,
     549             :     "Got doc write flush when reading from stage");
     550             : 
     551             : #ifdef DEBUG
     552           0 :   mStage.AssertEmpty();
     553             : #endif
     554             :   
     555           0 :   nsIContent* scriptElement = nullptr;
     556           0 :   bool interrupted = false;
     557             :   
     558           0 :   BeginDocUpdate();
     559             : 
     560           0 :   uint32_t numberOfOpsToFlush = mOpQueue.Length();
     561             : 
     562           0 :   const nsHtml5TreeOperation* start = mOpQueue.Elements();
     563           0 :   const nsHtml5TreeOperation* end = start + numberOfOpsToFlush;
     564           0 :   for (nsHtml5TreeOperation* iter = const_cast<nsHtml5TreeOperation*>(start);
     565           0 :        iter < end;
     566             :        ++iter) {
     567           0 :     if (MOZ_UNLIKELY(!mParser)) {
     568             :       // The previous tree op caused a call to nsIParser::Terminate().
     569           0 :       break;
     570             :     }
     571           0 :     NS_ASSERTION(mFlushState == eInDocUpdate, 
     572             :       "Tried to perform tree op outside update batch.");
     573           0 :     rv = iter->Perform(this, &scriptElement, &interrupted);
     574           0 :     if (NS_FAILED(rv)) {
     575           0 :       MarkAsBroken(rv);
     576           0 :       break;
     577             :     }
     578             :   }
     579             : 
     580           0 :   mOpQueue.Clear();
     581             :   
     582           0 :   EndDocUpdate();
     583             : 
     584           0 :   mFlushState = eNotFlushing;
     585             : 
     586           0 :   if (MOZ_UNLIKELY(!mParser)) {
     587             :     // Ending the doc update caused a call to nsIParser::Terminate().
     588           0 :     return rv;
     589             :   }
     590             : 
     591           0 :   if (scriptElement) {
     592             :     // must be tail call when mFlushState is eNotFlushing
     593           0 :     RunScript(scriptElement);
     594             :   }
     595           0 :   return rv;
     596             : }
     597             : 
     598             : // copied from HTML content sink
     599             : bool
     600           2 : nsHtml5TreeOpExecutor::IsScriptEnabled()
     601             : {
     602             :   // Note that if we have no document or no docshell or no global or whatnot we
     603             :   // want to claim script _is_ enabled, so we don't parse the contents of
     604             :   // <noscript> tags!
     605           2 :   if (!mDocument || !mDocShell)
     606           0 :     return true;
     607           4 :   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(mDocument->GetInnerWindow());
     608             :   // Getting context is tricky if the document hasn't had its
     609             :   // GlobalObject set yet
     610           2 :   if (!globalObject) {
     611           0 :     globalObject = mDocShell->GetScriptGlobalObject();
     612             :   }
     613           2 :   NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), true);
     614           2 :   return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
     615             : }
     616             : 
     617             : void
     618           2 : nsHtml5TreeOpExecutor::StartLayout(bool* aInterrupted) {
     619           2 :   if (mLayoutStarted || !mDocument) {
     620           0 :     return;
     621             :   }
     622             : 
     623           2 :   EndDocUpdate();
     624             : 
     625           2 :   if (MOZ_UNLIKELY(!mParser)) {
     626             :     // got terminate
     627           0 :     return;
     628             :   }
     629             : 
     630           2 :   nsContentSink::StartLayout(false);
     631             : 
     632           2 :   if (mParser) {
     633           2 :     *aInterrupted = !GetParser()->IsParserEnabled();
     634             : 
     635           2 :     BeginDocUpdate();
     636             :   }
     637             : }
     638             : 
     639             : void
     640           2 : nsHtml5TreeOpExecutor::PauseDocUpdate(bool* aInterrupted) {
     641             :   // Pausing the document update allows JS to run, and potentially block
     642             :   // further parsing.
     643           2 :   EndDocUpdate();
     644             : 
     645           2 :   if (MOZ_LIKELY(mParser)) {
     646           2 :     *aInterrupted = !GetParser()->IsParserEnabled();
     647             : 
     648           2 :     BeginDocUpdate();
     649             :   }
     650           2 : }
     651             : 
     652             : /**
     653             :  * The reason why this code is here and not in the tree builder even in the 
     654             :  * main-thread case is to allow the control to return from the tokenizer 
     655             :  * before scripts run. This way, the tokenizer is not invoked re-entrantly 
     656             :  * although the parser is.
     657             :  *
     658             :  * The reason why this is called as a tail call when mFlushState is set to
     659             :  * eNotFlushing is to allow re-entry to Flush() but only after the current 
     660             :  * Flush() has cleared the op queue and is otherwise done cleaning up after 
     661             :  * itself.
     662             :  */
     663             : void
     664           5 : nsHtml5TreeOpExecutor::RunScript(nsIContent* aScriptElement)
     665             : {
     666           5 :   if (mRunsToCompletion) {
     667             :     // We are in createContextualFragment() or in the upcoming document.parse().
     668             :     // Do nothing. Let's not even mark scripts malformed here, because that
     669             :     // could cause serialization weirdness later.
     670           0 :     return;
     671             :   }
     672             : 
     673           5 :   NS_ASSERTION(aScriptElement, "No script to run");
     674          10 :   nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aScriptElement);
     675           5 :   if (!sele) {
     676           0 :     MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
     677           0 :     return;
     678             :   }
     679             :   
     680           5 :   if (!mParser) {
     681           0 :     NS_ASSERTION(sele->IsMalformed(), "Script wasn't marked as malformed.");
     682             :     // We got here not because of an end tag but because the tree builder
     683             :     // popped an incomplete script element on EOF. Returning here to avoid
     684             :     // calling back into mParser anymore.
     685           0 :     return;
     686             :   }
     687             :   
     688           5 :   if (sele->GetScriptDeferred() || sele->GetScriptAsync()) {
     689           0 :     DebugOnly<bool> block = sele->AttemptToExecute();
     690           0 :     NS_ASSERTION(!block, "Defer or async script tried to block.");
     691           0 :     return;
     692             :   }
     693             :   
     694           5 :   NS_ASSERTION(mFlushState == eNotFlushing, "Tried to run script when flushing.");
     695             : 
     696           5 :   mReadingFromStage = false;
     697             :   
     698           5 :   sele->SetCreatorParser(GetParser());
     699             : 
     700             :   // Copied from nsXMLContentSink
     701             :   // Now tell the script that it's ready to go. This may execute the script
     702             :   // or return true, or neither if the script doesn't need executing.
     703           5 :   bool block = sele->AttemptToExecute();
     704             : 
     705             :   // If the act of insertion evaluated the script, we're fine.
     706             :   // Else, block the parser till the script has loaded.
     707           5 :   if (block) {
     708           3 :     if (mParser) {
     709           3 :       GetParser()->BlockParser();
     710             :     }
     711             :   } else {
     712             :     // mParser may have been nulled out by now, but the flusher deals
     713             : 
     714             :     // If this event isn't needed, it doesn't do anything. It is sometimes
     715             :     // necessary for the parse to continue after complex situations.
     716           2 :     nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
     717             :   }
     718             : }
     719             : 
     720             : void
     721           2 : nsHtml5TreeOpExecutor::Start()
     722             : {
     723           2 :   NS_PRECONDITION(!mStarted, "Tried to start when already started.");
     724           2 :   mStarted = true;
     725           2 : }
     726             : 
     727             : void
     728           0 : nsHtml5TreeOpExecutor::NeedsCharsetSwitchTo(NotNull<const Encoding*> aEncoding,
     729             :                                             int32_t aSource,
     730             :                                             uint32_t aLineNumber)
     731             : {
     732           0 :   EndDocUpdate();
     733             : 
     734           0 :   if (MOZ_UNLIKELY(!mParser)) {
     735             :     // got terminate
     736           0 :     return;
     737             :   }
     738             :   
     739           0 :   nsCOMPtr<nsIWebShellServices> wss = do_QueryInterface(mDocShell);
     740           0 :   if (!wss) {
     741           0 :     return;
     742             :   }
     743             : 
     744             :   // ask the webshellservice to load the URL
     745           0 :   if (NS_SUCCEEDED(wss->StopDocumentLoad())) {
     746           0 :     nsAutoCString charset;
     747           0 :     aEncoding->Name(charset);
     748           0 :     wss->ReloadDocument(charset.get(), aSource);
     749             :   }
     750             :   // if the charset switch was accepted, wss has called Terminate() on the
     751             :   // parser by now
     752             : 
     753           0 :   if (!mParser) {
     754             :     // success
     755           0 :     if (aSource == kCharsetFromMetaTag) {
     756           0 :       MaybeComplainAboutCharset("EncLateMetaReload", false, aLineNumber);
     757             :     }
     758           0 :     return;
     759             :   }
     760             : 
     761           0 :   if (aSource == kCharsetFromMetaTag) {
     762           0 :     MaybeComplainAboutCharset("EncLateMetaTooLate", true, aLineNumber);
     763             :   }
     764             : 
     765           0 :   GetParser()->ContinueAfterFailedCharsetSwitch();
     766             : 
     767           0 :   BeginDocUpdate();
     768             : }
     769             : 
     770             : void
     771           0 : nsHtml5TreeOpExecutor::MaybeComplainAboutCharset(const char* aMsgId,
     772             :                                                  bool aError,
     773             :                                                  uint32_t aLineNumber)
     774             : {
     775           0 :   if (mAlreadyComplainedAboutCharset) {
     776           0 :     return;
     777             :   }
     778             :   // The EncNoDeclaration case for advertising iframes is so common that it
     779             :   // would result is way too many errors. The iframe case doesn't matter
     780             :   // when the ad is an image or a Flash animation anyway. When the ad is
     781             :   // textual, a misrendered ad probably isn't a huge loss for users.
     782             :   // Let's suppress the message in this case.
     783             :   // This means that errors about other different-origin iframes in mashups
     784             :   // are lost as well, but generally, the site author isn't in control of
     785             :   // the embedded different-origin pages anyway and can't fix problems even
     786             :   // if alerted about them.
     787           0 :   if (!strcmp(aMsgId, "EncNoDeclaration") && mDocShell) {
     788           0 :     nsCOMPtr<nsIDocShellTreeItem> parent;
     789           0 :     mDocShell->GetSameTypeParent(getter_AddRefs(parent));
     790           0 :     if (parent) {
     791           0 :       return;
     792             :     }
     793             :   }
     794           0 :   mAlreadyComplainedAboutCharset = true;
     795           0 :   nsContentUtils::ReportToConsole(aError ? nsIScriptError::errorFlag
     796             :                                          : nsIScriptError::warningFlag,
     797           0 :                                   NS_LITERAL_CSTRING("HTML parser"),
     798             :                                   mDocument,
     799             :                                   nsContentUtils::eHTMLPARSER_PROPERTIES,
     800             :                                   aMsgId,
     801             :                                   nullptr,
     802             :                                   0,
     803             :                                   nullptr,
     804             :                                   EmptyString(),
     805           0 :                                   aLineNumber);
     806             : }
     807             : 
     808             : void
     809           0 : nsHtml5TreeOpExecutor::ComplainAboutBogusProtocolCharset(nsIDocument* aDoc)
     810             : {
     811           0 :   NS_ASSERTION(!mAlreadyComplainedAboutCharset,
     812             :                "How come we already managed to complain?");
     813           0 :   mAlreadyComplainedAboutCharset = true;
     814           0 :   nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
     815           0 :                                   NS_LITERAL_CSTRING("HTML parser"),
     816             :                                   aDoc,
     817             :                                   nsContentUtils::eHTMLPARSER_PROPERTIES,
     818           0 :                                   "EncProtocolUnsupported");
     819           0 : }
     820             : 
     821             : nsHtml5Parser*
     822          29 : nsHtml5TreeOpExecutor::GetParser()
     823             : {
     824          29 :   MOZ_ASSERT(!mRunsToCompletion);
     825          29 :   return static_cast<nsHtml5Parser*>(mParser.get());
     826             : }
     827             : 
     828             : void
     829           5 : nsHtml5TreeOpExecutor::MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue)
     830             : {
     831           5 :   NS_PRECONDITION(mFlushState == eNotFlushing, "mOpQueue modified during tree op execution.");
     832           5 :   mOpQueue.AppendElements(Move(aOpQueue));
     833           5 : }
     834             : 
     835             : void
     836           5 : nsHtml5TreeOpExecutor::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, int32_t aLine)
     837             : {
     838           5 :   GetParser()->InitializeDocWriteParserState(aState, aLine);
     839           5 : }
     840             : 
     841             : nsIURI*
     842           0 : nsHtml5TreeOpExecutor::GetViewSourceBaseURI()
     843             : {
     844           0 :   if (!mViewSourceBaseURI) {
     845             : 
     846             :     // We query the channel for the baseURI because in certain situations it
     847             :     // cannot otherwise be determined. If this process fails, fall back to the
     848             :     // standard method.
     849             :     nsCOMPtr<nsIViewSourceChannel> vsc =
     850           0 :       do_QueryInterface(mDocument->GetChannel());
     851           0 :     if (vsc) {
     852           0 :       nsresult rv =  vsc->GetBaseURI(getter_AddRefs(mViewSourceBaseURI));
     853           0 :       if (NS_SUCCEEDED(rv) && mViewSourceBaseURI) {
     854           0 :         return mViewSourceBaseURI;
     855             :       }
     856             :     }
     857             : 
     858           0 :     nsCOMPtr<nsIURI> orig = mDocument->GetOriginalURI();
     859             :     bool isViewSource;
     860           0 :     orig->SchemeIs("view-source", &isViewSource);
     861           0 :     if (isViewSource) {
     862           0 :       nsCOMPtr<nsINestedURI> nested = do_QueryInterface(orig);
     863           0 :       NS_ASSERTION(nested, "URI with scheme view-source didn't QI to nested!");
     864           0 :       nested->GetInnerURI(getter_AddRefs(mViewSourceBaseURI));
     865             :     } else {
     866             :       // Fail gracefully if the base URL isn't a view-source: URL.
     867             :       // Not sure if this can ever happen.
     868           0 :       mViewSourceBaseURI = orig;
     869             :     }
     870             :   }
     871           0 :   return mViewSourceBaseURI;
     872             : }
     873             : 
     874             : //static
     875             : void
     876           3 : nsHtml5TreeOpExecutor::InitializeStatics()
     877             : {
     878             :   mozilla::Preferences::AddBoolVarCache(&sExternalViewSource,
     879           3 :                                         "view_source.editor.external");
     880           3 : }
     881             : 
     882             : bool
     883           0 : nsHtml5TreeOpExecutor::IsExternalViewSource()
     884             : {
     885           0 :   if (!sExternalViewSource) {
     886           0 :     return false;
     887             :   }
     888           0 :   bool isViewSource = false;
     889           0 :   if (mDocumentURI) {
     890           0 :     mDocumentURI->SchemeIs("view-source", &isViewSource);
     891             :   }
     892           0 :   return isViewSource;
     893             : }
     894             : 
     895             : // Speculative loading
     896             : 
     897             : nsIURI*
     898           4 : nsHtml5TreeOpExecutor::BaseURIForPreload()
     899             : {
     900             :   // The URL of the document without <base>
     901           4 :   nsIURI* documentURI = mDocument->GetDocumentURI();
     902             :   // The URL of the document with non-speculative <base>
     903           4 :   nsIURI* documentBaseURI = mDocument->GetDocBaseURI();
     904             : 
     905             :   // If the two above are different, use documentBaseURI. If they are the same,
     906             :   // the document object isn't aware of a <base>, so attempt to use the
     907             :   // mSpeculationBaseURI or, failing, that, documentURI.
     908           8 :   return (documentURI == documentBaseURI) ?
     909           4 :           (mSpeculationBaseURI ?
     910           4 :            mSpeculationBaseURI.get() : documentURI)
     911           4 :          : documentBaseURI;
     912             : }
     913             : 
     914             : already_AddRefed<nsIURI>
     915           4 : nsHtml5TreeOpExecutor::ConvertIfNotPreloadedYet(const nsAString& aURL)
     916             : {
     917           4 :   if (aURL.IsEmpty()) {
     918           0 :     return nullptr;
     919             :   }
     920             : 
     921           4 :   nsIURI* base = BaseURIForPreload();
     922           4 :   auto encoding = mDocument->GetDocumentCharacterSet();
     923           8 :   nsCOMPtr<nsIURI> uri;
     924           4 :   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, base);
     925           4 :   if (NS_FAILED(rv)) {
     926           0 :     NS_WARNING("Failed to create a URI");
     927           0 :     return nullptr;
     928             :   }
     929             : 
     930           4 :   if (ShouldPreloadURI(uri)) {
     931           4 :     return uri.forget();
     932             :   }
     933             : 
     934           0 :   return nullptr;
     935             : }
     936             : 
     937             : bool
     938           4 : nsHtml5TreeOpExecutor::ShouldPreloadURI(nsIURI *aURI)
     939             : {
     940           8 :   nsAutoCString spec;
     941           4 :   nsresult rv = aURI->GetSpec(spec);
     942           4 :   NS_ENSURE_SUCCESS(rv, false);
     943           4 :   return mPreloadedURLs.EnsureInserted(spec);
     944             : }
     945             : 
     946             : void
     947           4 : nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
     948             :                                      const nsAString& aCharset,
     949             :                                      const nsAString& aType,
     950             :                                      const nsAString& aCrossOrigin,
     951             :                                      const nsAString& aIntegrity,
     952             :                                      bool aScriptFromHead)
     953             : {
     954           8 :   nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
     955           4 :   if (!uri) {
     956           0 :     return;
     957             :   }
     958           4 :   mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin,
     959             :                                            aIntegrity, aScriptFromHead,
     960           4 :                                            mSpeculationReferrerPolicy);
     961             : }
     962             : 
     963             : void
     964           0 : nsHtml5TreeOpExecutor::PreloadStyle(const nsAString& aURL,
     965             :                                     const nsAString& aCharset,
     966             :                                     const nsAString& aCrossOrigin,
     967             :                                     const nsAString& aIntegrity)
     968             : {
     969           0 :   nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
     970           0 :   if (!uri) {
     971           0 :     return;
     972             :   }
     973           0 :   mDocument->PreloadStyle(uri, aCharset, aCrossOrigin,
     974           0 :                           mSpeculationReferrerPolicy, aIntegrity);
     975             : }
     976             : 
     977             : void
     978           0 : nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
     979             :                                     const nsAString& aCrossOrigin,
     980             :                                     const nsAString& aSrcset,
     981             :                                     const nsAString& aSizes,
     982             :                                     const nsAString& aImageReferrerPolicy)
     983             : {
     984           0 :   nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
     985           0 :   nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset,
     986           0 :                                                         aSizes);
     987           0 :   if (uri && ShouldPreloadURI(uri)) {
     988             :     // use document wide referrer policy
     989           0 :     mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy;
     990             :     mozilla::net::ReferrerPolicy imageReferrerPolicy =
     991           0 :       mozilla::net::AttributeReferrerPolicyFromString(aImageReferrerPolicy);
     992           0 :     if (imageReferrerPolicy != mozilla::net::RP_Unset) {
     993           0 :       referrerPolicy = imageReferrerPolicy;
     994             :     }
     995             : 
     996           0 :     mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy);
     997             :   }
     998           0 : }
     999             : 
    1000             : // These calls inform the document of picture state and seen sources, such that
    1001             : // it can use them to inform ResolvePreLoadImage as necessary
    1002             : void
    1003           0 : nsHtml5TreeOpExecutor::PreloadPictureSource(const nsAString& aSrcset,
    1004             :                                             const nsAString& aSizes,
    1005             :                                             const nsAString& aType,
    1006             :                                             const nsAString& aMedia)
    1007             : {
    1008           0 :   mDocument->PreloadPictureImageSource(aSrcset, aSizes, aType, aMedia);
    1009           0 : }
    1010             : 
    1011             : void
    1012           0 : nsHtml5TreeOpExecutor::PreloadOpenPicture()
    1013             : {
    1014           0 :   mDocument->PreloadPictureOpened();
    1015           0 : }
    1016             : 
    1017             : void
    1018           0 : nsHtml5TreeOpExecutor::PreloadEndPicture()
    1019             : {
    1020           0 :   mDocument->PreloadPictureClosed();
    1021           0 : }
    1022             : 
    1023             : void
    1024           0 : nsHtml5TreeOpExecutor::AddBase(const nsAString& aURL)
    1025             : {
    1026           0 :   auto encoding = mDocument->GetDocumentCharacterSet();
    1027           0 :   nsresult rv = NS_NewURI(getter_AddRefs(mViewSourceBaseURI), aURL,
    1028           0 :                           encoding, GetViewSourceBaseURI());
    1029           0 :   if (NS_FAILED(rv)) {
    1030           0 :     mViewSourceBaseURI = nullptr;
    1031             :   }
    1032           0 : }
    1033             : void
    1034           0 : nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL)
    1035             : {
    1036           0 :   if (mSpeculationBaseURI) {
    1037             :     // the first one wins
    1038           0 :     return;
    1039             :   }
    1040           0 :   auto encoding = mDocument->GetDocumentCharacterSet();
    1041           0 :   DebugOnly<nsresult> rv = NS_NewURI(getter_AddRefs(mSpeculationBaseURI), aURL,
    1042           0 :                                      encoding, mDocument->GetDocumentURI());
    1043           0 :   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to create a URI");
    1044             : }
    1045             : 
    1046             : void
    1047           0 : nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy)
    1048             : {
    1049             :   // Specs says:
    1050             :   // - Let value be the result of stripping leading and trailing whitespace from
    1051             :   // the value of element's content attribute.
    1052             :   // - If value is not the empty string, then:
    1053           0 :   if (aReferrerPolicy.IsEmpty()) {
    1054           0 :     return;
    1055             :   }
    1056             : 
    1057           0 :   ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aReferrerPolicy);
    1058             :   // Specs says:
    1059             :   // - If policy is not the empty string, then set element's node document's
    1060             :   // referrer policy to policy
    1061           0 :   if (policy != mozilla::net::RP_Unset) {
    1062           0 :     SetSpeculationReferrerPolicy(policy);
    1063             :   }
    1064             : }
    1065             : 
    1066             : void
    1067           0 : nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP)
    1068             : {
    1069           0 :   if (!CSPService::sCSPEnabled) {
    1070           0 :     return;
    1071             :   }
    1072             : 
    1073           0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1074             : 
    1075           0 :   nsIPrincipal* principal = mDocument->NodePrincipal();
    1076           0 :   nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
    1077           0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
    1078           0 :   nsresult rv = principal->EnsurePreloadCSP(domDoc, getter_AddRefs(preloadCsp));
    1079           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    1080             : 
    1081             :   // please note that meta CSPs and CSPs delivered through a header need
    1082             :   // to be joined together.
    1083           0 :   rv = preloadCsp->AppendPolicy(aCSP,
    1084             :                                 false, // csp via meta tag can not be report only
    1085           0 :                                 true); // delivered through the meta tag
    1086           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    1087             : 
    1088             :   // Record "speculated" referrer policy for preloads
    1089           0 :   bool hasReferrerPolicy = false;
    1090           0 :   uint32_t referrerPolicy = mozilla::net::RP_Unset;
    1091           0 :   rv = preloadCsp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
    1092           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    1093           0 :   if (hasReferrerPolicy) {
    1094           0 :     SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(referrerPolicy));
    1095             :   }
    1096             : 
    1097           0 :   mDocument->ApplySettingsFromCSP(true);
    1098             : }
    1099             : 
    1100             : void
    1101           0 : nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy)
    1102             : {
    1103             :   // Record "speculated" referrer policy locally and thread through the
    1104             :   // speculation phase.  The actual referrer policy will be set by
    1105             :   // HTMLMetaElement::BindToTree().
    1106           0 :   mSpeculationReferrerPolicy = aReferrerPolicy;
    1107           0 : }
    1108             : 
    1109             : #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
    1110             : uint32_t nsHtml5TreeOpExecutor::sAppendBatchMaxSize = 0;
    1111             : uint32_t nsHtml5TreeOpExecutor::sAppendBatchSlotsExamined = 0;
    1112             : uint32_t nsHtml5TreeOpExecutor::sAppendBatchExaminations = 0;
    1113             : uint32_t nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop = 0;
    1114             : uint32_t nsHtml5TreeOpExecutor::sTimesFlushLoopInterrupted = 0;
    1115             : #endif
    1116             : bool nsHtml5TreeOpExecutor::sExternalViewSource = false;

Generated by: LCOV version 1.13