Onloadend event is not supported in XMLHttpRequest
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Dec 2011 08:55:04 +0000 (08:55 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Dec 2011 08:55:04 +0000 (08:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=40952

Patch by Hans Muller <hmuller@adobe.com> on 2011-12-22
Reviewed by Julien Chaffraix.

Source/WebCore:

Added support for the loadend ProgressEvent to XMLHttpRequest and XMLHttpRequestUpload.
A new method, dispatchEventAndLoadEnd(), was added to XMLHttpRequestProgressEventThrottle
and XMLHttpRequestUpload to foolproof the common case of dispatching a load, abort,
or error event followed by a loadend event.

Tests: http/tests/xmlhttprequest/onloadend-event-after-abort.html
       http/tests/xmlhttprequest/onloadend-event-after-error.html
       http/tests/xmlhttprequest/onloadend-event-after-load.html
       http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html
       http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html
       http/tests/xmlhttprequest/upload-onloadend-event-after-load.html
       http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html

* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::callReadyStateChangeListener):
(WebCore::XMLHttpRequest::abort):
(WebCore::XMLHttpRequest::networkError):
(WebCore::XMLHttpRequest::abortError):
(WebCore::XMLHttpRequest::didSendData):
* xml/XMLHttpRequest.h:
* xml/XMLHttpRequest.idl:
* xml/XMLHttpRequestProgressEventThrottle.cpp:
(WebCore::XMLHttpRequestProgressEventThrottle::dispatchEventAndLoadEnd):
* xml/XMLHttpRequestProgressEventThrottle.h:
* xml/XMLHttpRequestUpload.cpp:
(WebCore::XMLHttpRequestUpload::dispatchEventAndLoadEnd):
* xml/XMLHttpRequestUpload.h:
* xml/XMLHttpRequestUpload.idl:

LayoutTests:

Added support for the loadend ProgresEvent to XMLHttpRequest and XMLHttpRequestUpload.
The new tests verify that a loadend progress event is dispatched after a load, abort,
or error progress event for both synchronous and asynchronous requests.

* http/tests/xmlhttprequest/onloadend-event-after-abort-expected.txt: Added.
* http/tests/xmlhttprequest/onloadend-event-after-abort.html: Added.
* http/tests/xmlhttprequest/onloadend-event-after-error-expected.txt: Added.
* http/tests/xmlhttprequest/onloadend-event-after-error.html: Added.
* http/tests/xmlhttprequest/onloadend-event-after-load-expected.txt: Added.
* http/tests/xmlhttprequest/onloadend-event-after-load.html: Added.
* http/tests/xmlhttprequest/onloadend-event-after-sync-requests-expected.txt: Added.
* http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-abort-expected.txt: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-load-expected.txt: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-load.html: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests-expected.txt: Added.
* http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html: Added.
* http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@103502 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/xml/XMLHttpRequest.cpp
Source/WebCore/xml/XMLHttpRequest.h
Source/WebCore/xml/XMLHttpRequest.idl
Source/WebCore/xml/XMLHttpRequestProgressEventThrottle.cpp
Source/WebCore/xml/XMLHttpRequestProgressEventThrottle.h
Source/WebCore/xml/XMLHttpRequestUpload.cpp
Source/WebCore/xml/XMLHttpRequestUpload.h
Source/WebCore/xml/XMLHttpRequestUpload.idl

index 9d6f593..4eb5219 100644 (file)
@@ -1,3 +1,30 @@
+2011-12-22  Hans Muller  <hmuller@adobe.com>
+
+        Onloadend event is not supported in XMLHttpRequest
+        https://bugs.webkit.org/show_bug.cgi?id=40952
+
+        Reviewed by Julien Chaffraix.
+
+        Added support for the loadend ProgresEvent to XMLHttpRequest and XMLHttpRequestUpload.
+        The new tests verify that a loadend progress event is dispatched after a load, abort, 
+        or error progress event for both synchronous and asynchronous requests.
+
+        * http/tests/xmlhttprequest/onloadend-event-after-abort-expected.txt: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-abort.html: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-error-expected.txt: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-error.html: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-load-expected.txt: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-load.html: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-sync-requests-expected.txt: Added.
+        * http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-abort-expected.txt: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-load-expected.txt: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-load.html: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests-expected.txt: Added.
+        * http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html: Added.
+        * http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt:
+
 2011-12-22  Mark Pilgrim  <pilgrim@chromium.org>
 
         [FileSystem API] Entry.getMetadata successCallback is required
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort-expected.txt b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort-expected.txt
new file mode 100644 (file)
index 0000000..ff0e715
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the abort ProgressEvent when an async request is aborted.
+
+PASS should appear below:
+
+PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort.html b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-abort.html
new file mode 100644 (file)
index 0000000..5745761
--- /dev/null
@@ -0,0 +1,66 @@
+<html>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p>Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p>Verify that a loadend ProgressEvent is dispatched after the abort ProgressEvent when an async request is aborted.</p>
+<p>PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message));
+}
+
+var xhr = new XMLHttpRequest();
+var results = "";
+var expected = " loadstart readyState=DONE abort loadend";
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest()
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function test()
+{
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            results += " readyState=DONE";
+        else if (xhr.readyState > xhr.OPENED)
+            xhr.abort();
+    }
+    xhr.onloadstart = logProgressEvent;
+    xhr.onabort = logProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logUnexpectedProgressEvent;
+    xhr.onloadend = function(e) {
+        logProgressEvent(e);
+        completeTest();
+    }
+
+    xhr.open("GET", "resources/get.txt", true);
+    xhr.send();
+}
+
+test();
+
+</script>
+</body>
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error-expected.txt b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error-expected.txt
new file mode 100644 (file)
index 0000000..5b64c1a
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the error ProgressEvent when an async request fails.
+
+PASS should appear below:
+
+PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error.html b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-error.html
new file mode 100644 (file)
index 0000000..124fa8b
--- /dev/null
@@ -0,0 +1,66 @@
+<html>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after the error ProgressEvent when an async request fails.</p>
+<p>PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message));
+}
+
+var xhr = new XMLHttpRequest();
+var results = "";
+var expected = " loadstart readyState=DONE error loadend";
+
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest()
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function test()
+{
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            results += " readyState=DONE";
+    }
+    xhr.onloadstart = logProgressEvent;
+    xhr.onabort = logUnexpectedProgressEvent;
+    xhr.onerror = logProgressEvent;
+    xhr.onload = logUnexpectedProgressEvent;
+    xhr.onloadend = function(e) {
+        logProgressEvent(e);
+        completeTest();
+    }
+
+    xhr.open("GET", "resources/infinite-loop.php", true);
+    xhr.send();
+}
+
+test(); 
+
+</script>
+</body>
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load-expected.txt b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load-expected.txt
new file mode 100644 (file)
index 0000000..89976c0
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the load ProgressEvent when an async request completes normally.
+
+PASS should appear below:
+
+PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load.html b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-load.html
new file mode 100644 (file)
index 0000000..3656b8d
--- /dev/null
@@ -0,0 +1,64 @@
+<HTML>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after the load ProgressEvent when an async request completes normally.</p>
+<p>PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message));
+}
+
+var xhr = new XMLHttpRequest();
+var results = "";
+var expected = " loadstart readyState=DONE load loadend";
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest()
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function test() 
+{
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            results += " readyState=DONE";
+    }
+    xhr.onloadstart = logProgressEvent;
+    xhr.onabort = logUnexpectedProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logProgressEvent;
+    xhr.onloadend = function(e) {
+        logProgressEvent(e);
+        completeTest();
+    }
+
+    xhr.open("GET", "resources/get.txt", true); 
+    xhr.send();
+}
+
+test(); 
+
+</script>
+</body>
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests-expected.txt b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests-expected.txt
new file mode 100644 (file)
index 0000000..fc5467c
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after a load, error, or abort ProgressEvent when a synchronous request completes normally, fails, or is aborted respectively.
+
+PASS PASS PASS should appear below:
+
+PASS PASS PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html b/LayoutTests/http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html
new file mode 100644 (file)
index 0000000..706d880
--- /dev/null
@@ -0,0 +1,110 @@
+<HTML>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after a load, error, or abort ProgressEvent when a synchronous request completes normally, fails, or is aborted respectively.</p>
+<p>PASS PASS PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message + " "));
+}
+
+var xhr = new XMLHttpRequest();
+var results;
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest(expected)
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function testNormal()
+{
+    results = "";
+
+    xhr.onloadstart = logUnexpectedProgressEvent;
+    xhr.onabort = logUnexpectedProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logProgressEvent;
+    xhr.onloadend = logProgressEvent;
+
+    xhr.open("GET", "resources/get.txt", false); 
+    xhr.send();
+    
+    completeTest(" load loadend");
+}
+
+function testError()
+{
+    results = "";
+
+    xhr.onloadstart = logUnexpectedProgressEvent;
+    xhr.onabort = logUnexpectedProgressEvent;
+    xhr.onerror = logProgressEvent;
+    xhr.onload = logUnexpectedProgressEvent;
+    xhr.onloadend = logProgressEvent;
+
+    xhr.open("GET", "resources/infinite-loop.php", false); 
+    try {
+        xhr.send();
+    }
+    catch (e) {
+        if (e.code != e.NETWORK_ERR)
+            results += " " + e;
+    }
+    
+    completeTest(" error loadend");
+}
+
+function testAbort()
+{
+    results = "";
+
+    xhr.onloadstart = logUnexpectedProgressEvent;
+    xhr.onabort = logProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logUnexpectedProgressEvent;
+    xhr.onloadend = logProgressEvent;
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            xhr.abort();
+    }
+
+    xhr.open("GET", "resources/get.txt", false); 
+    try {
+        xhr.send();
+    }
+    catch (e) {
+        if (e.code != e.NETWORK_ERR)
+            results += " " + e;
+    }
+    
+    completeTest(" abort loadend");
+}
+
+testNormal();
+testError();
+testAbort();
+
+</script>
+</body>
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort-expected.txt b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort-expected.txt
new file mode 100644 (file)
index 0000000..165e1d7
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the abort ProgressEvent when an async upload request is aborted.
+
+PASS should appear below:
+
+PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html
new file mode 100644 (file)
index 0000000..894d5b4
--- /dev/null
@@ -0,0 +1,64 @@
+<html>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after the abort ProgressEvent when an async upload request is aborted.</p>
+<p>PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message));
+}
+
+var xhr = new XMLHttpRequest();
+var results = "";
+var expected = " progress abort loadend";
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest()
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function test()
+{
+    xhr.upload.onprogress = function(e) {
+        logProgressEvent(e);
+        xhr.abort();
+    }
+    xhr.upload.onabort = logProgressEvent;
+    xhr.upload.onerror = logUnexpectedProgressEvent;
+    xhr.upload.onload = logUnexpectedProgressEvent;
+    xhr.upload.onloadend = function(e) {
+        logProgressEvent(e);
+        completeTest();
+    }
+
+    xhr.open("POST", "resources/post-echo.cgi", true);
+    xhr.send("data");
+}
+
+test();
+
+</script>
+</body>
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load-expected.txt b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load-expected.txt
new file mode 100644 (file)
index 0000000..9622386
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the load ProgressEvent when an async upload request completes normally.
+
+PASS should appear below:
+
+PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load.html b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-load.html
new file mode 100644 (file)
index 0000000..7fc89ca
--- /dev/null
@@ -0,0 +1,61 @@
+<html>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after the load ProgressEvent when an async upload request completes normally.</p>
+<p>PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message));
+}
+
+var xhr = new XMLHttpRequest();
+var results = "";
+var expected = " loadstart load loadend";
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest()
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "', expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function test()
+{
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            completeTest();
+    }
+    xhr.upload.onloadstart = logProgressEvent;
+    xhr.upload.onabort = logUnexpectedProgressEvent;
+    xhr.upload.onerror = logUnexpectedProgressEvent;
+    xhr.upload.onload = logProgressEvent;
+    xhr.upload.onloadend = logProgressEvent;
+
+    xhr.open("POST", "resources/post-echo.cgi", true);
+    xhr.send("data");
+}
+
+test();
+
+</script>
+</body>
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests-expected.txt b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests-expected.txt
new file mode 100644 (file)
index 0000000..18c869c
--- /dev/null
@@ -0,0 +1,7 @@
+Test case for bug 40952: Onloadend event is not supported in XMLHttpRequest
+
+Verify that a loadend ProgressEvent is dispatched after the load or abort ProgressEvent when a synchronous upload request completes normally or is aborted.
+
+PASS PASS should appear below:
+
+PASS PASS
diff --git a/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html b/LayoutTests/http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html
new file mode 100644 (file)
index 0000000..0096daf
--- /dev/null
@@ -0,0 +1,87 @@
+<HTML>
+<head>
+<title>Test case for bug 40952</title>
+</head>
+<body>
+<p> Test case for <a href="https://bugs.webkit.org/show_bug.cgi?id=40952"> bug 40952</a>: Onloadend event is not supported in XMLHttpRequest</p>
+<p> Verify that a loadend ProgressEvent is dispatched after the load or abort ProgressEvent when a synchronous upload request completes normally or is aborted.</p>
+<p>PASS PASS should appear below:</p>
+<p id=console></p>
+<script type="text/javascript">
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    var consoleElt = document.getElementById("console");
+    consoleElt.appendChild(document.createTextNode(message + " "));
+}
+
+var xhr = new XMLHttpRequest();
+var results;
+
+function logProgressEvent(e) {
+    results += " " + e.type;
+}
+
+function logUnexpectedProgressEvent(e) {
+    results += " [unexpected ProgressEvent: " + e.type + "]";
+    completeTest();   
+}
+
+function completeTest(expected)
+{
+    log(results == expected ? "PASS" : "FAILED results : '" + results + "' expected : '" + expected + "'");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function testNormal()
+{
+    results = "";
+
+    xhr.onloadstart = logUnexpectedProgressEvent;
+    xhr.onabort = logUnexpectedProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logProgressEvent;
+    xhr.onloadend = logProgressEvent;
+
+    xhr.open("POST", "resources/post-echo.cgi", false); 
+    xhr.send("data");
+    
+    completeTest(" load loadend");
+}
+
+function testAbort()
+{
+    results = "";
+
+    xhr.onloadstart = logUnexpectedProgressEvent;
+    xhr.onabort = logProgressEvent;
+    xhr.onerror = logUnexpectedProgressEvent;
+    xhr.onload = logUnexpectedProgressEvent;
+    xhr.onloadend = logProgressEvent;
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState == xhr.DONE)
+            xhr.abort();
+    }
+
+    xhr.open("POST", "resources/get.txt", false); 
+    try {
+        xhr.send();
+    }
+    catch (e) {
+        if (e.code != e.NETWORK_ERR)
+            results += " " + e;
+    }
+    
+    completeTest(" abort loadend");
+}
+
+testNormal();
+testAbort();
+
+</script>
+</body>
index 245d3c0..a5126aa 100644 (file)
@@ -6,17 +6,21 @@ bug 17502: Assertion failure when trying to restart a sync XMLHttpRequest as an
  Step 1: Same origin request
 readystatechange 4
 load
