Bug 1511972 - Clean up byte buffer representation in method signatures in nsHtml5StreamParser. r=mrbkap
authorHenri Sivonen <hsivonen@hsivonen.fi>
Thu, 06 Dec 2018 18:59:56 +0000
changeset 508799 d8e07613f15e55f43d654af8708ffa0cba1710d1
parent 508798 6725a7f43baed5fb99ea7007c7df6147a94a419c
child 508800 5344a9d4ec9ca4a27fce29328183d1dc06ebd441
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1511972
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1511972 - Clean up byte buffer representation in method signatures in nsHtml5StreamParser. r=mrbkap Differential Revision: https://phabricator.services.mozilla.com/D13732
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5StreamParser.h
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -307,32 +307,27 @@ void nsHtml5StreamParser::SetViewSourceT
         mViewSourceTitle.AssignLiteral("\xE2\x80\xA6");
       }
     }
   }
 }
 
 nsresult
 nsHtml5StreamParser::SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-    const uint8_t* aFromSegment,  // can be null
-    uint32_t aCount, uint32_t* aWriteCount) {
+    Span<const uint8_t> aFromSegment) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   nsresult rv = NS_OK;
   mUnicodeDecoder = mEncoding->NewDecoderWithBOMRemoval();
   if (mSniffingBuffer) {
-    uint32_t writeCount;
-    rv = WriteStreamBytes(mSniffingBuffer.get(), mSniffingLength, &writeCount);
+    rv = WriteStreamBytes(MakeSpan(mSniffingBuffer.get(), mSniffingLength));
     NS_ENSURE_SUCCESS(rv, rv);
     mSniffingBuffer = nullptr;
   }
   mMetaScanner = nullptr;
-  if (aFromSegment) {
-    rv = WriteStreamBytes(aFromSegment, aCount, aWriteCount);
-  }
-  return rv;
+  return WriteStreamBytes(aFromSegment);
 }
 
 nsresult nsHtml5StreamParser::SetupDecodingFromBom(
     NotNull<const Encoding*> aEncoding) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   mEncoding = aEncoding;
   mUnicodeDecoder = mEncoding->NewDecoderWithoutBOMHandling();
   mCharsetSource = kCharsetFromByteOrderMark;
