Commit 68184463 authored by Ray Kraesig's avatar Ray Kraesig
Browse files

Bug 1815987 - Rewrite data-read loop in OnDataAvailable r=yjuglaret

The read-loop in OnDataAvailable is needlessly baroque and uses a very
strange dialect of Hungarian notation. Factor out the zero-element case
for simplicity (of explication, if nothing else), and add justificatory
comments as appropriate.

Differential Revision: https://phabricator.services.mozilla.com/D171001
parent 65ff8912
Loading
Loading
Loading
Loading
+35 −11
Original line number Diff line number Diff line
@@ -125,26 +125,50 @@ nsDataObj::CStream::OnDataAvailable(
    uint64_t aOffset,  // offset within the stream
    uint32_t aCount)   // bytes available on this call
{
  // If we've been asked to read zero bytes, call `Read` once, just to ensure
  // any side-effects take place, and return immediately.
  if (aCount == 0) {
    char buffer[1] = {0};
    uint32_t bytesReadByCall = 0;
    nsresult rv = aInputStream->Read(buffer, 0, &bytesReadByCall);
    MOZ_ASSERT(bytesReadByCall == 0);
    return rv;
  }

  // Extend the write buffer for the incoming data.
  uint8_t* buffer = mChannelData.AppendElements(aCount, fallible);
  size_t oldLength = mChannelData.Length();
  char* buffer =
      reinterpret_cast<char*>(mChannelData.AppendElements(aCount, fallible));
  if (!buffer) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  NS_ASSERTION((mChannelData.Length() == (aOffset + aCount)),
  MOZ_ASSERT(mChannelData.Length() == (aOffset + aCount),
             "stream length mismatch w/write buffer");

  // Read() may not return aCount on a single call, so loop until we've
  // accumulated all the data OnDataAvailable has promised.
  nsresult rv;
  uint32_t odaBytesReadTotal = 0;
  do {
  uint32_t bytesRead = 0;
  while (bytesRead < aCount) {
    uint32_t bytesReadByCall = 0;
    rv = aInputStream->Read((char*)(buffer + odaBytesReadTotal), aCount,
    nsresult rv = aInputStream->Read(buffer + bytesRead, aCount - bytesRead,
                                     &bytesReadByCall);
    odaBytesReadTotal += bytesReadByCall;
  } while (aCount < odaBytesReadTotal && NS_SUCCEEDED(rv));
    bytesRead += bytesReadByCall;

    if (bytesReadByCall == 0) {
      // A `bytesReadByCall` of zero indicates EOF without failure... but we
      // were promised `aCount` elements and haven't gotten them. Return a
      // generic failure.
      rv = NS_ERROR_FAILURE;
    }

    if (NS_FAILED(rv)) {
      // Drop any trailing uninitialized elements before erroring out.
      mChannelData.RemoveElementsAt(oldLength + bytesRead, aCount - bytesRead);
      return rv;
    }
  }
  return NS_OK;
}

NS_IMETHODIMP nsDataObj::CStream::OnStartRequest(nsIRequest* aRequest) {
  mChannelResult = NS_OK;