Title: [205115] trunk
Revision
205115
Author
[email protected]
Date
2016-08-29 02:18:06 -0700 (Mon, 29 Aug 2016)

Log Message

[Fetch API] Add support for BufferSource bodies
https://bugs.webkit.org/show_bug.cgi?id=161087

Patch by Youenn Fablet <[email protected]> on 2016-08-29
Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/basic/request-headers-expected.txt:
* web-platform-tests/fetch/api/basic/request-headers-worker-expected.txt:
* web-platform-tests/fetch/api/basic/request-headers.js:
(checkContentType):
(requestHeaders): Change the order of the header checks so that passing headers are checked first.
* web-platform-tests/fetch/api/request/request-consume-expected.txt:
* web-platform-tests/fetch/api/request/request-consume.html:
* web-platform-tests/fetch/api/response/response-consume-stream-expected.txt:
* web-platform-tests/fetch/api/response/response-consume-stream.html:

Source/WebCore:

Covered by updated tests.

Added support for ArrayBuffer, ArrayBufferView and FormData upload.
Added support for consuming ArrayBufferView.

To support FormData upload, FetchBOdy is now storing a FormData computed from the DOMFormData passed to the constructor.
This allows setting the content-type for FormData correctly with the boundary parameter.

* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::bodyForInternalRequest): Adding support for FormData upload.
(WebCore::FetchBody::FetchBody): Adding ArrayBuffer and ArrayBufferView constructors.
(WebCore::FetchBody::extract): Extracting in case of BufferSource (i.e. ArrayBuffer or ArrayBufferView) and FormData.
(WebCore::FetchBody::consume): Adding support to consume ArrayBufferView.
(WebCore::FetchBody::consumeAsStream): Adding support to consume ArrayBufferView as a stream.
Cloned the ArrayBuffer before enqueuing it in  the stream.
(WebCore::FetchBody::consumeArrayBuffer): Cleaning m_data after being consumed.
(WebCore::FetchBody::consumeArrayBufferView): Adding support to consume ArrayBufferView.
(WebCore::FetchBody::consumeText): Cleaning m_text after being consumed.
(WebCore::FetchBody::consumeBlob): Ditto for m_blob.
(WebCore::FetchBody::bodyForInternalRequest): Adding support for ArrayBuffer and ArrayBufferView upload.
* Modules/fetch/FetchBody.h:
* Modules/fetch/FetchRequest.cpp:
(WebCore::FetchRequest::internalRequest): Passing ScriptExecutionContext as this is needed for FormData upload.
(WebCore::FetchRequest::setBody): Ditto.
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::initializeWith): Ditto.
(WebCore::FetchResponse::fetch): Removing FormData upload rejection check.

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2016-08-29 09:18:06 UTC (rev 205115)
@@ -1,5 +1,22 @@
 2016-08-29  Youenn Fablet  <[email protected]>
 
+        [Fetch API] Add support for BufferSource bodies
+        https://bugs.webkit.org/show_bug.cgi?id=161087
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/fetch/api/basic/request-headers-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-headers-worker-expected.txt:
+        * web-platform-tests/fetch/api/basic/request-headers.js:
+        (checkContentType):
+        (requestHeaders): Change the order of the header checks so that passing headers are checked first.
+        * web-platform-tests/fetch/api/request/request-consume-expected.txt:
+        * web-platform-tests/fetch/api/request/request-consume.html:
+        * web-platform-tests/fetch/api/response/response-consume-stream-expected.txt:
+        * web-platform-tests/fetch/api/response/response-consume-stream.html:
+
+2016-08-29  Youenn Fablet  <[email protected]>
+
         data:// URL behavior of XHR does not match spec
         https://bugs.webkit.org/show_bug.cgi?id=109199
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-expected.txt	2016-08-29 09:18:06 UTC (rev 205115)
@@ -1,13 +1,18 @@
 
 FAIL Fetch with GET assert_equals: Request should have header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
-FAIL Fetch with HEAD assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
+FAIL Fetch with HEAD assert_equals: Request should have header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
 PASS Fetch with PUT without body 
 PASS Fetch with PUT with body 
 PASS Fetch with POST without body 
 PASS Fetch with POST with text body 
-FAIL Fetch with POST with FormData body promise_test: Unhandled rejection with value: object "TypeError: Uploading FormData is not yet implemented"
+PASS Fetch with POST with FormData body 
 FAIL Fetch with POST with Blob body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
