Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading a Request made from a ReadableStream body #425

Merged
merged 6 commits into from
Jan 17, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 102 additions & 22 deletions fetch.bs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -571,13 +571,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
Expand Down Expand Up @@ -2984,6 +2987,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>
Expand All @@ -3008,6 +3015,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>.
Expand Down Expand Up @@ -3035,17 +3051,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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still seems wrong. Shouldn't we be setting httpRequest's body rather than that of request? Also, what happens to request's body?

The note should probably also move to after the </ol> closing tag. We copy and move body around to preserve memory consumption. And we copy in the first place since it needs to be possible to add headers without affecting request, as request is reused with redirects et al. It seems you dropped part of that note, but we should keep that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry. Fixed. The intention is, passing the ReadableStream to httpRequests for sending the payload and keeping the source information in request in order to restore the payload if necessary.


<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
Expand All @@ -3068,18 +3101,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>.
Expand All @@ -3088,7 +3121,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
Expand Down Expand Up @@ -3326,6 +3358,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
Expand Down Expand Up @@ -3407,6 +3455,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:
Expand Down Expand Up @@ -3434,6 +3488,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>
Expand Down Expand Up @@ -4184,9 +4242,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
Expand All @@ -4199,7 +4255,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:
Expand All @@ -4212,6 +4270,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
Expand All @@ -4220,6 +4280,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
Expand All @@ -4232,6 +4294,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
Expand All @@ -4243,12 +4307,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>
Expand All @@ -4272,8 +4340,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>
Expand Down Expand Up @@ -4793,6 +4861,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. -->
Expand Down Expand Up @@ -4914,7 +4994,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();
Expand Down