@@ -340,23 +335,23 @@ nsresult nsHtml5StreamParser::SetupDecod
   mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
   mSniffingBuffer = nullptr;
   mMetaScanner = nullptr;
   mBomState = BOM_SNIFFING_OVER;
   return NS_OK;
 }
 
 void nsHtml5StreamParser::SniffBOMlessUTF16BasicLatin(
-    const uint8_t* aFromSegment, uint32_t aCountToSniffingLimit) {
+    Span<const uint8_t> aFromSegment) {
   // Avoid underspecified heuristic craziness for XHR
   if (mMode == LOAD_AS_DATA) {
     return;
   }
   // Make sure there's enough data. Require room for "<title></title>"
-  if (mSniffingLength + aCountToSniffingLimit < 30) {
+  if (mSniffingLength + aFromSegment.Length() < 30) {
     return;
   }
   // even-numbered bytes tracked at 0, odd-numbered bytes tracked at 1
   bool byteZero[2] = {false, false};
   bool byteNonZero[2] = {false, false};
   uint32_t i = 0;
   if (mSniffingBuffer) {
     for (; i < mSniffingLength; ++i) {
@@ -368,29 +363,27 @@ void nsHtml5StreamParser::SniffBOMlessUT
       } else {
         if (byteZero[1 - (i % 2)]) {
           return;
         }
         byteZero[i % 2] = true;
       }
     }
   }
-  if (aFromSegment) {
-    for (uint32_t j = 0; j < aCountToSniffingLimit; ++j) {
-      if (aFromSegment[j]) {
-        if (byteNonZero[1 - ((i + j) % 2)]) {
-          return;
-        }
-        byteNonZero[(i + j) % 2] = true;
-      } else {
-        if (byteZero[1 - ((i + j) % 2)]) {
-          return;
-        }
-        byteZero[(i + j) % 2] = true;
+  for (size_t j = 0; j < aFromSegment.Length(); ++j) {
+    if (aFromSegment[j]) {
+      if (byteNonZero[1 - ((i + j) % 2)]) {
+        return;
       }
+      byteNonZero[(i + j) % 2] = true;
+    } else {
+      if (byteZero[1 - ((i + j) % 2)]) {
+        return;
+      }
+      byteZero[(i + j) % 2] = true;
     }
   }
 
   if (byteNonZero[0]) {
     mEncoding = UTF_16LE_ENCODING;
   } else {
     mEncoding = UTF_16BE_ENCODING;
   }
@@ -458,19 +451,19 @@ static void HandleComment(void* aUserDat
 
 static void HandleProcessingInstruction(void* aUserData,
                                         const XML_Char* aTarget,
                                         const XML_Char* aData) {
   UserData* ud = static_cast<UserData*>(aUserData);
   XML_StopParser(ud->mExpat, false);
 }
 
-nsresult nsHtml5StreamParser::FinalizeSniffing(
-    const uint8_t* aFromSegment,  // can be null
-    uint32_t aCount, uint32_t* aWriteCount, uint32_t aCountToSniffingLimit) {
+nsresult nsHtml5StreamParser::FinalizeSniffing(Span<const uint8_t> aFromSegment,
+                                               uint32_t aCountToSniffingLimit,
+                                               bool aEof) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   NS_ASSERTION(mCharsetSource < kCharsetFromParentForced,
                "Should not finalize sniffing when using forced charset.");
   if (mMode == VIEW_SOURCE_XML) {
     static const XML_Memory_Handling_Suite memsuite = {
         (void* (*)(size_t))moz_xmalloc, (void* (*)(void*, size_t))moz_xrealloc,
         free};
 
@@ -506,70 +499,69 @@ nsresult nsHtml5StreamParser::FinalizeSn
     // first 1024 bytes of the file (or the file as a whole if the file is
     // 1024 bytes long or shorter). Thus, we parse both buffers, but if the
     // first call succeeds already, we skip parsing the second buffer.
     if (mSniffingBuffer) {
       status = XML_Parse(ud.mExpat,
                          reinterpret_cast<const char*>(mSniffingBuffer.get()),
                          mSniffingLength, false);
     }
-    if (status == XML_STATUS_OK && mCharsetSource < kCharsetFromMetaTag &&
-        aFromSegment) {
-      status = XML_Parse(ud.mExpat, reinterpret_cast<const char*>(aFromSegment),
-                         aCountToSniffingLimit, false);
+    if (status == XML_STATUS_OK && mCharsetSource < kCharsetFromMetaTag) {
+      mozilla::Unused << XML_Parse(
+          ud.mExpat, reinterpret_cast<const char*>(aFromSegment.Elements()),
+          aCountToSniffingLimit, false);
     }
     XML_ParserFree(ud.mExpat);
 
     if (mCharsetSource < kCharsetFromMetaTag) {
       // Failed to get an encoding from the XML declaration. XML defaults
       // confidently to UTF-8 in this case.
       // It is also possible that the document has an XML declaration that is
       // longer than 1024 bytes, but that case is not worth worrying about.
       mEncoding = UTF_8_ENCODING;
       mCharsetSource = kCharsetFromMetaTag;  // means confident
     }
 
-    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-        aFromSegment, aCount, aWriteCount);
+    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
   }
 
   // meta scan failed.
   if (mCharsetSource >= kCharsetFromHintPrevDoc) {
     mFeedChardet = false;
-    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-        aFromSegment, aCount, aWriteCount);
+    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
   }
   // Check for BOMless UTF-16 with Basic
   // Latin content for compat with IE. See bug 631751.
-  SniffBOMlessUTF16BasicLatin(aFromSegment, aCountToSniffingLimit);
+  SniffBOMlessUTF16BasicLatin(aFromSegment.To(aCountToSniffingLimit));
   // the charset may have been set now
   // maybe try chardet now;
   if (mFeedChardet) {
     bool dontFeed;
     nsresult rv;
     if (mSniffingBuffer) {
       rv = mChardet->DoIt((const char*)mSniffingBuffer.get(), mSniffingLength,
                           &dontFeed);
       mFeedChardet = !dontFeed;
       NS_ENSURE_SUCCESS(rv, rv);
     }
-    if (mFeedChardet && aFromSegment) {
-      rv = mChardet->DoIt((const char*)aFromSegment,
-                          // Avoid buffer boundary-dependent behavior when
-                          // reparsing is forbidden. If reparse is forbidden,
-                          // act as if we only saw the first 1024 bytes.
-                          // When reparsing isn't forbidden, buffer boundaries
-                          // can have an effect on whether the page is loaded
-                          // once or twice. :-(
-                          mReparseForbidden ? aCountToSniffingLimit : aCount,
-                          &dontFeed);
+    if (mFeedChardet && !aFromSegment.IsEmpty()) {
+      rv = mChardet->DoIt(
+          (const char*)aFromSegment.Elements(),
+          // Avoid buffer boundary-dependent behavior when
+          // reparsing is forbidden. If reparse is forbidden,
+          // act as if we only saw the first 1024 bytes.
+          // When reparsing isn't forbidden, buffer boundaries
+          // can have an effect on whether the page is loaded
+          // once or twice. :-(
+          mReparseForbidden ? aCountToSniffingLimit : aFromSegment.Length(),
+          &dontFeed);
       mFeedChardet = !dontFeed;
       NS_ENSURE_SUCCESS(rv, rv);
     }
-    if (mFeedChardet && (!aFromSegment || mReparseForbidden)) {
+    if (mFeedChardet && (aEof || mReparseForbidden)) {
       // mReparseForbidden is checked so that we get to use the sniffing
       // buffer with the best guess so far if we aren't allowed to guess
       // better later.
       mFeedChardet = false;
       rv = mChardet->Done();
       NS_ENSURE_SUCCESS(rv, rv);
     }
     // fall thru; callback may have changed charset
@@ -582,93 +574,75 @@ nsresult nsHtml5StreamParser::FinalizeSn
   } else if (mMode == LOAD_AS_DATA && mCharsetSource == kCharsetFromFallback) {
     NS_ASSERTION(mReparseForbidden, "Reparse should be forbidden for XHR");
     NS_ASSERTION(!mFeedChardet, "Should not feed chardet for XHR");
     NS_ASSERTION(mEncoding == UTF_8_ENCODING, "XHR should default to UTF-8");
     // Now mark charset source as non-weak to signal that we have a decision
     mCharsetSource = kCharsetFromDocTypeDefault;
     mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
   }
-  return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-      aFromSegment, aCount, aWriteCount);
+  return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
 }
 
-nsresult nsHtml5StreamParser::SniffStreamBytes(const uint8_t* aFromSegment,
-                                               uint32_t aCount,
-                                               uint32_t* aWriteCount) {
+nsresult nsHtml5StreamParser::SniffStreamBytes(
+    Span<const uint8_t> aFromSegment) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   nsresult rv = NS_OK;
-  uint32_t writeCount;
-
   // mEncoding and mCharsetSource potentially have come from channel or higher
   // by now. If we find a BOM, SetupDecodingFromBom() will overwrite them.
   // If we don't find a BOM, the previously set values of mEncoding and
   // mCharsetSource are not modified by the BOM sniffing here.
-  for (uint32_t i = 0; i < aCount && mBomState != BOM_SNIFFING_OVER; i++) {
+  for (uint32_t i = 0;
+       i < aFromSegment.Length() && mBomState != BOM_SNIFFING_OVER; i++) {
     switch (mBomState) {
       case BOM_SNIFFING_NOT_STARTED:
         NS_ASSERTION(i == 0, "Bad BOM sniffing state.");
-        switch (*aFromSegment) {
+        switch (aFromSegment[0]) {
           case 0xEF:
             mBomState = SEEN_UTF_8_FIRST_BYTE;
             break;
           case 0xFF:
             mBomState = SEEN_UTF_16_LE_FIRST_BYTE;
             break;
           case 0xFE:
             mBomState = SEEN_UTF_16_BE_FIRST_BYTE;
             break;
           default:
             mBomState = BOM_SNIFFING_OVER;
             break;
         }
         break;
       case SEEN_UTF_16_LE_FIRST_BYTE:
         if (aFromSegment[i] == 0xFE) {
-          rv = SetupDecodingFromBom(
-              UTF_16LE_ENCODING);  // upper case is the raw form
+          rv = SetupDecodingFromBom(UTF_16LE_ENCODING);
           NS_ENSURE_SUCCESS(rv, rv);
-          uint32_t count = aCount - (i + 1);
-          rv = WriteStreamBytes(aFromSegment + (i + 1), count, &writeCount);
-          NS_ENSURE_SUCCESS(rv, rv);
-          *aWriteCount = writeCount + (i + 1);
-          return rv;
+          return WriteStreamBytes(aFromSegment.From(i + 1));
         }
         mBomState = BOM_SNIFFING_OVER;
         break;
       case SEEN_UTF_16_BE_FIRST_BYTE:
         if (aFromSegment[i] == 0xFF) {
-          rv = SetupDecodingFromBom(
-              UTF_16BE_ENCODING);  // upper case is the raw form
+          rv = SetupDecodingFromBom(UTF_16BE_ENCODING);
           NS_ENSURE_SUCCESS(rv, rv);
-          uint32_t count = aCount - (i + 1);
-          rv = WriteStreamBytes(aFromSegment + (i + 1), count, &writeCount);
-          NS_ENSURE_SUCCESS(rv, rv);
-          *aWriteCount = writeCount + (i + 1);
-          return rv;
+          return WriteStreamBytes(aFromSegment.From(i + 1));
         }
         mBomState = BOM_SNIFFING_OVER;
         break;
       case SEEN_UTF_8_FIRST_BYTE:
         if (aFromSegment[i] == 0xBB) {
           mBomState = SEEN_UTF_8_SECOND_BYTE;
         } else {
           mBomState = BOM_SNIFFING_OVER;
         }
         break;
       case SEEN_UTF_8_SECOND_BYTE:
         if (aFromSegment[i] == 0xBF) {
-          rv = SetupDecodingFromBom(
-              UTF_8_ENCODING);  // upper case is the raw form
+          rv = SetupDecodingFromBom(UTF_8_ENCODING);
           NS_ENSURE_SUCCESS(rv, rv);
-          uint32_t count = aCount - (i + 1);
-          rv = WriteStreamBytes(aFromSegment + (i + 1), count, &writeCount);
-          NS_ENSURE_SUCCESS(rv, rv);
-          *aWriteCount = writeCount + (i + 1);
-          return rv;
+          return WriteStreamBytes(aFromSegment.From(i + 1));
         }
         mBomState = BOM_SNIFFING_OVER;
         break;
       default:
         mBomState = BOM_SNIFFING_OVER;
         break;
     }
   }
@@ -683,122 +657,121 @@ nsresult nsHtml5StreamParser::SniffStrea
   if (mBomState == BOM_SNIFFING_OVER && mCharsetSource == kCharsetFromChannel) {
     // There was no BOM and the charset came from channel. mEncoding
     // still contains the charset from the channel as set by an
     // earlier call to SetDocumentCharset(), since we didn't find a BOM and
     // overwrite mEncoding. (Note that if the user has overridden the charset,
     // we don't come here but check <meta> for XSS-dangerous charsets first.)
     mFeedChardet = false;
     mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
-    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-        aFromSegment, aCount, aWriteCount);
+    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
   }
 
   if (!mMetaScanner &&
       (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA)) {
     mMetaScanner = new nsHtml5MetaScanner(mTreeBuilder);
   }
 
-  if (mSniffingLength + aCount >= NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE) {
+  if (mSniffingLength + aFromSegment.Length() >=
+      NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE) {
     // this is the last buffer
     uint32_t countToSniffingLimit =
         NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE - mSniffingLength;
     if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) {
-      nsHtml5ByteReadable readable(aFromSegment,
-                                   aFromSegment + countToSniffingLimit);
+      nsHtml5ByteReadable readable(
+          aFromSegment.Elements(),
+          aFromSegment.Elements() + countToSniffingLimit);
       nsAutoCString charset;
       auto encoding = mMetaScanner->sniff(&readable);
       // Due to the way nsHtml5Portability reports OOM, ask the tree buider
       nsresult rv;
       if (NS_FAILED((rv = mTreeBuilder->IsBroken()))) {
         MarkAsBroken(rv);
         return rv;
       }
       if (encoding) {
         // meta scan successful; honor overrides unless meta is XSS-dangerous
         if ((mCharsetSource == kCharsetFromParentForced ||
              mCharsetSource == kCharsetFromUserForced) &&
             (encoding->IsAsciiCompatible() ||
              encoding == ISO_2022_JP_ENCODING)) {
           // Honor override
           return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-              aFromSegment, aCount, aWriteCount);
+              aFromSegment);
         }
         mEncoding = WrapNotNull(encoding);
         mCharsetSource = kCharsetFromMetaPrescan;
         mFeedChardet = false;
         mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
         return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-            aFromSegment, aCount, aWriteCount);
+            aFromSegment);
       }
     }
     if (mCharsetSource == kCharsetFromParentForced ||
         mCharsetSource == kCharsetFromUserForced) {
       // meta not found, honor override
-      return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-          aFromSegment, aCount, aWriteCount);
+      return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
     }
-    return FinalizeSniffing(aFromSegment, aCount, aWriteCount,
-                            countToSniffingLimit);
+    return FinalizeSniffing(aFromSegment, countToSniffingLimit, false);
   }
 
   // not the last buffer
   if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML || mMode == LOAD_AS_DATA) {
-    nsHtml5ByteReadable readable(aFromSegment, aFromSegment + aCount);
+    nsHtml5ByteReadable readable(
+        aFromSegment.Elements(),
+        aFromSegment.Elements() + aFromSegment.Length());
     auto encoding = mMetaScanner->sniff(&readable);
     // Due to the way nsHtml5Portability reports OOM, ask the tree buider
     nsresult rv;
     if (NS_FAILED((rv = mTreeBuilder->IsBroken()))) {
       MarkAsBroken(rv);
       return rv;
     }
     if (encoding) {
       // meta scan successful; honor overrides unless meta is XSS-dangerous
       if ((mCharsetSource == kCharsetFromParentForced ||
            mCharsetSource == kCharsetFromUserForced) &&
           (encoding->IsAsciiCompatible() || encoding == ISO_2022_JP_ENCODING)) {
         // Honor override
         return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-            aFromSegment, aCount, aWriteCount);
+            aFromSegment);
       }
       mEncoding = WrapNotNull(encoding);
       mCharsetSource = kCharsetFromMetaPrescan;
       mFeedChardet = false;
       mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
-      return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-          aFromSegment, aCount, aWriteCount);
+      return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
     }
   }
 
   if (!mSniffingBuffer) {
     mSniffingBuffer = MakeUniqueFallible<uint8_t[]>(
         NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE);
     if (!mSniffingBuffer) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
-  memcpy(&mSniffingBuffer[mSniffingLength], aFromSegment, aCount);
-  mSniffingLength += aCount;
-  *aWriteCount = aCount;
+  memcpy(&mSniffingBuffer[mSniffingLength], aFromSegment.Elements(),
+         aFromSegment.Length());
+  mSniffingLength += aFromSegment.Length();
   return NS_OK;
 }
 