-FAIL Fetch with POST with ArrayBuffer body promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
 PASS Fetch with POST with Blob body with mime type 
 FAIL Fetch with Chicken assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
 PASS Fetch with Chicken with body 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-worker-expected.txt (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-worker-expected.txt	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers-worker-expected.txt	2016-08-29 09:18:06 UTC (rev 205115)
@@ -1,12 +1,17 @@
 
 FAIL Fetch with GET assert_equals: Request should have header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
-FAIL Fetch with HEAD assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
+FAIL Fetch with HEAD assert_equals: Request should have header origin: http://localhost:8800 expected (string) "http://localhost:8800" but got (object) null
 PASS Fetch with PUT without body 
 PASS Fetch with PUT with body 
 PASS Fetch with POST without body 
 PASS Fetch with POST with text body 
 FAIL Fetch with POST with Blob body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
-FAIL Fetch with POST with ArrayBuffer body promise_test: Unhandled rejection with value: object "TypeError: Type error"
+FAIL Fetch with POST with ArrayBuffer body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Uint8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Int8Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float32Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with Float64Array body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
+FAIL Fetch with POST with DataView body assert_equals: Request should have header content-type: null expected (object) null but got (string) "application/x-www-form-urlencoded"
 PASS Fetch with POST with Blob body with mime type 
 FAIL Fetch with Chicken assert_equals: Request should have header content-length: null expected (object) null but got (string) "0"
 PASS Fetch with Chicken with body 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers.js (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers.js	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/request-headers.js	2016-08-29 09:18:06 UTC (rev 205115)
@@ -11,7 +11,7 @@
     }
 
     var expectedContentType = "text/plain;charset=UTF-8";
-    if(body === null || body instanceof ArrayBuffer)
+    if(body === null || body instanceof ArrayBuffer || body.buffer instanceof ArrayBuffer)
         expectedContentType = null;
     else if (body instanceof Blob)
         expectedContentType = body.type ? body.type : null;
@@ -28,12 +28,12 @@
     return fetch(url + urlParameters, requestInit).then(function(resp) {
       assert_equals(resp.status, 200, "HTTP status is 200");
       assert_equals(resp.type , "basic", "Response's type is basic");
-      checkContentType(resp.headers.get("x-request-content-type"), body);
-      if (expectedContentLength !== undefined)
-        assert_equals(resp.headers.get("x-request-content-length") , expectedContentLength, "Request should have header content-length: " + expectedContentLength);
       assert_true(resp.headers.has("x-request-user-agent"), "Request has header user-agent");
       assert_false(resp.headers.has("accept-charset"), "Request has header accept-charset");
       assert_equals(resp.headers.get("x-request-origin") , expectedOrigin, "Request should have header origin: " + expectedOrigin);
+      if (expectedContentLength !== undefined)
+        assert_equals(resp.headers.get("x-request-content-length") , expectedContentLength, "Request should have header content-length: " + expectedContentLength);
+      checkContentType(resp.headers.get("x-request-content-type"), body);
     });
   }, desc);
 }
@@ -50,6 +50,11 @@
     requestHeaders("Fetch with POST with FormData body", url, "POST", new FormData(), location.origin);
 requestHeaders("Fetch with POST with Blob body", url, "POST", new Blob(["Test"]), location.origin, "4");
 requestHeaders("Fetch with POST with ArrayBuffer body", url, "POST", new ArrayBuffer(4), location.origin, "4");
+requestHeaders("Fetch with POST with Uint8Array body", url, "POST", new Uint8Array(4), location.origin, "4");
+requestHeaders("Fetch with POST with Int8Array body", url, "POST", new Int8Array(4), location.origin, "4");
+requestHeaders("Fetch with POST with Float32Array body", url, "POST", new Float32Array(1), location.origin, "4");
+requestHeaders("Fetch with POST with Float64Array body", url, "POST", new Float64Array(1), location.origin, "8");
+requestHeaders("Fetch with POST with DataView body", url, "POST", new DataView(new ArrayBuffer(8), 0, 4), location.origin, "4");
 requestHeaders("Fetch with POST with Blob body with mime type", url, "POST", new Blob(["Test"], { type: "text/maybe" }), location.origin, "4");
 requestHeaders("Fetch with Chicken", url, "Chicken", null, location.origin, null);
 requestHeaders("Fetch with Chicken with body", url, "Chicken", "Request's body", location.origin, "14");

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume-expected.txt	2016-08-29 09:18:06 UTC (rev 205115)
@@ -1,9 +1,29 @@
 
