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