Index: Source/core/xml/XMLHttpRequest.cpp |
diff --git a/Source/core/xml/XMLHttpRequest.cpp b/Source/core/xml/XMLHttpRequest.cpp |
index ee407bcf459a6183fcf587a29e27176344d0836e..961278ebe0183e6070ffd6d277f8345f239c7e98 100644 |
--- a/Source/core/xml/XMLHttpRequest.cpp |
+++ b/Source/core/xml/XMLHttpRequest.cpp |
@@ -178,7 +178,6 @@ XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri |
, m_exceptionCode(0) |
, m_progressEventThrottle(this) |
, m_responseTypeCode(ResponseTypeDefault) |
- , m_dropProtectionRunner(this, &XMLHttpRequest::dropProtection) |
, m_securityOrigin(securityOrigin) |
{ |
initializeXMLHttpRequestStaticData(); |
@@ -849,12 +848,6 @@ void XMLHttpRequest::createRequest(ExceptionState& exceptionState) |
// FIXME: Maybe create() can return null for other reasons too? |
ASSERT(!m_loader); |
m_loader = ThreadableLoader::create(executionContext(), this, request, options); |
- if (m_loader) { |
- // Neither this object nor the JavaScript wrapper should be deleted while |
- // a request is in progress because we need to keep the listeners alive, |
- // and they are referenced by the JavaScript wrapper. |
- setPendingActivity(this); |
- } |
} else { |
ThreadableLoader::loadResourceSynchronously(executionContext(), request, *this, options); |
} |
@@ -869,15 +862,19 @@ void XMLHttpRequest::abort() |
{ |
WTF_LOG(Network, "XMLHttpRequest %p abort()", this); |
- // internalAbort() calls dropProtection(), which may release the last reference. |
- RefPtr<XMLHttpRequest> protect(this); |
- |
bool sendFlag = m_loader; |
// Response is cleared next, save needed progress event data. |
long long expectedLength = m_response.expectedContentLength(); |
long long receivedLength = m_receivedLength; |
+ // internalAbort() clears m_loader. hasPendingActivity() returns false when |
+ // m_loader is 0. So, if window.onload is dispatched (see comments in |
+ // internalAbort()), it's possible that the wrapper gets GC-ed during |
+ // execution of the event. So, we need to keep this object alive to |
+ // continue the rest of this method. |
+ RefPtr<XMLHttpRequest> protect(this); |
+ |
if (!internalAbort()) |
return; |
@@ -900,7 +897,7 @@ void XMLHttpRequest::clearVariablesForLoading() |
m_responseEncoding = String(); |
} |
-bool XMLHttpRequest::internalAbort(DropProtection async) |
+bool XMLHttpRequest::internalAbort() |
{ |
m_error = true; |
@@ -917,32 +914,23 @@ bool XMLHttpRequest::internalAbort(DropProtection async) |
// Cancelling the ThreadableLoader m_loader may result in calling |
// window.onload synchronously. If such an onload handler contains open() |
// call on the same XMLHttpRequest object, reentry happens. If m_loader |
- // is left to be non 0, internalAbort() call for the inner open() makes |
- // an extra dropProtection() call (when we're back to the outer open(), |
- // we'll call dropProtection()). To avoid that, clears m_loader before |
- // calling cancel. |
- // |
- // If, window.onload contains open() and send(), m_loader will be set to |
- // non 0 value. So, we cannot continue the outer open(). In such case, |
- // just abort the outer open() by returning false. |
+ // is left to be non 0, internalAbort() for the inner open() repeats the |
+ // the same work. To avoid that, clears m_loader before calling cancel(). |
RefPtr<ThreadableLoader> loader = m_loader.release(); |
loader->cancel(); |
- // Save to a local variable since we're going to drop protection. |
- bool newLoadStarted = m_loader; |
+ // If, window.onload contains open() and send(), m_loader will be set to |
+ // non 0 value. So, we cannot continue the outer open(). In such case, |
+ // just abort the outer open() by returning false. |
+ if (m_loader) |
+ return false; |
// If abort() called internalAbort() and a nested open() ended up |
// clearing the error flag, but didn't send(), make sure the error |
// flag is still set. |
- if (!newLoadStarted) |
- m_error = true; |
- |
- if (async == DropProtectionAsync) |
- dropProtectionSoon(); |
- else |
- dropProtection(); |
+ m_error = true; |
- return !newLoadStarted; |
+ return true; |
} |
void XMLHttpRequest::clearResponse() |
@@ -1061,16 +1049,6 @@ void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const Atomi |
dispatchEventAndLoadEnd(type, receivedLength, expectedLength); |
} |
-void XMLHttpRequest::dropProtectionSoon() |
-{ |
- m_dropProtectionRunner.runAsync(); |
-} |
- |
-void XMLHttpRequest::dropProtection() |
-{ |
- unsetPendingActivity(this); |
-} |
- |
void XMLHttpRequest::overrideMimeType(const AtomicString& override) |
{ |
m_mimeTypeOverride = override; |
@@ -1263,13 +1241,13 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double) |
InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this, identifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumber); |
- // Prevent dropProtection releasing the last reference, and retain |this| until the end of this method. |
+ // hasPendingActivity() returns false when m_loader is 0. So, it's possible |
+ // that the wrapper gets GC-ed during execution of the event. So, we need |
+ // to keep this object alive to continue the rest of this method. |
RefPtr<XMLHttpRequest> protect(this); |
- if (m_loader) { |
+ if (m_loader) |
m_loader = 0; |
- dropProtection(); |
- } |
changeState(DONE); |
} |
@@ -1382,9 +1360,6 @@ void XMLHttpRequest::handleDidTimeout() |
{ |
WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); |
- // internalAbort() calls dropProtection(), which may release the last reference. |
- RefPtr<XMLHttpRequest> protect(this); |
- |
// Response is cleared next, save needed progress event data. |
long long expectedLength = m_response.expectedContentLength(); |
long long receivedLength = m_receivedLength; |
@@ -1408,7 +1383,12 @@ void XMLHttpRequest::resume() |
void XMLHttpRequest::stop() |
{ |
- internalAbort(DropProtectionAsync); |
+ internalAbort(); |
+} |
+ |
+bool XMLHttpRequest::hasPendingActivity() const |
+{ |
+ return m_loader; |
} |
void XMLHttpRequest::contextDestroyed() |