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;
}