[Fetch API] Add basic loading of resources
authoryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Mar 2016 16:53:36 +0000 (16:53 +0000)
committeryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Mar 2016 16:53:36 +0000 (16:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155637

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Rebasing test expectations.
Updating scheme-blob.js to ensure generated test names are stable run after run.

* web-platform-tests/fetch/api/basic/accept-header-expected.txt:
* web-platform-tests/fetch/api/basic/integrity-expected.txt:
* web-platform-tests/fetch/api/basic/mode-no-cors-expected.txt:
* web-platform-tests/fetch/api/basic/mode-same-origin-expected.txt:
* web-platform-tests/fetch/api/basic/request-forbidden-headers-expected.txt:
* web-platform-tests/fetch/api/basic/request-headers-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-about-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-blob-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-blob-worker-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-blob.js:
(checkFetchResponse): Deleted.
(checkKoUrl): Deleted.
* web-platform-tests/fetch/api/basic/scheme-data-expected.txt:
* web-platform-tests/fetch/api/basic/scheme-others-expected.txt:
* web-platform-tests/fetch/api/basic/stream-response-expected.txt:

Source/WebCore:

Adding support for basic fetch for Window (no support for Worker yet).
A FetchResponse object is created for every fetch task.
But it will only be exposed to JS at promise fulfillment time, i.e. once initial response headers are retrieved.

Updating Blob resource handle to add Content-Type and Content-Length header and notifying of error in case of erroneous HTTP method.

Fetch is limited to same origin requests currently due to some WPT tests that would timeout otherwise.

Tests: http/tests/fetch/closing-while-fetching.html
       http/tests/fetch/get-response-body-while-loading.html
Also covered by rebased tests.

* Modules/fetch/DOMWindowFetch.cpp: Creating a FetchResponse to start fetching.
(WebCore::DOMWindowFetch::fetch):
* Modules/fetch/DOMWindowFetch.h:
* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::consume):
(WebCore::FetchBody::consumeArrayBuffer): Handling of body promises in case of data stored as a buffer.
(WebCore::FetchBody::consumeText): Passing the promise as a reference.
(WebCore::blobFromArrayBuffer): Helper routine.
(WebCore::FetchBody::fulfillTextPromise): Helper routine.
(WebCore::FetchBody::loadedAsArrayBuffer): Updated to handle storing of data as a buffer.
(WebCore::FetchBody::loadedAsText):
(WebCore::FetchBody::bodyForInternalRequest): Helper routine to generate the request body data to be sent as part of the fetch request.
(WebCore::FetchBody::extractFromText):
* Modules/fetch/FetchBody.h:
(WebCore::FetchBody::loadingBody):
(WebCore::FetchBody::FetchBody):
* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::loadBlob): Updated to cope with the change that FetchLoader::start does not return a boolean anymore
but will directly call failure callbacks.
(WebCore::FetchBodyOwner::loadedBlobAsText): Moving it closer to other blob loading routines.
(WebCore::FetchBodyOwner::finishBlobLoading):
* Modules/fetch/FetchBodyOwner.h:
(WebCore::FetchBodyOwner::body):
(WebCore::FetchBodyOwner::loadedBlobAsArrayBuffer):
* Modules/fetch/FetchHeaders.cpp:
(WebCore::FetchHeaders::fill):
(WebCore::FetchHeaders::filterAndFill): Helper routine to fill headers from a HTTPHeaderMap after being filtered.
* Modules/fetch/FetchHeaders.h:
(WebCore::FetchHeaders::internalHeaders):
* Modules/fetch/FetchLoader.cpp:
(WebCore::FetchLoader::start):
(WebCore::FetchLoader::didFailRedirectCheck):
* Modules/fetch/FetchLoader.h:
* Modules/fetch/FetchRequest.cpp:
(WebCore::FetchRequest::internalRequest): Routine used to create the ResourceRequest transmitted to ThreadableLoader.
       * Modules/fetch/FetchRequest.h:
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::fetch): Start fetching by creating a FetchLoader based on passed request.
(WebCore::FetchResponse::BodyLoader::didSucceed): FetchLoader callback.
(WebCore::FetchResponse::BodyLoader::didFail): Ditto.
(WebCore::FetchResponse::BodyLoader::BodyLoader): Ditto.
(WebCore::FetchResponse::BodyLoader::didReceiveResponse): Ditto.
(WebCore::FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer): Ditto.
(WebCore::FetchResponse::BodyLoader::start): Starting fetch loader.
(WebCore::FetchResponse::BodyLoader::stop): Stopping fetch loader.
(WebCore::FetchResponse::stop): Stop loader if any.
* Modules/fetch/FetchResponse.h:
* platform/network/BlobResourceHandle.cpp:
(WebCore::BlobResourceHandle::doStart: Notifying the loader with an error if verb is not GET.
(WebCore::BlobResourceHandle::notifyResponseOnSuccess): Adding support for Content-Type and Content-Lenth headers.
(WebCore::BlobResourceHandle::createAsync): Removing GET verb check.

LayoutTests:

* TestExpectations: Removed flaky test expectations.
* http/tests/fetch/closing-while-fetching-expected.txt: Added.
* http/tests/fetch/closing-while-fetching.html: Added.
* http/tests/fetch/get-response-body-while-loading-expected.txt: Added.
* http/tests/fetch/get-response-body-while-loading.html: Added.
* http/tests/resources/download-json-with-delay.php: Added.
* platform/gtk/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt: Added.

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/http/tests/fetch/closing-while-fetching-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/fetch/closing-while-fetching.html [new file with mode: 0644]
LayoutTests/http/tests/fetch/get-response-body-while-loading-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/fetch/get-response-body-while-loading.html [new file with mode: 0644]
LayoutTests/http/tests/resources/download-json-with-delay.php [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/accept-header-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/integrity-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/mode-no-cors-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/mode-same-origin-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-forbidden-headers-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-about-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-blob-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-blob-worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-blob.js
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-data-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/scheme-others-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/stream-response-expected.txt
LayoutTests/platform/gtk/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/DOMWindowFetch.cpp
Source/WebCore/Modules/fetch/DOMWindowFetch.h
Source/WebCore/Modules/fetch/FetchBody.cpp
Source/WebCore/Modules/fetch/FetchBody.h
Source/WebCore/Modules/fetch/FetchBodyOwner.cpp
Source/WebCore/Modules/fetch/FetchBodyOwner.h
Source/WebCore/Modules/fetch/FetchHeaders.cpp
Source/WebCore/Modules/fetch/FetchHeaders.h
Source/WebCore/Modules/fetch/FetchLoader.cpp
Source/WebCore/Modules/fetch/FetchLoader.h
Source/WebCore/Modules/fetch/FetchRequest.cpp
Source/WebCore/Modules/fetch/FetchRequest.h
Source/WebCore/Modules/fetch/FetchResponse.cpp
Source/WebCore/Modules/fetch/FetchResponse.h
Source/WebCore/platform/network/BlobResourceHandle.cpp

index 742849b..eef9fbd 100644 (file)
@@ -1,3 +1,18 @@
+2016-03-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Add basic loading of resources
+        https://bugs.webkit.org/show_bug.cgi?id=155637
+
+        Reviewed by Darin Adler.
+
+        * TestExpectations: Removed flaky test expectations.
+        * http/tests/fetch/closing-while-fetching-expected.txt: Added.
+        * http/tests/fetch/closing-while-fetching.html: Added.
+        * http/tests/fetch/get-response-body-while-loading-expected.txt: Added.
+        * http/tests/fetch/get-response-body-while-loading.html: Added.
+        * http/tests/resources/download-json-with-delay.php: Added.
+        * platform/gtk/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt: Added.
+
 2016-03-24  Michael Saboff  <msaboff@apple.com>
 
         [ES6] Greedy unicode RegExp's don't properly backtrack past non BMP characters
index 7bc739f..efec509 100644 (file)
@@ -317,10 +317,6 @@ imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-bogus.htm [ Skip ]
 imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-to-cors.htm [ Skip ]
 imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-to-non-cors.htm [ Skip ]
 
-# Tests that are flaky as failing assertions print a new token generated for each test run.
-imported/w3c/web-platform-tests/fetch/api/basic/scheme-blob.html [ Failure ]
-imported/w3c/web-platform-tests/fetch/api/basic/scheme-blob-worker.html [ Failure ]
-
 # New W3C ref tests that are failing.
 webkit.org/b/148856 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-video-element/video_initially_paused.html [ ImageOnlyFailure ]
 
diff --git a/LayoutTests/http/tests/fetch/closing-while-fetching-expected.txt b/LayoutTests/http/tests/fetch/closing-while-fetching-expected.txt
new file mode 100644 (file)
index 0000000..452b02c
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Ensuring that fetch response body promise is not fulfilled when window is closed 
+
diff --git a/LayoutTests/http/tests/fetch/closing-while-fetching.html b/LayoutTests/http/tests/fetch/closing-while-fetching.html
new file mode 100644 (file)
index 0000000..d3278b5
--- /dev/null
@@ -0,0 +1,33 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Fetch: retrieve response's body progressively</title>
+    <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch">
+    <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch">
+    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
+    <script src="/js-test-resources/testharness.js"></script>
+    <script src="/js-test-resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <script>
+        
+var test = async_test("Ensuring that fetch response body promise is not fulfilled when window is closed");
+test.step(function() {
+    var url = "/resources/download-json-with-delay.php?iteration=5&delay=1000";
+    fetch(url).then(test.step_func(function(response) {
+        assert_equals(response.status, 200);
+        response.text().then(test.step_func(function(buffer) {
+            assert_unreached();
+        }), test.step_func(function() {
+            assert_unreached();
+        }));
+        setTimeout(function() { test.done(); }, 100);
+    }), test.step_func(function() {
+        assert_unreached();
+    }));
+});
+
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/http/tests/fetch/get-response-body-while-loading-expected.txt b/LayoutTests/http/tests/fetch/get-response-body-while-loading-expected.txt
new file mode 100644 (file)
index 0000000..30b44fc
--- /dev/null
@@ -0,0 +1,6 @@
+
+PASS Testing calling Response.text() when still fetching data 
+PASS Testing calling Response.arrayBuffer() when still fetching data 
+PASS Testing calling Response.blob() when still fetching data 
+PASS Testing calling Response.json() when still fetching data 
+
diff --git a/LayoutTests/http/tests/fetch/get-response-body-while-loading.html b/LayoutTests/http/tests/fetch/get-response-body-while-loading.html
new file mode 100644 (file)
index 0000000..e936a78
--- /dev/null
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Fetch: retrieve response's body progressively</title>
+    <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch">
+    <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch">
+    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
+    <script src="/js-test-resources/testharness.js"></script>
+    <script src="/js-test-resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <script>
+
+promise_test(function() {
+    var url = "/resources/download-json-with-delay.php?iteration=5&delay=200";
+    var loadingFlag = false;
+    return fetch(url).then(function(response) {
+        assert_equals(response.status, 200);
+
+        setTimeout(function() { loadingFlag = true; }, 100);
+        return response.text().then(function(text) {
+            assert_true(loadingFlag, "ensuring that text() was called while loading is happening");
+            assert_true(text.indexOf("foobar") != -1, "text must contain foobar");
+        });
+    });
+}, "Testing calling Response.text() when still fetching data");
+
+promise_test(function() {
+    var url = "/resources/download-json-with-delay.php?iteration=5&delay=200";
+    var loadingFlag = false;
+    return fetch(url).then(function(response) {
+        assert_equals(response.status, 200);
+
+        setTimeout(function() { loadingFlag = true; }, 100);
+        return response.arrayBuffer().then(function(arrayBuffer) {
+            assert_true(arrayBuffer instanceof ArrayBuffer, "object must be an array buffer");
+            assert_true(loadingFlag, "ensuring that arrayBuffer() was called while loading is happening");
+        });
+    });
+}, "Testing calling Response.arrayBuffer() when still fetching data");
+
+promise_test(function() {
+    var url = "/resources/download-json-with-delay.php?iteration=5&delay=200";
+    var loadingFlag = false;
+    return fetch(url).then(function(response) {
+        assert_equals(response.status, 200);
+
+        setTimeout(function() { loadingFlag = true; }, 100);
+        return response.blob().then(function(blob) {
+            assert_true(blob instanceof Blob, "object must be a blob");
+            assert_true(loadingFlag, "ensuring that blob() was called while loading is happening");
+        });
+    });
+}, "Testing calling Response.blob() when still fetching data");
+
+promise_test(function() {
+    var url = "/resources/download-json-with-delay.php?iteration=5&delay=200";
+    var loadingFlag = false;
+    return fetch(url).then(function(response) {
+        assert_equals(response.status, 200);
+        
+        setTimeout(function() { loadingFlag = true; }, 100);
+        return response.json().then(function(object) {
+            assert_equals(object.constructor, Array);
+            assert_true(loadingFlag, "ensuring that json() was called while loading is happening");
+        });
+    });
+}, "Testing calling Response.json() when still fetching data");
+
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/http/tests/resources/download-json-with-delay.php b/LayoutTests/http/tests/resources/download-json-with-delay.php
new file mode 100644 (file)
index 0000000..d515850
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+header("Expires: Thu, 01 Dec 2003 16:00:00 GMT");
+header("Cache-Control: no-cache, no-store, must-revalidate");
+header("Pragma: no-cache");
+header("Content-Type: application/x-no-buffering-please");
+
+$iteration = $_GET['iteration'];
+$delay = $_GET['delay'];
+
+echo "[$iteration, $delay ";
+
+for ($i = 1; $i <= $iteration; ++$i) {
+    echo ", $i, \"foobar\"";
+    // Force content to be sent to the browser as is.
+    ob_flush();
+    flush();
+    usleep($delay * 1000);
+}
+echo "]";
+?>
index 8a72c2d..1901691 100644 (file)
@@ -1,3 +1,29 @@
+2016-03-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Add basic loading of resources
+        https://bugs.webkit.org/show_bug.cgi?id=155637
+
+        Reviewed by Darin Adler.
+
+        Rebasing test expectations.
+        Updating scheme-blob.js to ensure generated test names are stable run after run.
+
+        * web-platform-tests/fetch/api/basic/accept-header-expected.txt:
+        * web-platform-tests/fetch/api/basic/integrity-expected.txt:
+        * web-platform-tests/fetch/api/basic/mode-no-cors-expected.txt:
+        * web-platform-tests/fetch/api/basic/mode-same-origin-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-forbidden-headers-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-headers-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-about-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-blob-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-blob-worker-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-blob.js:
+        (checkFetchResponse): Deleted.
+        (checkKoUrl): Deleted.
+        * web-platform-tests/fetch/api/basic/scheme-data-expected.txt:
+        * web-platform-tests/fetch/api/basic/scheme-others-expected.txt:
+        * web-platform-tests/fetch/api/basic/stream-response-expected.txt:
+
 2016-03-18  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         Move IndexedDB regular test to web-platform-tests
index 4cd5973..0dd43a2 100644 (file)
@@ -1,3 +1,3 @@
 
-FAIL Request through fetch should have 'accept' header with value '*/*' promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+PASS Request through fetch should have 'accept' header with value '*/*' 
 
index 42be002..c2dadd1 100644 (file)
@@ -1,15 +1,15 @@
 
-FAIL Empty string integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL SHA-256 integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL SHA-384 integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL SHA-512 integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Invalid integrity assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Multiple integrities: valid stronger than invalid promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Multiple integrities: invalid stronger than valid assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Multiple integrities: invalid as strong as valid promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Multiple integrities: both are valid promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Multiple integrities: both are invalid assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL CORS empty integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL CORS SHA-512 integrity promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL CORS invalid integrity assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+PASS Empty string integrity 
+PASS SHA-256 integrity 
+PASS SHA-384 integrity 
+PASS SHA-512 integrity 
+FAIL Invalid integrity assert_unreached: Should have rejected. Reached unreachable code
+PASS Multiple integrities: valid stronger than invalid 
+FAIL Multiple integrities: invalid stronger than valid assert_unreached: Should have rejected. Reached unreachable code
+PASS Multiple integrities: invalid as strong as valid 
+PASS Multiple integrities: both are valid 
+FAIL Multiple integrities: both are invalid assert_unreached: Should have rejected. Reached unreachable code
+FAIL CORS empty integrity promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL CORS SHA-512 integrity promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS CORS invalid integrity 
 
index d150a73..47cbea7 100644 (file)
@@ -1,6 +1,6 @@
 
-FAIL Fetch ../resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch http://localhost:8800/fetch/api/resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch https://localhost:9443/fetch/api/resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch http://www.localhost:8800/fetch/api/resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+PASS Fetch ../resources/top.txt with no-cors mode 
+PASS Fetch http://localhost:8800/fetch/api/resources/top.txt with no-cors mode 
+FAIL Fetch https://localhost:9443/fetch/api/resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetch http://www.localhost:8800/fetch/api/resources/top.txt with no-cors mode promise_test: Unhandled rejection with value: object "TypeError: Type error"
 
index 9ac9869..9c3ae30 100644 (file)
@@ -1,6 +1,6 @@
 
-FAIL Fetch ../resources/top.txt with same-origin mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch http://localhost:8800/fetch/api/resources/top.txt with same-origin mode promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch https://localhost:9443/fetch/api/resources/top.txt with same-origin mode assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetch http://www.localhost:8800/fetch/api/resources/top.txt with same-origin mode assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+PASS Fetch ../resources/top.txt with same-origin mode 
+PASS Fetch http://localhost:8800/fetch/api/resources/top.txt with same-origin mode 
+PASS Fetch https://localhost:9443/fetch/api/resources/top.txt with same-origin mode 
+PASS Fetch http://www.localhost:8800/fetch/api/resources/top.txt with same-origin mode 
 
index d5740d1..b42edf1 100644 (file)
@@ -1,26 +1,26 @@
 
-FAIL Accept-Charset is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Accept-Encoding is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Access-Control-Request-Headers is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Access-Control-Request-Method is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Connection is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Content-Length is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Cookie is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Cookie2 is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Date is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL DNT is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Expect is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Host is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Keep-Alive is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Origin is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Referer is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL TE is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Trailer is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Transfer-Encoding is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Upgrade is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Via is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Proxy- is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Proxy-Test is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Sec- is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Sec-Test is a forbidden request header promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+PASS Accept-Charset is a forbidden request header 
+PASS Accept-Encoding is a forbidden request header 
+PASS Access-Control-Request-Headers is a forbidden request header 
+PASS Access-Control-Request-Method is a forbidden request header 
+PASS Connection is a forbidden request header 
+PASS Content-Length is a forbidden request header 
+PASS Cookie is a forbidden request header 
+PASS Cookie2 is a forbidden request header 
+PASS Date is a forbidden request header 
+PASS DNT is a forbidden request header 
+PASS Expect is a forbidden request header 
+PASS Host is a forbidden request header 
+PASS Keep-Alive is a forbidden request header 
+PASS Origin is a forbidden request header 
+PASS Referer is a forbidden request header 
+PASS TE is a forbidden request header 
+PASS Trailer is a forbidden request header 
+PASS Transfer-Encoding is a forbidden request header 
+PASS Upgrade is a forbidden request header 
+PASS Via is a forbidden request header 
+PASS Proxy- is a forbidden request header 
+PASS Proxy-Test is a forbidden request header 
+PASS Sec- is a forbidden request header 
+PASS Sec-Test is a forbidden request header 
 
index 05e4580..be0bbf7 100644 (file)
@@ -1,11 +1,11 @@
 
-FAIL Fetch with GET promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with HEAD promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with HEAD with body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with PUT without body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with PUT with body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with POST without body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with POST with body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with Chicken promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetch with Chicken with body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+FAIL Fetch with GET assert_equals: Request has header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
+FAIL Fetch with HEAD assert_equals: Request has header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
+FAIL Fetch with HEAD with body promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Fetch with PUT without body 
+PASS Fetch with PUT with body 
+PASS Fetch with POST without body 
+PASS Fetch with POST with body 
+FAIL Fetch with Chicken assert_equals: Request has header content-length: null expected (object) null but got (string) "0"
+PASS Fetch with Chicken with body 
 
index 67ed49d..1fb886c 100644 (file)
@@ -1,6 +1,6 @@
 
-FAIL Fetching about:blank is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching about:unicorn is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching about:invalid.com is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching about:config is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+FAIL Fetching about:blank is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetching about:unicorn is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Fetching about:invalid.com is KO 
+PASS Fetching about:config is KO 
 
index ceb0135..6c4bc8b 100644 (file)
@@ -1,5 +1,5 @@
 
-FAIL Fetching blob:http://localhost:8800/4580501e-3c0f-4b03[...] is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching [GET] blob:http://www.localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching [POST] blob:http://localhost:8800/ad829fe3-9045-4b29[...] is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+PASS Regular Blob loading 
+PASS Loading an erroneous blob scheme URL 
+FAIL Loading a blob URL using POST assert_unreached: Should have rejected. Reached unreachable code
 
index dc0d2af..4d1850d 100644 (file)
@@ -1,5 +1,5 @@
 
-FAIL Fetching blob:http://localhost:8800/8807dca8-91bf-4414[...] is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching [GET] blob:http://www.localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching [POST] blob:http://localhost:8800/41805be3-d8cc-490f[...] is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+FAIL Regular Blob loading promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+FAIL Loading an erroneous blob scheme URL assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+FAIL Loading a blob URL using POST assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
 
index d9b804d..ac9d35d 100644 (file)
@@ -4,9 +4,6 @@ if (this.document === undefined) {
 }
 
 function checkFetchResponse(url, data, mime, size, desc) {
-  if (!desc)
-    var cut = (url.length >= 45) ? "[...]" : "";
-    desc = "Fetching " + url.substring(0, 45) + cut + " is OK"
   promise_test(function(test) {
     size = size.toString();
     return fetch(url).then(function(resp) {
@@ -22,12 +19,9 @@ function checkFetchResponse(url, data, mime, size, desc) {
 }
 
 var blob = new Blob(["Blob's data"], { "type" : "text/plain" });
-checkFetchResponse(URL.createObjectURL(blob), "Blob's data", "text/plain",  blob.size);
+checkFetchResponse(URL.createObjectURL(blob), "Blob's data", "text/plain",  blob.size, "Regular Blob loading");
 
 function checkKoUrl(url, method, desc) {
-  if (!desc)
-    var cut = (url.length >= 45) ? "[...]" : "";
-    desc = "Fetching [" + method + "] " + url.substring(0, 45) + cut +  " is KO"
   promise_test(function(test) {
     var promise = fetch(url, {"method": method});
     return promise_rejects(test, new TypeError(), promise);
@@ -35,7 +29,7 @@ function checkKoUrl(url, method, desc) {
 }
 
 var blob2 = new Blob(["Blob's data"], { "type" : "text/plain" });
-checkKoUrl("blob:http://{{domains[www]}}:{{ports[http][0]}}/", "GET");
-checkKoUrl(URL.createObjectURL(blob2), "POST");
+checkKoUrl("blob:http://{{domains[www]}}:{{ports[http][0]}}/", "GET", "Loading an erroneous blob scheme URL");
+checkKoUrl(URL.createObjectURL(blob2), "POST", "Loading a blob URL using POST");
 
 done();
index 48f0aef..9b1e8b8 100644 (file)
@@ -1,8 +1,8 @@
 
-FAIL Fetching data:,response%27s%20body is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
-FAIL Fetching [GET] data:notAdataUrl.com is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching [POST] data:,response%27s%20body is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching [HEAD] data:,response%27s%20body is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+FAIL Fetching data:,response%27s%20body is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Fetching [GET] data:notAdataUrl.com is KO 
+PASS Fetching [POST] data:,response%27s%20body is KO 
+PASS Fetching [HEAD] data:,response%27s%20body is KO 
 
index c17442e..c1b695a 100644 (file)
@@ -1,18 +1,18 @@
 
-FAIL Fetching aaa://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching cap://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching cid://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching dav://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching dict://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching dns://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching geo://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching im://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching imap://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching ipp://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching ldap://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching mailto://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching nfs://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching pop://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching rtsp://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
-FAIL Fetching snmp://localhost:8800/ is KO assert_throws: function "function () { throw e }" threw "Fetch is not yet implemented" (undefined) expected object "TypeError" ("TypeError")
+PASS Fetching aaa://localhost:8800/ is KO 
+PASS Fetching cap://localhost:8800/ is KO 
+PASS Fetching cid://localhost:8800/ is KO 
+PASS Fetching dav://localhost:8800/ is KO 
+PASS Fetching dict://localhost:8800/ is KO 
+PASS Fetching dns://localhost:8800/ is KO 
+PASS Fetching geo://localhost:8800/ is KO 
+PASS Fetching im://localhost:8800/ is KO 
+PASS Fetching imap://localhost:8800/ is KO 
+PASS Fetching ipp://localhost:8800/ is KO 
+PASS Fetching ldap://localhost:8800/ is KO 
+PASS Fetching mailto://localhost:8800/ is KO 
+PASS Fetching nfs://localhost:8800/ is KO 
+PASS Fetching pop://localhost:8800/ is KO 
+PASS Fetching rtsp://localhost:8800/ is KO 
+PASS Fetching snmp://localhost:8800/ is KO 
 
index 118268f..d584d01 100644 (file)
@@ -1,3 +1,3 @@
 
-FAIL Stream response's body promise_test: Unhandled rejection with value: "Fetch is not yet implemented"
+FAIL Stream response's body assert_unreached: Body does not exist in response Reached unreachable code
 
diff --git a/LayoutTests/platform/gtk/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt b/LayoutTests/platform/gtk/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt
new file mode 100644 (file)
index 0000000..a005963
--- /dev/null
@@ -0,0 +1,11 @@
+
+FAIL Fetch with GET assert_equals: Request has header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
+FAIL Fetch with HEAD assert_equals: Request has header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
+FAIL Fetch with HEAD with body promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Fetch with PUT without body 
+PASS Fetch with PUT with body 
+PASS Fetch with POST without body 
+PASS Fetch with POST with body 
+PASS Fetch with Chicken 
+PASS Fetch with Chicken with body 
+
index 3387a27..ff7c78e 100644 (file)
@@ -1,3 +1,74 @@
+2016-03-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Add basic loading of resources
+        https://bugs.webkit.org/show_bug.cgi?id=155637
+
+        Reviewed by Darin Adler.
+
+        Adding support for basic fetch for Window (no support for Worker yet).
+        A FetchResponse object is created for every fetch task.
+        But it will only be exposed to JS at promise fulfillment time, i.e. once initial response headers are retrieved.
+
+        Updating Blob resource handle to add Content-Type and Content-Length header and notifying of error in case of erroneous HTTP method.
+
+        Fetch is limited to same origin requests currently due to some WPT tests that would timeout otherwise.
+
+        Tests: http/tests/fetch/closing-while-fetching.html
+               http/tests/fetch/get-response-body-while-loading.html
+        Also covered by rebased tests.
+
+        * Modules/fetch/DOMWindowFetch.cpp: Creating a FetchResponse to start fetching.
+        (WebCore::DOMWindowFetch::fetch):
+        * Modules/fetch/DOMWindowFetch.h:
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::consume):
+        (WebCore::FetchBody::consumeArrayBuffer): Handling of body promises in case of data stored as a buffer.
+        (WebCore::FetchBody::consumeText): Passing the promise as a reference.
+        (WebCore::blobFromArrayBuffer): Helper routine.
+        (WebCore::FetchBody::fulfillTextPromise): Helper routine.
+        (WebCore::FetchBody::loadedAsArrayBuffer): Updated to handle storing of data as a buffer.
+        (WebCore::FetchBody::loadedAsText):
+        (WebCore::FetchBody::bodyForInternalRequest): Helper routine to generate the request body data to be sent as part of the fetch request.
+        (WebCore::FetchBody::extractFromText):
+        * Modules/fetch/FetchBody.h:
+        (WebCore::FetchBody::loadingBody):
+        (WebCore::FetchBody::FetchBody):
+        * Modules/fetch/FetchBodyOwner.cpp:
+        (WebCore::FetchBodyOwner::loadBlob): Updated to cope with the change that FetchLoader::start does not return a boolean anymore
+        but will directly call failure callbacks.
+        (WebCore::FetchBodyOwner::loadedBlobAsText): Moving it closer to other blob loading routines.
+        (WebCore::FetchBodyOwner::finishBlobLoading):
+        * Modules/fetch/FetchBodyOwner.h:
+        (WebCore::FetchBodyOwner::body):
+        (WebCore::FetchBodyOwner::loadedBlobAsArrayBuffer):
+        * Modules/fetch/FetchHeaders.cpp:
+        (WebCore::FetchHeaders::fill):
+        (WebCore::FetchHeaders::filterAndFill): Helper routine to fill headers from a HTTPHeaderMap after being filtered.
+        * Modules/fetch/FetchHeaders.h:
+        (WebCore::FetchHeaders::internalHeaders):
+        * Modules/fetch/FetchLoader.cpp:
+        (WebCore::FetchLoader::start):
+        (WebCore::FetchLoader::didFailRedirectCheck):
+        * Modules/fetch/FetchLoader.h:
+        * Modules/fetch/FetchRequest.cpp:
+        (WebCore::FetchRequest::internalRequest): Routine used to create the ResourceRequest transmitted to ThreadableLoader.
+       * Modules/fetch/FetchRequest.h:
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::fetch): Start fetching by creating a FetchLoader based on passed request.
+        (WebCore::FetchResponse::BodyLoader::didSucceed): FetchLoader callback.
+        (WebCore::FetchResponse::BodyLoader::didFail): Ditto.
+        (WebCore::FetchResponse::BodyLoader::BodyLoader): Ditto.
+        (WebCore::FetchResponse::BodyLoader::didReceiveResponse): Ditto.
+        (WebCore::FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer): Ditto.
+        (WebCore::FetchResponse::BodyLoader::start): Starting fetch loader.
+        (WebCore::FetchResponse::BodyLoader::stop): Stopping fetch loader.
+        (WebCore::FetchResponse::stop): Stop loader if any.
+        * Modules/fetch/FetchResponse.h:
+        * platform/network/BlobResourceHandle.cpp:
+        (WebCore::BlobResourceHandle::doStart: Notifying the loader with an error if verb is not GET.
+        (WebCore::BlobResourceHandle::notifyResponseOnSuccess): Adding support for Content-Type and Content-Lenth headers.
+        (WebCore::BlobResourceHandle::createAsync): Removing GET verb check.
+
 2016-03-24  Andreas Kling  <akling@apple.com>
 
         Remove virtual inheritance from SVGTransformable.
index a4c83c3..cb0d02b 100644 (file)
 
 #if ENABLE(FETCH_API)
 
+#include "DOMWindow.h"
+#include "FetchRequest.h"
+#include "FetchResponse.h"
+
 namespace WebCore {
 
-void DOMWindowFetch::fetch(DOMWindow&, FetchRequest*, const Dictionary&, FetchPromise&& promise)
+void DOMWindowFetch::fetch(DOMWindow& window, FetchRequest* input, const Dictionary& dictionary, DeferredWrapper&& promise)
 {
-    promise.reject(ASCIILiteral("Fetch is not yet implemented"));
+    if (!window.scriptExecutionContext())
+        return;
+    ScriptExecutionContext& context = *window.scriptExecutionContext();
+
+    ExceptionCode ec = 0;
+    RefPtr<FetchRequest> fetchRequest = FetchRequest::create(context, input, dictionary, ec);
+    if (ec) {
+        promise.reject(ec);
+        return;
+    }
+    ASSERT(fetchRequest);
+    FetchResponse::fetch(context, *fetchRequest, WTFMove(promise));
 }
 
-void DOMWindowFetch::fetch(DOMWindow&, const String&, const Dictionary&, FetchPromise&& promise)
+void DOMWindowFetch::fetch(DOMWindow& window, const String& url, const Dictionary& dictionary, DeferredWrapper&& promise)
 {
-    promise.reject(ASCIILiteral("Fetch is not yet implemented"));
+    if (!window.scriptExecutionContext())
+        return;
+    ScriptExecutionContext& context = *window.scriptExecutionContext();
+    
+    ExceptionCode ec = 0;
+    RefPtr<FetchRequest> fetchRequest = FetchRequest::create(context, url, dictionary, ec);
+    if (ec) {
+        promise.reject(ec);
+        return;
+    }
+    ASSERT(fetchRequest);
+    FetchResponse::fetch(context, *fetchRequest, WTFMove(promise));
 }
 
 } // namespace WebCore
index 9fb155e..fe60f40 100644 (file)
 
 #if ENABLE(FETCH_API)
 
-#include "JSDOMPromise.h"
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
+class DOMWindow;
+class DeferredWrapper;
 class Dictionary;
 class FetchRequest;
-class FetchResponse;
 
 class DOMWindowFetch {
 public:
-    using FetchPromise = DOMPromise<RefPtr<FetchResponse>, String>;
-    static void fetch(DOMWindow&, FetchRequest*, const Dictionary&, FetchPromise&&);
-    static void fetch(DOMWindow&, const String&, const Dictionary&, FetchPromise&&);
+    static void fetch(DOMWindow&, FetchRequest*, const Dictionary&, DeferredWrapper&&);
+    static void fetch(DOMWindow&, const String&, const Dictionary&, DeferredWrapper&&);
 };
 
 } // namespace WebCore
index 1c0597e..dacc2d8 100644 (file)
 #include "Dictionary.h"
 #include "ExceptionCode.h"
 #include "FetchBodyOwner.h"
+#include "FormData.h"
 #include "HTTPParsers.h"
 #include "JSBlob.h"
 #include "JSDOMFormData.h"
 
 namespace WebCore {
 
+static RefPtr<Blob> blobFromArrayBuffer(ArrayBuffer*, const String&);
+
 FetchBody::FetchBody(Ref<Blob>&& blob)
     : m_type(Type::Blob)
     , m_mimeType(blob->type())
@@ -155,20 +158,45 @@ void FetchBody::text(FetchBodyOwner& owner, DeferredWrapper&& promise)
 
 void FetchBody::consume(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise)
 {
+    if (m_type == Type::ArrayBuffer) {
+        consumeArrayBuffer(type, promise);
+        return;
+    }
     if (m_type == Type::Text) {
-        consumeText(type, WTFMove(promise));
+        consumeText(type, promise);
         return;
     }
     if (m_type == Type::Blob) {
         consumeBlob(owner, type, WTFMove(promise));
         return;
     }
+    if (m_type == Type::Loading) {
+        // FIXME: We should be able to change the loading type to text if consumer type is JSON or Text.
+        m_consumer = Consumer({type, WTFMove(promise)});
+        return;
+    }
 
     // FIXME: Support other types.
     promise.reject<ExceptionCode>(0);
 }
 
-void FetchBody::consumeText(Consumer::Type type, DeferredWrapper&& promise)
+void FetchBody::consumeArrayBuffer(Consumer::Type type, DeferredWrapper& promise)
+{
+    if (type == Consumer::Type::ArrayBuffer) {
+        fulfillPromiseWithArrayBuffer(promise, m_data.get());
+        return;
+    }
+    if (type == Consumer::Type::Blob) {
+        promise.resolve(blobFromArrayBuffer(m_data.get(), Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType))));
+        return;
+    }
+
+    ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
+    // FIXME: Do we need TextResourceDecoder to create a String to decode UTF-8 data.
+    fulfillTextPromise(type, TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8")->decodeAndFlush(static_cast<const char*>(m_data->data()), m_data->byteLength()), promise);
+}
+
+void FetchBody::consumeText(Consumer::Type type, DeferredWrapper& promise)
 {
     ASSERT(type == Consumer::Type::ArrayBuffer || type == Consumer::Type::Blob);
 
@@ -214,6 +242,26 @@ Vector<char> FetchBody::extractFromText() const
     return value;
 }
 
+static inline RefPtr<Blob> blobFromArrayBuffer(ArrayBuffer* buffer, const String& contentType)
+{
+    if (!buffer)
+        return Blob::create(Vector<char>(), contentType);
+
+    // FIXME: We should try to move buffer to Blob without doing this copy.
+    Vector<char> value(buffer->byteLength());
+    memcpy(value.data(), buffer->data(), buffer->byteLength());
+    return Blob::create(WTFMove(value), contentType);
+}
+
+void FetchBody::fulfillTextPromise(FetchBody::Consumer::Type type, const String& text, DeferredWrapper& promise)
+{
+    ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
+    if (type == FetchBody::Consumer::Type::Text)
+        promise.resolve(text);
+    else
+        fulfillPromiseWithJSON(promise, text);
+}
+
 void FetchBody::loadingFailed()
 {
     ASSERT(m_consumer);
@@ -223,16 +271,23 @@ void FetchBody::loadingFailed()
 
 void FetchBody::loadedAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
 {
+    if (m_type == Type::Loading) {
+        m_type = Type::ArrayBuffer;
+        m_data = buffer;
+        if (m_consumer) {
+            consumeArrayBuffer(m_consumer->type, m_consumer->promise);
+            m_consumer = Nullopt;
+        }
+        return;
+    }
+
     ASSERT(m_consumer);
     ASSERT(m_consumer->type == Consumer::Type::Blob || m_consumer->type == Consumer::Type::ArrayBuffer);
     if (m_consumer->type == Consumer::Type::ArrayBuffer)
         fulfillPromiseWithArrayBuffer(m_consumer->promise, buffer.get());
     else {
         ASSERT(m_blob);
-        Vector<char> data;
-        data.reserveCapacity(buffer->byteLength());
-        data.append(static_cast<const char*>(buffer->data()), buffer->byteLength());
-        m_consumer->promise.resolve<RefPtr<Blob>>(Blob::create(WTFMove(data), m_blob->type()));
+        m_consumer->promise.resolve(blobFromArrayBuffer(buffer.get(), m_blob->type()));
     }
     m_consumer = Nullopt;
 }
@@ -241,13 +296,26 @@ void FetchBody::loadedAsText(String&& text)
 {
     ASSERT(m_consumer);
     ASSERT(m_consumer->type == Consumer::Type::Text || m_consumer->type == Consumer::Type::JSON);
-    if (m_consumer->type == Consumer::Type::Text)
-        m_consumer->promise.resolve(text);
-    else
-        fulfillPromiseWithJSON(m_consumer->promise, text);
+
+    fulfillTextPromise(m_consumer->type, text, m_consumer->promise);
     m_consumer = Nullopt;
 }
 
+RefPtr<FormData> FetchBody::bodyForInternalRequest() const
+{
+    if (m_type == Type::None)
+        return nullptr;
+    if (m_type == Type::Text)
+        return FormData::create(UTF8Encoding().encode(m_text, EntitiesForUnencodables));
+    if (m_type == Type::Blob) {
+        RefPtr<FormData> body = FormData::create();
+        body->appendBlob(m_blob->url());
+        return body;
+    }
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
 }
 
 #endif // ENABLE(FETCH_API)
index a5b3c06..f7ac6d7 100644 (file)
@@ -44,6 +44,7 @@ class JSValue;
 namespace WebCore {
 
 class FetchBodyOwner;
+class FormData;
 
 class FetchBody {
 public:
@@ -61,18 +62,22 @@ public:
 
     static FetchBody extract(JSC::ExecState&, JSC::JSValue);
     static FetchBody extractFromBody(FetchBody*);
+    static FetchBody loadingBody() { return { Type::Loading }; }
     FetchBody() = default;
 
     void loadingFailed();
     void loadedAsArrayBuffer(RefPtr<ArrayBuffer>&&);
     void loadedAsText(String&&);
 
+    RefPtr<FormData> bodyForInternalRequest() const;
+
 private:
-    enum class Type { None, Text, Blob, FormData };
+    enum class Type { None, ArrayBuffer, Loading, Text, Blob, FormData };
 
     FetchBody(Ref<Blob>&&);
     FetchBody(Ref<DOMFormData>&&);
     FetchBody(String&&);
+    FetchBody(Type type) : m_type(type) { }
 
     struct Consumer {
         enum class Type { Text, Blob, JSON, ArrayBuffer };
@@ -84,17 +89,21 @@ private:
 
     Vector<char> extractFromText() const;
     bool processIfEmptyOrDisturbed(Consumer::Type, DeferredWrapper&);
-    void consumeText(Consumer::Type, DeferredWrapper&&);
+    void consumeArrayBuffer(Consumer::Type, DeferredWrapper&);
+    void consumeText(Consumer::Type, DeferredWrapper&);
     void consumeBlob(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&);
     static FetchLoader::Type loadingType(Consumer::Type);
+    static void fulfillTextPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
+    static void fulfillArrayBufferPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
 
-    Type m_type = Type::None;
+    Type m_type { Type::None };
     String m_mimeType;
-    bool m_isDisturbed = false;
+    bool m_isDisturbed { false };
 
     // FIXME: Add support for BufferSource and URLSearchParams.
     RefPtr<Blob> m_blob;
     RefPtr<DOMFormData> m_formData;
+    RefPtr<ArrayBuffer> m_data;
     String m_text;
 
     Optional<Consumer> m_consumer;
index 860ee3f..ccb2b83 100644 (file)
@@ -59,17 +59,14 @@ void FetchBodyOwner::loadBlob(Blob& blob, FetchLoader::Type type)
     ASSERT(m_body.isDisturbed());
     ASSERT(!m_blobLoader);
 
+    if (!scriptExecutionContext())
+        blobLoadingFailed();
+
     m_blobLoader = { *this };
     m_blobLoader->loader = std::make_unique<FetchLoader>(type, *m_blobLoader);
 
     setPendingActivity(this);
-    if (!scriptExecutionContext() || !m_blobLoader->loader->start(*scriptExecutionContext(), blob))
-        blobLoadingFailed();
-}
-
-void FetchBodyOwner::loadedBlobAsText(String&& text)
-{
-    m_body.loadedAsText(WTFMove(text));
+    m_blobLoader->loader->start(*scriptExecutionContext(), blob);
 }
 
 void FetchBodyOwner::finishBlobLoading()
@@ -80,6 +77,11 @@ void FetchBodyOwner::finishBlobLoading()
     unsetPendingActivity(this);
 }
 
+void FetchBodyOwner::loadedBlobAsText(String&& text)
+{
+    m_body.loadedAsText(WTFMove(text));
+}
+
 void FetchBodyOwner::blobLoadingFailed()
 {
     m_body.loadingFailed();
index 3a698ea..4a01b2f 100644 (file)
@@ -54,6 +54,13 @@ public:
 
     bool isActive() const { return !!m_blobLoader; }
 
+protected:
+    const FetchBody& body() const { return m_body; }
+    FetchBody& body() { return m_body; }
+
+    // ActiveDOMObject API
+    void stop() override;
+
 private:
     // Blob loading routines
     void loadedBlobAsText(String&&);
@@ -62,9 +69,6 @@ private:
     void blobLoadingFailed();
     void finishBlobLoading();
 
-    // ActiveDOMObject API
-    void stop() override;
-
     struct BlobLoader final : FetchLoaderClient {
         BlobLoader(FetchBodyOwner&);
 
index 1669468..d84a5c4 100644 (file)
@@ -156,14 +156,19 @@ void FetchHeaders::set(const String& name, const String& value, ExceptionCode& e
 
 void FetchHeaders::fill(const FetchHeaders* headers)
 {
+    ASSERT(m_guard != Guard::Immutable);
+
     if (!headers)
         return;
 
-    ASSERT(m_guard != Guard::Immutable);
+    filterAndFill(headers->m_headers, m_guard);
+}
 
+void FetchHeaders::filterAndFill(const HTTPHeaderMap& headers, Guard guard)
+{
     ExceptionCode ec;
-    for (auto& header : headers->m_headers) {
-        if (canWriteHeader(header.key, header.value, m_guard, ec)) {
+    for (auto& header : headers) {
+        if (canWriteHeader(header.key, header.value, guard, ec)) {
             if (header.keyAsHTTPHeaderName)
                 m_headers.add(header.keyAsHTTPHeaderName.value(), header.value);
             else
index afc8cd2..c533227 100644 (file)
@@ -64,6 +64,8 @@ public:
 
     void fill(const FetchHeaders*);
 
+    void filterAndFill(const HTTPHeaderMap&, Guard);
+
     String fastGet(HTTPHeaderName name) const { return m_headers.get(name); }
     void fastSet(HTTPHeaderName name, const String& value) { m_headers.set(name, value); }
 
@@ -79,6 +81,8 @@ public:
     };
     Iterator createIterator() { return Iterator(*this); }
 
+    const HTTPHeaderMap& internalHeaders() const { return m_headers; }
+
 private:
     FetchHeaders(Guard guard) : m_guard(guard) { }
     FetchHeaders(Guard guard, const HTTPHeaderMap& headers) : m_guard(guard), m_headers(headers) { }
index 834a7ad..a760baf 100644 (file)
 #include "BlobURL.h"
 #include "FetchBody.h"
 #include "FetchLoaderClient.h"
+#include "FetchRequest.h"
 #include "ResourceRequest.h"
 #include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
 #include "SharedBuffer.h"
 #include "TextResourceDecoder.h"
 #include "ThreadableBlobRegistry.h"
 
 namespace WebCore {
 
-bool FetchLoader::start(ScriptExecutionContext& context, Blob& blob)
+void FetchLoader::start(ScriptExecutionContext& context, Blob& blob)
 {
     auto urlForReading = BlobURL::createPublicURL(context.securityOrigin());
-    if (urlForReading.isEmpty())
-        return false;
+    if (urlForReading.isEmpty()) {
+        m_client.didFail();
+        return;
+    }
+
     ThreadableBlobRegistry::registerBlobURL(context.securityOrigin(), urlForReading, blob.url());
 
     ResourceRequest request(urlForReading);
@@ -63,7 +68,21 @@ bool FetchLoader::start(ScriptExecutionContext& context, Blob& blob)
     options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
 
     m_loader = ThreadableLoader::create(&context, this, request, options);
-    return true;
+}
+
+void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
+{
+    // FIXME: Compute loading options according fetch options.
+    ThreadableLoaderOptions options;
+    options.setSendLoadCallbacks(SendCallbacks);
+    options.setSniffContent(DoNotSniffContent);
+    options.setDataBufferingPolicy(DoNotBufferData);
+    options.preflightPolicy = ConsiderPreflight;
+    options.setAllowCredentials(AllowStoredCredentials);
+    options.crossOriginRequestPolicy = DenyCrossOriginRequests;
+    options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
+
+    m_loader = ThreadableLoader::create(&context, this, request.internalRequest(), options);
 }
 
 FetchLoader::FetchLoader(Type type, FetchLoaderClient& client)
@@ -113,6 +132,11 @@ void FetchLoader::didFail(const ResourceError&)
     m_client.didFail();
 }
 
+void FetchLoader::didFailRedirectCheck()
+{
+    m_client.didFail();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(FETCH_API)
index ef0a736..0f39481 100644 (file)
@@ -39,6 +39,7 @@ namespace WebCore {
 
 class Blob;
 class FetchLoaderClient;
+class FetchRequest;
 class ScriptExecutionContext;
 
 class FetchLoader final : public ThreadableLoaderClient {
@@ -47,7 +48,8 @@ public:
 
     FetchLoader(Type, FetchLoaderClient&);
 
-    bool start(ScriptExecutionContext&, Blob&);
+    void start(ScriptExecutionContext&, const FetchRequest&);
+    void start(ScriptExecutionContext&, Blob&);
     void stop();
 
 private:
@@ -56,6 +58,7 @@ private:
     void didReceiveData(const char*, int) final;
     void didFinishLoading(unsigned long, double) final;
     void didFail(const ResourceError&) final;
+    void didFailRedirectCheck() final;
 
 private:
     Type m_type { Type::ArrayBuffer };
index d6aea56..fdee688 100644 (file)
@@ -435,6 +435,14 @@ String FetchRequest::redirect() const
     return String();
 }
 
+ResourceRequest FetchRequest::internalRequest() const
+{
+    ResourceRequest request = m_internalRequest.request;
+    request.setHTTPHeaderFields(m_headers->internalHeaders());
+    request.setHTTPBody(body().bodyForInternalRequest());
+    return request;
+}
+
 RefPtr<FetchRequest> FetchRequest::clone(ScriptExecutionContext& context, ExceptionCode& ec)
 {
     if (isDisturbed()) {
index 59c9b51..8fdcaca 100644 (file)
@@ -72,6 +72,9 @@ public:
         String integrity;
     };
 
+    const FetchOptions& fetchOptions() const { return m_internalRequest.options; }
+    ResourceRequest internalRequest() const;
+
 private:
     FetchRequest(ScriptExecutionContext&, FetchBody&&, Ref<FetchHeaders>&&, InternalRequest&&);
 
index 351049c..9eb3376 100644 (file)
@@ -153,6 +153,77 @@ JSC::JSValue JSFetchResponse::body(JSC::ExecState&) const
     return JSC::jsNull();
 }
 
+void FetchResponse::fetch(ScriptExecutionContext& context, const FetchRequest& request, FetchPromise&& promise)
+{
+    Ref<FetchResponse> response = adoptRef(*new FetchResponse(context, Type::Basic, FetchBody::loadingBody(), FetchHeaders::create(FetchHeaders::Guard::Immutable), ResourceResponse()));
+
+    // Setting pending activity until BodyLoader didFail or didSucceed callback is called.
+    response->setPendingActivity(response.ptr());
+
+    response->m_bodyLoader = BodyLoader(response.get(), WTFMove(promise));
+    response->m_bodyLoader->start(context, request);
+}
+
+void FetchResponse::BodyLoader::didSucceed()
+{
+    m_response.m_bodyLoader = Nullopt;
+    m_response.unsetPendingActivity(&m_response);
+}
+
+void FetchResponse::BodyLoader::didFail()
+{
+    if (m_promise)
+        std::exchange(m_promise, Nullopt)->reject(TypeError);
+
+    m_response.m_bodyLoader = Nullopt;
+    m_response.unsetPendingActivity(&m_response);
+
+    // FIXME: Handle the case of failing after didReceiveResponse is called.
+}
+
+FetchResponse::BodyLoader::BodyLoader(FetchResponse& response, FetchPromise&& promise)
+    : m_response(response)
+    , m_promise(WTFMove(promise))
+{
+}
+
+void FetchResponse::BodyLoader::didReceiveResponse(const ResourceResponse& resourceResponse)
+{
+    ASSERT(m_promise);
+
+    m_response.m_response = resourceResponse;
+    m_response.m_headers->filterAndFill(resourceResponse.httpHeaderFields(), FetchHeaders::Guard::Response);
+
+    std::exchange(m_promise, Nullopt)->resolve(&m_response);
+}
+
+void FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
+{
+    m_response.body().loadedAsArrayBuffer(WTFMove(buffer));
+}
+
+void FetchResponse::BodyLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
+{
+    m_loader = std::make_unique<FetchLoader>(FetchLoader::Type::ArrayBuffer, *this);
+    m_loader->start(context, request);
+}
+
+void FetchResponse::BodyLoader::stop()
+{
+    if (m_loader)
+        m_loader->stop();
+}
+
+void FetchResponse::stop()
+{
+    FetchBodyOwner::stop();
+    if (m_bodyLoader) {
+        RefPtr<FetchResponse> protect(this);
+        m_bodyLoader->stop();
+        m_bodyLoader = Nullopt;
+    }
+}
+
 const char* FetchResponse::activeDOMObjectName() const
 {
     return "Response";
index 8afccb4..29b39a8 100644 (file)
@@ -42,6 +42,7 @@ class ArrayBuffer;
 namespace WebCore {
 
 class Dictionary;
+class FetchRequest;
 
 typedef int ExceptionCode;
 
@@ -53,6 +54,9 @@ public:
     // FIXME: Binding generator should not require below method to handle optional status parameter.
     static RefPtr<FetchResponse> redirect(ScriptExecutionContext& context, const String& url, ExceptionCode& ec) { return redirect(context, url, 302, ec); }
 
+    using FetchPromise = DOMPromise<RefPtr<FetchResponse>, ExceptionCode>;
+    static void fetch(ScriptExecutionContext&, const FetchRequest&, FetchPromise&&);
+
     void initializeWith(const Dictionary&, ExceptionCode&);
 
     String type() const;
@@ -71,14 +75,35 @@ private:
     FetchResponse(ScriptExecutionContext&, Type, FetchBody&&, Ref<FetchHeaders>&&, ResourceResponse&&);
 
     // ActiveDOMObject API
+    void stop() final;
     const char* activeDOMObjectName() const final;
     bool canSuspendForDocumentSuspension() const final;
 
+    class BodyLoader final : public FetchLoaderClient {
+    public:
+        BodyLoader(FetchResponse&, FetchPromise&&);
+
+        void start(ScriptExecutionContext&, const FetchRequest&);
+        void stop();
+
+    private:
+        // FetchLoaderClient API
+        void didSucceed() final;
+        void didFail() final;
+        void didReceiveResponse(const ResourceResponse&);
+        void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&&) final;
+
+        FetchResponse& m_response;
+        Optional<FetchPromise> m_promise;
+        std::unique_ptr<FetchLoader> m_loader;
+    };
+
     Type m_type;
     ResourceResponse m_response;
     Ref<FetchHeaders> m_headers;
     bool m_isLocked = false;
     bool m_isRedirected = false;
+    Optional<BodyLoader> m_bodyLoader;
 };
 
 } // namespace WebCore
index 41d009e..61f2334 100644 (file)
@@ -136,10 +136,6 @@ void BlobResourceSynchronousLoader::didFail(ResourceHandle*, const ResourceError
 
 PassRefPtr<BlobResourceHandle> BlobResourceHandle::createAsync(BlobData* blobData, const ResourceRequest& request, ResourceHandleClient* client)
 {
-    // FIXME: Should probably call didFail() instead of blocking the load without explanation.
-    if (!equalLettersIgnoringASCIICase(request.httpMethod(), "get"))
-        return nullptr;
-
     return adoptRef(new BlobResourceHandle(blobData, request, client, true));
 }
 
@@ -207,6 +203,12 @@ void BlobResourceHandle::doStart()
     if (m_aborted || m_errorCode)
         return;
 
+    if (!equalLettersIgnoringASCIICase(firstRequest().httpMethod(), "get")) {
+        m_errorCode = methodNotAllowed;
+        notifyResponse();
+        return;
+    }
+
     // If the blob data is not found, fail now.
     if (!m_blobData) {
         m_errorCode = notFoundError;
@@ -578,6 +580,10 @@ void BlobResourceHandle::notifyResponseOnSuccess()
     ResourceResponse response(firstRequest().url(), m_blobData->contentType(), m_totalRemainingSize, String());
     response.setHTTPStatusCode(isRangeRequest ? httpPartialContent : httpOK);
     response.setHTTPStatusText(isRangeRequest ? httpPartialContentText : httpOKText);
+
+    response.setHTTPHeaderField(HTTPHeaderName::ContentType, m_blobData->contentType());
+    response.setHTTPHeaderField(HTTPHeaderName::ContentLength, String::number(m_totalRemainingSize));
+
     if (isRangeRequest)
         response.setHTTPHeaderField(HTTPHeaderName::ContentRange, ParsedContentRange(m_rangeOffset, m_rangeEnd, m_totalSize).headerValue());
     // FIXME: If a resource identified with a blob: URL is a File object, user agents must use that file's name attribute,