Bug 1353629 - PBlob refactoring - part 12 - nsInputStreamPump should use BufferedStreams, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 24 Apr 2017 12:09:41 +0200
changeset 354627 3a2c881ccf419304a7b728a9433fb3065f76f40a
parent 354626 a2d2d49d3e5774f788787cd375e46a69be5cf011
child 354628 6586412c7f6494e5d9df0c8a24e31ec55f9ab2d4
push id31707
push userkwierso@gmail.com
push dateMon, 24 Apr 2017 22:53:41 +0000
treeherdermozilla-central@abdcc8dfc283 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1353629
milestone55.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 1353629 - PBlob refactoring - part 12 - nsInputStreamPump should use BufferedStreams, r=smaug nsInputStreamPump should use the stream as nsIAsyncInputStream if available. In order to do so, we need to wrap a BufferedStream around it. MediaResource cannot use a simple sync nsIInputStream when BlobURL are involved in the content process.
dom/media/MediaResource.cpp
netwerk/base/nsInputStreamPump.cpp
netwerk/base/nsInputStreamPump.h
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -1515,17 +1515,17 @@ MediaResource::Create(MediaResourceCallb
   aChannel->GetContentType(contentTypeString);
   Maybe<MediaContainerType> containerType = MakeMediaContainerType(contentTypeString);
   if (!containerType) {
     return nullptr;
   }
 
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
   RefPtr<MediaResource> resource;
-  if (fc || IsBlobURI(uri)) {
+  if (fc || (IsBlobURI(uri) && XRE_IsParentProcess())) {
     resource = new FileMediaResource(aCallback, aChannel, uri, *containerType);
   } else {
     resource = new ChannelMediaResource(
       aCallback, aChannel, uri, *containerType, aIsPrivateBrowsing);
   }
   return resource.forget();
 }
 
--- a/netwerk/base/nsInputStreamPump.cpp
+++ b/netwerk/base/nsInputStreamPump.cpp
@@ -12,16 +12,17 @@
 #include "nsIThreadRetargetableStreamListener.h"
 #include "nsThreadUtils.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Logging.h"
 #include "GeckoProfiler.h"
 #include "nsIStreamListener.h"
 #include "nsILoadGroup.h"
 #include "nsNetCID.h"
+#include "nsStreamUtils.h"
 #include <algorithm>
 
 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
 
 //
 // MOZ_LOG=nsStreamPump:5
 //
 static mozilla::LazyLogModule gStreamPumpLog("nsStreamPump");
@@ -96,28 +97,31 @@ CallPeekFunc(nsIInputStream *aInStream, 
 
 nsresult
 nsInputStreamPump::PeekStream(PeekSegmentFun callback, void* closure)
 {
   ReentrantMonitorAutoEnter mon(mMonitor);
 
   NS_ASSERTION(mAsyncStream, "PeekStream called without stream");
 
+  nsresult rv = CreateBufferedStreamIfNeeded();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // See if the pipe is closed by checking the return of Available.
   uint64_t dummy64;
-  nsresult rv = mAsyncStream->Available(&dummy64);
+  rv = mBufferedStream->Available(&dummy64);
   if (NS_FAILED(rv))
     return rv;
   uint32_t dummy = (uint32_t)std::min(dummy64, (uint64_t)UINT32_MAX);
 
   PeekData data(callback, closure);
-  return mAsyncStream->ReadSegments(CallPeekFunc,
-                                    &data,
-                                    nsIOService::gDefaultSegmentSize,
-                                    &dummy);
+  return mBufferedStream->ReadSegments(CallPeekFunc,
+                                       &data,
+                                       nsIOService::gDefaultSegmentSize,
+                                       &dummy);
 }
 
 nsresult
 nsInputStreamPump::EnsureWaiting()
 {
     mMonitor.AssertCurrentThreadIn();
 
     // no need to worry about multiple threads... an input stream pump lives
@@ -545,20 +549,23 @@ nsInputStreamPump::OnStateTransfer()
         js::ProfileEntry::Category::NETWORK);
 
     LOG(("  OnStateTransfer [this=%p]\n", this));
 
     // if canceled, go directly to STATE_STOP...
     if (NS_FAILED(mStatus))
         return STATE_STOP;
 
-    nsresult rv;
+    nsresult rv = CreateBufferedStreamIfNeeded();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return STATE_STOP;
+    }
 
     uint64_t avail;
-    rv = mAsyncStream->Available(&avail);
+    rv = mBufferedStream->Available(&avail);
     LOG(("  Available returned [stream=%p rv=%" PRIx32 " avail=%" PRIu64 "]\n", mAsyncStream.get(),
          static_cast<uint32_t>(rv), avail));
 
     if (rv == NS_BASE_STREAM_CLOSED) {
         rv = NS_OK;
         avail = 0;
     }
     else if (NS_SUCCEEDED(rv) && avail) {
@@ -578,17 +585,17 @@ nsInputStreamPump::OnStateTransfer()
             //       in this regard; however, if an ODA does not consume any
             //       data from the stream, then we could potentially end up in
             //       an infinite loop.  we do our best here to try to catch
             //       such an error.  (see bug 189672)
 
             // in most cases this QI will succeed (mAsyncStream is almost always
             // a nsPipeInputStream, which implements nsISeekableStream::Tell).
             int64_t offsetBefore;
-            nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mAsyncStream);
+            nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mBufferedStream);
             if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) {
                 NS_NOTREACHED("Tell failed on readable stream");
                 offsetBefore = 0;
             }
 
             uint32_t odaAvail =
                 avail > UINT32_MAX ?
                 UINT32_MAX : uint32_t(avail);