+loadend
 
 Step 2: Cross origin request, disallowed
 readystatechange 4
 error
+loadend
 Error: NETWORK_ERR: XMLHttpRequest Exception 101
 
 Step 3: Cross origin request, allowed
 readystatechange 4
 load
+loadend
 
 Step 4: Cross origin request, check that preflight isn't attempted
 readystatechange 4
 load
+loadend
 
index 1c2304b..080095f 100644 (file)
@@ -1,3 +1,39 @@
+2011-12-22  Hans Muller  <hmuller@adobe.com>
+
+        Onloadend event is not supported in XMLHttpRequest
+        https://bugs.webkit.org/show_bug.cgi?id=40952
+
+        Reviewed by Julien Chaffraix.
+
+        Added support for the loadend ProgressEvent to XMLHttpRequest and XMLHttpRequestUpload.
+        A new method, dispatchEventAndLoadEnd(), was added to XMLHttpRequestProgressEventThrottle
+        and XMLHttpRequestUpload to foolproof the common case of dispatching a load, abort,
+        or error event followed by a loadend event.
+
+        Tests: http/tests/xmlhttprequest/onloadend-event-after-abort.html
+               http/tests/xmlhttprequest/onloadend-event-after-error.html
+               http/tests/xmlhttprequest/onloadend-event-after-load.html
+               http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html
+               http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html
+               http/tests/xmlhttprequest/upload-onloadend-event-after-load.html
+               http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html
+
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::callReadyStateChangeListener):
+        (WebCore::XMLHttpRequest::abort):
+        (WebCore::XMLHttpRequest::networkError):
+        (WebCore::XMLHttpRequest::abortError):
+        (WebCore::XMLHttpRequest::didSendData):
+        * xml/XMLHttpRequest.h:
+        * xml/XMLHttpRequest.idl:
+        * xml/XMLHttpRequestProgressEventThrottle.cpp:
+        (WebCore::XMLHttpRequestProgressEventThrottle::dispatchEventAndLoadEnd):
+        * xml/XMLHttpRequestProgressEventThrottle.h:
+        * xml/XMLHttpRequestUpload.cpp:
+        (WebCore::XMLHttpRequestUpload::dispatchEventAndLoadEnd):
+        * xml/XMLHttpRequestUpload.h:
+        * xml/XMLHttpRequestUpload.idl:
+
 2011-12-22  Mark Pilgrim  <pilgrim@chromium.org>
 
         [FileSystem API] Entry.getMetadata successCallback is required