-PASS Consume request's body as text 
-PASS Consume request's body as blob 
-PASS Consume request's body as arrayBuffer 
-PASS Consume request's body as json 
-FAIL Consume request's body as formData promise_test: Unhandled rejection with value: undefined
+PASS Consume String request's body as text 
+PASS Consume String request's body as blob 
+PASS Consume String request's body as arrayBuffer 
+PASS Consume String request's body as JSON 
+PASS Consume ArrayBuffer request's body as text 
+PASS Consume ArrayBuffer request's body as blob 
+PASS Consume ArrayBuffer request's body as arrayBuffer 
+PASS Consume ArrayBuffer request's body as JSON 
+PASS Consume Uint8Array request's body as text 
+PASS Consume Uint8Array request's body as blob 
+PASS Consume Uint8Array request's body as arrayBuffer 
+PASS Consume Uint8Array request's body as JSON 
+PASS Consume Int8Array request's body as text 
+PASS Consume Int8Array request's body as blob 
+PASS Consume Int8Array request's body as arrayBuffer 
+PASS Consume Int8Array request's body as JSON 
+PASS Consume Float32Array request's body as text 
+PASS Consume Float32Array request's body as blob 
+PASS Consume Float32Array request's body as arrayBuffer 
+PASS Consume Float32Array request's body as JSON 
+PASS Consume DataView request's body as text 
+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: undefined
 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-consume.html (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume.html	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/request/request-consume.html	2016-08-29 09:18:06 UTC (rev 205115)
@@ -13,7 +13,7 @@
   <body>
     <script>
     function checkBodyText(request, expectedBody) {
-      return request.text().then( function(bodyAsText) {
+      return request.text().then(function(bodyAsText) {
         assert_equals(bodyAsText, expectedBody, "Retrieve and verify request's body");
         assert_true(request.bodyUsed, "body as text: bodyUsed turned true");
       });
@@ -63,25 +63,65 @@
      });
     }
 
-    function checkRequestBody(body, bodyType, checkFunction) {
+    function checkRequestBody(body, expected, bodyType) {
       promise_test(function(test) {
         var request = new Request("", {"method": "POST", "body": body, "headers": [["Content-Type", "text/PLAIN"]] });
         assert_false(request.bodyUsed, "bodyUsed is false at init");
-        return checkFunction(request, body);
-      }, "Consume request's body as " + bodyType);
+        return checkBodyText(request, expected);
+      }, "Consume " + bodyType  + " request's body as text");
+      promise_test(function(test) {
+        var request = new Request("", {"method": "POST", "body": body });
+        assert_false(request.bodyUsed, "bodyUsed is false at init");
+        return checkBodyBlob(request, expected);
+      }, "Consume " + bodyType  + " request's body as blob");
+      promise_test(function(test) {
+        var request = new Request("", {"method": "POST", "body": body });
+        assert_false(request.bodyUsed, "bodyUsed is false at init");
+        return checkBodyArrayBuffer(request, expected);
+      }, "Consume " + bodyType  + " request's body as arrayBuffer");
+      promise_test(function(test) {
+        var request = new Request("", {"method": "POST", "body": body });
+        assert_false(request.bodyUsed, "bodyUsed is false at init");
+        return checkBodyJSON(request, expected);
+      }, "Consume " + bodyType  + " request's body as JSON");
     }
 
-    var formData = new FormData();
-    formData.append("name", "value")
     var textData = JSON.stringify("This is response's body");
     var blob = new Blob([textData], { "type" : "text/plain" });
 
-    checkRequestBody(textData, "text", checkBodyText);
-    checkRequestBody(textData, "blob", function(request, body) { checkBodyBlob(request, body, true); });
-    checkRequestBody(textData, "arrayBuffer", checkBodyArrayBuffer);
-    checkRequestBody(textData, "json", checkBodyJSON);
-    checkRequestBody(formData, "formData", checkBodyFormData);
+    checkRequestBody(textData, textData, "String");
 
