Bug 1494176 - nsHttpChannel must clone the upload stream if it doesn't implement ::Seek(), r=mayhemer
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 03 Oct 2018 22:51:55 +0200
changeset 439499 f2ff07352cbe9a60a0bb9c9705f3c911d4ae1f7d
parent 439498 8b6344a8c25c48a2180b6a5ba7050e2773f22f89
child 439500 90592dc5c3a86ebf39b23cded780a4857f1de62c
push id34776
push usernerli@mozilla.com
push dateThu, 04 Oct 2018 04:03:46 +0000
treeherdermozilla-central@8b1f1ebed0f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1494176
milestone64.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 1494176 - nsHttpChannel must clone the upload stream if it doesn't implement ::Seek(), r=mayhemer
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpChannelParent.cpp
xpcom/io/nsPipe3.cpp
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -909,19 +909,30 @@ HttpBaseChannel::EnsureUploadStreamIsClo
   MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
   NS_ENSURE_ARG_POINTER(aCallback);
 
   // We could in theory allow multiple callers to use this method,
   // but the complexity does not seem worth it yet.  Just fail if
   // this is called more than once simultaneously.
   NS_ENSURE_FALSE(mUploadCloneableCallback, NS_ERROR_UNEXPECTED);
 
-  // If the CloneUploadStream() will succeed, then synchronously invoke
-  // the callback to indicate we're already cloneable.
-  if (!mUploadStream || NS_InputStreamIsCloneable(mUploadStream)) {
+  // We can immediately exec the callback if we don't have an upload stream.
+  if (!mUploadStream) {
+    aCallback->Run();
+    return NS_OK;
+  }
+
+  // Some nsSeekableStreams do not implement ::Seek() (see nsPipeInputStream).
+  // In this case, we must clone the uploadStream into a memory stream in order
+  // to have it seekable.  If the CloneUploadStream() will succeed, then
+  // synchronously invoke the callback to indicate we're already cloneable.
+  nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
+  if (seekable &&
+      NS_SUCCEEDED(seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0)) &&
+      NS_InputStreamIsCloneable(mUploadStream)) {
     aCallback->Run();
     return NS_OK;
   }
 
   nsCOMPtr<nsIStorageStream> storageStream;
   nsresult rv = NS_NewStorageStream(4096, UINT32_MAX,
                                     getter_AddRefs(storageStream));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -713,16 +713,25 @@ HttpChannelParent::DoAsyncOpen(  const U
                   self->TryInvokeAsyncOpen(NS_OK);
                 },
                 [self](nsresult aStatus) {
                   self->mRequest.Complete();
                   self->TryInvokeAsyncOpen(aStatus);
                 })
          ->Track(mRequest);
 
+  // The stream, received from the child process, must be cloneable and seekable
+  // in order to allow devtools to inspect its content.
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("HttpChannelParent::EnsureUploadStreamIsCloneable",
+      [self]() {
+        self->TryInvokeAsyncOpen(NS_OK);
+      });
+  ++mAsyncOpenBarrier;
+  mChannel->EnsureUploadStreamIsCloneable(r);
   return true;
 }
 
 already_AddRefed<GenericPromise>
 HttpChannelParent::WaitForBgParent()
 {
   LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
   MOZ_ASSERT(!mBgParent);
@@ -736,17 +745,17 @@ HttpChannelParent::WaitForBgParent()
 
   if (mBgParent) {
     RefPtr<GenericPromise> promise = mPromise.Ensure(__func__);
     // resolve promise immediatedly if bg channel is ready.
     mPromise.Resolve(true, __func__);
     return promise.forget();
   }
 
-  return mPromise.Ensure(__func__);;
+  return mPromise.Ensure(__func__);
 }
 
 bool
 HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
 {
   nsresult rv;
 
   LOG(("HttpChannelParent::ConnectChannel: Looking for a registered channel "
--- a/xpcom/io/nsPipe3.cpp
+++ b/xpcom/io/nsPipe3.cpp
@@ -1523,17 +1523,16 @@ nsPipeInputStream::AsyncWait(nsIInputStr
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPipeInputStream::Seek(int32_t aWhence, int64_t aOffset)
 {
-  MOZ_ASSERT_UNREACHABLE("nsPipeInputStream::Seek");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsPipeInputStream::Tell(int64_t* aOffset)
 {
   ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);