index 5efe054..c2b5829 100644 (file)
@@ -352,6 +352,7 @@ void XMLHttpRequest::callReadyStateChangeListener()
         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this);
         m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
         InspectorInstrumentation::didLoadXHR(cookie);
+        m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadendEvent));
     }
 }
 
@@ -710,11 +711,11 @@ void XMLHttpRequest::abort()
         m_state = UNSENT;
     }
 
-    m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
+    m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
     if (!m_uploadComplete) {
         m_uploadComplete = true;
         if (m_upload && m_uploadEventsAllowed)
-            m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
+            m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
     }
 }
 
@@ -774,11 +775,11 @@ void XMLHttpRequest::genericError()
 void XMLHttpRequest::networkError()
 {
     genericError();
-    m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
+    m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
     if (!m_uploadComplete) {
         m_uploadComplete = true;
         if (m_upload && m_uploadEventsAllowed)
-            m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
+            m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
     }
     internalAbort();
 }
@@ -786,11 +787,11 @@ void XMLHttpRequest::networkError()
 void XMLHttpRequest::abortError()
 {
     genericError();
-    m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
+    m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
     if (!m_uploadComplete) {
         m_uploadComplete = true;
         if (m_upload && m_uploadEventsAllowed)
-            m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
+            m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().abortEvent));
     }
 }
 
