Commit 9222a901 authored by yhirano@chromium.org's avatar yhirano@chromium.org

Protect readystatechange event dispatch on XMLHttpRequest.

XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent may dispatch
multiple events: a deferred progress event and the given ready state change.
Multiple dispatching may lead to a use-after-free bug.

This CL adds a protection for the event target. In addition to that,
XMLHttpRequestProgressEventThrottle stops dispatching the latter event when
dispatching the former event changes the readyState.

BUG=505362

Review URL: https://codereview.chromium.org/1217803002

git-svn-id: svn://svn.chromium.org/blink/trunk@197983 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 307688bd
......@@ -664,6 +664,9 @@ void XMLHttpRequest::dispatchReadyStateChangeEvent()
if (!executionContext())
return;
// We need this protection because dispatchReadyStateChangeEvent may
// dispatch multiple events.
ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
if (m_async || (m_state <= OPENED || m_state == DONE)) {
TRACE_EVENT1("devtools.timeline", "XHRReadyStateChange", "data", InspectorXhrReadyStateChangeEvent::data(executionContext(), this));
XMLHttpRequestProgressEventThrottle::DeferredEventAction action = XMLHttpRequestProgressEventThrottle::Ignore;
......
......@@ -28,7 +28,7 @@
#include "core/xmlhttprequest/XMLHttpRequestProgressEventThrottle.h"
#include "core/EventTypeNames.h"
#include "core/events/EventTarget.h"
#include "core/xmlhttprequest/XMLHttpRequest.h"
#include "core/xmlhttprequest/XMLHttpRequestProgressEvent.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
......@@ -66,7 +66,7 @@ private:
const double XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingIntervalInSeconds = .05; // 50 ms per specification.
XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(EventTarget* target)
XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(XMLHttpRequest* target)
: m_target(target)
, m_deferred(adoptPtr(new DeferredEvent))
{
......@@ -96,17 +96,25 @@ void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(const AtomicStri
void XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent(PassRefPtrWillBeRawPtr<Event> event, DeferredEventAction action)
{
XMLHttpRequest::State state = m_target->readyState();
// Given that ResourceDispatcher doesn't deliver an event when suspended,
// we don't have to worry about event dispatching while suspended.
if (action == Flush) {
dispatchDeferredEvent();
// |m_target| is protected by the caller.
stop();
} else if (action == Clear) {
m_deferred->clear();
stop();
}
m_target->dispatchEvent(event);
if (state == m_target->readyState()) {
// We don't dispatch the event when an event handler associated with
// the previously dispatched event changes the readyState (e.g. when
// the event handler calls xhr.abort()). In such cases a
// readystatechange should have been already dispatched if necessary.
m_target->dispatchEvent(event);
}
}
void XMLHttpRequestProgressEventThrottle::dispatchDeferredEvent()
......
......@@ -36,7 +36,7 @@
namespace blink {
class Event;
class EventTarget;
class XMLHttpRequest;
// This class implements the XHR2 ProgressEvent dispatching:
// "dispatch a progress event named progress about every 50ms or for every
......@@ -51,7 +51,7 @@ class EventTarget;
// the spec.
class XMLHttpRequestProgressEventThrottle final : public NoBaseWillBeGarbageCollectedFinalized<XMLHttpRequestProgressEventThrottle>, public TimerBase {
public:
static PassOwnPtrWillBeRawPtr<XMLHttpRequestProgressEventThrottle> create(EventTarget* eventTarget)
static PassOwnPtrWillBeRawPtr<XMLHttpRequestProgressEventThrottle> create(XMLHttpRequest* eventTarget)
{
return adoptPtrWillBeNoop(new XMLHttpRequestProgressEventThrottle(eventTarget));
}
......@@ -84,7 +84,7 @@ public:
DECLARE_TRACE();
private:
explicit XMLHttpRequestProgressEventThrottle(EventTarget*);
explicit XMLHttpRequestProgressEventThrottle(XMLHttpRequest*);
// The main purpose of this class is to throttle the "progress"
// ProgressEvent dispatching. This class represents such a deferred
......@@ -99,7 +99,7 @@ private:
// the one holding us. With Oilpan, a simple strong Member can be used -
// this XMLHttpRequestProgressEventThrottle (part) object dies together
// with the XMLHttpRequest object.
RawPtrWillBeMember<EventTarget> m_target;
RawPtrWillBeMember<XMLHttpRequest> m_target;
// A slot for the deferred "progress" ProgressEvent. When multiple events
// arrive, only the last one is stored and others are discarded.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment