Suspend counter for HttTransactionParent. r=kershaw
authorDragana Damjanovic <dd.mozilla@gmail.com>
Tue, 16 Apr 2019 16:17:02 +0200
changeset 467145 75cf15143ffa128216cdb6f8ea23e2ba3c124dbb
parent 467144 a8d91bca70d7f41525eb7951d8c2dbfb45dffaf7
child 467146 3625ade8e123591f52b2ddd2e4bc4d8b337e42f2
push id49
push userdd.mozilla@gmail.com
push dateTue, 16 Apr 2019 14:17:15 +0000
reviewerskershaw
milestone68.0a1
Suspend counter for HttTransactionParent. r=kershaw
netwerk/protocol/http/HttpTransactionParent.cpp
netwerk/protocol/http/HttpTransactionParent.h
--- a/netwerk/protocol/http/HttpTransactionParent.cpp
+++ b/netwerk/protocol/http/HttpTransactionParent.cpp
@@ -275,20 +275,29 @@ mozilla::ipc::IPCResult HttpTransactionP
   }
   mProxyConnectFailed = aProxyConnectFailed;
   mSelfAddr = aSelfAddr;
   mPeerAddr = aPeerAddr;
   mTimings = aTimings;
 
   nsCOMPtr<nsIStreamListener> chan = mChannel;
 
-  nsresult rv = chan->OnStartRequest(this);
-  if (NS_FAILED(rv)) {
-    Cancel(rv);
+  RefPtr<HttpTransactionParent> self(this);
+  auto call = [self{std::move(self)}, chan{std::move(chan)}]() {
+    nsresult rv = chan->OnStartRequest(self);
+    if (NS_FAILED(rv)) {
+      self->Cancel(rv);
+    }
+  };
+  if (mSuspendCount > 0) {
+    mSuspendQueue.emplace(std::move(call));
+  } else {
+    call();
   }
+
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnTransportStatus(
     const nsresult& aStatus, const int64_t& aProgress,
     const int64_t& aProgressMax) {
   LOG(("HttpTransactionParent::OnTransportStatus [this=%p]\n", this));
 
@@ -316,19 +325,29 @@ mozilla::ipc::IPCResult HttpTransactionP
                                       NS_ASSIGNMENT_DEPEND);
 
   if (NS_FAILED(rv)) {
     Cancel(rv);
     return IPC_OK();
   }
 
   mDataAlreadySent = dataSentToChildProcess;
-  rv = chan->OnDataAvailable(this, stringStream, aOffset, aCount);
-  if (NS_FAILED(rv)) {
-    Cancel(rv);
+  RefPtr<HttpTransactionParent> self(this);
+  auto call = [self{std::move(self)}, chan{std::move(chan)},
+               stringStream{std::move(stringStream)}, aOffset, aCount]() {
+    nsresult rv = chan->OnDataAvailable(self, stringStream, aOffset, aCount);
+    if (NS_FAILED(rv)) {
+      self->Cancel(rv);
+    }
+  };
+
+  if (mSuspendCount > 0) {
+    mSuspendQueue.emplace(std::move(call));
+  } else {
+    call();
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnStopRequest(
     const nsresult& aStatus, const bool& aResponseIsComplete,
     const int64_t& aTransferSize, const TimingStruct& aTimings,
@@ -345,22 +364,31 @@ mozilla::ipc::IPCResult HttpTransactionP
 
   mResponseIsComplete = aResponseIsComplete;
   mTransferSize = aTransferSize;
   mTimings = aTimings;
   mResponseTrailers = new nsHttpHeaderArray(aResponseTrailers);
   mHasStickyConnection = aHasStickyConn;
 
   nsCOMPtr<nsIStreamListener> chan = mChannel;
-  Unused << chan->OnStopRequest(this, aStatus);
+  RefPtr<HttpTransactionParent> self(this);
+  auto call = [self{std::move(self)}, chan{std::move(chan)}]() {
+    Unused << chan->OnStopRequest(self, self->mStatus);
 
-  // We are done with this transaction after OnStopRequest.
-  if (mIPCOpen) {
-    Unused << Send__delete__(this);
+    // We are done with this transaction after OnStopRequest.
+    if (self->mIPCOpen) {
+      Unused << Send__delete__(self);
+    }
+  };
+  if (mSuspendCount > 0) {
+    mSuspendQueue.emplace(std::move(call));
+  } else {
+    call();
   }
+
   return IPC_OK();
 }
 
 //-----------------------------------------------------------------------------
 // HttpTransactionParent <nsIRequest>
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
@@ -391,23 +419,48 @@ HttpTransactionParent::Cancel(nsresult a
     mStatus = aStatus;
     Unused << SendCancelPump(mStatus);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpTransactionParent::Suspend(void) {
+  ++mSuspendCount;
+
   Unused << SendSuspendPump();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpTransactionParent::Resume(void) {
+  MOZ_ASSERT(mSuspendCount, "Resume called more than Suspend");
+
   Unused << SendResumePump();
+  if (mSuspendCount && !--mSuspendCount && !mSuspendQueue.empty()) {
+    RefPtr<HttpTransactionParent> self(this);
+    nsCOMPtr<nsIRunnable> dequeue(NS_NewRunnableFunction(
+        "HttpTransactionParent::Resume", [self{std::move(self)}]() {
+          while (!self->mSuspendQueue.empty()) {
+            auto call = self->mSuspendQueue.front();
+            self->mSuspendQueue.pop();
+            call();
+            if (self->mSuspendCount) {
+              break;
+            }
+            // Note that we don't need to call OnStopRequest
+            // from here artifically when the channel is cancelled
+            // from one of the callbacks.  We bypass calling stream
+            // listener when cancelled, channel cancels us.
+          }
+        }));
+
+    Unused << NS_DispatchToMainThread(dequeue);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpTransactionParent::GetLoadGroup(nsILoadGroup** aLoadGroup) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/netwerk/protocol/http/HttpTransactionParent.h
+++ b/netwerk/protocol/http/HttpTransactionParent.h
@@ -11,16 +11,18 @@
 #include "mozilla/net/PHttpTransactionParent.h"
 #include "nsHttp.h"
 #include "nsCOMPtr.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsITransport.h"
 #include "nsIRequest.h"
 #include "TimingStruct.h"
 
+#include <queue>
+
 namespace mozilla {
 namespace net {
 
 class nsHttpConnectionInfo;
 
 // HttpTransactionParent plays the role of nsHttpTransaction and delegates the
 // work to the nsHttpTransport in socket process.
 class HttpTransactionParent final : public PHttpTransactionParent,
@@ -72,16 +74,18 @@ class HttpTransactionParent final : publ
   nsAutoPtr<nsHttpResponseHead> mResponseHead;
   nsAutoPtr<nsHttpHeaderArray> mResponseTrailers;
 
   nsLoadFlags mLoadFlags = LOAD_NORMAL;
   bool mProxyConnectFailed = false;
   bool mCanceled = false;
   nsresult mStatus = NS_OK;
   bool mDataAlreadySent = false;
+  int32_t mSuspendCount = 0;
+  std::queue<std::function<void()>> mSuspendQueue;
 
   NetAddr mSelfAddr;
   NetAddr mPeerAddr;
 
   TimingStruct mTimings;
   bool mIPCOpen;
   bool mResponseHeadTaken;
   bool mResponseTrailersTaken;