@@ -597,17 +604,17 @@ nsInputStreamPump::OnStateTransfer()
                 mStreamOffset, avail, odaAvail));
 
             {
                 // Note: Must exit monitor for call to OnStartRequest to avoid
                 // deadlocks when calls to RetargetDeliveryTo for multiple
                 // nsInputStreamPumps are needed (e.g. nsHttpChannel).
                 mMonitor.Exit();
                 rv = mListener->OnDataAvailable(this, mListenerContext,
-                                                mAsyncStream, mStreamOffset,
+                                                mBufferedStream, mStreamOffset,
                                                 odaAvail);
                 mMonitor.Enter();
             }
 
             // don't enter this code if ODA failed or called Cancel
             if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
                 // test to see if this ODA failed to consume data
                 if (seekable) {
@@ -642,17 +649,17 @@ nsInputStreamPump::OnStateTransfer()
     if (NS_SUCCEEDED(mStatus)) {
         if (NS_FAILED(rv))
             mStatus = rv;
         else if (avail) {
             // if stream is now closed, advance to STATE_STOP right away.
             // Available may return 0 bytes available at the moment; that
             // would not mean that we are done.
             // XXX async streams should have a GetStatus method!
-            rv = mAsyncStream->Available(&avail);
+            rv = mBufferedStream->Available(&avail);
             if (NS_SUCCEEDED(rv))
                 return STATE_TRANSFER;
             if (rv != NS_BASE_STREAM_CLOSED)
                 mStatus = rv;
         }
     }
     return STATE_STOP;
 }
@@ -703,16 +710,17 @@ nsInputStreamPump::OnStateStop()
     }
 
     if (NS_FAILED(mStatus))
         mAsyncStream->CloseWithStatus(mStatus);
     else if (mCloseWhenDone)
         mAsyncStream->Close();
 
     mAsyncStream = nullptr;
+    mBufferedStream = nullptr;
     mTargetThread = nullptr;
     mIsPending = false;
     {
         // Note: Must exit monitor for call to OnStartRequest to avoid
         // deadlocks when calls to RetargetDeliveryTo for multiple
         // nsInputStreamPumps are needed (e.g. nsHttpChannel).
         mMonitor.Exit();
         mListener->OnStopRequest(this, mListenerContext, mStatus);
@@ -722,16 +730,38 @@ nsInputStreamPump::OnStateStop()
     mListenerContext = nullptr;
 
     if (mLoadGroup)
         mLoadGroup->RemoveRequest(this, nullptr, mStatus);
 
     return STATE_IDLE;
 }
 
+nsresult
+nsInputStreamPump::CreateBufferedStreamIfNeeded()
+{
+  if (mBufferedStream) {
+    return NS_OK;
+  }
+
+  // ReadSegments is not available for any nsIAsyncInputStream. In order to use
+  // it, we wrap a nsIBufferedInputStream around it, if needed.
+
+  if (NS_InputStreamIsBuffered(mAsyncStream)) {
+    mBufferedStream = mAsyncStream;
+    return NS_OK;
+  }
+
+  nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(mBufferedStream),
+                                          mAsyncStream, 4096);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // nsIThreadRetargetableRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsInputStreamPump::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
 {
     ReentrantMonitorAutoEnter mon(mMonitor);
--- a/netwerk/base/nsInputStreamPump.h
+++ b/netwerk/base/nsInputStreamPump.h
@@ -70,24 +70,26 @@ protected:
         STATE_TRANSFER,
         STATE_STOP
     };
 
     nsresult EnsureWaiting();
     uint32_t OnStateStart();
     uint32_t OnStateTransfer();
     uint32_t OnStateStop();
+    nsresult CreateBufferedStreamIfNeeded();
 
     uint32_t                      mState;
     nsCOMPtr<nsILoadGroup>        mLoadGroup;
     nsCOMPtr<nsIStreamListener>   mListener;
     nsCOMPtr<nsISupports>         mListenerContext;
     nsCOMPtr<nsIEventTarget>      mTargetThread;
     nsCOMPtr<nsIInputStream>      mStream;
     nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
+    nsCOMPtr<nsIInputStream>      mBufferedStream;
     uint64_t                      mStreamOffset;
     uint64_t                      mStreamLength;
     uint32_t                      mSegSize;
     uint32_t                      mSegCount;
     nsresult                      mStatus;
     uint32_t                      mSuspendCount;
     uint32_t                      mLoadFlags;
     bool                          mIsPending;