Bug 1255894: Part 1 - Allow applying content conversions in parent rather than child when necessary. r?dragana draft
authorKris Maglione <maglione.k@gmail.com>
Wed, 22 Mar 2017 20:30:49 -0700
changeset 503931 45da67ddd151c81b665864957cb13d40f6fab055
parent 501245 b316fdd7d8fcdf83210bebe6b81f24cce64fc648
child 503932 5d1c3a4d8e78d12163dd55e64434c8fc6d2103b3
child 558951 6269de5619d3d781029130f6a5b1893931234364
push id50715
push usermaglione.k@gmail.com
push dateThu, 23 Mar 2017 21:04:18 +0000
reviewersdragana
bugs1255894
milestone55.0a1
Bug 1255894: Part 1 - Allow applying content conversions in parent rather than child when necessary. r?dragana In order to allow extensions to monitor and filter response streams, we need to make sure conversions are applied before the extension listeners, and that additional conversions are not applied afterwards. This patch adds a channel method which moves the conversions to the parent process when filters are about to be applied. Ideally, we'd offload the conversions to a background thread in this circumstance, but that's a larger task than fits easily within this bug. MozReview-Commit-ID: DNSNeFr1OTX
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsIHttpChannelInternal.idl
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2961,16 +2961,22 @@ HttpChannelChild::ForceIntercepted(uint6
 void
 HttpChannelChild::ForceIntercepted(nsIInputStream* aSynthesizedInput)
 {
   mSynthesizedInput = aSynthesizedInput;
   mSynthesizedResponse = true;
   mRedirectingForSubsequentSynthesizedResponse = true;
 }
 
+NS_IMETHODIMP
+HttpChannelChild::ApplyContentConversionsInParent()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 mozilla::ipc::IPCResult
 HttpChannelChild::RecvIssueDeprecationWarning(const uint32_t& warning,
                                               const bool& asError)
 {
   nsCOMPtr<nsIDeprecationWarner> warner;
   GetCallback(warner);
   if (warner) {
     warner->IssueWarning(warning, asError);
@@ -3012,10 +3018,18 @@ HttpChannelChild::ShouldInterceptURI(nsI
 
 mozilla::ipc::IPCResult
 HttpChannelChild::RecvSetPriority(const int16_t& aPriority)
 {
   mPriority = aPriority;
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+HttpChannelChild::RecvApplyContentConversionsInParent()
+{
+  MOZ_ASSERT(!mCompressListener);
+  mApplyConversion = false;
+  return IPC_OK();
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -83,16 +83,17 @@ public:
                               const nsACString& aValue,
                               bool aMerge) override;
   NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override;
   NS_IMETHOD RedirectTo(nsIURI *newURI) override;
   NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override;
   // nsIHttpChannelInternal
   NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
   NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
+  NS_IMETHOD ApplyContentConversionsInParent() override;
   // nsISupportsPriority
   NS_IMETHOD SetPriority(int32_t value) override;
   // nsIClassOfService
   NS_IMETHOD SetClassFlags(uint32_t inFlags) override;
   NS_IMETHOD AddClassFlags(uint32_t inFlags) override;
   NS_IMETHOD ClearClassFlags(uint32_t inFlags) override;
   // nsIResumableChannel
   NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID) override;
@@ -152,16 +153,18 @@ protected:
   mozilla::ipc::IPCResult RecvReportSecurityMessage(const nsString& messageTag,
                                                     const nsString& messageCategory) override;
 
   mozilla::ipc::IPCResult RecvIssueDeprecationWarning(const uint32_t& warning,
                                                       const bool& asError) override;
 
   mozilla::ipc::IPCResult RecvSetPriority(const int16_t& aPriority) override;
 
+  mozilla::ipc::IPCResult RecvApplyContentConversionsInParent() override;
+
   MOZ_MUST_USE bool
   GetAssociatedContentSecurity(nsIAssociatedContentSecurity** res = nullptr);
   virtual void DoNotifyListenerCleanup() override;
 
   NS_IMETHOD GetResponseSynthesized(bool* aSynthesized) override;
 
 private:
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -49,16 +49,17 @@ using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
                                      nsILoadContext* aLoadContext,
                                      PBOverrideStatus aOverrideStatus)
   : mIPCClosed(false)
+  , mApplyConversion(false)
   , mIgnoreProgress(false)
   , mSentRedirect1Begin(false)
   , mSentRedirect1BeginFailed(false)
   , mReceivedRedirect2Verify(false)
   , mPBOverride(aOverrideStatus)
   , mLoadContext(aLoadContext)
   , mStatus(NS_OK)
   , mPendingDiversion(false)
@@ -1149,17 +1150,17 @@ HttpChannelParent::OnStartRequest(nsIReq
         !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId))
     {
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(aRequest);
   if (encodedChannel)
-    encodedChannel->SetApplyConversion(false);
+    encodedChannel->SetApplyConversion(mApplyConversion);
 
   // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
   // It could be already released by nsHttpChannel at that time.
   nsCOMPtr<nsISupports> cacheEntry;
   chan->GetCacheToken(getter_AddRefs(cacheEntry));
   mCacheEntry = do_QueryInterface(cacheEntry);
 
   nsresult channelStatus = NS_OK;
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -86,16 +86,17 @@ public:
   void StartDiversion();
 
   // Handles calling OnStart/Stop if there are errors during diversion.
   // Called asynchronously from FailDiversion.
   void NotifyDiversionFailed(nsresult aErrorCode, bool aSkipResume = true);
 
   // Forwarded to nsHttpChannel::SetApplyConversion.
   void SetApplyConversion(bool aApplyConversion) {
+    mApplyConversion = aApplyConversion;
     if (mChannel) {
       mChannel->SetApplyConversion(aApplyConversion);
     }
   }
 
   MOZ_MUST_USE nsresult OpenAlternativeOutputStream(const nsACString & type,
                                                     nsIOutputStream * *_retval);
 
@@ -214,16 +215,17 @@ private:
   friend class DivertDataAvailableEvent;
   friend class DivertStopRequestEvent;
   friend class DivertCompleteEvent;
 
   RefPtr<nsHttpChannel>       mChannel;
   nsCOMPtr<nsICacheEntry>       mCacheEntry;
   nsCOMPtr<nsIAssociatedContentSecurity>  mAssociatedContentSecurity;
   bool mIPCClosed;                // PHttpChannel actor has been Closed()
+  bool mApplyConversion;
 
   nsCOMPtr<nsIChannel> mRedirectChannel;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
 
   nsAutoPtr<class nsHttpChannel::OfflineCacheEntryAsForeignMarker> mOfflineForeignMarker;
 
   // OnStatus is always called before OnProgress.
   // Set true in OnStatus if next OnProgress can be ignored
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -168,16 +168,19 @@ child:
   async DeleteSelf();
 
   // Tell the child to issue a deprecation warning.
   async IssueDeprecationWarning(uint32_t warning, bool asError);
 
   // Tell the child information of matched URL againts SafeBrowsing list
   async SetClassifierMatchedInfo(ClassifierInfo info);
 
+  // Tell the child that content conversions will be applied in the parent
+  async ApplyContentConversionsInParent();
+
 both:
   // After receiving this message, the parent also calls
   // SendFinishInterceptedRedirect, and makes sure not to send any more messages
   // after that. When receiving this message, the child will call
   // Send__delete__() and complete the steps required to finish the redirect.
   async FinishInterceptedRedirect();
 
   async SetPriority(int16_t priority);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6220,16 +6220,31 @@ nsHttpChannel::ForceIntercepted(uint64_t
     }
 
     MarkIntercepted();
     mResponseCouldBeSynthesized = true;
     mInterceptionID = aInterceptionID;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsHttpChannel::ApplyContentConversionsInParent()
+{
+    nsCOMPtr<nsIParentChannel> parentChannel;
+    NS_QueryNotificationCallbacks(this, parentChannel);
+    RefPtr<HttpChannelParent> httpParent = do_QueryObject(parentChannel);
+    if (httpParent) {
+        if (!httpParent->SendApplyContentConversionsInParent()) {
+            return NS_ERROR_FAILURE;
+        }
+        httpParent->SetApplyConversion(true);
+    }
+    return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsISupportsPriority
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::SetPriority(int32_t value)
 {
     int16_t newValue = clamped<int32_t>(value, INT16_MIN, INT16_MAX);
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -150,16 +150,17 @@ public:
     NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
     NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
     NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
     // nsIHttpChannel
     NS_IMETHOD GetEncodedBodySize(uint64_t *aEncodedBodySize) override;
     // nsIHttpChannelInternal
     NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
     NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
+    NS_IMETHOD ApplyContentConversionsInParent() override;
     // nsISupportsPriority
     NS_IMETHOD SetPriority(int32_t value) override;
     // nsIClassOfService
     NS_IMETHOD SetClassFlags(uint32_t inFlags) override;
     NS_IMETHOD AddClassFlags(uint32_t inFlags) override;
     NS_IMETHOD ClearClassFlags(uint32_t inFlags) override;
 
     // nsIResumableChannel
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -222,16 +222,18 @@ interface nsIHttpChannelInternal : nsISu
      * Force a channel that has not been AsyncOpen'ed to skip any check for possible
      * interception and proceed immediately to open a previously-synthesized cache
      * entry using the provided ID.
      */
     [must_use] void forceIntercepted(in uint64_t aInterceptionID);
 
     [must_use] readonly attribute boolean responseSynthesized;
 
+    [must_use] void applyContentConversionsInParent();
+
     /**
      * Set by nsCORSListenerProxy if credentials should be included in
      * cross-origin requests. false indicates "same-origin", users should still
      * check flag LOAD_ANONYMOUS!
      */
     [must_use] attribute boolean corsIncludeCredentials;
 
     const unsigned long CORS_MODE_SAME_ORIGIN = 0;