Title: [287612] trunk
Revision
287612
Author
you...@apple.com
Date
2022-01-05 02:46:30 -0800 (Wed, 05 Jan 2022)

Log Message

Fetch using FormData with file doesn't go through Service Worker
https://bugs.webkit.org/show_bug.cgi?id=187461
<rdar://problem/41975544>

Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/response/response-consume-expected.txt:
* web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt:
* web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt:

Source/WebCore:

Add support for reading formData based bodies through streams or regular methods like text.
For that purpose, we add FormDataConsumer which allows serializing form datas that may contain files or blobs.
Add the ability to load blobs from BlobLoader using the internal URL (stored in FormData) in lieu of passing a blob object.
Enable fetch events for form data based fetch events.

Test: http/wpt/service-workers/form-data-upload.html

* Modules/fetch/FetchBody.cpp:
* Modules/fetch/FetchBody.h:
* Modules/fetch/FetchBodyConsumer.cpp:
* Modules/fetch/FetchBodyConsumer.h:
* Modules/fetch/FormDataConsumer.cpp: Added.
* Modules/fetch/FormDataConsumer.h: Added.
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* fileapi/BlobLoader.h:
* fileapi/FileReaderLoader.cpp:
* fileapi/FileReaderLoader.h:
* workers/service/context/ServiceWorkerFetch.cpp:

LayoutTests:

In addition to adding a test to http/wpt/fetch/request-consume-stream.html, we fix the other tests that should all be passing.
Add http/wpt/service-workers/form-data-upload.html and translate exiting http/tests scripts for the WPT server.

* http/wpt/fetch/request-consume-stream-expected.txt:
* http/wpt/fetch/request-consume-stream.html:
* http/wpt/service-workers/form-data-upload-expected.txt: Added.
* http/wpt/service-workers/form-data-upload-worker.js: Added.
* http/wpt/service-workers/form-data-upload.html: Added.
* http/wpt/service-workers/resources/create-temp-file-iframe.html: Added.
* http/wpt/service-workers/resources/reset-temp-file.py: Added.
* http/wpt/service-workers/resources/temp-file-utils.js: Added.
* http/wpt/service-workers/resources/touch-temp-file.py: Added.
* http/wpt/service-workers/resources/write-temp-file.py: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (287611 => 287612)


--- trunk/LayoutTests/ChangeLog	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/ChangeLog	2022-01-05 10:46:30 UTC (rev 287612)
@@ -1,5 +1,27 @@
 2022-01-05  Youenn Fablet  <you...@apple.com>
 
+        Fetch using FormData with file doesn't go through Service Worker
+        https://bugs.webkit.org/show_bug.cgi?id=187461
+        <rdar://problem/41975544>
+
+        Reviewed by Chris Dumez.
+
+        In addition to adding a test to http/wpt/fetch/request-consume-stream.html, we fix the other tests that should all be passing.
+        Add http/wpt/service-workers/form-data-upload.html and translate exiting http/tests scripts for the WPT server.
+
+        * http/wpt/fetch/request-consume-stream-expected.txt:
+        * http/wpt/fetch/request-consume-stream.html:
+        * http/wpt/service-workers/form-data-upload-expected.txt: Added.
+        * http/wpt/service-workers/form-data-upload-worker.js: Added.
+        * http/wpt/service-workers/form-data-upload.html: Added.
+        * http/wpt/service-workers/resources/create-temp-file-iframe.html: Added.
+        * http/wpt/service-workers/resources/reset-temp-file.py: Added.
+        * http/wpt/service-workers/resources/temp-file-utils.js: Added.
+        * http/wpt/service-workers/resources/touch-temp-file.py: Added.
+        * http/wpt/service-workers/resources/write-temp-file.py: Added.
+
+2022-01-05  Youenn Fablet  <you...@apple.com>
+
         Make sure secure websocket connections in service workers can trigger authentication challenge callbacks
         https://bugs.webkit.org/show_bug.cgi?id=234809
         <rdar://85888177>

Modified: trunk/LayoutTests/http/wpt/fetch/request-consume-stream-expected.txt (287611 => 287612)


--- trunk/LayoutTests/http/wpt/fetch/request-consume-stream-expected.txt	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/http/wpt/fetch/request-consume-stream-expected.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -1,9 +1,10 @@
 
-FAIL Read empty text request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "" length 0, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read empty blob request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "" length 0, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read blob request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read text request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read URLSearchParams request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "110,97,109,101,61,118,97,108,117,101" length 10, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read array buffer request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
-FAIL Read form data request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "110,97,109,101,61,118,97,108,117,101" length 10, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
+PASS Read empty text request's body as readableStream
+PASS Read empty blob request's body as readableStream
+PASS Read blob request's body as readableStream
+PASS Read text request's body as readableStream
+PASS Read URLSearchParams request's body as readableStream
+PASS Read array buffer request's body as readableStream
+PASS Read form data request's body as readableStream
+PASS Read form data with blob request's body as readableStream
 

Modified: trunk/LayoutTests/http/wpt/fetch/request-consume-stream.html (287611 => 287612)