+    var string = "\"123456\"";
+    function getArrayBuffer() {
+        var arrayBuffer = new ArrayBuffer(8);
+        var int8Array = new Int8Array(arrayBuffer);
+        for (var cptr = 0; cptr < 8; cptr++)
+            int8Array[cptr] = string.charCodeAt(cptr);
+        return arrayBuffer;
+    }
+
+    function getArrayBufferWithZeros() {
+        var arrayBuffer = new ArrayBuffer(10);
+        var int8Array = new Int8Array(arrayBuffer);
+        for (var cptr = 0; cptr < 8; cptr++)
+            int8Array[cptr + 1] = string.charCodeAt(cptr);
+        return arrayBuffer;
+    }
+
+    checkRequestBody(getArrayBuffer(), string, "ArrayBuffer");
+    checkRequestBody(new Uint8Array(getArrayBuffer()), string, "Uint8Array");
+    checkRequestBody(new Int8Array(getArrayBufferWithZeros(), 1, 8), string, "Int8Array");
+    checkRequestBody(new Float32Array(getArrayBuffer()), string, "Float32Array");
+    checkRequestBody(new DataView(getArrayBufferWithZeros(), 1, 8), string, "DataView");
+
+    promise_test(function(test) {
+      var formData = new FormData();
+      formData.append("name", "value")
+      var request = new Request("", {"method": "POST", "body": formData });
+      assert_false(request.bodyUsed, "bodyUsed is false at init");
+      return checkBodyFormData(request, formData);
+    }, "Consume FormData request's body as FormData");
+
     function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) {
       promise_test(function(test) {
         var response = new Response(blobBody);

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


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream-expected.txt	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream-expected.txt	2016-08-29 09:18:06 UTC (rev 205115)
@@ -3,6 +3,7 @@
 PASS Read empty blob response's body as readableStream 
 PASS Read blob response's body as readableStream 
 PASS Read text 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: "not implemented"
 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.html (205114 => 205115)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.html	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.html	2016-08-29 09:18:06 UTC (rev 205115)
@@ -40,6 +40,15 @@
 }, "Read text response's body as readableStream");
 
 promise_test(function(test) {
+    var arrayBuffer = new ArrayBuffer(textData.length);
+    var int8Array = new Int8Array(arrayBuffer);
+    for (var cptr = 0; cptr < textData.length; cptr++)
+        int8Array[cptr] = textData.charCodeAt(cptr);
+
+    return validateStreamFromString(new Response(arrayBuffer).body.getReader(), textData);
+}, "Read array buffer response's body as readableStream");
+
+promise_test(function(test) {
     var response = new Response(formData);
     return validateStreamFromString(response.body.getReader(), "name=value");
 }, "Read form data response's body as readableStream");

Modified: trunk/Source/WebCore/ChangeLog (205114 => 205115)


--- trunk/Source/WebCore/ChangeLog	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/Source/WebCore/ChangeLog	2016-08-29 09:18:06 UTC (rev 205115)
@@ -1,3 +1,38 @@
+2016-08-29  Youenn Fablet  <[email protected]>
+
+        [Fetch API] Add support for BufferSource bodies
+        https://bugs.webkit.org/show_bug.cgi?id=161087
+
+        Reviewed by Darin Adler.
+
+        Covered by updated tests.
+
+        Added support for ArrayBuffer, ArrayBufferView and FormData upload.
+        Added support for consuming ArrayBufferView.
+
+        To support FormData upload, FetchBOdy is now storing a FormData computed from the DOMFormData passed to the constructor.
+        This allows setting the content-type for FormData correctly with the boundary parameter.
+
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::bodyForInternalRequest): Adding support for FormData upload.
+        (WebCore::FetchBody::FetchBody): Adding ArrayBuffer and ArrayBufferView constructors.
+        (WebCore::FetchBody::extract): Extracting in case of BufferSource (i.e. ArrayBuffer or ArrayBufferView) and FormData.
+        (WebCore::FetchBody::consume): Adding support to consume ArrayBufferView.
+        (WebCore::FetchBody::consumeAsStream): Adding support to consume ArrayBufferView as a stream.
+        Cloned the ArrayBuffer before enqueuing it in  the stream.
+        (WebCore::FetchBody::consumeArrayBuffer): Cleaning m_data after being consumed.
+        (WebCore::FetchBody::consumeArrayBufferView): Adding support to consume ArrayBufferView.
+        (WebCore::FetchBody::consumeText): Cleaning m_text after being consumed.
+        (WebCore::FetchBody::consumeBlob): Ditto for m_blob.
+        (WebCore::FetchBody::bodyForInternalRequest): Adding support for ArrayBuffer and ArrayBufferView upload.
+        * Modules/fetch/FetchBody.h:
+        * Modules/fetch/FetchRequest.cpp:
+        (WebCore::FetchRequest::internalRequest): Passing ScriptExecutionContext as this is needed for FormData upload.
+        (WebCore::FetchRequest::setBody): Ditto.
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::initializeWith): Ditto.
+        (WebCore::FetchResponse::fetch): Removing FormData upload rejection check.
+
 2016-08-26  Sergio Villar Senin  <[email protected]>
 
         [css-grid] Do not recursively call layout during auto repeat computation

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (205114 => 205115)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2016-08-29 09:18:06 UTC (rev 205115)
@@ -42,6 +42,7 @@
 #include "JSDOMFormData.h"
 #include "JSReadableStream.h"
 #include "ReadableStreamSource.h"