-nsresult nsHtml5StreamParser::WriteStreamBytes(const uint8_t* aFromSegment,
-                                               uint32_t aCount,
-                                               uint32_t* aWriteCount) {
+nsresult nsHtml5StreamParser::WriteStreamBytes(
+    Span<const uint8_t> aFromSegment) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   // mLastBuffer should always point to a buffer of the size
   // NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE.
   if (!mLastBuffer) {
     NS_WARNING("mLastBuffer should not be null!");
     MarkAsBroken(NS_ERROR_NULL_POINTER);
     return NS_ERROR_NULL_POINTER;
   }
   size_t totalRead = 0;
-  auto src = MakeSpan(aFromSegment, aCount);
+  auto src = aFromSegment;
   for (;;) {
     auto dst = mLastBuffer->TailAsSpan(NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE);
     uint32_t result;
     size_t read;
     size_t written;
     bool hadErrors;
     Tie(result, read, written, hadErrors) =
         mUnicodeDecoder->DecodeToUTF16(src, dst, false);
@@ -819,19 +792,18 @@ nsresult nsHtml5StreamParser::WriteStrea
           nsHtml5OwningUTF16Buffer::FalliblyCreate(
               NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE);
       if (!newBuf) {
         MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
         return NS_ERROR_OUT_OF_MEMORY;
       }
       mLastBuffer = (mLastBuffer->next = newBuf.forget());
     } else {
-      MOZ_ASSERT(totalRead == aCount,
+      MOZ_ASSERT(totalRead == aFromSegment.Length(),
                  "The Unicode decoder consumed the wrong number of bytes.");
-      *aWriteCount = totalRead;
       return NS_OK;
     }
   }
 }
 
 class MaybeRunCollector : public Runnable {
  public:
   explicit MaybeRunCollector(nsIDocShell* aDocShell)
@@ -1016,19 +988,19 @@ void nsHtml5StreamParser::DoStopRequest(
 
   if (IsTerminated()) {
     return;
   }
 
   mStreamState = STREAM_ENDED;
 
   if (!mUnicodeDecoder) {
-    uint32_t writeCount;
     nsresult rv;
-    if (NS_FAILED(rv = FinalizeSniffing(nullptr, 0, &writeCount, 0))) {
+    Span<const uint8_t> empty;
+    if (NS_FAILED(rv = FinalizeSniffing(empty, 0, true))) {
       MarkAsBroken(rv);
       return;
     }
   } else if (mFeedChardet) {
     mChardet->Done();
   }
 
   MOZ_ASSERT(mUnicodeDecoder,
@@ -1107,45 +1079,42 @@ nsresult nsHtml5StreamParser::OnStopRequ
   }
   nsCOMPtr<nsIRunnable> stopper = new nsHtml5RequestStopper(this);
   if (NS_FAILED(mEventTarget->Dispatch(stopper, nsIThread::DISPATCH_NORMAL))) {
     NS_WARNING("Dispatching StopRequest event failed.");
   }
   return NS_OK;
 }
 
-void nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer,
-                                          uint32_t aLength) {
+void nsHtml5StreamParser::DoDataAvailable(Span<const uint8_t> aBuffer) {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   MOZ_RELEASE_ASSERT(STREAM_BEING_READ == mStreamState,
                      "DoDataAvailable called when stream not open.");
   mTokenizerMutex.AssertCurrentThreadOwns();
 
   if (IsTerminated()) {
     return;
   }
 
-  uint32_t writeCount;
   nsresult rv;
   if (HasDecoder()) {
     if (mFeedChardet) {
       bool dontFeed;
-      mChardet->DoIt((const char*)aBuffer, aLength, &dontFeed);
+      mChardet->DoIt((const char*)aBuffer.Elements(), aBuffer.Length(),
+                     &dontFeed);
       mFeedChardet = !dontFeed;
     }
-    rv = WriteStreamBytes(aBuffer, aLength, &writeCount);
+    rv = WriteStreamBytes(aBuffer);
   } else {
-    rv = SniffStreamBytes(aBuffer, aLength, &writeCount);
+    rv = SniffStreamBytes(aBuffer);
   }
   if (NS_FAILED(rv)) {
     MarkAsBroken(rv);
     return;
   }
-  NS_ASSERTION(writeCount == aLength,
-               "Wrong number of stream bytes written/sniffed.");
 
   if (IsTerminatedOrInterrupted()) {
     return;
   }
 
   ParseAvailableData();
 
   if (mFlushTimerArmed || mSpeculating) {
@@ -1173,17 +1142,17 @@ class nsHtml5DataAvailable : public Runn
   nsHtml5DataAvailable(nsHtml5StreamParser* aStreamParser,
                        UniquePtr<uint8_t[]> aData, uint32_t aLength)
       : Runnable("nsHtml5DataAvailable"),
         mStreamParser(aStreamParser),
         mData(std::move(aData)),
         mLength(aLength) {}
   NS_IMETHOD Run() override {
     mozilla::MutexAutoLock autoLock(mStreamParser->mTokenizerMutex);
-    mStreamParser->DoDataAvailable(mData.get(), mLength);
+    mStreamParser->DoDataAvailable(MakeSpan(mData.get(), mLength));
     return NS_OK;
   }
 };
 
 nsresult nsHtml5StreamParser::OnDataAvailable(nsIRequest* aRequest,
                                               nsISupports* aContext,
                                               nsIInputStream* aInStream,
                                               uint64_t aSourceOffset,
@@ -1228,17 +1197,17 @@ nsresult nsHtml5StreamParser::OnDataAvai
   }
 }
 
 /* static */ nsresult nsHtml5StreamParser::CopySegmentsToParser(
     nsIInputStream* aInStream, void* aClosure, const char* aFromSegment,
     uint32_t aToOffset, uint32_t aCount, uint32_t* aWriteCount) {
   nsHtml5StreamParser* parser = static_cast<nsHtml5StreamParser*>(aClosure);
 
-  parser->DoDataAvailable((const uint8_t*)aFromSegment, aCount);
+  parser->DoDataAvailable(AsBytes(MakeSpan(aFromSegment, aCount)));
   // Assume DoDataAvailable consumed all available bytes.
   *aWriteCount = aCount;
   return NS_OK;
 }
 
 const Encoding* nsHtml5StreamParser::PreferredForInternalEncodingDecl(
     const nsACString& aEncoding) {
   const Encoding* newEncoding = Encoding::ForLabel(aEncoding);
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -238,17 +238,17 @@ class nsHtml5StreamParser final : public
    * timer.
    */
   void FlushTreeOpsAndDisarmTimer();
 
   void ParseAvailableData();
 
   void DoStopRequest();
 
-  void DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength);
+  void DoDataAvailable(mozilla::Span<const uint8_t> aBuffer);
 
   static nsresult CopySegmentsToParser(nsIInputStream* aInStream,
                                        void* aClosure, const char* aFromSegment,
                                        uint32_t aToOffset, uint32_t aCount,
                                        uint32_t* aWriteCount);
 
   bool IsTerminatedOrInterrupted() {
     mozilla::MutexAutoLock autoLock(mTerminatedMutex);
@@ -263,61 +263,48 @@ class nsHtml5StreamParser final : public
   /**
    * True when there is a Unicode decoder already
    */
   inline bool HasDecoder() { return !!mUnicodeDecoder; }
 
   /**
    * Push bytes from network when there is no Unicode decoder yet
    */
-  nsresult SniffStreamBytes(const uint8_t* aFromSegment, uint32_t aCount,
-                            uint32_t* aWriteCount);
+  nsresult SniffStreamBytes(mozilla::Span<const uint8_t> aFromSegment);
 
   /**
    * Push bytes from network when there is a Unicode decoder already
    */
-  nsresult WriteStreamBytes(const uint8_t* aFromSegment, uint32_t aCount,
-                            uint32_t* aWriteCount);
+  nsresult WriteStreamBytes(mozilla::Span<const uint8_t> aFromSegment);
 
   /**
    * Check whether every other byte in the sniffing buffer is zero.
    */
-  void SniffBOMlessUTF16BasicLatin(const uint8_t* aFromSegment,
-                                   uint32_t aCountToSniffingLimit);
+  void SniffBOMlessUTF16BasicLatin(mozilla::Span<const uint8_t> aFromSegment);
 
   /**
    * <meta charset> scan failed. Try chardet if applicable. After this, the
    * the parser will have some encoding even if a last resolt fallback.
    *
-   * @param aFromSegment The current network buffer or null if the sniffing
-   *                     buffer is being flushed due to network stream ending.
-   * @param aCount       The number of bytes in aFromSegment (ignored if
-   *                     aFromSegment is null)
-   * @param aWriteCount  Return value for how many bytes got read from the
-   *                     buffer.
+   * @param aFromSegment The current network buffer
    * @param aCountToSniffingLimit The number of unfilled slots in
    *                              mSniffingBuffer
+   * @param aEof true iff called upon end of stream
    */
-  nsresult FinalizeSniffing(const uint8_t* aFromSegment, uint32_t aCount,
-                            uint32_t* aWriteCount,
-                            uint32_t aCountToSniffingLimit);
+  nsresult FinalizeSniffing(mozilla::Span<const uint8_t> aFromSegment,
+                            uint32_t aCountToSniffingLimit, bool aEof);
 
   /**
    * Set up the Unicode decoder and write the sniffing buffer into it
    * followed by the current network buffer.
    *
-   * @param aFromSegment The current network buffer or null if the sniffing
-   *                     buffer is being flushed due to network stream ending.
-   * @param aCount       The number of bytes in aFromSegment (ignored if
-   *                     aFromSegment is null)
-   * @param aWriteCount  Return value for how many bytes got read from the
-   *                     buffer.
+   * @param aFromSegment The current network buffer
    */
   nsresult SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
-      const uint8_t* aFromSegment, uint32_t aCount, uint32_t* aWriteCount);
+      mozilla::Span<const uint8_t> aFromSegment);
 
   /**
    * Initialize the Unicode decoder, mark the BOM as the source and
    * drop the sniffer.
    *
    * @param aDecoderCharsetName The name for the decoder's charset
    *                            (UTF-16BE, UTF-16LE or UTF-8; the BOM has
    *                            been swallowed)