1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsHtml5StreamParser_h
7 #define nsHtml5StreamParser_h
8 
9 #include <tuple>
10 
11 #include "MainThreadUtils.h"
12 #include "mozilla/AlreadyAddRefed.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Encoding.h"
15 #include "mozilla/Mutex.h"
16 #include "mozilla/NotNull.h"
17 #include "mozilla/RefPtr.h"
18 #include "mozilla/Span.h"
19 #include "mozilla/UniquePtr.h"
20 #include "nsCharsetSource.h"
21 #include "nsCOMPtr.h"
22 #include "nsCycleCollectionParticipant.h"
23 #include "nsDebug.h"
24 #include "nsHtml5AtomTable.h"
25 #include "nsIRequestObserver.h"
26 #include "nsISerialEventTarget.h"
27 #include "nsISupports.h"
28 #include "nsStringFwd.h"
29 #include "nsTArray.h"
30 #include "nscore.h"
31 
32 class nsCycleCollectionTraversalCallback;
33 class nsHtml5OwningUTF16Buffer;
34 class nsHtml5Parser;
35 class nsHtml5Speculation;
36 class nsHtml5String;
37 class nsHtml5Tokenizer;
38 class nsHtml5TreeBuilder;
39 class nsHtml5TreeOpExecutor;
40 class nsIChannel;
41 class nsIInputStream;
42 class nsIRequest;
43 class nsIRunnable;
44 class nsITimer;
45 class nsIURI;
46 
47 namespace mozilla {
48 class EncodingDetector;
49 template <typename T>
50 class Buffer;
51 
52 namespace dom {
53 class DocGroup;
54 }
55 }  // namespace mozilla
56 
57 enum eParserMode {
58   /**
59    * Parse a document normally as HTML.
60    */
61   NORMAL,
62 
63   /**
64    * View document as HTML source.
65    */
66   VIEW_SOURCE_HTML,
67 
68   /**
69    * View document as XML source
70    */
71   VIEW_SOURCE_XML,
72 
73   /**
74    * View document as plain text source
75    */
76   VIEW_SOURCE_PLAIN,
77 
78   /**
79    * View document as plain text
80    */
81   PLAIN_TEXT,
82 
83   /**
84    * Load as data (XHR)
85    */
86   LOAD_AS_DATA
87 };
88 
89 enum eBomState {
90   /**
91    * BOM sniffing hasn't started.
92    */
93   BOM_SNIFFING_NOT_STARTED,
94 
95   /**
96    * BOM sniffing is ongoing, and the first byte of an UTF-16LE BOM has been
97    * seen.
98    */
99   SEEN_UTF_16_LE_FIRST_BYTE,
100 
101   /**
102    * BOM sniffing is ongoing, and the first byte of an UTF-16BE BOM has been
103    * seen.
104    */
105   SEEN_UTF_16_BE_FIRST_BYTE,
106 
107   /**
108    * BOM sniffing is ongoing, and the first byte of an UTF-8 BOM has been
109    * seen.
110    */
111   SEEN_UTF_8_FIRST_BYTE,
112 
113   /**
114    * BOM sniffing is ongoing, and the first and second bytes of an UTF-8 BOM
115    * have been seen.
116    */
117   SEEN_UTF_8_SECOND_BYTE,
118 
119   /**
120    * Seen \x00 in UTF-16BE bogo-XML declaration.
121    */
122   SEEN_UTF_16_BE_XML_FIRST,
123 
124   /**
125    * Seen \x00< in UTF-16BE bogo-XML declaration.
126    */
127   SEEN_UTF_16_BE_XML_SECOND,
128 
129   /**
130    * Seen \x00<\x00 in UTF-16BE bogo-XML declaration.
131    */
132   SEEN_UTF_16_BE_XML_THIRD,
133 
134   /**
135    * Seen \x00<\x00? in UTF-16BE bogo-XML declaration.
136    */
137   SEEN_UTF_16_BE_XML_FOURTH,
138 
139   /**
140    * Seen \x00<\x00?\x00 in UTF-16BE bogo-XML declaration.
141    */
142   SEEN_UTF_16_BE_XML_FIFTH,
143 
144   /**
145    * Seen < in UTF-16BE bogo-XML declaration.
146    */
147   SEEN_UTF_16_LE_XML_FIRST,
148 
149   /**
150    * Seen <\x00 in UTF-16BE bogo-XML declaration.
151    */
152   SEEN_UTF_16_LE_XML_SECOND,
153 
154   /**
155    * Seen <\x00? in UTF-16BE bogo-XML declaration.
156    */
157   SEEN_UTF_16_LE_XML_THIRD,
158 
159   /**
160    * Seen <\x00?\x00 in UTF-16BE bogo-XML declaration.
161    */
162   SEEN_UTF_16_LE_XML_FOURTH,
163 
164   /**
165    * Seen <\x00?\x00x in UTF-16BE bogo-XML declaration.
166    */
167   SEEN_UTF_16_LE_XML_FIFTH,
168 
169   /**
170    * BOM sniffing was started but is now over for whatever reason.
171    */
172   BOM_SNIFFING_OVER,
173 };
174 
175 enum eHtml5StreamState {
176   STREAM_NOT_STARTED = 0,
177   STREAM_BEING_READ = 1,
178   STREAM_ENDED = 2
179 };
180 
181 class nsHtml5StreamParser final : public nsISupports {
182   template <typename T>
183   using NotNull = mozilla::NotNull<T>;
184   using Encoding = mozilla::Encoding;
185 
186   const uint32_t UNCONDITIONAL_META_SCAN_BOUNDARY = 1024;
187   const uint32_t READ_BUFFER_SIZE = 1024;
188   const uint32_t LOCAL_FILE_UTF_8_BUFFER_SIZE = 1024 * 1024 * 4;  // 4 MB
189 
190   friend class nsHtml5RequestStopper;
191   friend class nsHtml5DataAvailable;
192   friend class nsHtml5StreamParserContinuation;
193   friend class nsHtml5TimerKungFu;
194   friend class nsHtml5StreamParserPtr;
195   friend class nsHtml5StreamListener;
196 
197  public:
198   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
199   NS_DECL_CYCLE_COLLECTION_CLASS(nsHtml5StreamParser)
200 
201   nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor, nsHtml5Parser* aOwner,
202                       eParserMode aMode);
203 
204   nsresult OnStartRequest(nsIRequest* aRequest);
205 
206   nsresult OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInStream,
207                            uint64_t aSourceOffset, uint32_t aLength);
208 
209   nsresult OnStopRequest(nsIRequest* aRequest, nsresult status);
210 
211   // EncodingDeclarationHandler
212   // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
213   /**
214    * Tree builder uses this to report a late <meta charset>
215    */
216   bool internalEncodingDeclaration(nsHtml5String aEncoding);
217 
218   bool TemplatePushedOrHeadPopped();
219 
220   void RememberGt(int32_t aPos);
221 
222   // Not from an external interface
223 
224   /**
225    * Post a runnable to the main thread to perform the speculative load
226    * operations without performing the tree operations.
227    *
228    * This should be called at the end of each data available or stop
229    * request runnable running on the parser thread.
230    */
231   void PostLoadFlusher();
232 
233   /**
234    * Pass a buffer to chardetng.
235    */
236   void FeedDetector(mozilla::Span<const uint8_t> aBuffer);
237 
238   /**
239    * Report EOF to chardetng.
240    */
241   void DetectorEof();
242 
243   /**
244    *  Call this method once you've created a parser, and want to instruct it
245    *  about what charset to load
246    *
247    *  @param   aEncoding the charset of a document
248    *  @param   aCharsetSource the source of the charset
249    */
SetDocumentCharset(NotNull<const Encoding * > aEncoding,nsCharsetSource aSource,bool aForceAutoDetection)250   inline void SetDocumentCharset(NotNull<const Encoding*> aEncoding,
251                                  nsCharsetSource aSource,
252                                  bool aForceAutoDetection) {
253     MOZ_ASSERT(mStreamState == STREAM_NOT_STARTED,
254                "SetDocumentCharset called too late.");
255     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
256     MOZ_ASSERT(!(aForceAutoDetection && aSource >= kCharsetFromOtherComponent),
257                "Can't force with high-ranking source.");
258     mEncoding = aEncoding;
259     mCharsetSource = aSource;
260     mForceAutoDetection = aForceAutoDetection;
261     mChannelHadCharset = (aSource == kCharsetFromChannel);
262   }
263 
264   nsresult GetChannel(nsIChannel** aChannel);
265 
266   /**
267    * The owner parser must call this after script execution
268    * when no scripts are executing and the document.written
269    * buffer has been exhausted.
270    *
271    * If the first two arguments are nullptr, instead of
272    * continuing after scripts, this method commits to an
273    * internally-discovered encoding.
274    */
275   void ContinueAfterScriptsOrEncodingCommitment(
276       nsHtml5Tokenizer* aTokenizer, nsHtml5TreeBuilder* aTreeBuilder,
277       bool aLastWasCR);
278 
279   /**
280    * Continues the stream parser if the charset switch failed.
281    */
282   void ContinueAfterFailedCharsetSwitch();
283 
Terminate()284   void Terminate() { mTerminated = true; }
285 
286   void DropTimer();
287 
288   /**
289    * Sets the URL for View Source title in case this parser ends up being
290    * used for View Source. If aURL is a view-source: URL, takes the inner
291    * URL. data: URLs are shown with an ellipsis instead of the actual data.
292    */
293   void SetViewSourceTitle(nsIURI* aURL);
294 
295  private:
296   virtual ~nsHtml5StreamParser();
297 
298 #ifdef DEBUG
IsParserThread()299   bool IsParserThread() { return mEventTarget->IsOnCurrentThread(); }
300 #endif
301 
302   void MarkAsBroken(nsresult aRv);
303 
304   /**
305    * Marks the stream parser as interrupted. If you ever add calls to this
306    * method, be sure to review Uninterrupt usage very, very carefully to
307    * avoid having a previous in-flight runnable cancel your Interrupt()
308    * call on the other thread too soon.
309    */
Interrupt()310   void Interrupt() {
311     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
312     mInterrupted = true;
313   }
314 
Uninterrupt()315   void Uninterrupt() {
316     MOZ_ASSERT(IsParserThread(), "Wrong thread!");
317     mTokenizerMutex.AssertCurrentThreadOwns();
318     mInterrupted = false;
319   }
320 
321   /**
322    * Flushes the tree ops from the tree builder and disarms the flush
323    * timer.
324    */
325   void FlushTreeOpsAndDisarmTimer();
326 
327   void SwitchDecoderIfAsciiSoFar(NotNull<const Encoding*> aEncoding);
328 
329   size_t CountGts();
330 
331   void DiscardMetaSpeculation();
332 
333   bool ProcessLookingForMetaCharset(bool aEof);
334 
335   void ParseAvailableData();
336 
337   void DoStopRequest();
338 
339   void DoDataAvailableBuffer(mozilla::Buffer<uint8_t>&& aBuffer);
340 
341   void DoDataAvailable(mozilla::Span<const uint8_t> aBuffer);
342 
343   static nsresult CopySegmentsToParser(nsIInputStream* aInStream,
344                                        void* aClosure, const char* aFromSegment,
345                                        uint32_t aToOffset, uint32_t aCount,
346                                        uint32_t* aWriteCount);
347 
IsTerminatedOrInterrupted()348   bool IsTerminatedOrInterrupted() { return mTerminated || mInterrupted; }
349 
IsTerminated()350   bool IsTerminated() { return mTerminated; }
351 
352   /**
353    * True when there is a Unicode decoder already
354    */
HasDecoder()355   inline bool HasDecoder() { return !!mUnicodeDecoder; }
356 
357   /**
358    * Returns 0 if 1) there aren't at least 2 buffers in mBufferedBytes
359    * or 2) there is no byte '>' in the second buffer.
360    * Otherwise, returns the length of the prefix of the second buffer
361    * that is long enough to contain the first byte '>' in the second
362    * buffer (including the '>' byte).
363    */
364   size_t LengthOfLtContainingPrefixInSecondBuffer();
365 
366   /**
367    * Push bytes from network when there is no Unicode decoder yet
368    */
369   nsresult SniffStreamBytes(mozilla::Span<const uint8_t> aFromSegment,
370                             bool aEof);
371 
372   /**
373    * Push bytes from network when there is a Unicode decoder already
374    */
375   nsresult WriteStreamBytes(mozilla::Span<const uint8_t> aFromSegment);
376 
377   /**
378    * Set up the Unicode decoder and write the sniffing buffer into it
379    * followed by the current network buffer.
380    *
381    * @param aPrefix the part of the stream that has already been seen
382    *                prior to aFromSegment. In practice, these are the
383    *                bytes that are baked into the state of the BOM
384    *                and UTF-16 XML declaration-like sniffing state
385    *                machine state.
386    * @param aFromSegment The current network buffer
387    */
388   nsresult SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
389       mozilla::Span<const uint8_t> aPrefix,
390       mozilla::Span<const uint8_t> aFromSegment);
391 
392   /**
393    * Initialize the Unicode decoder, mark the BOM as the source and
394    * drop the sniffer.
395    *
396    * @param aDecoderCharsetName The name for the decoder's charset
397    *                            (UTF-16BE, UTF-16LE or UTF-8; the BOM has
398    *                            been swallowed)
399    */
400   void SetupDecodingFromBom(NotNull<const Encoding*> aEncoding);
401 
402   void SetupDecodingFromUtf16BogoXml(NotNull<const Encoding*> aEncoding);
403 
404   /**
405    * When speculatively decoding from file: URL as UTF-8, commit
406    * to UTF-8 as the non-speculative encoding and start processing
407    * the decoded data.
408    */
409   void CommitLocalFileToEncoding();
410 
411   /**
412    * When speculatively decoding from file: URL as UTF-8, redecode
413    * using fallback and then continue normally with the fallback.
414    */
415   void ReDecodeLocalFile();
416 
417   /**
418    * Potentially guess the encoding using mozilla::EncodingDetector.
419    * Returns the guessed encoding and a telemetry-appropriate source.
420    */
421   std::tuple<NotNull<const Encoding*>, nsCharsetSource> GuessEncoding(
422       bool aInitial);
423 
424   /**
425    * Become confident or resolve and encoding name to its preferred form.
426    * @param aEncoding the value of an internal encoding decl. Acts as an
427    *                  out param, too, when the method returns true.
428    * @return true if the parser needs to start using the new value of
429    *         aEncoding and false if the parser became confident or if
430    *         the encoding name did not specify a usable encoding
431    */
432   const Encoding* PreferredForInternalEncodingDecl(const nsAString& aEncoding);
433 
434   /**
435    * Callback for mFlushTimer.
436    */
437   static void TimerCallback(nsITimer* aTimer, void* aClosure);
438 
439   /**
440    * Parser thread entry point for (maybe) flushing the ops and posting
441    * a flush runnable back on the main thread.
442    */
443   void TimerFlush();
444 
445   /**
446    * Called when speculation fails.
447    */
MaybeDisableFutureSpeculation()448   void MaybeDisableFutureSpeculation() { mSpeculationFailureCount++; }
449 
450   /**
451    * Used to check whether we're getting too many speculation failures and
452    * should just stop trying.  The 100 is picked pretty randomly to be not too
453    * small (so most pages are not affected) but small enough that we don't end
454    * up with failed speculations over and over in pathological cases.
455    */
IsSpeculationEnabled()456   bool IsSpeculationEnabled() { return mSpeculationFailureCount < 100; }
457 
458   /**
459    * Dispatch an event to a Quantum DOM main thread-ish thread.
460    * (Not the parser thread.)
461    */
462   nsresult DispatchToMain(already_AddRefed<nsIRunnable>&& aRunnable);
463 
464   /**
465    * Notify any devtools listeners about content newly received for parsing.
466    */
467   inline void OnNewContent(mozilla::Span<const char16_t> aData);
468 
469   /**
470    * Notify any devtools listeners after all parse content has been received.
471    */
472   inline void OnContentComplete();
473 
474   nsCOMPtr<nsIRequest> mRequest;
475 
476   /**
477    * The document title to use if this turns out to be a View Source parser.
478    */
479   nsCString mViewSourceTitle;
480 
481   /**
482    * The Unicode decoder
483    */
484   mozilla::UniquePtr<mozilla::Decoder> mUnicodeDecoder;
485 
486   /**
487    * BOM sniffing state
488    */
489   eBomState mBomState;
490 
491   // encoding-related stuff
492   /**
493    * The source (confidence) of the character encoding in use
494    */
495   nsCharsetSource mCharsetSource;
496 
497   nsCharsetSource mEncodingSwitchSource;
498 
499   /**
500    * The character encoding in use
501    */
502   NotNull<const Encoding*> mEncoding;
503 
504   const Encoding* mNeedsEncodingSwitchTo;
505 
506   bool mSeenEligibleMetaCharset;
507 
508   bool mChardetEof;
509 
510 #ifdef DEBUG
511 
512   bool mStartedFeedingDetector;
513 
514   bool mStartedFeedingDevTools;
515 
516 #endif
517 
518   /**
519    * Whether reparse is forbidden
520    */
521   bool mReparseForbidden;
522 
523   /**
524    * Whether the Repair Text Encoding menu item was invoked
525    */
526   bool mForceAutoDetection;
527 
528   /**
529    * Whether there was a valid charset parameter on the HTTP layer.
530    */
531   bool mChannelHadCharset;
532 
533   /**
534    * We are in the process of looking for <meta charset>
535    */
536   bool mLookingForMetaCharset;
537 
538   /**
539    * Whether the byte stream started with ASCII <?
540    */
541   bool mStartsWithLtQuestion;
542 
543   /**
544    * If we are viewing XML source and are waiting for a '>' form the network.
545    */
546   bool mLookingForXmlDeclarationForXmlViewSource;
547 
548   /**
549    * Whether template has been pushed or head popped within the first 1024
550    * bytes.
551    */
552   bool mTemplatePushedOrHeadPopped;
553 
554   // Portable parser objects
555   /**
556    * The first buffer in the pending UTF-16 buffer queue
557    */
558   RefPtr<nsHtml5OwningUTF16Buffer> mFirstBuffer;
559 
560   /**
561    * Non-owning pointer to the most recent buffer that contains the most recent
562    * remembered greater-than sign. Used only while mLookingForMetaCharset is
563    * true. While mLookingForMetaCharset is true, mFirstBuffer is not changed and
564    * keeps the whole linked list of buffers alive. This pointer is non-owning to
565    * avoid frequent refcounting.
566    */
567   nsHtml5OwningUTF16Buffer* mGtBuffer;
568 
569   int32_t mGtPos;
570 
571   /**
572    * The last buffer in the pending UTF-16 buffer queue
573    */
574   nsHtml5OwningUTF16Buffer*
575       mLastBuffer;  // weak ref; always points to
576                     // a buffer of the size
577                     // NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE
578 
579   /**
580    * The first buffer of the document if looking for <meta charset> or
581    * nullptr afterwards.
582    */
583   RefPtr<nsHtml5OwningUTF16Buffer> mFirstBufferOfMetaScan;
584 
585   /**
586    * The tree operation executor
587    */
588   nsHtml5TreeOpExecutor* mExecutor;
589 
590   /**
591    * Network event target for mExecutor->mDocument
592    */
593   nsCOMPtr<nsISerialEventTarget> mNetworkEventTarget;
594 
595   /**
596    * The HTML5 tree builder
597    */
598   mozilla::UniquePtr<nsHtml5TreeBuilder> mTreeBuilder;
599 
600   /**
601    * The HTML5 tokenizer
602    */
603   mozilla::UniquePtr<nsHtml5Tokenizer> mTokenizer;
604 
605   /**
606    * Makes sure the main thread can't mess the tokenizer state while it's
607    * tokenizing. This mutex also protects the current speculation.
608    */
609   mozilla::Mutex mTokenizerMutex;
610 
611   /**
612    * The scoped atom table
613    */
614   nsHtml5AtomTable mAtomTable;
615 
616   /**
617    * The owner parser.
618    */
619   RefPtr<nsHtml5Parser> mOwner;
620 
621   /**
622    * Whether the last character tokenized was a carriage return (for CRLF)
623    */
624   bool mLastWasCR;
625 
626   /**
627    * For tracking stream life cycle
628    */
629   eHtml5StreamState mStreamState;
630 
631   /**
632    * Whether we are speculating.
633    */
634   bool mSpeculating;
635 
636   /**
637    * Whether the tokenizer has reached EOF. (Reset when stream rewinded.)
638    */
639   bool mAtEOF;
640 
641   /**
642    * The speculations. The mutex protects the nsTArray itself.
643    * To access the queue of current speculation, mTokenizerMutex must be
644    * obtained.
645    * The current speculation is the last element
646    */
647   nsTArray<mozilla::UniquePtr<nsHtml5Speculation>> mSpeculations;
648   mozilla::Mutex mSpeculationMutex;
649 
650   /**
651    * Number of times speculation has failed for this parser.
652    */
653   mozilla::Atomic<uint32_t> mSpeculationFailureCount;
654 
655   /**
656    * Number of bytes already buffered into mBufferedBytes.
657    */
658   uint32_t mNumBytesBuffered;
659 
660   nsTArray<mozilla::Buffer<uint8_t>> mBufferedBytes;
661 
662   /**
663    * True to terminate early.
664    */
665   mozilla::Atomic<bool> mTerminated;
666 
667   /**
668    * True to release mTokenizerMutex early.
669    */
670   mozilla::Atomic<bool> mInterrupted;
671 
672   /**
673    * The thread this stream parser runs on.
674    */
675   nsCOMPtr<nsISerialEventTarget> mEventTarget;
676 
677   nsCOMPtr<nsIRunnable> mExecutorFlusher;
678 
679   nsCOMPtr<nsIRunnable> mLoadFlusher;
680 
681   /**
682    * This runnable is distinct from the regular flushers to
683    * signal the intent of encoding commitment without having to
684    * protect mPendingEncodingCommitment in the executer with a
685    * mutex.
686    */
687   nsCOMPtr<nsIRunnable> mEncodingCommitter;
688 
689   /**
690    * The generict detector.
691    */
692   mozilla::UniquePtr<mozilla::EncodingDetector> mDetector;
693 
694   /**
695    * The TLD we're loading from or empty if unknown.
696    */
697   nsCString mTLD;
698 
699   /**
700    * Whether the initial charset source was kCharsetFromParentFrame
701    */
702   bool mInitialEncodingWasFromParentFrame;
703 
704   bool mHasHadErrors;
705 
706   bool mDetectorHasSeenNonAscii;
707 
708   bool mDetectorHadOnlySeenAsciiWhenFirstGuessing;
709 
710   /**
711    * If true, we are decoding a local file that lacks an encoding
712    * declaration and we are not tokenizing yet.
713    */
714   bool mDecodingLocalFileWithoutTokenizing;
715 
716   /**
717    * Whether we are keeping the incoming bytes.
718    */
719   bool mBufferingBytes;
720 
721   /**
722    * Timer for flushing tree ops once in a while when not speculating.
723    */
724   nsCOMPtr<nsITimer> mFlushTimer;
725 
726   /**
727    * Mutex for protecting access to mFlushTimer (but not for the two
728    * mFlushTimerFoo booleans below).
729    */
730   mozilla::Mutex mFlushTimerMutex;
731 
732   /**
733    * Keeps track whether mFlushTimer has been armed. Unfortunately,
734    * nsITimer doesn't enable querying this from the timer itself.
735    */
736   bool mFlushTimerArmed;
737 
738   /**
739    * False initially and true after the timer has fired at least once.
740    */
741   bool mFlushTimerEverFired;
742 
743   /**
744    * Whether the parser is doing a normal parse, view source or plain text.
745    */
746   eParserMode mMode;
747 
748   /**
749    * If the associated docshell is being watched by the devtools, this is
750    * set to the URI associated with the parse. All parse data is sent to the
751    * devtools, along with this URI. This URI is cleared out after the parse has
752    * been marked as completed.
753    */
754   nsCOMPtr<nsIURI> mURIToSendToDevtools;
755 
756   /**
757    * If content is being sent to the devtools, an encoded UUID for the parser.
758    */
759   nsString mUUIDForDevtools;
760 };
761 
762 #endif  // nsHtml5StreamParser_h
763