bug 1460312 - cancel the timeout timer in OCSP request implementation r?jcj
Bug 1456489 cleaned up our OCSP request implementation a bit. One simplification
it made was to not cancel the timeout timer. It turns out that if we don't, the
OCSPRequest that constitutes the timeout callback's closure might not be valid
if the request has completed (because the timer doesn't own a strong reference
to it). The fix is simple: cancel the timer when the request completes. Note
that we don't have to do the reverse because necko has a strong reference to the
request.
MozReview-Commit-ID: 2WHFLAcGBAw
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -91,19 +91,21 @@ private:
// On the main thread, a channel is set up to perform the request. This gets
// dispatched to necko. At the same time, a timeout timer is initialized. If
// the necko request completes, the response data is filled out, mNotifiedDone
// is set to true, and the monitor is notified. The original thread then wakes
// up and continues with the results that have been filled out. If the request
// times out, again the response data is filled out, mNotifiedDone is set to
// true, and the monitor is notified. The first of these two events wins. That
// is, if the timeout timer fires but the request completes shortly after, the
- // caller will see the request as having timed out, and vice-versa. (Also note
- // that no effort is made to cancel either the request or the timeout timer if
- // the other event completes first.)
+ // caller will see the request as having timed out.
+ // When the request completes (i.e. OnStreamComplete runs), the timer will be
+ // cancelled. This is how we know the closure in OnTimeout is valid. If the
+ // timer fires before OnStreamComplete runs, it should be safe to not cancel
+ // the request because necko has a strong reference to it.
Monitor mMonitor;
bool mNotifiedDone;
nsCOMPtr<nsIStreamLoader> mLoader;
const nsCString mAIALocation;
const OriginAttributes mOriginAttributes;
const Vector<uint8_t> mPOSTData;
const TimeDuration mTimeout;
nsCOMPtr<nsITimer> mTimeoutTimer;
@@ -356,16 +358,19 @@ OCSPRequest::NotifyDone(nsresult rv, Mon
return NS_ERROR_FAILURE;
}
if (mNotifiedDone) {
return mResponseResult;
}
mLoader = nullptr;
mResponseResult = rv;
+ if (mTimeoutTimer) {
+ Unused << mTimeoutTimer->Cancel();
+ }
mNotifiedDone = true;
lock.Notify();
return rv;
}
NS_IMETHODIMP
OCSPRequest::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* aContext,
@@ -425,16 +430,19 @@ OCSPRequest::OnStreamComplete(nsIStreamL
void
OCSPRequest::OnTimeout(nsITimer* timer, void* closure)
{
MOZ_ASSERT(NS_IsMainThread());
if (!NS_IsMainThread()) {
return;
}
+ // We know the OCSPRequest is still alive because if the request had completed
+ // (i.e. OnStreamComplete ran), the timer would have been cancelled in
+ // NotifyDone.
OCSPRequest* self = static_cast<OCSPRequest*>(closure);
MonitorAutoLock lock(self->mMonitor);
self->mTimeoutTimer = nullptr;
self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
}
mozilla::pkix::Result
DoOCSPRequest(const nsCString& aiaLocation,