+#include <runtime/ArrayBufferView.h>
 
 namespace WebCore {
 
@@ -52,12 +53,12 @@
 {
 }
 
-FetchBody::FetchBody(Ref<DOMFormData>&& formData)
+FetchBody::FetchBody(DOMFormData& formData, Document& document)
     : m_type(Type::FormData)
     , m_contentType(ASCIILiteral("multipart/form-data"))
-    , m_formData(WTFMove(formData))
 {
-    // FIXME: Handle the boundary parameter of multipart/form-data MIME type.
+    m_formData = FormData::createMultiPart(formData, formData.encoding(), &document);
+    m_contentType = makeString("multipart/form-data;boundary=", m_formData->boundary().data());
 }
 
 FetchBody::FetchBody(String&& text)
@@ -67,17 +68,40 @@
 {
 }
 
-FetchBody FetchBody::extract(JSC::ExecState& state, JSC::JSValue value)
+FetchBody::FetchBody(Ref<ArrayBuffer>&& data)
+    : m_type(Type::ArrayBuffer)
+    , m_data(WTFMove(data))
 {
+}
+
+FetchBody::FetchBody(Ref<ArrayBufferView>&& dataView)
+    : m_type(Type::ArrayBufferView)
+    , m_dataView(WTFMove(dataView))
+{
+}
+
+FetchBody FetchBody::extract(ScriptExecutionContext& context, JSC::ExecState& state, JSC::JSValue value)
+{
     if (value.inherits(JSBlob::info()))
         return FetchBody(*JSBlob::toWrapped(value));
-    if (value.inherits(JSDOMFormData::info()))
-        return FetchBody(*JSDOMFormData::toWrapped(value));
+    if (value.inherits(JSDOMFormData::info())) {
+        ASSERT(!context.isWorkerGlobalScope());
+        return FetchBody(*JSDOMFormData::toWrapped(value), static_cast<Document&>(context));
+    }
     if (value.isString())
         return FetchBody(value.toWTFString(&state));
     if (value.inherits(JSReadableStream::info()))
         return { Type::ReadableStream };
-    // FIXME: Implement BufferSource extraction.
+    if (value.inherits(JSC::JSArrayBuffer::info())) {
+        ArrayBuffer* data = ""
+        ASSERT(data);
+        return { *data };
+    }
+    if (value.inherits(JSC::JSArrayBufferView::info())) {
+        RefPtr<JSC::ArrayBufferView> data = ""
+        ASSERT(data);
+        return { data.releaseNonNull() };
+    }
     return { };
 }
 
@@ -150,6 +174,9 @@
     case Type::ArrayBuffer:
         consumeArrayBuffer(promise);
         return;
+    case Type::ArrayBufferView:
+        consumeArrayBufferView(promise);
+        return;
     case Type::Text:
         consumeText(promise);
         return;
@@ -162,9 +189,12 @@
     case Type::Loaded:
         m_consumer.resolve(promise);
         return;
+    case Type::FormData:
+        // FIXME: Support consuming FormData.
+        promise.reject(0);
+        return;
     default:
-        // FIXME: Support other types.
-        promise.reject(0);
+        ASSERT_NOT_REACHED();
     }
 }
 
