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: https://svn.webkit.org/repository/webkit/trunk@198665
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-03-25 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-25 Gyuyoung Kim <gyuyoung.kim@webkit.org>
Unreviewed EFL gardening.
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 ]
--- /dev/null
+
+PASS Ensuring that fetch response body promise is not fulfilled when window is closed
+
--- /dev/null
+<!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>
--- /dev/null
+
+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
+
--- /dev/null
+<!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>
--- /dev/null
+<?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 "]";
+?>
+2016-03-25 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-24 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r198627.
-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 '*/*'
-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
-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"
-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
-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
-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
-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
-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
-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")
}
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) {
}
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);
}
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();
-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
-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
-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
--- /dev/null
+
+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
+
+2016-03-25 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-25 Konstantin Tokarev <annulen@yandex.ru>
Removed leftovers of WCHAR_UNICODE code path after r162782.
#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
#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
#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())
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);
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);
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;
}
{
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)
namespace WebCore {
class FetchBodyOwner;
+class FormData;
class FetchBody {
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 };
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;
ASSERT(m_body.isDisturbed());
ASSERT(!m_blobLoader);
+ if (!scriptExecutionContext()) {
+ m_body.loadingFailed();
+ return;
+ }
+
m_blobLoader = { *this };
m_blobLoader->loader = std::make_unique<FetchLoader>(type, *m_blobLoader);
+ m_blobLoader->loader->start(*scriptExecutionContext(), blob);
+ if (!m_blobLoader->loader->isStarted()) {
+ m_body.loadingFailed();
+ m_blobLoader = Nullopt;
+ return;
+ }
setPendingActivity(this);
- if (!scriptExecutionContext() || !m_blobLoader->loader->start(*scriptExecutionContext(), blob))
- blobLoadingFailed();
-}
-
-void FetchBodyOwner::loadedBlobAsText(String&& text)
-{
- m_body.loadedAsText(WTFMove(text));
}
void FetchBodyOwner::finishBlobLoading()
unsetPendingActivity(this);
}
+void FetchBodyOwner::loadedBlobAsText(String&& text)
+{
+ m_body.loadedAsText(WTFMove(text));
+}
+
void FetchBodyOwner::blobLoadingFailed()
{
m_body.loadingFailed();
didFail();
}
+void FetchBodyOwner::BlobLoader::didFail()
+{
+ // didFail might be called within FetchLoader::start call.
+ if (loader->isStarted())
+ owner.blobLoadingFailed();
+}
+
} // namespace WebCore
#endif // ENABLE(FETCH_API)
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&&);
void blobLoadingFailed();
void finishBlobLoading();
- // ActiveDOMObject API
- void stop() override;
-
struct BlobLoader final : FetchLoaderClient {
BlobLoader(FetchBodyOwner&);
void didFinishLoadingAsText(String&& text) final { owner.loadedBlobAsText(WTFMove(text)); }
void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) final { owner.loadedBlobAsArrayBuffer(WTFMove(buffer)); }
void didReceiveResponse(const ResourceResponse&) final;
- void didFail() final { owner.blobLoadingFailed(); };
+ void didFail() final;
void didSucceed() final { owner.blobLoadingSucceeded(); }
FetchBodyOwner& owner;
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
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); }
};
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) { }
#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);
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)
m_client.didFail();
}
+void FetchLoader::didFailRedirectCheck()
+{
+ m_client.didFail();
+}
+
} // namespace WebCore
#endif // ENABLE(FETCH_API)
class Blob;
class FetchLoaderClient;
+class FetchRequest;
class ScriptExecutionContext;
class FetchLoader final : public ThreadableLoaderClient {
FetchLoader(Type, FetchLoaderClient&);
- bool start(ScriptExecutionContext&, Blob&);
+ void start(ScriptExecutionContext&, const FetchRequest&);
+ void start(ScriptExecutionContext&, Blob&);
void stop();
+ bool isStarted() const { return !!m_loader; }
private:
// ThreadableLoaderClient API.
void didReceiveResponse(unsigned long, const ResourceResponse&) final;
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 };
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()) {
String integrity;
};
+ const FetchOptions& fetchOptions() const { return m_internalRequest.options; }
+ ResourceRequest internalRequest() const;
+
private:
FetchRequest(ScriptExecutionContext&, FetchBody&&, Ref<FetchHeaders>&&, InternalRequest&&);
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));
+ if (!response->m_bodyLoader->start(context, request))
+ response->m_bodyLoader = Nullopt;
+}
+
+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);
+
+ // Check whether didFail is called as part of FetchLoader::start.
+ if (m_loader->isStarted())
+ m_response.m_bodyLoader = Nullopt;
+
+ // FIXME: Handle the case of failing after didReceiveResponse is called.
+
+ m_response.unsetPendingActivity(&m_response);
+}
+
+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));
+}
+
+bool FetchResponse::BodyLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
+{
+ m_loader = std::make_unique<FetchLoader>(FetchLoader::Type::ArrayBuffer, *this);
+ m_loader->start(context, request);
+ return m_loader->isStarted();
+}
+
+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";
namespace WebCore {
class Dictionary;
+class FetchRequest;
typedef int ExceptionCode;
// 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;
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&&);
+
+ bool 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
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));
}
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;
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,