Changeset 174684 in webkit


Ignore:
Timestamp:
Oct 14, 2014 10:10:24 AM (10 years ago)
Author:
commit-queue@webkit.org
Message:

[XHR] Abort method execution when m_loader->cancel() in internalAbort() caused reentry
https://bugs.webkit.org/show_bug.cgi?id=126975

Patch by Youenn Fablet <youennf@gmail.com> on 2014-10-14
Reviewed by Alexey Proskuryakov.

Source/WebCore:

Merging https://chromium.googlesource.com/chromium/blink/+/0d75daf2053631518606ae15daaece701a25b2c4
Ensuring new test from https://codereview.chromium.org/76133002/ is passing.

Test: http/tests/xmlhttprequest/reentrant-cancel-abort.html

  • xml/XMLHttpRequest.cpp:

(WebCore::XMLHttpRequest::open): exit early if internalAbort asks so
(WebCore::XMLHttpRequest::abort): exit early if internalAbort asks so
(WebCore::XMLHttpRequest::internalAbort): ask calling function to exit early if a new loader is created during the cancellation of the loader (potential reentrant case through window.onload callback)
(WebCore::XMLHttpRequest::didTimeout): exit early if internalAbort asks so

  • xml/XMLHttpRequest.h:

LayoutTests:

Adding reentrant-cancel-abort.html (from https://codereview.chromium.org/76133002/)
that crashes without the patch
Updated reentrant-cancel.html test to expect the exception
that is now hit in initSend function (since a XHR open() call is aborted)

  • http/tests/xmlhttprequest/reentrant-cancel-abort-expected.txt: Added.
  • http/tests/xmlhttprequest/reentrant-cancel-abort.html: Added.
  • http/tests/xmlhttprequest/reentrant-cancel.html:
Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r174680 r174684  
     12014-10-14  Youenn Fablet  <youennf@gmail.com>
     2
     3        [XHR] Abort method execution when m_loader->cancel() in internalAbort() caused reentry
     4        https://bugs.webkit.org/show_bug.cgi?id=126975
     5
     6        Reviewed by Alexey Proskuryakov.
     7
     8        Adding reentrant-cancel-abort.html (from https://codereview.chromium.org/76133002/)
     9        that crashes without the patch
     10        Updated reentrant-cancel.html test to expect the exception
     11        that is now hit in initSend function (since a XHR open() call is aborted)
     12
     13        * http/tests/xmlhttprequest/reentrant-cancel-abort-expected.txt: Added.
     14        * http/tests/xmlhttprequest/reentrant-cancel-abort.html: Added.
     15        * http/tests/xmlhttprequest/reentrant-cancel.html:
     16
    1172014-10-14  Alejandro G. Castro  <alex@igalia.com>
    218
  • trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel.html

    r124692 r174684  
    11<script>
    2 if (window.testRunner)
     2if (window.testRunner) {
    33    testRunner.dumpAsText();
     4    testRunner.waitUntilDone();
     5}
    46
    57function addElement() {
     
    1315{
    1416    xhr.open("GET", "", true);
    15     xhr.send();
     17    try {
     18        xhr.send();
     19    }
     20    catch(e) {
     21        // In case of reentrant call, the call to "open" will be aborted by reentrant call.
     22        // The call to "send" following the "open" aborted call will throw an exception (XHR not in open mode)
     23        if (e.name != "InvalidStateError") {
     24            console.log("FAILED: Was expecting an InvalidStateError exception");
     25        }
     26        testRunner.notifyDone();
     27    }
    1628}
    1729window.addEventListener("DOMSubtreeModified", sendXHR);
  • trunk/Source/WebCore/ChangeLog

    r174678 r174684  
     12014-10-14  Youenn Fablet  <youennf@gmail.com>
     2
     3        [XHR] Abort method execution when m_loader->cancel() in internalAbort() caused reentry
     4        https://bugs.webkit.org/show_bug.cgi?id=126975
     5
     6        Reviewed by Alexey Proskuryakov.
     7
     8        Merging https://chromium.googlesource.com/chromium/blink/+/0d75daf2053631518606ae15daaece701a25b2c4
     9        Ensuring new test from https://codereview.chromium.org/76133002/ is passing.
     10
     11        Test: http/tests/xmlhttprequest/reentrant-cancel-abort.html
     12
     13        * xml/XMLHttpRequest.cpp:
     14        (WebCore::XMLHttpRequest::open): exit early if internalAbort asks so
     15        (WebCore::XMLHttpRequest::abort): exit early if internalAbort asks so
     16        (WebCore::XMLHttpRequest::internalAbort): ask calling function to exit early if a new loader is created during the cancellation of the loader (potential reentrant case through window.onload callback)   
     17        (WebCore::XMLHttpRequest::didTimeout): exit early if internalAbort asks so
     18        * xml/XMLHttpRequest.h:
     19
    1202014-10-14  Alejandro G. Castro  <alex@igalia.com>
    221
  • trunk/Source/WebCore/xml/XMLHttpRequest.cpp

    r174225 r174684  
    464464void XMLHttpRequest::open(const String& method, const URL& url, bool async, ExceptionCode& ec)
    465465{
    466     internalAbort();
     466    if (!internalAbort())
     467        return;
     468
    467469    State previousState = m_state;
    468470    m_state = UNSENT;
     
    806808    bool sendFlag = m_loader;
    807809
    808     internalAbort();
     810    if (!internalAbort())
     811        return;
    809812
    810813    clearResponseBuffers();
     
    824827}
    825828
    826 void XMLHttpRequest::internalAbort()
    827 {
    828     bool hadLoader = m_loader;
    829 
     829bool XMLHttpRequest::internalAbort()
     830{
    830831    m_error = true;
    831832
     
    833834    m_receivedLength = 0;
    834835
    835     if (hadLoader) {
    836         m_loader->cancel();
    837         m_loader = 0;
    838     }
    839 
    840836    m_decoder = 0;
    841837
    842838    InspectorInstrumentation::didFailXHRLoading(scriptExecutionContext(), this);
    843839
    844     if (hadLoader)
    845         dropProtection();
     840    if (!m_loader)
     841        return true;
     842
     843    // Cancelling m_loader may trigger a window.onload callback which can call open() on the same xhr.
     844    // This would create internalAbort reentrant call.
     845    // m_loader is set to null before being cancelled to exit early in any reentrant internalAbort() call.
     846    RefPtr<ThreadableLoader> loader = m_loader.release();
     847    loader->cancel();
     848
     849    // If window.onload callback calls open() and send() on the same xhr, m_loader is now set to a new value.
     850    // The function calling internalAbort() should abort to let the open() and send() calls continue properly.
     851    // We ask the function calling internalAbort() to exit by returning false.
     852    // Save this information to a local variable since we are going to drop protection.
     853    bool newLoadStarted = m_loader;
     854
     855    dropProtection();
     856
     857    return !newLoadStarted;
    846858}
    847859
     
    12191231    // internalAbort() calls dropProtection(), which may release the last reference.
    12201232    Ref<XMLHttpRequest> protect(*this);
    1221     internalAbort();
     1233    if (!internalAbort())
     1234        return;
    12221235
    12231236    clearResponse();
  • trunk/Source/WebCore/xml/XMLHttpRequest.h

    r173552 r174684  
    195195    void callReadyStateChangeListener();
    196196    void dropProtection();
    197     void internalAbort();
     197
     198    // Returns false when cancelling the loader within internalAbort() triggers an event whose callback creates a new loader.
     199    // In that case, the function calling internalAbort should exit.
     200    bool internalAbort();
     201
    198202    void clearResponse();
    199203    void clearResponseBuffers();
Note: See TracChangeset for help on using the changeset viewer.