@@ -180,16 +210,25 @@
     switch (m_type) {
     case Type::ArrayBuffer:
         ASSERT(m_data);
-        closeStream = source.enqueue(RefPtr<JSC::ArrayBuffer>(m_data));
+        closeStream = source.enqueue(ArrayBuffer::tryCreate(m_data->data(), m_data->byteLength()));
+        m_data = nullptr;
         break;
+    case Type::ArrayBufferView: {
+        ASSERT(m_dataView);
+        closeStream = source.enqueue(ArrayBuffer::tryCreate(m_dataView->baseAddress(), m_dataView->byteLength()));
+        m_dataView = nullptr;
+        break;
+    }
     case Type::Text: {
         Vector<uint8_t> data = ""
         closeStream = source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size()));
+        m_text = { };
         break;
     }
     case Type::Blob:
         ASSERT(m_blob);
         owner.loadBlob(*m_blob, nullptr);
+        m_blob = nullptr;
         break;
     case Type::None:
         closeStream = true;
@@ -209,13 +248,23 @@
 
 void FetchBody::consumeArrayBuffer(DeferredWrapper& promise)
 {
+    ASSERT(m_data);
     m_consumer.resolveWithData(promise, static_cast<const uint8_t*>(m_data->data()), m_data->byteLength());
+    m_data = nullptr;
 }
 
+void FetchBody::consumeArrayBufferView(DeferredWrapper& promise)
+{
+    ASSERT(m_dataView);
+    m_consumer.resolveWithData(promise, static_cast<const uint8_t*>(m_dataView->baseAddress()), m_dataView->byteLength());
+    m_dataView = nullptr;
+}
+
 void FetchBody::consumeText(DeferredWrapper& promise)
 {
     Vector<uint8_t> data = ""
     m_consumer.resolveWithData(promise, data.data(), data.size());
+    m_text = { };
 }
 
 void FetchBody::consumeBlob(FetchBodyOwner& owner, DeferredWrapper&& promise)
@@ -224,6 +273,7 @@
 
     m_consumePromise = WTFMove(promise);
     owner.loadBlob(*m_blob, &m_consumer);
+    m_blob = nullptr;
 }
 
 Vector<uint8_t> FetchBody::extractFromText() const
@@ -253,19 +303,36 @@
     }
 }
 
