<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[203637] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/203637">203637</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-07-23 00:46:44 -0700 (Sat, 23 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Fetch API] Fetch response stream should enqueue Uint8Array
https://bugs.webkit.org/show_bug.cgi?id=160083

Patch by Youenn Fablet &lt;youenn@apple.com&gt; on 2016-07-23
Reviewed by Sam Weinig.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/resources/utils.js:

Source/WebCore:

Covered by updated tests.

Before enqueuing, ReadableStreamController::enqueue will convert ArrayBuffer as Uint8Array.
It also returns a boolean whether the operation is successful or not.

If returned value is false, calling code will stop loading or if everything is loaded it will refrain from closing the stream.
The enqueuing should be succesful except in OutOfMemory cases. This case is not yet handled in test cases.

Updated the code to remove templated enqueuing as Fetch has no use of it.

* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::consumeAsStream): Do not close the stream if enqueuing failed.
* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::blobChunk): Stop blob loading if enqueuing failed.
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::BodyLoader::didReceiveData): Stop resource loading if enqueuing failed.
(WebCore::FetchResponse::consumeBodyAsStream): Ditto.
* Modules/fetch/FetchResponseSource.h:
* bindings/js/ReadableStreamController.h:
(WebCore::ReadableStreamController::enqueue):
(WebCore::ReadableStreamController::enqueue&lt;RefPtr&lt;JSC::ArrayBuffer&gt;&gt;): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsimportedw3cChangeLog">trunk/LayoutTests/imported/w3c/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsimportedw3cwebplatformtestsfetchapiresourcesutilsjs">trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/resources/utils.js</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesfetchFetchBodycpp">trunk/Source/WebCore/Modules/fetch/FetchBody.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesfetchFetchBodyOwnercpp">trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesfetchFetchResponsecpp">trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesfetchFetchResponseSourceh">trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h</a></li>
<li><a href="#trunkSourceWebCorebindingsjsReadableStreamControllerh">trunk/Source/WebCore/bindings/js/ReadableStreamController.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsimportedw3cChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/ChangeLog (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/ChangeLog        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/LayoutTests/imported/w3c/ChangeLog        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -1,3 +1,12 @@
</span><ins>+2016-07-23  Youenn Fablet  &lt;youenn@apple.com&gt;
+
+        [Fetch API] Fetch response stream should enqueue Uint8Array
+        https://bugs.webkit.org/show_bug.cgi?id=160083
+
+        Reviewed by Sam Weinig.
+
+        * web-platform-tests/fetch/api/resources/utils.js:
+
</ins><span class="cx"> 2016-07-22  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Parameter to HTMLCollection.item() / namedItem() should be mandatory
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cwebplatformtestsfetchapiresourcesutilsjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/resources/utils.js (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/resources/utils.js        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/resources/utils.js        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -59,6 +59,7 @@
</span><span class="cx"> function validateStreamFromString(reader, expectedValue, retrievedArrayBuffer) {
</span><span class="cx">   return reader.read().then(function(data) {
</span><span class="cx">     if (!data.done) {
</span><ins>+      assert_true(data.value instanceof Uint8Array, &quot;Fetch ReadableStream chunks should be Uint8Array&quot;);
</ins><span class="cx">       var newBuffer;
</span><span class="cx">       if (retrievedArrayBuffer) {
</span><span class="cx">         newBuffer =  new ArrayBuffer(data.value.length + retrievedArrayBuffer.length);
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/ChangeLog        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2016-07-23  Youenn Fablet  &lt;youenn@apple.com&gt;
+
+        [Fetch API] Fetch response stream should enqueue Uint8Array
+        https://bugs.webkit.org/show_bug.cgi?id=160083
+
+        Reviewed by Sam Weinig.
+
+        Covered by updated tests.
+
+        Before enqueuing, ReadableStreamController::enqueue will convert ArrayBuffer as Uint8Array.
+        It also returns a boolean whether the operation is successful or not.
+
+        If returned value is false, calling code will stop loading or if everything is loaded it will refrain from closing the stream.
+        The enqueuing should be succesful except in OutOfMemory cases. This case is not yet handled in test cases.
+
+        Updated the code to remove templated enqueuing as Fetch has no use of it.
+
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::consumeAsStream): Do not close the stream if enqueuing failed.
+        * Modules/fetch/FetchBodyOwner.cpp:
+        (WebCore::FetchBodyOwner::blobChunk): Stop blob loading if enqueuing failed.
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::BodyLoader::didReceiveData): Stop resource loading if enqueuing failed.
+        (WebCore::FetchResponse::consumeBodyAsStream): Ditto.
+        * Modules/fetch/FetchResponseSource.h:
+        * bindings/js/ReadableStreamController.h:
+        (WebCore::ReadableStreamController::enqueue):
+        (WebCore::ReadableStreamController::enqueue&lt;RefPtr&lt;JSC::ArrayBuffer&gt;&gt;): Deleted.
+
</ins><span class="cx"> 2016-07-22  Youenn Fablet  &lt;youenn@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Use a private property to implement FetchResponse.body getter
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesfetchFetchBodycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -151,14 +151,14 @@
</span><span class="cx"> 
</span><span class="cx">     switch (m_type) {
</span><span class="cx">     case Type::ArrayBuffer:
</span><del>-        source.enqueue(m_data);
-        source.close();
</del><ins>+        ASSERT(m_data);
+        if (source.enqueue(RefPtr&lt;JSC::ArrayBuffer&gt;(m_data)))
+            source.close();
</ins><span class="cx">         return;
</span><span class="cx">     case Type::Text: {
</span><span class="cx">         Vector&lt;uint8_t&gt; data = extractFromText();
</span><del>-        // FIXME: We should not close the source if ArrayBuffer;;tryCreate returns null.
-        source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size()));
-        source.close();
</del><ins>+        if (source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size())))
+            source.close();
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     case Type::Blob:
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesfetchFetchBodyOwnercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -204,10 +204,11 @@
</span><span class="cx"> 
</span><span class="cx"> void FetchBodyOwner::blobChunk(const char* data, size_t size)
</span><span class="cx"> {
</span><ins>+    ASSERT(data);
</ins><span class="cx"> #if ENABLE(STREAMS_API)
</span><span class="cx">     ASSERT(m_readableStreamSource);
</span><del>-    // FIXME: If ArrayBuffer::tryCreate returns null, we should probably cancel the load.
-    m_readableStreamSource-&gt;enqueue(ArrayBuffer::tryCreate(data, size));
</del><ins>+    if (!m_readableStreamSource-&gt;enqueue(ArrayBuffer::tryCreate(data, size)))
+        stop();
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(data);
</span><span class="cx">     UNUSED_PARAM(size);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesfetchFetchResponsecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -203,8 +203,8 @@
</span><span class="cx"> #if ENABLE(STREAMS_API)
</span><span class="cx">     ASSERT(m_response.m_readableStreamSource);
</span><span class="cx"> 
</span><del>-    // FIXME: If ArrayBuffer::tryCreate returns null, we should probably cancel the load.
-    m_response.m_readableStreamSource-&gt;enqueue(ArrayBuffer::tryCreate(data, size));
</del><ins>+    if (!m_response.m_readableStreamSource-&gt;enqueue(ArrayBuffer::tryCreate(data, size)))
+        stop();
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(data);
</span><span class="cx">     UNUSED_PARAM(size);
</span><span class="lines">@@ -237,7 +237,7 @@
</span><span class="cx">     if (body().type() != FetchBody::Type::Loading) {
</span><span class="cx">         body().consumeAsStream(*this, *m_readableStreamSource);
</span><span class="cx">         if (!m_readableStreamSource-&gt;isStarting())
</span><del>-            m_readableStreamSource = nullptr;        
</del><ins>+            m_readableStreamSource = nullptr;
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -246,9 +246,8 @@
</span><span class="cx">     RefPtr&lt;SharedBuffer&gt; data = m_bodyLoader-&gt;startStreaming();
</span><span class="cx">     if (data) {
</span><span class="cx">         // FIXME: We might want to enqueue each internal SharedBuffer chunk as an individual ArrayBuffer.
</span><del>-        // Also, createArrayBuffer might return nullptr which will lead to erroring the stream.
-        // We might want to cancel the load and rename createArrayBuffer to tryCreateArrayBuffer.
-        m_readableStreamSource-&gt;enqueue(data-&gt;createArrayBuffer());
</del><ins>+        if (!m_readableStreamSource-&gt;enqueue(data-&gt;createArrayBuffer()))
+            stop();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesfetchFetchResponseSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -32,6 +32,10 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ReadableStreamSource.h&quot;
</span><span class="cx"> 
</span><ins>+namespace JSC {
+class ArrayBuffer;
+};
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class FetchResponse;
</span><span class="lines">@@ -40,7 +44,7 @@
</span><span class="cx"> public:
</span><span class="cx">     FetchResponseSource(FetchResponse&amp;);
</span><span class="cx"> 
</span><del>-    template&lt;typename T&gt; void enqueue(const T&amp; t) { controller().enqueue(t); }
</del><ins>+    bool enqueue(RefPtr&lt;JSC::ArrayBuffer&gt;&amp;&amp; chunk) { return controller().enqueue(WTFMove(chunk)); }
</ins><span class="cx">     void close();
</span><span class="cx">     void error(const String&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsReadableStreamControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/ReadableStreamController.h (203636 => 203637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/ReadableStreamController.h        2016-07-23 07:17:37 UTC (rev 203636)
+++ trunk/Source/WebCore/bindings/js/ReadableStreamController.h        2016-07-23 07:46:44 UTC (rev 203637)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;JSReadableStreamController.h&quot;
</span><span class="cx"> #include &lt;runtime/JSCJSValue.h&gt;
</span><span class="cx"> #include &lt;runtime/JSCJSValueInlines.h&gt;
</span><ins>+#include &lt;runtime/TypedArrays.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -46,8 +47,7 @@
</span><span class="cx"> 
</span><span class="cx">     static JSC::JSValue invoke(JSC::ExecState&amp;, JSC::JSObject&amp;, const char*, JSC::JSValue);
</span><span class="cx"> 
</span><del>-    template&lt;class ResolveResultType&gt;
-    void enqueue(const ResolveResultType&amp;);
</del><ins>+    bool enqueue(RefPtr&lt;JSC::ArrayBuffer&gt;&amp;&amp;);
</ins><span class="cx"> 
</span><span class="cx">     template&lt;class ResolveResultType&gt;
</span><span class="cx">     void error(const ResolveResultType&amp;);
</span><span class="lines">@@ -72,16 +72,21 @@
</span><span class="cx">     return static_cast&lt;JSDOMGlobalObject*&gt;(m_jsController-&gt;globalObject());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;&gt;
-inline void ReadableStreamController::enqueue&lt;RefPtr&lt;JSC::ArrayBuffer&gt;&gt;(const RefPtr&lt;JSC::ArrayBuffer&gt;&amp; result)
</del><ins>+inline bool ReadableStreamController::enqueue(RefPtr&lt;JSC::ArrayBuffer&gt;&amp;&amp; buffer)
</ins><span class="cx"> {
</span><span class="cx">     JSC::ExecState&amp; state = *globalObject()-&gt;globalExec();
</span><span class="cx">     JSC::JSLockHolder locker(&amp;state);
</span><span class="cx"> 
</span><del>-    if (result)
-        enqueue(state, toJS(&amp;state, globalObject(), result.get()));
-    else
</del><ins>+    if (!buffer) {
</ins><span class="cx">         error(state, createOutOfMemoryError(&amp;state));
</span><ins>+        return false;
+    }
+    auto length = buffer-&gt;byteLength();
+    auto chunk = JSC::Uint8Array::create(WTFMove(buffer), 0, length);
+    ASSERT(chunk);
+    enqueue(state, toJS(&amp;state, globalObject(), chunk.get()));
+    ASSERT(!state.hadException());
+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;&gt;
</span></span></pre>
</div>
</div>

</body>
</html>