--- trunk/LayoutTests/http/wpt/fetch/request-consume-stream.html	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/http/wpt/fetch/request-consume-stream.html	2022-01-05 10:46:30 UTC (rev 287612)
@@ -11,9 +11,25 @@
   </head>
   <body>
     <script>
+async function getStringFromStream(reader, currentValue) {
+    const data = "" reader.read();
+    if (!data.done) {
+        let buffer;
+        if (currentValue) {
+            const newBuffer = new ArrayBuffer(data.value.length + currentValue.length);
+            buffer = new Uint8Array(newBuffer);
+            buffer.set(currentValue, 0);
+            buffer.set(data.value, currentValue.length);
+        } else
+            buffer = data.value;
+        return getStringFromStream(reader, buffer);
+    }
+    return (new TextDecoder).decode(currentValue);
+}
+
 function createRequestWithBody(body)
 {
-    return new Request("", {body: "{\"key\": \"value\"}", method: "POST"});
+    return new Request("", {body: body, method: "POST"});
 }
 
 promise_test(function(test) {
@@ -58,10 +74,29 @@
     return validateStreamFromString(createRequestWithBody(arrayBuffer).body.getReader(), textData);
 }, "Read array buffer request's body as readableStream");
 
-promise_test(function(test) {
+promise_test(async (test) => {
     var request = createRequestWithBody(formData);
-    return validateStreamFromString(request.body.getReader(), "name=value");
+    const value = await getStringFromStream(request.body.getReader());
+
+    assert_true(value.includes('name="name"'), "name");
+    assert_true(value.includes('value'), "name");
 }, "Read form data request's body as readableStream");
+
+promise_test(async (test) => {
+    const formData = new FormData();
+    const blob = new Blob(["'Hello'"], { "type" : "text/plain" });
+    formData.append("blob", blob, "blob.file");
+    formData.append("name", "value");
+
+    const request = createRequestWithBody(formData);
+    const value = await getStringFromStream(request.body.getReader());
+
+    assert_true(value.includes('name="name"'), "name");
+    assert_true(value.includes('value'), "name");
+
+    assert_true(value.includes('name="blob"'), "blob");
+    assert_true(value.includes('Hello'), "Hello");
+}, "Read form data with blob request's body as readableStream");
     </script>
   </body>
 </html>

Added: trunk/LayoutTests/http/wpt/service-workers/form-data-upload-expected.txt (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/form-data-upload-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/form-data-upload-expected.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,12 @@
+OPEN FILE PANEL
+
+
+PASS Setup worker
+PASS Create channel with worker
+PASS Setup frame
+PASS Setup file to upload
+PASS Setup file form data
+PASS Upload intercepted by service worker
+PASS Upload cloned by service worker
+PASS Delete temporary file
+

Added: trunk/LayoutTests/http/wpt/service-workers/form-data-upload-worker.js (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/form-data-upload-worker.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/form-data-upload-worker.js	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,18 @@
+addEventListener("message", async (e) => {
+    if (!e.data.port)
+        return;
+
+    self.port = e.data.port;
+    self.port.postMessage("ok");
+});
+
+addEventListener("fetch", async (e) => {
+    if (e.request.url.includes("clone")) {
+        const cloned = e.request.clone();
+        e.respondWith(fetch(e.request.clone()));
+        if (self.port)
+            self.port.postMessage(await cloned.text());
+        return;
+    }
+    e.respondWith(fetch(e.request));
+});

Added: trunk/LayoutTests/http/wpt/service-workers/form-data-upload.html (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/form-data-upload.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/form-data-upload.html	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+const tempFileContent = "TEST";
+const tempFileName = "test.tmp";
+
+var fileInput = document.createElement("input");
+fileInput.type = 'file';
+fileInput.style.width = "100%"; // So that any manual testing will show full file names
+document.body.insertBefore(fileInput, document.body.firstChild);
+
+var scope = "resources";
+var activeWorker;
+var frame;
+var fileFrame;
+var formData;
+var fileSize;
+
+function with_iframe(url) {
+    return new Promise(function(resolve) {
+        var frame = document.createElement('iframe');
+        frame.className = 'test-iframe';
+        frame.src = ""
+        frame._onload_ = function() { resolve(frame); };
+        document.body.appendChild(frame);
+    });
+}
+
+function prepareUpload()
+{
+    let resolve, reject;
+    const promise = new Promise((resolve_, reject_) => {
+        resolve = resolve_;
+        reject = reject_;
+    });
+    setTimeout(() => reject("test timed out"), 5000);
+
+    var input = document.getElementsByTagName("input")[0];
+    input._onchange_ = async (e) => {
+        var formData = new FormData;
+        formData.append("file", e.target.files[0], tempFileName);
+        fileSize = e.target.files[0].size;
+        resolve(formData);
+    };
+
+    if (window.testRunner) {
+        testRunner.setOpenPanelFiles([tempFilePath]);
+
+        var centerX = input.offsetLeft + input.offsetWidth / 2;
+        var centerY = input.offsetTop + input.offsetHeight / 2;
+        UIHelper.activateAt(centerX, centerY);
+    }
+    return promise;
+}
+
+promise_test(async (test) => {
+    if (window.testRunner) {
+        testRunner.setUseSeparateServiceWorkerProcess(true);
+        await fetch("").then(() => { }, () => { });
+    }
+
+    var registration = await navigator.serviceWorker.register("form-data-upload-worker.js", { scope : scope });
+    activeWorker = registration.active;
+    if (!activeWorker) {
+        activeWorker = registration.installing;
+        await new Promise(resolve => {
+            activeWorker.addEventListener('statechange', () => {
+                if (activeWorker.state === "activated")
+                    resolve();
+            });
+        });
+    }
+}, "Setup worker");
+
+const channel = new MessageChannel();
+promise_test(async (test) => {
+    activeWorker.postMessage({ port: channel.port1 }, [channel.port1]);
+    await new Promise(resolve => channel.port2._onmessage_ = resolve);
+}, "Create channel with worker");
+
+promise_test(async (test) => {
+    frame = await with_iframe("resources/");
+}, "Setup frame");
+
+promise_test(async (test) => {
+    const promise = new Promise(resolve => window._onmessage_ = resolve);
+    fileFrame = await with_iframe("/WebKit/service-workers/resources/create-temp-file-iframe.html");
+    let event = await promise;
+    tempFilePath = event.data;
+}, "Setup file to upload");
+
+promise_test(async (test) => {
+    formData = await prepareUpload();
+    assert_equals(fileSize, 4);
+}, "Setup file form data");
+
+promise_test(async (test) => {
+    const blob = new Blob(["'Hello'"], { "type" : "text/plain" });
+    formData.append("blob", blob, "blob.file");
+    formData.append("name", "value");
+
+    const response = await frame.contentWindow.fetch("/WebKit/service-workers/resources/file-upload-check.py", {method: "POST", body: formData});
+    const text = await response.text();
+
+    assert_true(text.includes(tempFileContent), "content");
+    assert_true(text.includes(tempFileName), "name");
+
+    assert_true(text.includes('name="name"'), "name");
+    assert_true(text.includes('value'), "name");
+
+    assert_true(text.includes('name="blob"'), "blob");
+    assert_true(text.includes('Hello'), "Hello");
+}, "Upload intercepted by service worker");
+
+promise_test(async (test) => {
+    const blob = new Blob(["'Hello'"], { "type" : "text/plain" });
+    formData.append("blob", blob, "blob.file");
+    formData.append("name", "value");
+
+    const messagePromise = new Promise(resolve => channel.port2._onmessage_ = (e) => resolve(e.data));
+
+    const response = await frame.contentWindow.fetch("/WebKit/service-workers/resources/file-upload-check.py?clone", {method: "POST", body: formData});
+    const text = await response.text();
+
+    const messageText = await messagePromise;
+    assert_equals(text, messageText);
+
+    assert_true(text.includes('name="name"'), "name");
+    assert_true(text.includes('value'), "name");
+
+    assert_true(text.includes('name="blob"'), "blob");
+    assert_true(text.includes('Hello'), "Hello");
+}, "Upload cloned by service worker");
+
+promise_test(async (test) => {
+    await with_iframe("/WebKit/resources/delete-temp-file-iframe.html");
+}, "Delete temporary file");
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/wpt/service-workers/resources/create-temp-file-iframe.html (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/resources/create-temp-file-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/create-temp-file-iframe.html	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+const tempFileContent = "TEST";
+const tempFileName = "test.tmp";
+
+const path = createTempFile(tempFileName, tempFileContent);
+window.parent.postMessage(path, "*");
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/wpt/service-workers/resources/reset-temp-file.py (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/resources/reset-temp-file.py	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/reset-temp-file.py	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,11 @@
+#!/usr/bin/env python3
+import os
+import tempfile
+
+
+def main(request, response):
+    filename = request.GET[b'filename']
+    state_file = os.path.join(tempfile.gettempdir(), filename.decode())
+    if os.path.exists(state_file):
+        os.remove(state_file)
+    return 200, [(b"Content-Type", b"text/html")], ""
Property changes on: trunk/LayoutTests/http/wpt/service-workers/resources/reset-temp-file.py
___________________________________________________________________

Added: svn:executable

+* \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/service-workers/resources/temp-file-utils.js (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/resources/temp-file-utils.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/temp-file-utils.js	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,32 @@
+function createTempFile(fileName, fileData)
+{
+    var xhr = new XMLHttpRequest();
+    xhr.open("POST", "/WebKit/service-workers/resources/write-temp-file.py?filename=" + fileName + "&data="" + fileData, false);
+    xhr.send();
+    if (xhr.status != 200) {
+        testFailed("Unexpected response status received: " + xhr.status);
+        return;
+    }
+
+    var values = xhr.responseText.split('\n');
+    if (xhr.responseText.indexOf("FAIL") == 0) {
+        testFailed("Unexpected response text received: " + xhr.responseText);
+        return;
+    }
+
+    return xhr.responseText;
+}
+
+function touchTempFile(fileName)
+{
+    var xhr = new XMLHttpRequest();
+    xhr.open("POST", "/WebKit/service-workers/resources/touch-temp-file.py?filename=" + fileName, false);
+    xhr.send();
+}
+
+function removeTempFile(fileName)
+{
+    var xhr = new XMLHttpRequest();
+    xhr.open("POST", "/WebKit/service-workers/resources/reset-temp-file.py?filename=" + fileName, false);
+    xhr.send();
+}

Added: trunk/LayoutTests/http/wpt/service-workers/resources/touch-temp-file.py (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/resources/touch-temp-file.py	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/touch-temp-file.py	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+
+import os
+import tempfile
+
+
+def main(request, response):
+    filename = request.GET[b'filename']
+    tmpFilePath = os.path.join(tempfile.gettempdir(), filename.decode())
+    stat = os.stat(tmpFilePath)
+
+    if not stat:
+        return 200, [(b"Content-Type", b"text/html")], "FAIL: stat() call failed.\n"
+
+    atime = stat.st_atime
+    mtime = stat.st_mtime
+    try:
+        os.utime(tmpFilePath, times=(atime, mtime + 1))
+    except:
+        return 200, [(b"Content-Type", b"text/html")], "FAIL: touch() call failed.\n"
+    return 200, [(b"Content-Type", b"text/html")], ""
Property changes on: trunk/LayoutTests/http/wpt/service-workers/resources/touch-temp-file.py
___________________________________________________________________

Added: svn:executable

+* \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/service-workers/resources/write-temp-file.py (0 => 287612)


--- trunk/LayoutTests/http/wpt/service-workers/resources/write-temp-file.py	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/service-workers/resources/write-temp-file.py	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import tempfile
+
+
+def main(request, response):
+    filename = request.GET[b'filename']
+    data = ""
+
+    tmp_file = os.path.join(tempfile.gettempdir(), filename.decode())
+    with open(tmp_file, 'w') as open_file:
+        open_file.write(data.decode())
+
+    return 200, [(b"Content-Type", b"text/html")], tmp_file
Property changes on: trunk/LayoutTests/http/wpt/service-workers/resources/write-temp-file.py
___________________________________________________________________

Added: svn:executable

+* \ No newline at end of property

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (287611 => 287612)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2022-01-05 10:46:30 UTC (rev 287612)
@@ -1,3 +1,15 @@
+2022-01-05  Youenn Fablet  <you...@apple.com>
+
+        Fetch using FormData with file doesn't go through Service Worker
+        https://bugs.webkit.org/show_bug.cgi?id=187461
+        <rdar://problem/41975544>
+
+        Reviewed by Chris Dumez.
+
+        * web-platform-tests/fetch/api/response/response-consume-expected.txt:
+        * web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt:
+        * web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt:
+
 2022-01-05  Martin Robinson  <mrobin...@webkit.org>
 
         Change offsetParent to match spec change

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt (287611 => 287612)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -38,5 +38,5 @@
 PASS Consume response's body: from fetch to text
 PASS Consume response's body: from fetch to arrayBuffer
 PASS Consume response's body: from fetch without correct type to formData (error case)
-FAIL Consume response's body: from multipart form data blob to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS Consume response's body: from multipart form data blob to formData
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt (287611 => 287612)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -5,7 +5,7 @@
 PASS Read text response's body as readableStream
 PASS Read URLSearchParams response's body as readableStream
 PASS Read array buffer response's body as readableStream
-FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS Read form data response's body as readableStream
 PASS Getting an error Response stream
 PASS Getting a redirect Response stream
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt (287611 => 287612)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -5,7 +5,7 @@
 PASS Read text response's body as readableStream
 PASS Read URLSearchParams response's body as readableStream
 PASS Read array buffer response's body as readableStream
-FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+PASS Read form data response's body as readableStream
 PASS Getting an error Response stream
 PASS Getting a redirect Response stream
 

Modified: trunk/Source/WebCore/ChangeLog (287611 => 287612)


--- trunk/Source/WebCore/ChangeLog	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/ChangeLog	2022-01-05 10:46:30 UTC (rev 287612)
@@ -1,5 +1,33 @@
 2022-01-05  Youenn Fablet  <you...@apple.com>
 
+        Fetch using FormData with file doesn't go through Service Worker
+        https://bugs.webkit.org/show_bug.cgi?id=187461
+        <rdar://problem/41975544>
+
+        Reviewed by Chris Dumez.
+
+        Add support for reading formData based bodies through streams or regular methods like text.
+        For that purpose, we add FormDataConsumer which allows serializing form datas that may contain files or blobs.
+        Add the ability to load blobs from BlobLoader using the internal URL (stored in FormData) in lieu of passing a blob object.
+        Enable fetch events for form data based fetch events.
+
+        Test: http/wpt/service-workers/form-data-upload.html
+
+        * Modules/fetch/FetchBody.cpp:
+        * Modules/fetch/FetchBody.h:
+        * Modules/fetch/FetchBodyConsumer.cpp:
+        * Modules/fetch/FetchBodyConsumer.h:
+        * Modules/fetch/FormDataConsumer.cpp: Added.
+        * Modules/fetch/FormDataConsumer.h: Added.
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * fileapi/BlobLoader.h:
+        * fileapi/FileReaderLoader.cpp:
+        * fileapi/FileReaderLoader.h:
+        * workers/service/context/ServiceWorkerFetch.cpp:
+
+2022-01-05  Youenn Fablet  <you...@apple.com>
+
         Make sure secure websocket connections in service workers can trigger authentication challenge callbacks
         https://bugs.webkit.org/show_bug.cgi?id=234809
         <rdar://85888177>

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (287611 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2022-01-05 10:46:30 UTC (rev 287612)
@@ -94,8 +94,7 @@
         return FetchBody { WTFMove(blob) };
     }
 
-    // FIXME: Support form data bodies.
-    return std::nullopt;
+    return FetchBody { Ref { formData } };
 }
 
 void FetchBody::arrayBuffer(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
@@ -196,7 +195,7 @@
         owner.loadBlob(blobBody(), nullptr);
         m_data = nullptr;
     } else if (isFormData())
-        source.error(Exception { NotSupportedError, "Not implemented"_s });
+        m_consumer.consumeFormDataAsStream(formDataBody(), source, owner.scriptExecutionContext());
     else if (m_consumer.hasData())
         closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
     else
@@ -234,14 +233,8 @@
 
 void FetchBody::consumeFormData(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
 {
-    if (auto sharedBuffer = formDataBody().asSharedBuffer()) {
-        m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), sharedBuffer->makeContiguous()->data(), sharedBuffer->size());
-        m_data = nullptr;
-    } else {
-        // FIXME: If the form data contains blobs, load them like we do other blobs.
-        // That will fix the last WPT test in response-consume.html.
-        promise->reject(NotSupportedError);
-    }
+    m_consumer.resolveWithFormData(WTFMove(promise), owner.contentType(), formDataBody(), owner.scriptExecutionContext());
+    m_data = nullptr;
 }
 
 void FetchBody::loadingFailed(const Exception& exception)
@@ -311,7 +304,7 @@
 
 FetchBody FetchBody::clone()
 {
-    FetchBody clone(m_consumer);
+    FetchBody clone(m_consumer.clone());
 
     if (isArrayBuffer())
         clone.m_data = arrayBufferBody();

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.h (287611 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.h	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -94,7 +94,7 @@
     explicit FetchBody(Ref<FormData>&& data) : m_data(WTFMove(data)) { }
     explicit FetchBody(String&& data) : m_data(WTFMove(data)) { }
     explicit FetchBody(Ref<const URLSearchParams>&& data) : m_data(WTFMove(data)) { }
-    explicit FetchBody(const FetchBodyConsumer& consumer) : m_consumer(consumer) { }
+    explicit FetchBody(FetchBodyConsumer&& consumer) : m_consumer(WTFMove(consumer)) { }
     explicit FetchBody(Ref<ReadableStream>&& stream) : m_readableStream(WTFMove(stream)) { }
 
     void consume(FetchBodyOwner&, Ref<DeferredPromise>&&);

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (287611 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	2022-01-05 10:46:30 UTC (rev 287612)
@@ -30,6 +30,7 @@
 #include "FetchBodyConsumer.h"
 
 #include "DOMFormData.h"
+#include "FormDataConsumer.h"
 #include "HTTPHeaderField.h"
 #include "HTTPParsers.h"
 #include "JSBlob.h"
@@ -243,6 +244,8 @@
 void FetchBodyConsumer::clean()
 {
     m_buffer.reset();
+    if (m_formDataConsumer)
+        m_formDataConsumer->cancel();
     resetConsumePromise();
     if (m_sink) {
         m_sink->clearCallback();
@@ -255,6 +258,61 @@
     resolveWithTypeAndData(WTFMove(promise), m_type, contentType, data, length);
 }
 
+void FetchBodyConsumer::resolveWithFormData(Ref<DeferredPromise>&& promise, const String& contentType, const FormData& formData, ScriptExecutionContext* context)
+{
+    if (auto sharedBuffer = formData.asSharedBuffer()) {
+        resolveWithData(WTFMove(promise), contentType, sharedBuffer->makeContiguous()->data(), sharedBuffer->size());
+        return;
+    }
+
+    if (!context)
+        return;
+
+    m_formDataConsumer = makeUnique<FormDataConsumer>(formData, *context, [this, promise = WTFMove(promise), contentType, builder = SharedBufferBuilder { }](auto&& result) mutable {
+        if (result.hasException()) {
+            promise->reject(result.releaseException());
+            return;
+        }
+
+        auto& value = result.returnValue();
+        if (value.empty()) {
+            auto buffer = builder.takeAsContiguous();
+            resolveWithData(WTFMove(promise), contentType, buffer->data(), buffer->size());
+            return;
+        }
+
+        builder.append(value);
+    });
+}
+
+void FetchBodyConsumer::consumeFormDataAsStream(const FormData& formData, FetchBodySource& source, ScriptExecutionContext* context)
+{
+    if (auto sharedBuffer = formData.asSharedBuffer()) {
+        if (source.enqueue(ArrayBuffer::tryCreate(sharedBuffer->makeContiguous()->data(), sharedBuffer->size())))
+            source.close();
+        return;
+    }
+
+    if (!context)
+        return;
+
+    m_formDataConsumer = makeUnique<FormDataConsumer>(formData, *context, [this, source = Ref { source }](auto&& result) {
+        if (result.hasException()) {
+            source->error(result.releaseException());
+            return;
+        }
+
+        auto& value = result.returnValue();
+        if (value.empty()) {
+            source->close();
+            return;
+        }
+
+        if (!source->enqueue(ArrayBuffer::tryCreate(value.data(), value.size())))
+            m_formDataConsumer->cancel();
+    });
+}
+
 void FetchBodyConsumer::extract(ReadableStream& stream, ReadableStreamToSharedBufferSink::Callback&& callback)
 {
     ASSERT(!m_sink);
@@ -416,4 +474,12 @@
     }
 }
 
+FetchBodyConsumer FetchBodyConsumer::clone()
+{
+    FetchBodyConsumer clone { m_type };
+    clone.m_contentType = m_contentType;
+    clone.m_buffer = m_buffer;
+    return clone;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h (287611 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -29,8 +29,10 @@
 #pragma once
 
 #include "FetchBodySource.h"
+#include "FormDataConsumer.h"
 #include "JSDOMPromiseDeferred.h"
 #include "ReadableStreamSink.h"
+#include "ScriptExecutionContextIdentifier.h"
 #include "SharedBuffer.h"
 #include "UserGestureIndicator.h"
 
@@ -39,6 +41,7 @@
 class Blob;
 class DOMFormData;
 class FetchBodySource;
+class FormData;
 class ReadableStream;
 
 class FetchBodyConsumer {
@@ -47,6 +50,8 @@
 
     explicit FetchBodyConsumer(Type type) : m_type(type) { }
 
+    FetchBodyConsumer clone();
+
     void append(const uint8_t* data, unsigned);
 
     bool hasData() const { return !!m_buffer; }
@@ -65,6 +70,8 @@
     void extract(ReadableStream&, ReadableStreamToSharedBufferSink::Callback&&);
     void resolve(Ref<DeferredPromise>&&, const String& contentType, ReadableStream*);
     void resolveWithData(Ref<DeferredPromise>&&, const String& contentType, const unsigned char*, unsigned);
+    void resolveWithFormData(Ref<DeferredPromise>&&, const String& contentType, const FormData&, ScriptExecutionContext*);
+    void consumeFormDataAsStream(const FormData&, FetchBodySource&, ScriptExecutionContext*);
 
     void loadingFailed(const Exception&);
     void loadingSucceeded(const String& contentType);
@@ -88,6 +95,7 @@
     RefPtr<FetchBodySource> m_source;
     bool m_isLoading { false };
     RefPtr<UserGestureToken> m_userGestureToken;
+    std::unique_ptr<FormDataConsumer> m_formDataConsumer;
 };
 
 } // namespace WebCore

Added: trunk/Source/WebCore/Modules/fetch/FormDataConsumer.cpp (0 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FormDataConsumer.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/fetch/FormDataConsumer.cpp	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FormDataConsumer.h"
+
+#include "BlobLoader.h"
+#include "FormData.h"
+#include <wtf/WorkQueue.h>
+
+namespace WebCore {
+
+FormDataConsumer::FormDataConsumer(const FormData& formData, ScriptExecutionContext& context, Callback&& callback)
+    : m_formData(formData.copy())
+    , m_context(&context)
+    , m_callback(WTFMove(callback))
+    , m_fileQueue(WorkQueue::create("FormDataConsumer file queue"))
+{
+    read();
+}
+
+FormDataConsumer::~FormDataConsumer()
+{
+}
+
+void FormDataConsumer::read()
+{
+    ASSERT(m_callback);
+    ASSERT(m_context);
+    ASSERT(!m_blobLoader);
+
+    if (m_currentElementIndex >= m_formData->elements().size()) {
+        m_callback(Span<const uint8_t> { });
+        return;
+    }
+
+    switchOn(m_formData->elements()[m_currentElementIndex++].data, [this](const Vector<uint8_t>& content) {
+        consumeData(content);
+    }, [this](const FormDataElement::EncodedFileData& fileData) {
+        consumeFile(fileData.filename);
+    }, [this](const FormDataElement::EncodedBlobData& blobData) {
+        consumeBlob(blobData.url);
+    });
+}
+
+void FormDataConsumer::consumeData(const Vector<uint8_t>& content)
+{
+    consume(content.span());
+}
+
+void FormDataConsumer::consumeFile(const String& filename)
+{
+    m_fileQueue->dispatch([weakThis = WeakPtr { *this }, identifier = m_context->identifier(), path = filename.isolatedCopy()]() mutable {
+        ScriptExecutionContext::postTaskTo(identifier, [weakThis = WTFMove(weakThis), content = FileSystem::readEntireFile(path)](auto&) {
+            if (!weakThis)
+                return;
+
+            if (!content) {
+                if (weakThis->m_callback)
+                    weakThis->m_callback(Exception { InvalidStateError, "Unable to read form data file"_s });
+                return;
+            }
+
+            weakThis->consume(*content);
+        });
+    });
+}
+
+void FormDataConsumer::consumeBlob(const URL& blobURL)
+{
+    m_blobLoader = makeUnique<BlobLoader>([weakThis = WeakPtr { *this }](BlobLoader&) mutable {
+        if (!weakThis)
+            return;
+
+        auto loader = std::exchange(weakThis->m_blobLoader, { });
+        if (auto optionalErrorCode = loader->errorCode()) {
+            if (weakThis->m_callback)
+                weakThis->m_callback(Exception { InvalidStateError, "Failed to read form data blob"_s });
+            return;
+        }
+
+        if (auto data = ""
+            weakThis->consume(Span<const uint8_t> { static_cast<const uint8_t*>(data->data()), data->byteLength() });
+    });
+
+    m_blobLoader->start(blobURL, m_context.get(), FileReaderLoader::ReadAsArrayBuffer);
+
+    if (!m_blobLoader->isLoading()) {
+        m_callback(Exception { InvalidStateError, "Unable to read form data blob"_s });
+        m_blobLoader = nullptr;
+    }
+}
+
+void FormDataConsumer::consume(Span<const uint8_t> content)
+{
+    if (!m_callback)
+        return;
+
+    m_callback(WTFMove(content));
+    if (!m_callback)
+        return;
+
+    read();
+}
+
+void FormDataConsumer::cancel()
+{
+    m_callback = nullptr;
+    if (m_blobLoader) {
+        m_blobLoader->cancel();
+        m_blobLoader = nullptr;
+    }
+    m_context = nullptr;
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/Modules/fetch/FormDataConsumer.h (0 => 287612)


--- trunk/Source/WebCore/Modules/fetch/FormDataConsumer.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/fetch/FormDataConsumer.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ScriptExecutionContextIdentifier.h"
+#include <wtf/FastMalloc.h>
+#include <wtf/Function.h>
+#include <wtf/Span.h>
+#include <wtf/WeakPtr.h>
+#include <wtf/WorkQueue.h>
+
+namespace WebCore {
+
+class BlobLoader;
+class FormData;
+
+class FormDataConsumer : public CanMakeWeakPtr<FormDataConsumer> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    using Callback = Function<void(ExceptionOr<Span<const uint8_t>>)>;
+    FormDataConsumer(const FormData&, ScriptExecutionContext&, Callback&&);
+    WEBCORE_EXPORT ~FormDataConsumer();
+
+    void cancel();
+
+private:
+    void consumeData(const Vector<uint8_t>&);
+    void consumeFile(const String&);
+    void consumeBlob(const URL&);
+
+    void consume(Span<const uint8_t>);
+    void read();
+
+    Ref<FormData> m_formData;
+    RefPtr<ScriptExecutionContext> m_context;
+    Callback m_callback;
+
+    size_t m_currentElementIndex { 0 };
+    Ref<WorkQueue> m_fileQueue;
+    std::unique_ptr<BlobLoader> m_blobLoader;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/Sources.txt (287611 => 287612)


--- trunk/Source/WebCore/Sources.txt	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/Sources.txt	2022-01-05 10:46:30 UTC (rev 287612)
@@ -88,6 +88,7 @@
 Modules/fetch/FetchLoader.cpp
 Modules/fetch/FetchRequest.cpp
 Modules/fetch/FetchResponse.cpp
+Modules/fetch/FormDataConsumer.cpp
 Modules/fetch/WindowOrWorkerGlobalScopeFetch.cpp
 Modules/filesystemaccess/FileSystemDirectoryHandle.cpp
 Modules/filesystemaccess/FileSystemFileHandle.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (287611 => 287612)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-01-05 10:46:30 UTC (rev 287612)
@@ -8485,6 +8485,8 @@
 		3FBC4AF1189881560046EE38 /* VideoFullscreenInterfaceAVKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenInterfaceAVKit.mm; sourceTree = "<group>"; };
 		3FBC4AF2189881560046EE38 /* VideoFullscreenInterfaceAVKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenInterfaceAVKit.h; sourceTree = "<group>"; };
 		41024FC823CF254F00FDF98E /* SampleBufferDisplayLayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SampleBufferDisplayLayer.cpp; sourceTree = "<group>"; };
+		4102EE0E27830E6300D6BE74 /* FormDataConsumer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FormDataConsumer.h; sourceTree = "<group>"; };
+		4102EE1027830E6300D6BE74 /* FormDataConsumer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormDataConsumer.cpp; sourceTree = "<group>"; };
 		4107908A1FC3E4F20061B27A /* ClientOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClientOrigin.h; sourceTree = "<group>"; };
 		4109382C2347850E009428BA /* JSAbortSignalCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSAbortSignalCustom.cpp; sourceTree = "<group>"; };
 		410A8EF424F823B9004F9070 /* TextEncoderStream.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextEncoderStream.idl; sourceTree = "<group>"; };
@@ -21281,6 +21283,8 @@
 				413015D51C7B570400091C6E /* FetchResponse.cpp */,
 				413015D61C7B570400091C6E /* FetchResponse.h */,
 				413015D71C7B570400091C6E /* FetchResponse.idl */,
+				4102EE1027830E6300D6BE74 /* FormDataConsumer.cpp */,
+				4102EE0E27830E6300D6BE74 /* FormDataConsumer.h */,
 				7C2E0BD125106AC4005F3C87 /* WindowOrWorkerGlobalScope+Fetch.idl */,
 				7C2E0BD025106AC4005F3C87 /* WindowOrWorkerGlobalScopeFetch.cpp */,
 				7C2E0BCF25106AC4005F3C87 /* WindowOrWorkerGlobalScopeFetch.h */,

Modified: trunk/Source/WebCore/fileapi/BlobLoader.h (287611 => 287612)


--- trunk/Source/WebCore/fileapi/BlobLoader.h	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/fileapi/BlobLoader.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -43,6 +43,7 @@
     ~BlobLoader();
 
     void start(Blob&, ScriptExecutionContext*, FileReaderLoader::ReadType);
+    void start(const URL&, ScriptExecutionContext*, FileReaderLoader::ReadType);
 
     void cancel();
     bool isLoading() const { return m_loader && m_completionHandler; }
@@ -89,6 +90,13 @@
     m_loader->start(context, blob);
 }
 
+inline void BlobLoader::start(const URL& blobURL, ScriptExecutionContext* context, FileReaderLoader::ReadType readType)
+{
+    ASSERT(!m_loader);
+    m_loader = makeUnique<FileReaderLoader>(readType, this);
+    m_loader->start(context, blobURL);
+}
+
 inline void BlobLoader::didFinishLoading()
 {
     m_completionHandler(*this);

Modified: trunk/Source/WebCore/fileapi/FileReaderLoader.cpp (287611 => 287612)


--- trunk/Source/WebCore/fileapi/FileReaderLoader.cpp	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/fileapi/FileReaderLoader.cpp	2022-01-05 10:46:30 UTC (rev 287612)
@@ -74,6 +74,11 @@
 
 void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob& blob)
 {
+    start(scriptExecutionContext, blob.url());
+}
+
+void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const URL& blobURL)
+{
     ASSERT(scriptExecutionContext);
 
     // The blob is read by routing through the request handling layer given a temporary public url.
@@ -82,7 +87,7 @@
         failed(SecurityError);
         return;
     }
-    ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), scriptExecutionContext->policyContainer(), m_urlForReading, blob.url());
+    ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), scriptExecutionContext->policyContainer(), m_urlForReading, blobURL);
 
     // Construct and load the request.
     ResourceRequest request(m_urlForReading);

Modified: trunk/Source/WebCore/fileapi/FileReaderLoader.h (287611 => 287612)


--- trunk/Source/WebCore/fileapi/FileReaderLoader.h	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/fileapi/FileReaderLoader.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -66,6 +66,7 @@
     ~FileReaderLoader();
 
     WEBCORE_EXPORT void start(ScriptExecutionContext*, Blob&);
+    void start(ScriptExecutionContext*, const URL&);
     WEBCORE_EXPORT void cancel();
 
     // ThreadableLoaderClient

Modified: trunk/Source/WebCore/platform/SharedBuffer.h (287611 => 287612)


--- trunk/Source/WebCore/platform/SharedBuffer.h	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/platform/SharedBuffer.h	2022-01-05 10:46:30 UTC (rev 287612)
@@ -230,6 +230,7 @@
     friend class SharedBufferBuilder;
     WEBCORE_EXPORT void append(const FragmentedSharedBuffer&);
     WEBCORE_EXPORT void append(const uint8_t*, size_t);
+    void append(Span<const uint8_t> value) { append(value.data(), value.size()); }
     void append(const char* data, size_t length) { append(reinterpret_cast<const uint8_t*>(data), length); }
     WEBCORE_EXPORT void append(Vector<uint8_t>&&);
 #if USE(FOUNDATION)

Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp (287611 => 287612)


--- trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp	2022-01-05 10:35:47 UTC (rev 287611)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp	2022-01-05 10:46:30 UTC (rev 287612)
@@ -46,7 +46,7 @@
 namespace ServiceWorkerFetch {
 
 // https://fetch.spec.whatwg.org/#http-fetch step 3.3
-static inline std::optional<ResourceError> validateResponse(const ResourceResponse& response, FetchOptions::Mode mode, FetchOptions::Redirect redirect)
+static inline ResourceError validateResponse(const ResourceResponse& response, FetchOptions::Mode mode, FetchOptions::Redirect redirect)
 {
     if (response.type() == ResourceResponse::Type::Error)
         return ResourceError { errorDomainWebKitInternal, 0, response.url(), "Response served by service worker is an error"_s, ResourceError::Type::General, ResourceError::IsSanitized::Yes };
@@ -84,8 +84,8 @@
     }
 
     auto resourceResponse = response->resourceResponse();
-    if (auto error = validateResponse(resourceResponse, mode, redirect)) {
-        client->didFail(error.value());
+    if (auto error = validateResponse(resourceResponse, mode, redirect); !error.isNull()) {
+        client->didFail(error);
         return;
     }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to