-RefPtr<FormData> FetchBody::bodyForInternalRequest() const
+RefPtr<FormData> FetchBody::bodyForInternalRequest(ScriptExecutionContext& context) const
 {
-    if (m_type == Type::None)
+    switch (m_type) {
+    case Type::None:
         return nullptr;
-    if (m_type == Type::Text)
+    case Type::Text:
         return FormData::create(UTF8Encoding().encode(m_text, EntitiesForUnencodables));
-    if (m_type == Type::Blob) {
+    case Type::Blob: {
+        ASSERT(m_blob);
         RefPtr<FormData> body = FormData::create();
         body->appendBlob(m_blob->url());
         return body;
     }
-    ASSERT_NOT_REACHED();
-    return nullptr;
+    case Type::ArrayBuffer:
+        ASSERT(m_data);
+        return FormData::create(m_data->data(), m_data->byteLength());
+    case Type::ArrayBufferView:
+        ASSERT(m_dataView);
+        return FormData::create(m_dataView->baseAddress(), m_dataView->byteLength());
+    case Type::FormData: {
+        ASSERT(m_formData);
+        ASSERT(!context.isWorkerGlobalScope());
+        auto body = m_formData;
+        body->generateFiles(static_cast<Document*>(&context));
+        return body;
+    }
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
 }
 
 }

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.h (205114 => 205115)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.h	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.h	2016-08-29 09:18:06 UTC (rev 205115)
@@ -32,9 +32,9 @@
 #if ENABLE(FETCH_API)
 
 #include "Blob.h"
-#include "DOMFormData.h"
 #include "FetchBodyConsumer.h"
 #include "FetchLoader.h"
+#include "FormData.h"
 #include "JSDOMPromise.h"
 
 namespace JSC {
@@ -44,10 +44,11 @@
 
 namespace WebCore {
 
+class DOMFormData;
 class FetchBodyOwner;
 class FetchHeaders;
 class FetchResponseSource;
-class FormData;
+class ScriptExecutionContext;
 
 class FetchBody {
 public:
@@ -67,7 +68,7 @@
     void setContentType(const String& contentType) { m_contentType = contentType; }
     String contentType() const { return m_contentType; }
 
-    static FetchBody extract(JSC::ExecState&, JSC::JSValue);
+    static FetchBody extract(ScriptExecutionContext&, JSC::ExecState&, JSC::JSValue);
     static FetchBody extractFromBody(FetchBody*);
     static FetchBody loadingBody() { return { Type::Loading }; }
     FetchBody() = default;
@@ -75,9 +76,9 @@
     void loadingFailed();
     void loadingSucceeded();
 
-    RefPtr<FormData> bodyForInternalRequest() const;
+    RefPtr<FormData> bodyForInternalRequest(ScriptExecutionContext&) const;
 
-    enum class Type { None, ArrayBuffer, Blob, FormData, Text, Loading, Loaded, ReadableStream };
+    enum class Type { None, ArrayBuffer, ArrayBufferView, Blob, FormData, Text, Loading, Loaded, ReadableStream };
     Type type() const { return m_type; }
 
     FetchBodyConsumer& consumer() { return m_consumer; }
@@ -86,7 +87,9 @@
 
 private:
     FetchBody(Ref<Blob>&&);
-    FetchBody(Ref<DOMFormData>&&);
+    FetchBody(Ref<ArrayBuffer>&&);
+    FetchBody(Ref<ArrayBufferView>&&);
+    FetchBody(DOMFormData&, Document&);
     FetchBody(String&&);
     FetchBody(Type type) : m_type(type) { }
 
@@ -94,6 +97,7 @@
 
     Vector<uint8_t> extractFromText() const;
     void consumeArrayBuffer(DeferredWrapper&);
+    void consumeArrayBufferView(DeferredWrapper&);
     void consumeText(DeferredWrapper&);
     void consumeBlob(FetchBodyOwner&, DeferredWrapper&&);
 
@@ -100,10 +104,11 @@
     Type m_type { Type::None };
     String m_contentType;
 
-    // FIXME: Add support for BufferSource and URLSearchParams.
+    // FIXME: Add support for URLSearchParams.
     RefPtr<Blob> m_blob;
-    RefPtr<DOMFormData> m_formData;
+    RefPtr<FormData> m_formData;
     RefPtr<ArrayBuffer> m_data;
+    RefPtr<ArrayBufferView> m_dataView;
     String m_text;
 
     FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::None };

Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp (205114 => 205115)


--- trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp	2016-08-29 09:18:06 UTC (rev 205115)
@@ -257,7 +257,8 @@
 void FetchRequest::setBody(JSC::ExecState& execState, JSC::JSValue body, FetchRequest* request, ExceptionCode& ec)
 {
     if (!body.isNull()) {
-        m_body = FetchBody::extract(execState, body);
+        ASSERT(scriptExecutionContext());
+        m_body = FetchBody::extract(*scriptExecutionContext(), execState, body);
         if (m_body.type() == FetchBody::Type::None) {
             ec = TypeError;
             return;
@@ -292,9 +293,11 @@
 
 ResourceRequest FetchRequest::internalRequest() const
 {
+    ASSERT(scriptExecutionContext());
+
     ResourceRequest request = m_internalRequest.request;
     request.setHTTPHeaderFields(m_headers->internalHeaders());
-    request.setHTTPBody(body().bodyForInternalRequest());
+    request.setHTTPBody(body().bodyForInternalRequest(*scriptExecutionContext()));
 
     // FIXME: Support no-referrer and client. Ensure this case-sensitive comparison is ok.
     if (m_internalRequest.referrer != "no-referrer" && m_internalRequest.referrer != "client")

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (205114 => 205115)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-08-29 08:50:13 UTC (rev 205114)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-08-29 09:18:06 UTC (rev 205115)
@@ -82,7 +82,8 @@
 
 void FetchResponse::initializeWith(JSC::ExecState& execState, JSC::JSValue body)
 {
-    m_body = FetchBody::extract(execState, body);
+    ASSERT(scriptExecutionContext());
+    m_body = FetchBody::extract(*scriptExecutionContext(), execState, body);
     m_body.updateContentType(m_headers);
 }
 
@@ -104,11 +105,6 @@
 {
     auto response = adoptRef(*new FetchResponse(context, FetchBody::loadingBody(), FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
 
-    // FIXME: Implement form data upload.
-    if (request.bodyType() == FetchBody::Type::FormData) {
-        promise.reject(TypeError, "Uploading FormData is not yet implemented");
-        return;
-    }
     // Setting pending activity until BodyLoader didFail or didSucceed callback is called.
     response->setPendingActivity(response.ptr());
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to