Permalink
Browse files

Stream-based requests (Request with ReadableStream)

Basic tests: web-platform-tests/wpt#4362. More tests are expected to be written as part of the implementation effort.

Fixes #88, fixes yutakahirano/fetch-with-streams#10, fixes yutakahirano/fetch-with-streams#57, and fixes yutakahirano/fetch-with-streams#66.
  • Loading branch information...
yutakahirano authored and annevk committed Jan 17, 2017
1 parent 82380e5 commit 0c470b5860fe690b1136b0242951f682405103cc
Showing with 102 additions and 22 deletions.
  1. +102 −22 fetch.bs
View
124 fetch.bs
@@ -15,7 +15,7 @@ Markup Shorthands: css off
!Commits: [SNAPSHOT-LINK]
!Commits: <a href=https://twitter.com/fetchstandard>@fetchstandard</a>
!Translation (non-normative): <span title=Japanese><a href=https://triple-underscore.github.io/Fetch-ja.html lang=ja hreflang=ja rel=alternate>日本語</a></span>
Translate IDs: typedefdef-bodyinit bodyinit,typedefdef-responsebodyinit responsebodyinit,dictdef-requestinit requestinit,typedefdef-requestinfo requestinfo,enumdef-requesttype requesttype,enumdef-requestdestination requestdestination,enumdef-requestmode requestmode,enumdef-requestcredentials requestcredentials,enumdef-requestcache requestcache,enumdef-requestredirect requestredirect,dictdef-responseinit responseinit,enumdef-responsetype responsetype
Translate IDs: typedefdef-bodyinit bodyinit,dictdef-requestinit requestinit,typedefdef-requestinfo requestinfo,enumdef-requesttype requesttype,enumdef-requestdestination requestdestination,enumdef-requestmode requestmode,enumdef-requestcredentials requestcredentials,enumdef-requestcache requestcache,enumdef-requestredirect requestredirect,dictdef-responseinit responseinit,enumdef-responsetype responsetype
</pre>
<script src=https://resources.whatwg.org/file-issue.js async></script>
@@ -559,13 +559,16 @@ user-agent-defined <a for=header>value</a> for the
<p>A <dfn export id=concept-body>body</dfn> consists of:
<ul>
<li><p>A <dfn export for=body id=concept-body-stream>stream</dfn> (a {{ReadableStream}} object).
<li><p>A <dfn export for=body id=concept-body-stream>stream</dfn> (null or a {{ReadableStream}}
object).
<li><p>A <dfn export for=body id=concept-body-transmitted>transmitted bytes</dfn>
(an integer), initially 0.
<li><p>A <dfn export for=body id=concept-body-total-bytes>total bytes</dfn> (an
integer), initially 0.
<li><p>A <dfn export for=body id=concept-body-source>source</dfn>, initially null.
</ul>
<p>A <a for=/>body</a> <var>body</var> is said to be
@@ -3018,6 +3021,10 @@ in addition to <a>HTTP fetch</a> above.
<a lt="include credential">includes credentials</a>, then return a
<a>network error</a>.
<li><p>If <var>actualResponse</var>'s <a for=response>status</a> is not <code>303</code>,
<var>request</var>'s <a for=request>body</a> is non-null, and <var>request</var>'s
<a for=request>body</a>'s <a for=body>source</a> is null, then return a <a>network error</a>.
<li>
<p>If <i>CORS flag</i> is set and <var>actualResponse</var>'s
<a for=response>location URL</a>
@@ -3042,6 +3049,15 @@ in addition to <a>HTTP fetch</a> above.
to `<code>GET</code>` and <var>request</var>'s <a for=request>body</a>
to null.
<li>
<p>If <var>request</var>'s <a for=request>body</a> is non-null, then set <var>request</var>'s
<a for=request>body</a> to the first part of <a lt=extract for=BodyInit>extracting</a>
<var>request</var>'s <a for=request>body</a>'s <a for=body>source</a>.
<p class="note no-backref"><var>request</var>'s <a for=request>body</a>'s <a for=body>source</a>'s
nullity has already been checked. The <a lt=extract for=BodyInit>extracting</a> operation cannot
throw as it was called for the same <a for=body>source</a> before.
<li><p>Append <var>actualResponse</var>'s
<a for=response>location URL</a> to <var>request</var>'s
<a for=request>url list</a>.
@@ -3069,17 +3085,34 @@ steps:
<i>authentication-fetch flag</i>.
<ol>
<li><p>Let <var>httpRequest</var> be null.
<li><p>If <var>request</var>'s <a for=request>window</a> is "<code>no-window</code>" and
<var>request</var>'s <a for=request>redirect mode</a> is "<code>error</code>", then set
<var>httpRequest</var> to <var>request</var>.
<li>
<p>Let <var>httpRequest</var> be <var>request</var> if
<var>request</var>'s <a for=request>window</a> is "<code>no-window</code>"
and <var>request</var>'s <a for=request>redirect mode</a> is
"<code>error</code>", and the result of <a lt=clone for=request>cloning</a>
<var>request</var> otherwise.
<p>Otherwise, run these substeps:
<ol>
<li><p>Set <var>httpRequest</var> to a copy of <var>request</var> except for its
<a for=request>body</a>.
<li><p>Let <var>body</var> be <var>request</var>'s <a for=request>body</a>.
<p class="note no-backref">A <var>request</var> is typically cloned as it needs to be possible to
add <a>headers</a> and read its
<a for=request>body</a> without affecting <var>request</var>. As
<var>request</var> is reused with redirects, authentication, and proxy authentication.
<li><p>Set <var>httpRequest</var>'s <a for=request>body</a> to <var>body</var>.
<li><p>If <var>body</var> is non-null, then set <var>request</var>'s <a for=request>body</a> to a
new <a for=/>body</a> whose <a for=body>stream</a> is null and whose <a for=body>source</a> is
<var>body</var>'s <a for=body>source</a>.
</ol>
<p class="note no-backref"><var>request</var> is copied as <var>httpRequest</var> here as we need
to be able to add headers to <var>httpRequest</var> and read its <a for=request>body</a> without
affecting <var>request</var>. Namely, <var>request</var> can be reused with redirects,
authentication, and proxy authentication. We copy rather than clone in order to reduce memory
consumption. In case <var>request</var>'s <a for=request>body</a>'s <a for=body>source</a> is
null, redirects and authentication will end up failing the fetch.
<li>
<p>Let <i>credentials flag</i> be set if one of
@@ -3102,18 +3135,18 @@ steps:
`<code>0</code>`.
<!-- https://chromium.googlesource.com/chromium/src/+/master/net/http/http_network_transaction.cc#982 -->
<li><p>If <var>httpRequest</var>'s <a for=request>body</a> is non-null, set
<li><p>If <var>httpRequest</var>'s <a for=request>body</a> is non-null and <var>httpRequest</var>'s
<a for=request>body</a>'s <a for=request>source</a> is non-null, then set
<var>contentLengthValue</var> to <var>httpRequest</var>'s <a for=request>body</a>'s
<a for=body>total bytes</a>, <a>UTF-8 encoded</a>.
<!-- XXX with streams we don't always know the length and so need to do chunked here -->
<li><p>If <var>contentLengthValue</var> is non-null,
<a for="header list">append</a>
`<code>Content-Length</code>`/<var>contentLengthValue</var> to
<var>httpRequest</var>'s
<a for=request>header list</a>.
<li>
<li>
<p>If <var>contentLengthValue</var> is non-null, <var>httpRequest</var>'s
<a>keepalive flag</a> is set, and <var>contentLengthValue</var> is greater than a
user-agent-defined maximum, then return a <a>network error</a>.
@@ -3122,7 +3155,6 @@ steps:
allowed to outlive the <a>environment settings object</a> and contain
a body, have a bounded size and are not allowed to stay alive indefinitely.
<li><p>If <var>httpRequest</var>'s <a for=request>referrer</a> is a <a for=/>URL</a>, then
<a for="header list">append</a> `<code>Referer</code>`/<var>httpRequest</var>'s
<a for=request>referrer</a>, <a lt="url serializer">serialized</a> and <a>UTF-8 encoded</a>, to
@@ -3360,6 +3392,22 @@ steps:
<li class=XXX><p>Needs testing: multiple `<code>WWW-Authenticate</code>` headers, missing,
parsing issues.
<li>
<p>If <var>request</var>'s <a for=request>body</a> is non-null, then run these subsubsteps:
<ol>
<li><p>If <var>request</var>'s <a for=request>body</a>'s <a for=body>source</a> is null,
then return a <a>network error</a>.
<li>
<p>Set <var>request</var>'s <a for=request>body</a> to the first part of
<a lt=extract for=BodyInit>extracting</a> <var>request</var>'s <a for=request>body</a>'s
<a for=body>source</a>.
<p class="note no-backref">The <a lt=extract for=BodyInit>extracting</a> operation cannot
throw as it was called for the same <a for=body>source</a> before.
</ol>
<li>
<p>If <var>request</var>'s
<a for=request>use-URL-credentials flag</a> is unset or
@@ -3441,6 +3489,12 @@ steps:
<li><p>If <var>connection</var> is failure, return a
<a>network error</a>.
<li><p>If <var>connection</var> is not an HTTP/2 connection, <var>request</var>'s
<a for=request>body</a> is non-null, and <var>request</var>'s <a for=request>body</a>'s
<a for=request>source</a> is null, then <a for="header list">append</a>
`<code>Transfer-Encoding</code>`/`<code>chunked</code>` to <var>request</var>'s
<a for=request>header list</a>.
<li>
<p>Let <var>response</var> be the result of making an HTTP request over <var>connection</var>
using <var>request</var> with the following caveats:
@@ -3468,6 +3522,10 @@ steps:
therefore <var>response</var> represents both a <a for=/>response</a> and
an HTTP response here.
<p>If <var>request</var>'s <a for=request>header list</a> contains
`<code>Transfer-Encoding</code>`/`<code>chunked</code>` and <var>response</var> is transferred
via HTTP/1.0 or older, then return a <a>network error</a>.
<p>If the HTTP request results in a TLS client certificate dialog, run these substeps:
<ol>
@@ -4218,9 +4276,7 @@ method, when invoked, must run these steps:
<h3 id=body-mixin>Body mixin</h3>
<pre class=idl>
typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit;
typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
typedef (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString) BodyInit;</pre>
<p>To <dfn id=concept-bodyinit-extract for=BodyInit export>extract</dfn> a <a for=/>body</a> and a
`<code>Content-Type</code>` <a for=header>value</a> from
@@ -4233,7 +4289,9 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<li><p>Let <var>Content-Type</var> be null.
<li><p>Let <var>action</var> be null.
<li><p>Let <var>action</var> be null.
<li><p>Let <var>source</var> be null.
<li>
<p>Switch on <var>object</var>'s type:
@@ -4246,6 +4304,8 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<p>If <var>object</var>'s {{Blob/type}}
attribute is not the empty byte sequence, set <var>Content-Type</var> to its value.
<p>Set <var>source</var> to <var>object</var>.
<dt><code>BufferSource</code>
<dd>
<p><a for=ReadableStream>Enqueue</a> a <code>Uint8Array</code> object
@@ -4254,6 +4314,8 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<var>stream</var>. If that threw an exception,
<a abstract-op>error</a> <var>stream</var> with that exception.
<p>Set <var>source</var> to <var>object</var>.
<dt>{{FormData}}
<dd>
<p>Set <var>action</var> to an action that runs the
@@ -4266,6 +4328,8 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<a><code>multipart/form-data</code> boundary string</a> generated by the
<a><code>multipart/form-data</code> encoding algorithm</a>.
<p>Set <var>source</var> to <var>object</var>.
<dt>{{URLSearchParams}}
<dd>
<p>Set <var>action</var> to an action that runs the
@@ -4277,12 +4341,16 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<p>Set <var>Content-Type</var> to
`<code>application/x-www-form-urlencoded;charset=UTF-8</code>`.
<p>Set <var>source</var> to <var>object</var>.
<dt><code>USVString</code>
<dd>
<p>Set <var>action</var> to an action that runs <a>UTF-8 encode</a> on <var>object</var>.
<p>Set <var>Content-Type</var> to `<code>text/plain;charset=UTF-8</code>`.
<p>Set <var>source</var> to <var>object</var>.
<dt>{{ReadableStream}}
<dd><p>Set <var>stream</var> to <var>object</var>.
</dl>
@@ -4306,8 +4374,8 @@ typedef (BodyInit or ReadableStream) ResponseBodyInit;</pre>
<a abstract-op>close</a> <var>stream</var>.
</ol>
<li><p>Let <var>body</var> be a <a for=/>body</a> whose
<a for=body>stream</a> is <var>stream</var>.
<li><p>Let <var>body</var> be a <a for=/>body</a> whose <a for=body>stream</a> is
<var>stream</var> and whose <a for=body>source</a> is <var>source</var>.
<li><p>Return <var>body</var> and <var>Content-Type</var>.
</ol>
@@ -4827,6 +4895,18 @@ constructor must run these steps:
{{Headers}} object. Rethrow any exception.
</ol>
<li>
<p>If <var>inputBody</var> is non-null and <var>inputBody</var>'s <a for=body>source</a> is
null, then run these substeps:
<ol>
<li><p>If <var>r</var>'s <a for=Request>request</a>'s <a for=request>mode</a> is neither
"<code>same-origin</code>" nor "<code>cors</code>", then throw a <code>TypeError</code>.
<li><p>Set <var>r</var>'s <a for=Request>request</a>'s
<a for=request>use-CORS-preflight flag</a>.
</ol>
<li><p>Set <var>r</var>'s <a for=Request>request</a>'s
<a for=request>body</a> to <var>inputBody</var>.
<!-- Any steps after this must not throw. -->
@@ -4948,7 +5028,7 @@ run these steps:
<h3 id=response-class>Response class</h3>
<pre class=idl>[Constructor(optional ResponseBodyInit? body = null, optional ResponseInit init),
<pre class=idl>[Constructor(optional BodyInit? body = null, optional ResponseInit init),
Exposed=(Window,Worker)]
interface Response {
[NewObject] static Response error();

0 comments on commit 0c470b5

Please sign in to comment.