summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/HttpChannelChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/HttpChannelChild.cpp')
-rw-r--r--netwerk/protocol/http/HttpChannelChild.cpp49
1 files changed, 21 insertions, 28 deletions
diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp
index 34e7a2cf0d..240bb14433 100644
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -87,7 +87,8 @@ HttpChannelChild::HttpChannelChild()
mIsLastPartOfMultiPart(false),
mSuspendForWaitCompleteRedirectSetup(false),
mRecvOnStartRequestSentCalled(false),
- mSuspendedByWaitingForPermissionCookie(false) {
+ mSuspendedByWaitingForPermissionCookie(false),
+ mAlreadyReleased(false) {
LOG(("Creating HttpChannelChild @%p\n", this));
mChannelCreationTime = PR_Now();
@@ -199,12 +200,16 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() {
// We don't have a listener when AsyncOpen has failed or when this channel
// has been sucessfully redirected.
if (MOZ_LIKELY(LoadOnStartRequestCalled() && LoadOnStopRequestCalled()) ||
- !mListener) {
+ !mListener || mAlreadyReleased) {
NS_LOG_RELEASE(this, 0, "HttpChannelChild");
delete this;
return 0;
}
+ // This ensures that when the refcount goes to 0 again, we don't dispatch
+ // yet another runnable and get in a loop.
+ mAlreadyReleased = true;
+
// This makes sure we fulfill the stream listener contract all the time.
if (NS_SUCCEEDED(mStatus)) {
mStatus = NS_ERROR_ABORT;
@@ -223,27 +228,11 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() {
// 3) Finally, we turn the reference into a regular smart pointer.
RefPtr<HttpChannelChild> channel = dont_AddRef(this);
-
- // This runnable will create a strong reference to |this|.
- NS_DispatchToMainThread(
- NewRunnableMethod("~HttpChannelChild>DoNotifyListener", channel,
- &HttpChannelChild::DoNotifyListener));
-
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ "~HttpChannelChild>DoNotifyListener",
+ [chan = std::move(channel)] { chan->DoNotifyListener(false); }));
// If NS_DispatchToMainThread failed then we're going to leak the runnable,
// and thus the channel, so there's no need to do anything else.
-
- // We should have already done any special handling for the refcount = 1
- // case when the refcount first went from 2 to 1. We don't want it to happen
- // when |channel| is destroyed.
- MOZ_ASSERT(!mKeptAlive || !CanSend());
-
- // XXX If std::move(channel) is allowed, then we don't have to have extra
- // checks for the refcount going from 2 to 1. See bug 1680217.
-
- // This will release the stabilization refcount, which is necessary to avoid
- // a leak.
- channel = nullptr;
-
return mRefCnt;
}
@@ -1233,7 +1222,7 @@ void HttpChannelChild::NotifyOrReleaseListeners(nsresult rv) {
DoNotifyListener();
}
-void HttpChannelChild::DoNotifyListener() {
+void HttpChannelChild::DoNotifyListener(bool aUseEventQueue) {
LOG(("HttpChannelChild::DoNotifyListener this=%p", this));
MOZ_ASSERT(NS_IsMainThread());
@@ -1246,16 +1235,20 @@ void HttpChannelChild::DoNotifyListener() {
if (mListener && !LoadOnStartRequestCalled()) {
nsCOMPtr<nsIStreamListener> listener = mListener;
- StoreOnStartRequestCalled(
- true); // avoid reentrancy bugs by setting this now
+ // avoid reentrancy bugs by setting this now
+ StoreOnStartRequestCalled(true);
listener->OnStartRequest(this);
}
StoreOnStartRequestCalled(true);
- mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
- this, [self = UnsafePtr<HttpChannelChild>(this)] {
- self->ContinueDoNotifyListener();
- }));
+ if (aUseEventQueue) {
+ mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
+ this, [self = UnsafePtr<HttpChannelChild>(this)] {
+ self->ContinueDoNotifyListener();
+ }));
+ } else {
+ ContinueDoNotifyListener();
+ }
}
void HttpChannelChild::ContinueDoNotifyListener() {