Bug 1370819 - Postpone the dispatching of XHR events with opened synchronously, r=smaug

This commit is contained in:
Andrea Marchesini 2017-06-16 08:07:00 +02:00
Родитель c4243d211b
Коммит 9e04e35075
2 изменённых файлов: 64 добавлений и 8 удалений

Просмотреть файл

@ -201,7 +201,8 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
mResultJSON(JS::UndefinedValue()),
mResultArrayBuffer(nullptr),
mIsMappedArrayBuffer(false),
mXPCOMifier(nullptr)
mXPCOMifier(nullptr),
mEventDispatchingSuspended(false)
{
mozilla::HoldJSObjects(this);
}
@ -1368,7 +1369,7 @@ XMLHttpRequestMainThread::FireReadystatechangeEvent()
event->InitEvent(kLiteralString_readystatechange, false, false);
// We assume anyone who managed to call CreateReadystatechangeEvent is trusted
event->SetTrusted(true);
DispatchDOMEvent(nullptr, event, nullptr, nullptr);
DispatchOrStoreEvent(this, event);
return NS_OK;
}
@ -1411,7 +1412,7 @@ XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
ProgressEvent::Constructor(aTarget, typeString, init);
event->SetTrusted(true);
aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
DispatchOrStoreEvent(aTarget, event);
if (aType == ProgressEventType::progress) {
mInLoadProgressEvent = false;
@ -1434,6 +1435,45 @@ XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
}
}
void
XMLHttpRequestMainThread::DispatchOrStoreEvent(DOMEventTargetHelper* aTarget,
Event* aEvent)
{
MOZ_ASSERT(aTarget);
MOZ_ASSERT(aEvent);
if (mEventDispatchingSuspended) {
PendingEvent* event = mPendingEvents.AppendElement();
event->mTarget = aTarget;
event->mEvent = aEvent;
return;
}
aTarget->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
}
void
XMLHttpRequestMainThread::SuspendEventDispatching()
{
MOZ_ASSERT(!mEventDispatchingSuspended);
mEventDispatchingSuspended = true;
}
void
XMLHttpRequestMainThread::ResumeEventDispatching()
{
MOZ_ASSERT(mEventDispatchingSuspended);
mEventDispatchingSuspended = false;
nsTArray<PendingEvent> pendingEvents;
pendingEvents.SwapElements(mPendingEvents);
for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
pendingEvents[i].mTarget->
DispatchDOMEvent(nullptr, pendingEvents[i].mEvent, nullptr, nullptr);
}
}
already_AddRefed<nsIHttpChannel>
XMLHttpRequestMainThread::GetCurrentHttpChannel()
{
@ -2409,10 +2449,6 @@ XMLHttpRequestMainThread::ChangeStateToDone()
mTimeoutTimer->Cancel();
}
if (mFlagSynchronous) {
UnsuppressEventHandlingAndResume();
}
// Per spec, fire the last download progress event, if any,
// before readystatechange=4/done. (Note that 0-sized responses
// will have not sent a progress event yet, so one must be sent here).
@ -3033,6 +3069,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
}
}
SuspendEventDispatching();
StopProgressEventTimer();
SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
@ -3056,6 +3093,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
}
UnsuppressEventHandlingAndResume();
ResumeEventDispatching();
} else {
// Now that we've successfully opened the channel, we can change state. Note
// that this needs to come after the AsyncOpen() and rv check, because this

Просмотреть файл

@ -401,7 +401,8 @@ public:
ErrorResult& aRv);
void
Abort() {
Abort()
{
ErrorResult rv;
Abort(rv);
MOZ_ASSERT(!rv.Failed());
@ -607,8 +608,21 @@ protected:
nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable);
void DispatchOrStoreEvent(DOMEventTargetHelper* aTarget, Event* aEvent);
already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier();
void SuspendEventDispatching();
void ResumeEventDispatching();
struct PendingEvent
{
RefPtr<DOMEventTargetHelper> mTarget;
RefPtr<Event> mEvent;
};
nsTArray<PendingEvent> mPendingEvents;
nsCOMPtr<nsISupports> mContext;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIChannel> mChannel;
@ -837,6 +851,10 @@ protected:
// Helper object to manage our XPCOM scriptability bits
nsXMLHttpRequestXPCOMifier* mXPCOMifier;
// When this is set to true, the event dispatching is suspended. This is
// useful to change the correct state when XHR is working sync.
bool mEventDispatchingSuspended;
static bool sDontWarnAboutSyncXHR;
};