From 6be6d69d7c99d992dd6c7f5d0e0a207921f5aec5 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 13 Aug 2009 13:20:41 +0200 Subject: [PATCH] Bug 509929 - Reference cycle between nsProgressNotificationProxy and nsHttpChannel on channel redirect. r=biesi --- modules/libpr0n/src/imgLoader.cpp | 35 ++++++++++++++++++++- netwerk/protocol/http/src/nsHttpChannel.cpp | 7 +++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/libpr0n/src/imgLoader.cpp b/modules/libpr0n/src/imgLoader.cpp index d14b011f342d..d71118db4304 100644 --- a/modules/libpr0n/src/imgLoader.cpp +++ b/modules/libpr0n/src/imgLoader.cpp @@ -49,6 +49,7 @@ #include "nsIPrefBranch2.h" #include "nsIPrefService.h" #include "nsIProgressEventSink.h" +#include "nsIChannelEventSink.h" #include "nsIProxyObjectManager.h" #include "nsIServiceManager.h" #include "nsIFileURL.h" @@ -118,6 +119,7 @@ static void PrintImageDecoders() * and forwards everything else to the channel's notification callbacks. */ class nsProgressNotificationProxy : public nsIProgressEventSink + , public nsIChannelEventSink , public nsIInterfaceRequestor { public: @@ -129,6 +131,7 @@ class nsProgressNotificationProxy : public nsIProgressEventSink NS_DECL_ISUPPORTS NS_DECL_NSIPROGRESSEVENTSINK + NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR private: ~nsProgressNotificationProxy() {} @@ -138,8 +141,9 @@ class nsProgressNotificationProxy : public nsIProgressEventSink nsCOMPtr mImageRequest; }; -NS_IMPL_ISUPPORTS2(nsProgressNotificationProxy, +NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy, nsIProgressEventSink, + nsIChannelEventSink, nsIInterfaceRequestor) NS_IMETHODIMP @@ -178,6 +182,30 @@ nsProgressNotificationProxy::OnStatus(nsIRequest* request, return target->OnStatus(mImageRequest, ctxt, status, statusArg); } +NS_IMETHODIMP +nsProgressNotificationProxy::OnChannelRedirect(nsIChannel *oldChannel, + nsIChannel *newChannel, + PRUint32 flags) { + // The 'old' channel should match the current one + NS_ABORT_IF_FALSE(oldChannel == mChannel, + "old channel doesn't match current!"); + + // Save the new channel + mChannel = newChannel; + + // Tell the original original callbacks about it too + nsCOMPtr loadGroup; + mChannel->GetLoadGroup(getter_AddRefs(loadGroup)); + nsCOMPtr target; + NS_QueryNotificationCallbacks(mOriginalCallbacks, + loadGroup, + NS_GET_IID(nsIChannelEventSink), + getter_AddRefs(target)); + if (!target) + return NS_OK; + return target->OnChannelRedirect(oldChannel, newChannel, flags); +} + NS_IMETHODIMP nsProgressNotificationProxy::GetInterface(const nsIID& iid, void** result) { @@ -186,6 +214,11 @@ nsProgressNotificationProxy::GetInterface(const nsIID& iid, NS_ADDREF_THIS(); return NS_OK; } + if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) { + *result = static_cast(this); + NS_ADDREF_THIS(); + return NS_OK; + } if (mOriginalCallbacks) return mOriginalCallbacks->GetInterface(iid, result); return NS_NOINTERFACE; diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index 0ad55cbb4873..87c4aadf6be5 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -1279,8 +1279,15 @@ nsHttpChannel::DoReplaceWithProxy(nsIProxyInfo* pi) return rv; mStatus = NS_BINDING_REDIRECTED; + + // disconnect from the old listeners... mListener = nsnull; mListenerContext = nsnull; + + // ...and the old callbacks + mCallbacks = nsnull; + mProgressSink = nsnull; + return rv; }