Bug 1073872 - Fix data encoding if a channel is diverted from a child back to the parent. r=sworkman
authorDragana Damjanovic <dd.mozilla@gmail.com>
Fri, 07 Nov 2014 07:50:00 +0100
changeset 226157 a33eb2f32a326620cf21ad1de9a6e5f38a14273c
parent 226156 1d6c19a7af9f1da475a78fc586b409b81a28c653
child 226158 eca9d4c70a7b60521c574e79a17d083544ff2305
push id36
push userdburns@mozilla.com
push dateMon, 10 Nov 2014 15:14:02 +0000
reviewerssworkman
bugs1073872
milestone36.0a1
Bug 1073872 - Fix data encoding if a channel is diverted from a child back to the parent. r=sworkman
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -557,24 +557,17 @@ HttpChannelParent::RecvDivertOnDataAvail
   if (NS_FAILED(rv)) {
     if (mChannel) {
       mChannel->Cancel(rv);
     }
     mStatus = rv;
     return true;
   }
 
-  nsCOMPtr<nsIStreamListener> listener;
-  if (mConverterListener) {
-    listener = mConverterListener;
-  } else {
-    listener = mParentListener;
-    MOZ_ASSERT(listener);
-  }
-  rv = listener->OnDataAvailable(mChannel, nullptr, stringStream,
+  rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream,
                                         offset, count);
   stringStream->Close();
   if (NS_FAILED(rv)) {
     if (mChannel) {
       mChannel->Cancel(rv);
     }
     mStatus = rv;
     return true;
@@ -596,24 +589,17 @@ HttpChannelParent::RecvDivertOnStopReque
   // Honor the channel's status even if the underlying transaction completed.
   nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
 
   // Reset fake pending status in case OnStopRequest has already been called.
   if (mChannel) {
     mChannel->ForcePending(false);
   }
 
-  nsCOMPtr<nsIStreamListener> listener;
-  if (mConverterListener) {
-    listener = mConverterListener;
-  } else {
-    listener = mParentListener;
-    MOZ_ASSERT(listener);
-  }
-  listener->OnStopRequest(mChannel, nullptr, status);
+  mParentListener->OnStopRequest(mChannel, nullptr, status);
   return true;
 }
 
 bool
 HttpChannelParent::RecvDivertComplete()
 {
   MOZ_ASSERT(mParentListener);
   if (NS_WARN_IF(!mDivertingFromChild)) {
@@ -624,17 +610,16 @@ HttpChannelParent::RecvDivertComplete()
   }
 
   nsresult rv = ResumeForDiversion();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailDiversion(NS_ERROR_UNEXPECTED);
     return false;
   }
 
-  mConverterListener = nullptr; 
   mParentListener = nullptr;
   return true;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::nsIRequestObserver
 //-----------------------------------------------------------------------------
 
@@ -961,18 +946,17 @@ HttpChannelParent::DivertTo(nsIStreamLis
 {
   MOZ_ASSERT(mParentListener);
   if (NS_WARN_IF(!mDivertingFromChild)) {
     MOZ_ASSERT(mDivertingFromChild,
                "Cannot DivertTo new listener if diverting is not set!");
     return;
   }
 
-  DebugOnly<nsresult> rv = mParentListener->DivertTo(aListener);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  mDivertListener = aListener;
 
   if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
     FailDiversion(NS_ERROR_UNEXPECTED);
     return;
   }
 
   // Call OnStartRequest and SendDivertMessages asynchronously to avoid
   // reentering client context.
@@ -991,47 +975,41 @@ HttpChannelParent::StartDiversion()
   }
 
   // Fake pending status in case OnStopRequest has already been called.
   if (mChannel) {
     mChannel->ForcePending(true);
   }
 
   // Call OnStartRequest for the "DivertTo" listener.
-  nsresult rv = mParentListener->OnStartRequest(mChannel, nullptr);
+  nsresult rv = mDivertListener->OnStartRequest(mChannel, nullptr);
   if (NS_FAILED(rv)) {
     if (mChannel) {
       mChannel->Cancel(rv);
     }
     mStatus = rv;
   }
   mDivertedOnStartRequest = true;
 
   // After OnStartRequest has been called, setup content decoders if needed.
   //
-  // We want to use the same decoders that the nsHttpChannel might use. There
-  // are two possible scenarios depending on whether OnStopRequest has been
-  // called or not.
-  //
-  // 1. nsHttpChannel has not called OnStopRequest yet.
-  // Create content conversion chain based on nsHttpChannel::mListener
-  // Get ptr to final listener and set that in mContentConverter, as well as
-  // nsHttpChannel::mListener.
-  //
-  // 2. nsHttpChannel has called OnStopRequest.
-  // Create a content conversion chain based on mParentListener.
-  // Get ptr to final listener and set that in mContentConverter.
-
+  // Create a content conversion chain based on mDivertListener and update
+  // mDivertListener.
   nsCOMPtr<nsIStreamListener> converterListener;
-  mChannel->DoApplyContentConversions(mParentListener,
+  mChannel->DoApplyContentConversions(mDivertListener,
                                       getter_AddRefs(converterListener));
   if (converterListener) {
-    mConverterListener = converterListener.forget();
+    mDivertListener = converterListener.forget();
   }
 
+  // Now mParentListener can be diverted to mDivertListener.
+  DebugOnly<nsresult> rvdbg = mParentListener->DivertTo(mDivertListener);
+  MOZ_ASSERT(NS_SUCCEEDED(rvdbg));
+  mDivertListener = nullptr;
+
   // The listener chain should now be setup; tell HttpChannelChild to divert
   // the OnDataAvailables and OnStopRequest to this HttpChannelParent.
   if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
     FailDiversion(NS_ERROR_UNEXPECTED);
     return;
   }
 }
 
@@ -1101,17 +1079,16 @@ HttpChannelParent::NotifyDiversionFailed
     mChannel->ForcePending(false);
   }
   // If the channel is pending, it will call OnStopRequest itself; otherwise, do
   // it here.
   if (!isPending) {
     mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
   }
   mParentListener = nullptr;
-  mConverterListener = nullptr;
   mChannel = nullptr;
 
   if (!mIPCClosed) {
     unused << SendDeleteSelf();
   }
 }
 
 void
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -168,18 +168,18 @@ private:
   nsRefPtr<OfflineObserver> mObserver;
 
   PBOverrideStatus mPBOverride;
 
   nsCOMPtr<nsILoadContext> mLoadContext;
   nsRefPtr<nsHttpHandler>  mHttpHandler;
 
   nsRefPtr<HttpChannelParentListener> mParentListener;
-  // The first listener in the decode chain if channel decoding is applied.
-  nsCOMPtr<nsIStreamListener> mConverterListener;
+  // This is listener we are diverting to.
+  nsCOMPtr<nsIStreamListener> mDivertListener;
   // Set to the canceled status value if the main channel was canceled.
   nsresult mStatus;
   // Once set, no OnStart/OnData/OnStop calls should be accepted; conversely, it
   // must be set when RecvDivertOnData/~DivertOnStop/~DivertComplete are
   // received from the child channel.
   bool mDivertingFromChild;
 
   // Set if OnStart|StopRequest was called during a diversion from the child.