Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,3 +1,27 @@
+2020-08-24 Alex Christensen <achristen...@webkit.org>
+
+ Implement Request/Response consuming as FormData
+ https://bugs.webkit.org/show_bug.cgi?id=215671
+
+ Reviewed by Darin Adler.
+
+ * web-platform-tests/fetch/api/abort/general.any-expected.txt:
+ * web-platform-tests/fetch/api/abort/general.any.worker-expected.txt:
+ * web-platform-tests/fetch/api/request/request-consume-empty-expected.txt:
+ This remaining failing test now fails similarly in all browsers.
+ * web-platform-tests/fetch/api/request/request-consume-expected.txt:
+ * web-platform-tests/fetch/api/request/request-init-002-expected.txt:
+ * web-platform-tests/fetch/api/response/response-consume-empty-expected.txt:
+ This remaining failing test now fails similarly in all browsers.
+ * web-platform-tests/fetch/api/response/response-consume-expected.txt:
+ * web-platform-tests/fetch/api/response/response-error-from-stream-expected.txt:
+ This change makes the formData failures in this file look like all the other failures in this file,
+ which should be fixed together in a separate patch.
+ * web-platform-tests/fetch/api/response/response-init-002-expected.txt:
+ * web-platform-tests/url/urlencoded-parser.any-expected.txt:
+ * web-platform-tests/url/urlencoded-parser.any.worker-expected.txt:
+ * web-platform-tests/service-workers/service-worker/fetch-event-respond-with-custom-response.https-expected.txt:
+
2020-08-24 Emilio Cobos Álvarez <emi...@crisal.io>
Support quotes:auto and fix quotes serialization.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -38,7 +38,7 @@
PASS Underlying connection is closed when aborting after receiving response - no-cors
PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
PASS Fetch aborted & connection closed when aborted after calling response.blob()
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() promise_rejects_dom: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
+PASS Fetch aborted & connection closed when aborted after calling response.formData()
PASS Fetch aborted & connection closed when aborted after calling response.json()
PASS Fetch aborted & connection closed when aborted after calling response.text()
PASS Stream errors once aborted. Underlying connection closed.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -38,7 +38,7 @@
PASS Underlying connection is closed when aborting after receiving response - no-cors
PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
PASS Fetch aborted & connection closed when aborted after calling response.blob()
-FAIL Fetch aborted & connection closed when aborted after calling response.formData() promise_rejects_dom: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
+PASS Fetch aborted & connection closed when aborted after calling response.formData()
PASS Fetch aborted & connection closed when aborted after calling response.json()
PASS Fetch aborted & connection closed when aborted after calling response.text()
PASS Stream errors once aborted. Underlying connection closed.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-empty-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-empty-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-empty-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -11,6 +11,6 @@
PASS Consume empty blob request body as text
PASS Consume empty text request body as text
PASS Consume empty URLSearchParams request body as text
-FAIL Consume empty FormData request body as text promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+FAIL Consume empty FormData request body as text assert_equals: Resolved value should be empty expected 0 but got 44
PASS Consume empty ArrayBuffer request body as text
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -23,7 +23,7 @@
PASS Consume DataView request's body as blob
PASS Consume DataView request's body as arrayBuffer
PASS Consume DataView request's body as JSON
-FAIL Consume FormData request's body as FormData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS Consume FormData request's body as FormData
PASS Consume blob response's body as blob
PASS Consume blob response's body as text
PASS Consume blob response's body as json
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-init-002-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-init-002-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-init-002-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -3,7 +3,7 @@
PASS Initialize Request's body with "undefined", undefined
PASS Initialize Request's body with "null", null
PASS Initialize Request's body with "[object Blob]", application/octet-binary
-FAIL Initialize Request's body with "[object FormData]", multipart/form-data promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS Initialize Request's body with "[object FormData]", multipart/form-data
PASS Initialize Request's body with "This is a USVString", text/plain;charset=UTF-8
PASS Initialize Request's body with "hi!", text/plain;charset=UTF-8
PASS Initialize Request's body with "name=value", application/x-www-form-urlencoded;charset=UTF-8
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -11,6 +11,6 @@
PASS Consume empty blob response body as text
PASS Consume empty text response body as text
PASS Consume empty URLSearchParams response body as text
-FAIL Consume empty FormData response body as text promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+FAIL Consume empty FormData response body as text assert_equals: Resolved value should be empty expected 0 but got 44
PASS Consume empty ArrayBuffer response body as text
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -3,39 +3,27 @@
PASS Consume response's body: from text to blob
PASS Consume response's body: from text to arrayBuffer
PASS Consume response's body: from text to json
-FAIL Consume response's body: from text with correct multipart type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from text with correct multipart type to formData with BOM promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from text without correct multipart type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from text with correct urlencoded type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from text without correct urlencoded type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
+PASS Consume response's body: from text with correct multipart type to formData
+PASS Consume response's body: from text with correct multipart type to formData with BOM
+PASS Consume response's body: from text without correct multipart type to formData (error case)
+PASS Consume response's body: from text with correct urlencoded type to formData
+PASS Consume response's body: from text without correct urlencoded type to formData (error case)
PASS Consume response's body: from blob to blob
PASS Consume response's body: from blob to text
PASS Consume response's body: from blob to arrayBuffer
PASS Consume response's body: from blob to json
-FAIL Consume response's body: from blob with correct multipart type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from blob without correct multipart type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from blob with correct urlencoded type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from blob without correct urlencoded type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from FormData to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from FormData without correct type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from FormData to blob promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from FormData to text promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from FormData to arrayBuffer promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from URLSearchParams to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from URLSearchParams without correct type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from URLSearchParams to blob assert_equals: Blob body type should be computed from the response Content-Type expected "application/x-www-form-urlencoded;charset=utf-8" but got "application/x-www-form-urlencoded"
+PASS Consume response's body: from blob with correct multipart type to formData
+PASS Consume response's body: from blob without correct multipart type to formData (error case)
+PASS Consume response's body: from blob with correct urlencoded type to formData
+PASS Consume response's body: from blob without correct urlencoded type to formData (error case)
+PASS Consume response's body: from FormData to formData
+PASS Consume response's body: from FormData without correct type to formData (error case)
+PASS Consume response's body: from FormData to blob
+PASS Consume response's body: from FormData to text
+PASS Consume response's body: from FormData to arrayBuffer
+PASS Consume response's body: from URLSearchParams to formData
+PASS Consume response's body: from URLSearchParams without correct type to formData (error case)
+PASS Consume response's body: from URLSearchParams to blob
PASS Consume response's body: from URLSearchParams to text
PASS Consume response's body: from URLSearchParams to arrayBuffer
PASS Consume response's body: from stream to blob
@@ -42,19 +30,13 @@
PASS Consume response's body: from stream to text
PASS Consume response's body: from stream to arrayBuffer
PASS Consume response's body: from stream to json
-FAIL Consume response's body: from stream with correct multipart type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from stream without correct multipart type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
-FAIL Consume response's body: from stream with correct urlencoded type to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL Consume response's body: from stream without correct urlencoded type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
+PASS Consume response's body: from stream with correct multipart type to formData
+PASS Consume response's body: from stream without correct multipart type to formData (error case)
+PASS Consume response's body: from stream with correct urlencoded type to formData
+PASS Consume response's body: from stream without correct urlencoded type to formData (error case)
PASS Consume response's body: from fetch to blob
PASS Consume response's body: from fetch to text
PASS Consume response's body: from fetch to arrayBuffer
-FAIL Consume response's body: from fetch without correct type to formData (error case) promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected instance of function "function TypeError() {
- [native code]
-}" ("TypeError")
+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."
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-error-from-stream-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-error-from-stream-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-error-from-stream-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -3,12 +3,12 @@
PASS ReadableStreamDefaultReader Promise receives ReadableStream pull() Error
FAIL ReadableStream start() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Start error" but we expected it to throw object "Error: Start error"
FAIL ReadableStream start() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Start error" but we expected it to throw object "Error: Start error"
-FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Start error" but we expected it to throw object "Error: Start error"
FAIL ReadableStream start() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Start error" but we expected it to throw object "Error: Start error"
FAIL ReadableStream start() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Start error" but we expected it to throw object "Error: Start error"
FAIL ReadableStream pull() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Pull error" but we expected it to throw object "Error: Pull error"
FAIL ReadableStream pull() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Pull error" but we expected it to throw object "Error: Pull error"
-FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Pull error" but we expected it to throw object "Error: Pull error"
FAIL ReadableStream pull() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Pull error" but we expected it to throw object "Error: Pull error"
FAIL ReadableStream pull() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function () { throw e }" threw object "TypeError: Error: Pull error" but we expected it to throw object "Error: Pull error"
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-init-002-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-init-002-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-init-002-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,7 +1,7 @@
PASS Initialize Response with headers values
PASS Initialize Response's body with application/octet-binary
-FAIL Initialize Response's body with multipart/form-data promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS Initialize Response's body with multipart/form-data
PASS Initialize Response's body with application/x-www-form-urlencoded;charset=UTF-8
PASS Initialize Response's body with text/plain;charset=UTF-8
PASS Read Response's body as readableStream
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-respond-with-custom-response.https-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-respond-with-custom-response.https-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-respond-with-custom-response.https-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -3,7 +3,7 @@
PASS Subresource built from a blob
PASS Subresource built from a buffer
PASS Subresource built from a buffer-view
-FAIL Subresource built from form-data promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS Subresource built from form-data
PASS Subresource built from search-params
PASS Navigation resource built from a string
PASS Navigation resource built from a blob
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,104 +1,104 @@
PASS URLSearchParams constructed with: test
-FAIL request.formData() with input: test promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: test promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: test
+PASS response.formData() with input: test
PASS URLSearchParams constructed with: test=
-FAIL request.formData() with input: test= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: test= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: test=
+PASS response.formData() with input: test=
PASS URLSearchParams constructed with: %EF%BB%BFtest=%EF%BB%BF
-FAIL request.formData() with input: %EF%BB%BFtest=%EF%BB%BF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %EF%BB%BFtest=%EF%BB%BF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %FE%FF assert_array_equals: expected property 0 to be "\ufffd\ufffd" but got "" (expected array ["\ufffd\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %FE%FF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %FE%FF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %FF%FE assert_array_equals: expected property 0 to be "\ufffd\ufffd" but got "" (expected array ["\ufffd\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %FF%FE promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %FF%FE promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %EF%BB%BFtest=%EF%BB%BF
+PASS response.formData() with input: %EF%BB%BFtest=%EF%BB%BF
+PASS URLSearchParams constructed with: %FE%FF
+PASS request.formData() with input: %FE%FF
+PASS response.formData() with input: %FE%FF
+PASS URLSearchParams constructed with: %FF%FE
+PASS request.formData() with input: %FF%FE
+PASS response.formData() with input: %FF%FE
PASS URLSearchParams constructed with: †&†=x
-FAIL request.formData() with input: †&†=x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: †&†=x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %C2 assert_array_equals: expected property 0 to be "\ufffd" but got "" (expected array ["\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %C2 promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %C2 promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %C2x assert_array_equals: expected property 0 to be "\ufffdx" but got "" (expected array ["\ufffdx", ""] got ["", ""])
-FAIL request.formData() with input: %C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: _charset_=windows-1252&test=%C2x assert_array_equals: expected property 1 to be "\ufffdx" but got "" (expected array ["test", "\ufffdx"] got ["test", ""])
-FAIL request.formData() with input: _charset_=windows-1252&test=%C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: _charset_=windows-1252&test=%C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: †&†=x
+PASS response.formData() with input: †&†=x
+PASS URLSearchParams constructed with: %C2
+PASS request.formData() with input: %C2
+PASS response.formData() with input: %C2
+PASS URLSearchParams constructed with: %C2x
+PASS request.formData() with input: %C2x
+PASS response.formData() with input: %C2x
+PASS URLSearchParams constructed with: _charset_=windows-1252&test=%C2x
+PASS request.formData() with input: _charset_=windows-1252&test=%C2x
+PASS response.formData() with input: _charset_=windows-1252&test=%C2x
PASS URLSearchParams constructed with:
-FAIL request.formData() with input: promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input:
+PASS response.formData() with input:
PASS URLSearchParams constructed with: a
-FAIL request.formData() with input: a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a
+PASS response.formData() with input: a
PASS URLSearchParams constructed with: a=b
-FAIL request.formData() with input: a=b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b
+PASS response.formData() with input: a=b
PASS URLSearchParams constructed with: a=
-FAIL request.formData() with input: a= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=
+PASS response.formData() with input: a=
PASS URLSearchParams constructed with: =b
-FAIL request.formData() with input: =b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: =b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: =b
+PASS response.formData() with input: =b
PASS URLSearchParams constructed with: &
-FAIL request.formData() with input: & promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: & promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &
+PASS response.formData() with input: &
PASS URLSearchParams constructed with: &a
-FAIL request.formData() with input: &a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: &a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &a
+PASS response.formData() with input: &a
PASS URLSearchParams constructed with: a&
-FAIL request.formData() with input: a& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&
+PASS response.formData() with input: a&
PASS URLSearchParams constructed with: a&a
-FAIL request.formData() with input: a&a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a&a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&a
+PASS response.formData() with input: a&a
PASS URLSearchParams constructed with: a&b&c
-FAIL request.formData() with input: a&b&c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a&b&c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&b&c
+PASS response.formData() with input: a&b&c
PASS URLSearchParams constructed with: a=b&c=d
-FAIL request.formData() with input: a=b&c=d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b&c=d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b&c=d
+PASS response.formData() with input: a=b&c=d
PASS URLSearchParams constructed with: a=b&c=d&
-FAIL request.formData() with input: a=b&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b&c=d&
+PASS response.formData() with input: a=b&c=d&
PASS URLSearchParams constructed with: &&&a=b&&&&c=d&
-FAIL request.formData() with input: &&&a=b&&&&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: &&&a=b&&&&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &&&a=b&&&&c=d&
+PASS response.formData() with input: &&&a=b&&&&c=d&
PASS URLSearchParams constructed with: a=a&a=b&a=c
-FAIL request.formData() with input: a=a&a=b&a=c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=a&a=b&a=c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=a&a=b&a=c
+PASS response.formData() with input: a=a&a=b&a=c
PASS URLSearchParams constructed with: a==a
-FAIL request.formData() with input: a==a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a==a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a==a
+PASS response.formData() with input: a==a
PASS URLSearchParams constructed with: a=a+b+c+d
-FAIL request.formData() with input: a=a+b+c+d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=a+b+c+d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=a+b+c+d
+PASS response.formData() with input: a=a+b+c+d
PASS URLSearchParams constructed with: %=a
-FAIL request.formData() with input: %=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %=a
+PASS response.formData() with input: %=a
PASS URLSearchParams constructed with: %a=a
-FAIL request.formData() with input: %a=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %a=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %a=a
+PASS response.formData() with input: %a=a
PASS URLSearchParams constructed with: %a_=a
-FAIL request.formData() with input: %a_=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %a_=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %a_=a
+PASS response.formData() with input: %a_=a
PASS URLSearchParams constructed with: %61=a
-FAIL request.formData() with input: %61=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %61=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %61=a
+PASS response.formData() with input: %61=a
PASS URLSearchParams constructed with: %61+%4d%4D=
-FAIL request.formData() with input: %61+%4d%4D= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %61+%4d%4D= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %61+%4d%4D=
+PASS response.formData() with input: %61+%4d%4D=
PASS URLSearchParams constructed with: id=0&value=%
-FAIL request.formData() with input: id=0&value=% promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: id=0&value=% promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: id=0&value=%
+PASS response.formData() with input: id=0&value=%
PASS URLSearchParams constructed with: b=%2sf%2a
-FAIL request.formData() with input: b=%2sf%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%2sf%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%2sf%2a
+PASS response.formData() with input: b=%2sf%2a
PASS URLSearchParams constructed with: b=%2%2af%2a
-FAIL request.formData() with input: b=%2%2af%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%2%2af%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%2%2af%2a
+PASS response.formData() with input: b=%2%2af%2a
PASS URLSearchParams constructed with: b=%%2a
-FAIL request.formData() with input: b=%%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%%2a
+PASS response.formData() with input: b=%%2a
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any.worker-expected.txt (266086 => 266087)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any.worker-expected.txt 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/url/urlencoded-parser.any.worker-expected.txt 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,104 +1,104 @@
PASS URLSearchParams constructed with: test
-FAIL request.formData() with input: test promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: test promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: test
+PASS response.formData() with input: test
PASS URLSearchParams constructed with: test=
-FAIL request.formData() with input: test= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: test= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: test=
+PASS response.formData() with input: test=
PASS URLSearchParams constructed with: %EF%BB%BFtest=%EF%BB%BF
-FAIL request.formData() with input: %EF%BB%BFtest=%EF%BB%BF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %EF%BB%BFtest=%EF%BB%BF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %FE%FF assert_array_equals: expected property 0 to be "\ufffd\ufffd" but got "" (expected array ["\ufffd\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %FE%FF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %FE%FF promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %FF%FE assert_array_equals: expected property 0 to be "\ufffd\ufffd" but got "" (expected array ["\ufffd\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %FF%FE promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %FF%FE promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %EF%BB%BFtest=%EF%BB%BF
+PASS response.formData() with input: %EF%BB%BFtest=%EF%BB%BF
+PASS URLSearchParams constructed with: %FE%FF
+PASS request.formData() with input: %FE%FF
+PASS response.formData() with input: %FE%FF
+PASS URLSearchParams constructed with: %FF%FE
+PASS request.formData() with input: %FF%FE
+PASS response.formData() with input: %FF%FE
PASS URLSearchParams constructed with: †&†=x
-FAIL request.formData() with input: †&†=x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: †&†=x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %C2 assert_array_equals: expected property 0 to be "\ufffd" but got "" (expected array ["\ufffd", ""] got ["", ""])
-FAIL request.formData() with input: %C2 promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %C2 promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: %C2x assert_array_equals: expected property 0 to be "\ufffdx" but got "" (expected array ["\ufffdx", ""] got ["", ""])
-FAIL request.formData() with input: %C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL URLSearchParams constructed with: _charset_=windows-1252&test=%C2x assert_array_equals: expected property 1 to be "\ufffdx" but got "" (expected array ["test", "\ufffdx"] got ["test", ""])
-FAIL request.formData() with input: _charset_=windows-1252&test=%C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: _charset_=windows-1252&test=%C2x promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: †&†=x
+PASS response.formData() with input: †&†=x
+PASS URLSearchParams constructed with: %C2
+PASS request.formData() with input: %C2
+PASS response.formData() with input: %C2
+PASS URLSearchParams constructed with: %C2x
+PASS request.formData() with input: %C2x
+PASS response.formData() with input: %C2x
+PASS URLSearchParams constructed with: _charset_=windows-1252&test=%C2x
+PASS request.formData() with input: _charset_=windows-1252&test=%C2x
+PASS response.formData() with input: _charset_=windows-1252&test=%C2x
PASS URLSearchParams constructed with:
-FAIL request.formData() with input: promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input:
+PASS response.formData() with input:
PASS URLSearchParams constructed with: a
-FAIL request.formData() with input: a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a
+PASS response.formData() with input: a
PASS URLSearchParams constructed with: a=b
-FAIL request.formData() with input: a=b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b
+PASS response.formData() with input: a=b
PASS URLSearchParams constructed with: a=
-FAIL request.formData() with input: a= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=
+PASS response.formData() with input: a=
PASS URLSearchParams constructed with: =b
-FAIL request.formData() with input: =b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: =b promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: =b
+PASS response.formData() with input: =b
PASS URLSearchParams constructed with: &
-FAIL request.formData() with input: & promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: & promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &
+PASS response.formData() with input: &
PASS URLSearchParams constructed with: &a
-FAIL request.formData() with input: &a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: &a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &a
+PASS response.formData() with input: &a
PASS URLSearchParams constructed with: a&
-FAIL request.formData() with input: a& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&
+PASS response.formData() with input: a&
PASS URLSearchParams constructed with: a&a
-FAIL request.formData() with input: a&a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a&a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&a
+PASS response.formData() with input: a&a
PASS URLSearchParams constructed with: a&b&c
-FAIL request.formData() with input: a&b&c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a&b&c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a&b&c
+PASS response.formData() with input: a&b&c
PASS URLSearchParams constructed with: a=b&c=d
-FAIL request.formData() with input: a=b&c=d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b&c=d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b&c=d
+PASS response.formData() with input: a=b&c=d
PASS URLSearchParams constructed with: a=b&c=d&
-FAIL request.formData() with input: a=b&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=b&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=b&c=d&
+PASS response.formData() with input: a=b&c=d&
PASS URLSearchParams constructed with: &&&a=b&&&&c=d&
-FAIL request.formData() with input: &&&a=b&&&&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: &&&a=b&&&&c=d& promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: &&&a=b&&&&c=d&
+PASS response.formData() with input: &&&a=b&&&&c=d&
PASS URLSearchParams constructed with: a=a&a=b&a=c
-FAIL request.formData() with input: a=a&a=b&a=c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=a&a=b&a=c promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=a&a=b&a=c
+PASS response.formData() with input: a=a&a=b&a=c
PASS URLSearchParams constructed with: a==a
-FAIL request.formData() with input: a==a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a==a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a==a
+PASS response.formData() with input: a==a
PASS URLSearchParams constructed with: a=a+b+c+d
-FAIL request.formData() with input: a=a+b+c+d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: a=a+b+c+d promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: a=a+b+c+d
+PASS response.formData() with input: a=a+b+c+d
PASS URLSearchParams constructed with: %=a
-FAIL request.formData() with input: %=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %=a
+PASS response.formData() with input: %=a
PASS URLSearchParams constructed with: %a=a
-FAIL request.formData() with input: %a=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %a=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %a=a
+PASS response.formData() with input: %a=a
PASS URLSearchParams constructed with: %a_=a
-FAIL request.formData() with input: %a_=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %a_=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %a_=a
+PASS response.formData() with input: %a_=a
PASS URLSearchParams constructed with: %61=a
-FAIL request.formData() with input: %61=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %61=a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %61=a
+PASS response.formData() with input: %61=a
PASS URLSearchParams constructed with: %61+%4d%4D=
-FAIL request.formData() with input: %61+%4d%4D= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: %61+%4d%4D= promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: %61+%4d%4D=
+PASS response.formData() with input: %61+%4d%4D=
PASS URLSearchParams constructed with: id=0&value=%
-FAIL request.formData() with input: id=0&value=% promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: id=0&value=% promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: id=0&value=%
+PASS response.formData() with input: id=0&value=%
PASS URLSearchParams constructed with: b=%2sf%2a
-FAIL request.formData() with input: b=%2sf%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%2sf%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%2sf%2a
+PASS response.formData() with input: b=%2sf%2a
PASS URLSearchParams constructed with: b=%2%2af%2a
-FAIL request.formData() with input: b=%2%2af%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%2%2af%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%2%2af%2a
+PASS response.formData() with input: b=%2%2af%2a
PASS URLSearchParams constructed with: b=%%2a
-FAIL request.formData() with input: b=%%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL response.formData() with input: b=%%2a promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS request.formData() with input: b=%%2a
+PASS response.formData() with input: b=%%2a
Modified: trunk/Source/WTF/ChangeLog (266086 => 266087)
--- trunk/Source/WTF/ChangeLog 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/ChangeLog 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,5 +1,28 @@
2020-08-24 Alex Christensen <achristen...@webkit.org>
+ Implement Request/Response consuming as FormData
+ https://bugs.webkit.org/show_bug.cgi?id=215671
+
+ Reviewed by Darin Adler.
+
+ In order to be compatible with other browsers, we need a verson of String::fromUTF8 that
+ uses U8_NEXT_OR_FFFD instead of U8_NEXT, but changing that across the board will break other things.
+ Leave everything else as it is, use templates and constexpr to not add any branches, but add
+ String::fromUTF8ReplacingInvalidSequences to allow me to make our FormData consuming compatible with other browsers.
+
+ * wtf/text/WTFString.cpp:
+ (WTF::fromUTF8Helper):
+ (WTF::String::fromUTF8):
+ (WTF::String::fromUTF8ReplacingInvalidSequences):
+ * wtf/text/WTFString.h:
+ * wtf/unicode/UTF8Conversion.cpp:
+ (WTF::Unicode::convertUTF8ToUTF16Impl):
+ (WTF::Unicode::convertUTF8ToUTF16):
+ (WTF::Unicode::convertUTF8ToUTF16ReplacingInvalidSequences):
+ * wtf/unicode/UTF8Conversion.h:
+
+2020-08-24 Alex Christensen <achristen...@webkit.org>
+
Make _WKWebsiteDataStoreConfiguration SPI for HSTS storage to replace _WKProcessPoolConfiguration.hstsStorageDirectory
https://bugs.webkit.org/show_bug.cgi?id=213048
Modified: trunk/Source/WTF/wtf/PlatformHave.h (266086 => 266087)
--- trunk/Source/WTF/wtf/PlatformHave.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/PlatformHave.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -308,6 +308,7 @@
#if !OS(WINDOWS)
#define HAVE_STACK_BOUNDS_FOR_NEW_THREAD 1
+#define HAVE_MEMMEM 1
#endif
#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(MACCATALYST)
Modified: trunk/Source/WTF/wtf/StringExtras.h (266086 => 266087)
--- trunk/Source/WTF/wtf/StringExtras.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/StringExtras.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -43,3 +43,19 @@
}
#endif
+
+#if !HAVE(MEMMEM)
+
+inline const void* memmem(const void* haystack, size_t haystackLength, const void* needle, size_t needleLength)
+{
+ const char* pointer = static_cast<const char*>(haystack);
+ while (haystackLength >= needleLength) {
+ if (!memcmp(pointer, needle, needleLength))
+ return pointer;
+ pointer++;
+ haystackLength--;
+ }
+ return nullptr;
+}
+
+#endif
Modified: trunk/Source/WTF/wtf/URLParser.cpp (266086 => 266087)
--- trunk/Source/WTF/wtf/URLParser.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/URLParser.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -2773,7 +2773,7 @@
if (utf8.isNull())
return WTF::nullopt;
auto percentDecoded = percentDecode(reinterpret_cast<const LChar*>(utf8.data()), utf8.length());
- return String::fromUTF8(percentDecoded.data(), percentDecoded.size());
+ return String::fromUTF8ReplacingInvalidSequences(percentDecoded.data(), percentDecoded.size());
}
// https://url.spec.whatwg.org/#concept-urlencoded-parser
Modified: trunk/Source/WTF/wtf/text/WTFString.cpp (266086 => 266087)
--- trunk/Source/WTF/wtf/text/WTFString.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/text/WTFString.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -844,9 +844,10 @@
return result;
}
-String String::fromUTF8(const LChar* stringStart, size_t length)
+template<bool replaceInvalidSequences>
+String fromUTF8Impl(const LChar* stringStart, size_t length)
{
- if (length > MaxLength)
+ if (length > StringImplShape::MaxLength)
CRASH();
if (!stringStart)
@@ -863,14 +864,25 @@
UChar* bufferCurrent = bufferStart;
const char* stringCurrent = reinterpret_cast<const char*>(stringStart);
- if (!convertUTF8ToUTF16(stringCurrent, reinterpret_cast<const char *>(stringStart + length), &bufferCurrent, bufferCurrent + buffer.size()))
+ constexpr auto function = replaceInvalidSequences ? convertUTF8ToUTF16ReplacingInvalidSequences : convertUTF8ToUTF16;
+ if (!function(stringCurrent, reinterpret_cast<const char*>(stringStart + length), &bufferCurrent, bufferCurrent + buffer.size(), nullptr))
return String();
unsigned utf16Length = bufferCurrent - bufferStart;
- ASSERT_WITH_SECURITY_IMPLICATION(utf16Length < length);
+ RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(utf16Length <= length);
return StringImpl::create(bufferStart, utf16Length);
}
+String String::fromUTF8(const LChar* stringStart, size_t length)
+{
+ return fromUTF8Impl<false>(stringStart, length);
+}
+
+String String::fromUTF8ReplacingInvalidSequences(const LChar* characters, size_t length)
+{
+ return fromUTF8Impl<true>(characters, length);
+}
+
String String::fromUTF8(const LChar* string)
{
if (!string)
Modified: trunk/Source/WTF/wtf/text/WTFString.h (266086 => 266087)
--- trunk/Source/WTF/wtf/text/WTFString.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/text/WTFString.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -350,6 +350,7 @@
static String fromUTF8(const char* string) { return fromUTF8(reinterpret_cast<const LChar*>(string)); };
WTF_EXPORT_PRIVATE static String fromUTF8(const CString&);
static String fromUTF8(const Vector<LChar>& characters);
+ static String fromUTF8ReplacingInvalidSequences(const LChar*, size_t);
// Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8.
WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(const LChar*, size_t);
Modified: trunk/Source/WTF/wtf/unicode/UTF8Conversion.cpp (266086 => 266087)
--- trunk/Source/WTF/wtf/unicode/UTF8Conversion.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/unicode/UTF8Conversion.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -87,7 +87,8 @@
return result;
}
-bool convertUTF8ToUTF16(const char* source, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* sourceAllASCII)
+template<bool replaceInvalidSequences>
+bool convertUTF8ToUTF16Impl(const char* source, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* sourceAllASCII)
{
RELEASE_ASSERT(sourceEnd - source <= std::numeric_limits<int>::max());
UBool error = false;
@@ -97,7 +98,11 @@
int targetOffset = 0;
for (int sourceOffset = 0; sourceOffset < sourceEnd - source; ) {
UChar32 character;
- U8_NEXT(reinterpret_cast<const uint8_t*>(source), sourceOffset, sourceEnd - source, character);
+ if constexpr (replaceInvalidSequences) {
+ U8_NEXT_OR_FFFD(reinterpret_cast<const uint8_t*>(source), sourceOffset, sourceEnd - source, character);
+ } else {
+ U8_NEXT(reinterpret_cast<const uint8_t*>(source), sourceOffset, sourceEnd - source, character);
+ }
if (character < 0)
return false;
U16_APPEND(target, targetOffset, targetEnd - target, character, error);
@@ -112,6 +117,16 @@
return true;
}
+bool convertUTF8ToUTF16(const char* source, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* sourceAllASCII)
+{
+ return convertUTF8ToUTF16Impl<false>(source, sourceEnd, targetStart, targetEnd, sourceAllASCII);
+}
+
+bool convertUTF8ToUTF16ReplacingInvalidSequences(const char* source, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* sourceAllASCII)
+{
+ return convertUTF8ToUTF16Impl<true>(source, sourceEnd, targetStart, targetEnd, sourceAllASCII);
+}
+
unsigned calculateStringHashAndLengthFromUTF8MaskingTop8Bits(const char* data, const char* dataEnd, unsigned& dataLength, unsigned& utf16Length)
{
StringHasher stringHasher;
Modified: trunk/Source/WTF/wtf/unicode/UTF8Conversion.h (266086 => 266087)
--- trunk/Source/WTF/wtf/unicode/UTF8Conversion.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WTF/wtf/unicode/UTF8Conversion.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -45,6 +45,7 @@
// at the end of the source, which will instead cause a SourceExhausted error.
WTF_EXPORT_PRIVATE bool convertUTF8ToUTF16(const char* sourceStart, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* isSourceAllASCII = nullptr);
+WTF_EXPORT_PRIVATE bool convertUTF8ToUTF16ReplacingInvalidSequences(const char* sourceStart, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* isSourceAllASCII = nullptr);
WTF_EXPORT_PRIVATE bool convertLatin1ToUTF8(const LChar** sourceStart, const LChar* sourceEnd, char** targetStart, char* targetEnd);
WTF_EXPORT_PRIVATE ConversionResult convertUTF16ToUTF8(const UChar** sourceStart, const UChar* sourceEnd, char** targetStart, char* targetEnd, bool strict = true);
Modified: trunk/Source/WebCore/ChangeLog (266086 => 266087)
--- trunk/Source/WebCore/ChangeLog 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/ChangeLog 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,3 +1,23 @@
+2020-08-24 Alex Christensen <achristen...@webkit.org>
+
+ Implement Request/Response consuming as FormData
+ https://bugs.webkit.org/show_bug.cgi?id=215671
+
+ Reviewed by Darin Adler.
+
+ Covered by many newly passing WPT tests, for most of which Safari was the only failing browser.
+
+ * Modules/fetch/FetchBody.cpp:
+ (WebCore::FetchBody::formData):
+ (WebCore::FetchBody::consume):
+ (WebCore::FetchBody::consumeFormData):
+ * Modules/fetch/FetchBody.h:
+ * Modules/fetch/FetchBodyConsumer.cpp:
+ (WebCore::formDataFromData):
+ (WebCore::resolveWithTypeAndData):
+ (WebCore::FetchBodyConsumer::resolve):
+ * Modules/fetch/FetchBodyConsumer.h:
+
2020-08-24 Emilio Cobos Álvarez <emi...@crisal.io>
Support quotes:auto and fix quotes serialization.
Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -35,6 +35,7 @@
#include "FetchHeaders.h"
#include "HTTPHeaderValues.h"
#include "HTTPParsers.h"
+#include "JSDOMFormData.h"
#include "JSDOMPromiseDeferred.h"
#include "ReadableStreamSource.h"
#include <_javascript_Core/ArrayBufferView.h>
@@ -130,9 +131,10 @@
consume(owner, WTFMove(promise));
}
-void FetchBody::formData(FetchBodyOwner&, Ref<DeferredPromise>&& promise)
+void FetchBody::formData(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
{
- promise.get().reject(NotSupportedError);
+ m_consumer.setType(FetchBodyConsumer::Type::FormData);
+ consume(owner, WTFMove(promise));
}
void FetchBody::consumeOnceLoadingFinished(FetchBodyConsumer::Type type, Ref<DeferredPromise>&& promise, const String& contentType)
@@ -146,19 +148,19 @@
void FetchBody::consume(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
{
if (isArrayBuffer()) {
- consumeArrayBuffer(WTFMove(promise));
+ consumeArrayBuffer(owner, WTFMove(promise));
return;
}
if (isArrayBufferView()) {
- consumeArrayBufferView(WTFMove(promise));
+ consumeArrayBufferView(owner, WTFMove(promise));
return;
}
if (isText()) {
- consumeText(WTFMove(promise), textBody());
+ consumeText(owner, WTFMove(promise), textBody());
return;
}
if (isURLSearchParams()) {
- consumeText(WTFMove(promise), urlSearchParamsBody().toString());
+ consumeText(owner, WTFMove(promise), urlSearchParamsBody().toString());
return;
}
if (isBlob()) {
@@ -166,12 +168,11 @@
return;
}
if (isFormData()) {
- // FIXME: Support consuming FormData.
- promise->reject(NotSupportedError);
+ consumeFormData(owner, WTFMove(promise));
return;
}
- m_consumer.resolve(WTFMove(promise), m_readableStream.get());
+ m_consumer.resolve(WTFMove(promise), owner.contentType(), m_readableStream.get());
}
void FetchBody::consumeAsStream(FetchBodyOwner& owner, FetchBodySource& source)
@@ -205,22 +206,22 @@
source.close();
}
-void FetchBody::consumeArrayBuffer(Ref<DeferredPromise>&& promise)
+void FetchBody::consumeArrayBuffer(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
{
- m_consumer.resolveWithData(WTFMove(promise), static_cast<const uint8_t*>(arrayBufferBody().data()), arrayBufferBody().byteLength());
+ m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), static_cast<const uint8_t*>(arrayBufferBody().data()), arrayBufferBody().byteLength());
m_data = nullptr;
}
-void FetchBody::consumeArrayBufferView(Ref<DeferredPromise>&& promise)
+void FetchBody::consumeArrayBufferView(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
{
- m_consumer.resolveWithData(WTFMove(promise), static_cast<const uint8_t*>(arrayBufferViewBody().baseAddress()), arrayBufferViewBody().byteLength());
+ m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), static_cast<const uint8_t*>(arrayBufferViewBody().baseAddress()), arrayBufferViewBody().byteLength());
m_data = nullptr;
}
-void FetchBody::consumeText(Ref<DeferredPromise>&& promise, const String& text)
+void FetchBody::consumeText(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise, const String& text)
{
auto data = "" UnencodableHandling::Entities);
- m_consumer.resolveWithData(WTFMove(promise), data.data(), data.size());
+ m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), data.data(), data.size());
m_data = nullptr;
}
@@ -231,14 +232,26 @@
m_data = nullptr;
}
+void FetchBody::consumeFormData(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
+{
+ if (auto sharedBuffer = formDataBody().asSharedBuffer()) {
+ m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), sharedBuffer->dataAsUInt8Ptr(), 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);
+ }
+}
+
void FetchBody::loadingFailed(const Exception& exception)
{
m_consumer.loadingFailed(exception);
}
-void FetchBody::loadingSucceeded()
+void FetchBody::loadingSucceeded(const String& contentType)
{
- m_consumer.loadingSucceeded();
+ m_consumer.loadingSucceeded(contentType);
}
RefPtr<FormData> FetchBody::bodyAsFormData() const
Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.h (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBody.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -60,7 +60,7 @@
WEBCORE_EXPORT static Optional<FetchBody> fromFormData(FormData&);
void loadingFailed(const Exception&);
- void loadingSucceeded();
+ void loadingSucceeded(const String& contentType);
RefPtr<FormData> bodyAsFormData() const;
@@ -99,10 +99,11 @@
void consume(FetchBodyOwner&, Ref<DeferredPromise>&&);
- void consumeArrayBuffer(Ref<DeferredPromise>&&);
- void consumeArrayBufferView(Ref<DeferredPromise>&&);
- void consumeText(Ref<DeferredPromise>&&, const String&);
+ void consumeArrayBuffer(FetchBodyOwner&, Ref<DeferredPromise>&&);
+ void consumeArrayBufferView(FetchBodyOwner&, Ref<DeferredPromise>&&);
+ void consumeText(FetchBodyOwner&, Ref<DeferredPromise>&&, const String&);
void consumeBlob(FetchBodyOwner&, Ref<DeferredPromise>&&);
+ void consumeFormData(FetchBodyOwner&, Ref<DeferredPromise>&&);
bool isArrayBuffer() const { return WTF::holds_alternative<Ref<const ArrayBuffer>>(m_data); }
bool isArrayBufferView() const { return WTF::holds_alternative<Ref<const ArrayBufferView>>(m_data); }
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -29,9 +29,12 @@
#include "config.h"
#include "FetchBodyConsumer.h"
+#include "HTTPHeaderField.h"
#include "JSBlob.h"
#include "ReadableStreamChunk.h"
#include "TextResourceDecoder.h"
+#include <wtf/StringExtras.h>
+#include <wtf/URLParser.h>
namespace WebCore {
@@ -39,9 +42,175 @@
{
Vector<uint8_t> value(length);
memcpy(value.data(), data, length);
- return Blob::create(WTFMove(value), contentType);
+ return Blob::create(WTFMove(value), Blob::normalizedContentType(contentType));
}
+// https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
+static bool isHTTPQuotedStringTokenCodePoint(UChar c)
+{
+ return c == 0x09
+ || (c >= 0x20 && c <= 0x7E)
+ || (c >= 0x80 && c <= 0xFF);
+}
+
+struct MimeType {
+ String type;
+ String subtype;
+ HashMap<String, String> parameters;
+};
+
+static HashMap<String, String> parseParameters(StringView input, size_t position)
+{
+ HashMap<String, String> parameters;
+ while (position < input.length()) {
+ while (position < input.length() && RFC7230::isWhitespace(input[position]))
+ position++;
+ size_t nameBegin = position;
+ while (position < input.length() && input[position] != '=' && input[position] != ';')
+ position++;
+ if (position >= input.length())
+ break;
+ if (input[position] == ';') {
+ position++;
+ continue;
+ }
+ StringView parameterName = input.substring(nameBegin, position - nameBegin);
+ position++;
+ if (position >= input.length())
+ break;
+
+ StringView parameterValue;
+ if (position < input.length() && input[position] == '"') {
+ position++;
+ size_t valueBegin = position;
+ while (position < input.length() && input[position] != '"')
+ position++;
+ parameterValue = input.substring(valueBegin, position - valueBegin);
+ position++;
+ } else {
+ size_t valueBegin = position;
+ while (position < input.length() && input[position] != ';')
+ position++;
+ parameterValue = stripLeadingAndTrailingHTTPSpaces(input.substring(valueBegin, position - valueBegin));
+ }
+
+ if (parameterName.length()
+ && isValidHTTPToken(parameterName)
+ && parameterValue.isAllSpecialCharacters<isHTTPQuotedStringTokenCodePoint>()) {
+ String nameString = parameterName.toString();
+ if (!parameters.contains(nameString))
+ parameters.set(nameString, parameterValue.toString());
+ }
+ }
+ return parameters;
+}
+
+// https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
+static Optional<MimeType> parseMIMEType(const String& contentType)
+{
+ String input = stripLeadingAndTrailingHTTPSpaces(contentType);
+ size_t slashIndex = input.find('/');
+ if (slashIndex == notFound)
+ return WTF::nullopt;
+
+ String type = input.substring(0, slashIndex);
+ if (!type.length() || !isValidHTTPToken(type))
+ return WTF::nullopt;
+
+ size_t semicolonIndex = input.find(';', slashIndex);
+ String subtype = stripLeadingAndTrailingHTTPSpaces(input.substring(slashIndex + 1, semicolonIndex - slashIndex - 1));
+ if (!subtype.length() || !isValidHTTPToken(subtype))
+ return WTF::nullopt;
+
+ return {{ WTFMove(type), WTFMove(subtype), parseParameters(StringView(input), semicolonIndex + 1) }};
+}
+
+// https://fetch.spec.whatwg.org/#concept-body-package-data
+static RefPtr<DOMFormData> packageFormData(const String& contentType, const char* data, size_t length)
+{
+ auto parseMultipartPart = [] (const char* part, size_t partLength, DOMFormData& form) -> bool {
+ const char* headerEnd = static_cast<const char*>(memmem(part, partLength, "\r\n\r\n", 4));
+ if (!headerEnd)
+ return false;
+ const char* headerBegin = part;
+ size_t headerLength = headerEnd - headerBegin;
+
+ const char* bodyBegin = headerEnd + strlen("\r\n\r\n");
+ size_t bodyLength = partLength - (bodyBegin - headerBegin);
+
+ String header = String::fromUTF8(headerBegin, headerLength);
+
+ const char* contentDispositionCharacters = "Content-Disposition:";
+ size_t contentDispositionBegin = header.find(contentDispositionCharacters);
+ if (contentDispositionBegin == notFound)
+ return false;
+ size_t contentDispositionEnd = header.find("\r\n", contentDispositionBegin);
+ size_t contentDispositionParametersBegin = header.find(';', contentDispositionBegin + strlen(contentDispositionCharacters));
+ if (contentDispositionParametersBegin != notFound)
+ contentDispositionParametersBegin++;
+
+ auto parameters = parseParameters(StringView(header).substring(contentDispositionParametersBegin, contentDispositionEnd - contentDispositionParametersBegin), 0);
+ String name = parameters.get("name");
+ if (!name)
+ return false;
+ String filename = parameters.get("filename");
+ if (!filename)
+ form.append(name, String::fromUTF8(bodyBegin, bodyLength));
+ else {
+ String contentType = "text/plain"_s;
+
+ const char* contentTypeCharacters = "Content-Type:";
+ size_t contentTypePrefixLength = strlen(contentTypeCharacters);
+ size_t contentTypeBegin = header.find(contentTypeCharacters);
+ if (contentTypeBegin != notFound) {
+ size_t contentTypeEnd = header.find("\r\n", contentTypeBegin);
+ contentType = stripLeadingAndTrailingHTTPSpaces(header.substring(contentTypeBegin + contentTypePrefixLength, contentTypeEnd - contentTypeBegin - contentTypePrefixLength));
+ }
+
+ form.append(name, File::create(Blob::create(SharedBuffer::create(bodyBegin, bodyLength).get(), Blob::normalizedContentType(contentType)).get(), filename).get(), filename);
+ }
+ return true;
+ };
+
+ auto parseMultipartBoundary = [] (const Optional<MimeType>& mimeType) -> Optional<String> {
+ if (!mimeType)
+ return WTF::nullopt;
+ if (equalIgnoringASCIICase(mimeType->type, "multipart") && equalIgnoringASCIICase(mimeType->subtype, "form-data")) {
+ auto iterator = mimeType->parameters.find("boundary"_s);
+ if (iterator != mimeType->parameters.end())
+ return iterator->value;
+ }
+ return WTF::nullopt;
+ };
+
+ auto form = DOMFormData::create(UTF8Encoding());
+ auto mimeType = parseMIMEType(contentType);
+ if (auto multipartBoundary = parseMultipartBoundary(mimeType)) {
+ String boundaryWithDashes = makeString("--", *multipartBoundary);
+ const char* boundary = boundaryWithDashes.utf8().data();
+ size_t boundaryLength = strlen(boundary);
+
+ const char* currentBoundary = static_cast<const char*>(memmem(data, length, boundary, boundaryLength));
+ if (!currentBoundary)
+ return nullptr;
+ const char* nextBoundary = static_cast<const char*>(memmem(currentBoundary + boundaryLength, length - (currentBoundary + boundaryLength - data), boundary, boundaryLength));
+ if (!nextBoundary)
+ return nullptr;
+ while (nextBoundary) {
+ parseMultipartPart(currentBoundary + boundaryLength, nextBoundary - currentBoundary - boundaryLength - strlen("\r\n"), form.get());
+ currentBoundary = nextBoundary;
+ nextBoundary = static_cast<const char*>(memmem(nextBoundary + boundaryLength, length - (nextBoundary + boundaryLength - data), boundary, boundaryLength));
+ }
+ } else if (mimeType && equalIgnoringASCIICase(mimeType->type, "application") && equalIgnoringASCIICase(mimeType->subtype, "x-www-form-urlencoded")) {
+ auto dataString = String::fromUTF8(data, length);
+ for (auto& pair : WTF::URLParser::parseURLEncodedForm(dataString))
+ form->append(pair.key, pair.value);
+ } else
+ return nullptr;
+
+ return form;
+}
+
static void resolveWithTypeAndData(Ref<DeferredPromise>&& promise, FetchBodyConsumer::Type type, const String& contentType, const unsigned char* data, unsigned length)
{
switch (type) {
@@ -59,6 +228,12 @@
case FetchBodyConsumer::Type::Text:
promise->resolve<IDLDOMString>(TextResourceDecoder::textFromUTF8(data, length));
return;
+ case FetchBodyConsumer::Type::FormData:
+ if (auto formData = packageFormData(contentType, reinterpret_cast<const char*>(data), length))
+ promise->resolve<IDLInterface<DOMFormData>>(*formData);
+ else
+ promise->reject(TypeError);
+ return;
case FetchBodyConsumer::Type::None:
ASSERT_NOT_REACHED();
return;
@@ -75,9 +250,9 @@
}
}
-void FetchBodyConsumer::resolveWithData(Ref<DeferredPromise>&& promise, const unsigned char* data, unsigned length)
+void FetchBodyConsumer::resolveWithData(Ref<DeferredPromise>&& promise, const String& contentType, const unsigned char* data, unsigned length)
{
- resolveWithTypeAndData(WTFMove(promise), m_type, m_contentType, data, length);
+ resolveWithTypeAndData(WTFMove(promise), m_type, contentType, data, length);
}
void FetchBodyConsumer::extract(ReadableStream& stream, ReadableStreamToSharedBufferSink::Callback&& callback)
@@ -87,11 +262,11 @@
m_sink->pipeFrom(stream);
}
-void FetchBodyConsumer::resolve(Ref<DeferredPromise>&& promise, ReadableStream* stream)
+void FetchBodyConsumer::resolve(Ref<DeferredPromise>&& promise, const String& contentType, ReadableStream* stream)
{
if (stream) {
ASSERT(!m_sink);
- m_sink = ReadableStreamToSharedBufferSink::create([promise = WTFMove(promise), data = "" type = m_type, contentType = m_contentType](auto&& result) mutable {
+ m_sink = ReadableStreamToSharedBufferSink::create([promise = WTFMove(promise), data = "" type = m_type, contentType](auto&& result) mutable {
if (result.hasException()) {
promise->reject(result.releaseException());
return;
@@ -127,6 +302,14 @@
case Type::Text:
promise->resolve<IDLDOMString>(takeAsText());
return;
+ case FetchBodyConsumer::Type::FormData: {
+ auto buffer = takeData();
+ if (auto formData = packageFormData(contentType, buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0))
+ promise->resolve<IDLInterface<DOMFormData>>(*formData);
+ else
+ promise->reject(TypeError);
+ return;
+ }
case Type::None:
ASSERT_NOT_REACHED();
return;
@@ -169,7 +352,7 @@
Ref<Blob> FetchBodyConsumer::takeAsBlob()
{
if (!m_buffer)
- return Blob::create(Vector<uint8_t>(), m_contentType);
+ return Blob::create(Vector<uint8_t>(), Blob::normalizedContentType(m_contentType));
// FIXME: We should try to move m_buffer to Blob without doing extra copy.
return blobFromData(reinterpret_cast<const unsigned char*>(m_buffer->data()), m_buffer->size(), m_contentType);
@@ -221,16 +404,16 @@
}
}
-void FetchBodyConsumer::loadingSucceeded()
+void FetchBodyConsumer::loadingSucceeded(const String& contentType)
{
m_isLoading = false;
if (m_consumePromise) {
if (!m_userGestureToken || m_userGestureToken->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()) || !m_userGestureToken->processingUserGesture())
- resolve(m_consumePromise.releaseNonNull(), nullptr);
+ resolve(m_consumePromise.releaseNonNull(), contentType, nullptr);
else {
UserGestureIndicator gestureIndicator(m_userGestureToken, UserGestureToken::GestureScope::MediaOnly, UserGestureToken::IsPropagatedFromFetch::Yes);
- resolve(m_consumePromise.releaseNonNull(), nullptr);
+ resolve(m_consumePromise.releaseNonNull(), contentType, nullptr);
}
}
if (m_source) {
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -42,7 +42,7 @@
class FetchBodyConsumer {
public:
- enum class Type { None, ArrayBuffer, Blob, JSON, Text };
+ enum class Type { None, ArrayBuffer, Blob, JSON, Text, FormData };
explicit FetchBodyConsumer(Type type) : m_type(type) { }
@@ -63,11 +63,11 @@
void clean();
void extract(ReadableStream&, ReadableStreamToSharedBufferSink::Callback&&);
- void resolve(Ref<DeferredPromise>&&, ReadableStream*);
- void resolveWithData(Ref<DeferredPromise>&&, const unsigned char*, unsigned);
+ void resolve(Ref<DeferredPromise>&&, const String& contentType, ReadableStream*);
+ void resolveWithData(Ref<DeferredPromise>&&, const String& contentType, const unsigned char*, unsigned);
void loadingFailed(const Exception&);
- void loadingSucceeded();
+ void loadingSucceeded(const String& contentType);
void setConsumePromise(Ref<DeferredPromise>&&);
void setSource(Ref<FetchBodySource>&&);
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -270,7 +270,7 @@
m_readableStreamSource = nullptr;
}
- m_body->loadingSucceeded();
+ m_body->loadingSucceeded(contentType());
finishBlobLoading();
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -70,6 +70,8 @@
ResourceError loadingError() const;
Optional<Exception> loadingException() const;
+ const String& contentType() const { return m_contentType; }
+
protected:
const FetchBody& body() const { return *m_body; }
FetchBody& body() { return *m_body; }
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (266086 => 266087)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -273,7 +273,7 @@
void FetchResponse::BodyLoader::didSucceed()
{
ASSERT(m_response.hasPendingActivity());
- m_response.m_body->loadingSucceeded();
+ m_response.m_body->loadingSucceeded(m_response.contentType());
if (m_response.m_readableStreamSource) {
if (m_response.body().consumer().hasData())
Modified: trunk/Source/WebCore/platform/network/FormData.h (266086 => 266087)
--- trunk/Source/WebCore/platform/network/FormData.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/platform/network/FormData.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -228,7 +228,7 @@
const Vector<FormDataElement>& elements() const { return m_elements; }
const Vector<char>& boundary() const { return m_boundary; }
- RefPtr<SharedBuffer> asSharedBuffer() const;
+ WEBCORE_EXPORT RefPtr<SharedBuffer> asSharedBuffer() const;
bool alwaysStream() const { return m_alwaysStream; }
void setAlwaysStream(bool alwaysStream) { m_alwaysStream = alwaysStream; }
Modified: trunk/Source/WebCore/platform/network/HTTPParsers.cpp (266086 => 266087)
--- trunk/Source/WebCore/platform/network/HTTPParsers.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/platform/network/HTTPParsers.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -184,12 +184,11 @@
}
// See RFC 7230, Section 3.2.6.
-bool isValidHTTPToken(const String& value)
+bool isValidHTTPToken(StringView value)
{
if (value.isEmpty())
return false;
- auto valueStringView = StringView(value);
- for (UChar c : valueStringView.codeUnits()) {
+ for (UChar c : value.codeUnits()) {
if (!RFC7230::isTokenCharacter(c))
return false;
}
@@ -196,6 +195,11 @@
return true;
}
+bool isValidHTTPToken(const String& value)
+{
+ return isValidHTTPToken(StringView(value));
+}
+
#if USE(GLIB)
// True if the character at the given position satisifies a predicate, incrementing "pos" by one.
// Note: Might return pos == str.length()
Modified: trunk/Source/WebCore/platform/network/HTTPParsers.h (266086 => 266087)
--- trunk/Source/WebCore/platform/network/HTTPParsers.h 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebCore/platform/network/HTTPParsers.h 2020-08-24 22:36:02 UTC (rev 266087)
@@ -76,6 +76,7 @@
WEBCORE_EXPORT bool isValidUserAgentHeaderValue(const String&);
#endif
bool isValidHTTPToken(const String&);
+bool isValidHTTPToken(StringView);
Optional<WallTime> parseHTTPDate(const String&);
String filenameFromHTTPContentDisposition(const String&);
String extractMIMETypeFromMediaType(const String&);
Modified: trunk/Source/WebKit/ChangeLog (266086 => 266087)
--- trunk/Source/WebKit/ChangeLog 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebKit/ChangeLog 2020-08-24 22:36:02 UTC (rev 266087)
@@ -1,5 +1,18 @@
2020-08-24 Alex Christensen <achristen...@webkit.org>
+ Implement Request/Response consuming as FormData
+ https://bugs.webkit.org/show_bug.cgi?id=215671
+
+ Reviewed by Darin Adler.
+
+ * WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp:
+ (WebKit::WebServiceWorkerFetchTaskClient::didReceiveFormDataAndFinish):
+ Add a fast path that allows non-blob FormData responses from service workers to not hang.
+ This part is covered by this layout test:
+ imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-respond-with-custom-response.https.html
+
+2020-08-24 Alex Christensen <achristen...@webkit.org>
+
Make _WKWebsiteDataStoreConfiguration SPI for HSTS storage to replace _WKProcessPoolConfiguration.hstsStorageDirectory
https://bugs.webkit.org/show_bug.cgi?id=213048
Modified: trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp (266086 => 266087)
--- trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp 2020-08-24 21:41:43 UTC (rev 266086)
+++ trunk/Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp 2020-08-24 22:36:02 UTC (rev 266087)
@@ -89,6 +89,12 @@
void WebServiceWorkerFetchTaskClient::didReceiveFormDataAndFinish(Ref<FormData>&& formData)
{
+ if (auto sharedBuffer = formData->asSharedBuffer()) {
+ didReceiveData(sharedBuffer.releaseNonNull());
+ didFinish();
+ return;
+ }
+
if (!m_connection)
return;