@@ -1032,7 +1033,7 @@ void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long lon
     if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
         m_uploadComplete = true;
         if (m_uploadEventsAllowed)
-            m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
+            m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
     }
 }
 
index bcba098..26ee65c 100644 (file)
@@ -133,6 +133,7 @@ public:
     DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(load);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(loadend);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
 
index 826d101..6fb4dfd 100644 (file)
@@ -42,6 +42,7 @@ module xml {
         attribute EventListener onabort;
         attribute EventListener onerror;
         attribute EventListener onload;
+        attribute EventListener onloadend;
         attribute EventListener onloadstart;
         attribute EventListener onprogress;
 
index 5d4afa3..3bc8c30 100644 (file)
@@ -81,6 +81,14 @@ void XMLHttpRequestProgressEventThrottle::dispatchEvent(PassRefPtr<Event> event,
     m_target->dispatchEvent(event);
 }
 
+void XMLHttpRequestProgressEventThrottle::dispatchEventAndLoadEnd(PassRefPtr<Event> event)
+{
+    ASSERT(event->type() == eventNames().loadEvent || event->type() == eventNames().abortEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().timeoutEvent);
+
+    dispatchEvent(event);
+    dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadendEvent));
+}
+
 void XMLHttpRequestProgressEventThrottle::flushProgressEvent()
 {
     if (!hasEventToDispatch())
index 036905e..42ceebf 100644 (file)
@@ -50,6 +50,7 @@ public:
 
     void dispatchProgressEvent(bool lengthComputable, unsigned long long loaded, unsigned long long total);
     void dispatchEvent(PassRefPtr<Event>, ProgressEventAction = DoNotFlushProgressEvent);
+    void dispatchEventAndLoadEnd(PassRefPtr<Event>);
 
     void suspend();
     void resume();
index 3f1cafa..60627a0 100644 (file)
@@ -61,4 +61,14 @@ EventTargetData* XMLHttpRequestUpload::ensureEventTargetData()
     return &m_eventTargetData;
 }
 
+void XMLHttpRequestUpload::dispatchEventAndLoadEnd(PassRefPtr<Event> event)
+{
+    ASSERT(event->type() == eventNames().loadEvent || event->type() == eventNames().abortEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().timeoutEvent);
+
+    dispatchEvent(event);
+    dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadendEvent));
+}
+
+
+
 } // namespace WebCore
index 7f45861..a62a175 100644 (file)
@@ -60,9 +60,12 @@ namespace WebCore {
         DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
         DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
         DEFINE_ATTRIBUTE_EVENT_LISTENER(load);
+        DEFINE_ATTRIBUTE_EVENT_LISTENER(loadend);
         DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
         DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
 
+        void dispatchEventAndLoadEnd(PassRefPtr<Event>);
+
     private:
         XMLHttpRequestUpload(XMLHttpRequest*);
 
index 734939d..5f98cb7 100644 (file)
@@ -38,6 +38,7 @@ module xml {
         attribute EventListener onabort;
         attribute EventListener onerror;
         attribute EventListener onload;
+        attribute EventListener onloadend;
         attribute EventListener onloadstart;
         attribute EventListener onprogress;