Bug 1307122 - Introducing a timeout for sync XHR when unload events are dispatched, r=smaug

This commit is contained in:
Andrea Marchesini
2016-10-16 08:46:10 +02:00
parent 5c4824fc92
commit 884f0f2753
10 changed files with 221 additions and 3 deletions

View File

@@ -125,6 +125,7 @@ namespace {
"@mozilla.org/content/xmlhttprequest-bad-cert-handler;1"
#define NS_PROGRESS_EVENT_INTERVAL 50
#define MAX_SYNC_TIMEOUT_WHEN_UNLOADING 10000 /* 10 secs */
NS_IMPL_ISUPPORTS(nsXHRParseEndListener, nsIDOMEventListener)
@@ -2932,7 +2933,13 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
StopProgressEventTimer();
{
SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
if (syncTimeoutType == eErrorOrExpired) {
Abort();
rv = NS_ERROR_DOM_NETWORK_ERR;
}
if (NS_SUCCEEDED(rv)) {
nsAutoSyncOperation sync(suspendedDoc);
nsIThread *thread = NS_GetCurrentThread();
while (mFlagSyncLooping) {
@@ -2941,6 +2948,13 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
break;
}
}
// Time expired... We should throw.
if (syncTimeoutType == eTimerStarted && !mSyncTimeoutTimer) {
rv = NS_ERROR_DOM_NETWORK_ERR;
}
CancelSyncTimeoutTimer();
}
if (suspendedDoc) {
@@ -3512,6 +3526,11 @@ XMLHttpRequestMainThread::Notify(nsITimer* aTimer)
return NS_OK;
}
if (mSyncTimeoutTimer == aTimer) {
HandleSyncTimeoutTimer();
return NS_OK;
}
// Just in case some JS user wants to QI to nsITimerCallback and play with us...
NS_WARNING("Unexpected timer!");
return NS_ERROR_INVALID_POINTER;
@@ -3564,6 +3583,52 @@ XMLHttpRequestMainThread::StartProgressEventTimer()
}
}
XMLHttpRequestMainThread::SyncTimeoutType
XMLHttpRequestMainThread::MaybeStartSyncTimeoutTimer()
{
MOZ_ASSERT(mFlagSynchronous);
nsIDocument* doc = GetDocumentIfCurrent();
if (!doc || !doc->GetPageUnloadingEventTimeStamp()) {
return eNoTimerNeeded;
}
// If we are in a beforeunload or a unload event, we must force a timeout.
TimeDuration diff = (TimeStamp::NowLoRes() - doc->GetPageUnloadingEventTimeStamp());
if (diff.ToMilliseconds() > MAX_SYNC_TIMEOUT_WHEN_UNLOADING) {
return eErrorOrExpired;
}
mSyncTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!mSyncTimeoutTimer) {
return eErrorOrExpired;
}
uint32_t timeout = MAX_SYNC_TIMEOUT_WHEN_UNLOADING - diff.ToMilliseconds();
nsresult rv = mSyncTimeoutTimer->InitWithCallback(this, timeout,
nsITimer::TYPE_ONE_SHOT);
return NS_FAILED(rv) ? eErrorOrExpired : eTimerStarted;
}
void
XMLHttpRequestMainThread::HandleSyncTimeoutTimer()
{
MOZ_ASSERT(mSyncTimeoutTimer);
MOZ_ASSERT(mFlagSyncLooping);
CancelSyncTimeoutTimer();
Abort();
}
void
XMLHttpRequestMainThread::CancelSyncTimeoutTimer()
{
if (mSyncTimeoutTimer) {
mSyncTimeoutTimer->Cancel();
mSyncTimeoutTimer = nullptr;
}
}
already_AddRefed<nsXMLHttpRequestXPCOMifier>
XMLHttpRequestMainThread::EnsureXPCOMifier()
{