@@ -11,16 +11,15 @@ import FetchError from './fetch-error.js';
1111const Stream = require ( 'stream' ) ;
1212const { PassThrough } = require ( 'stream' ) ;
1313
14- const DISTURBED = Symbol ( 'disturbed' ) ;
15- const ERROR = Symbol ( 'error' ) ;
16-
1714let convert ;
1815try { convert = require ( 'encoding' ) . convert ; } catch ( e ) { }
1916
17+ const INTERNALS = Symbol ( 'Body internals' ) ;
18+
2019/**
21- * Body class
20+ * Body mixin
2221 *
23- * Cannot use ES6 class because Body must be called with .call().
22+ * Ref: https://fetch.spec.whatwg.org/#body
2423 *
2524 * @param Stream body Readable stream
2625 * @param Object opts Response options
@@ -48,22 +47,28 @@ export default function Body(body, {
4847 // coerce to string
4948 body = String ( body ) ;
5049 }
51- this . body = body ;
52- this [ DISTURBED ] = false ;
53- this [ ERROR ] = null ;
50+ this [ INTERNALS ] = {
51+ body,
52+ disturbed : false ,
53+ error : null
54+ } ;
5455 this . size = size ;
5556 this . timeout = timeout ;
5657
57- if ( this . body instanceof Stream ) {
58- this . body . on ( 'error' , err => {
59- this [ ERROR ] = new FetchError ( `Invalid response body while trying to fetch ${ this . url } : ${ err . message } ` , 'system' , err ) ;
58+ if ( body instanceof Stream ) {
59+ body . on ( 'error' , err => {
60+ this [ INTERNALS ] . error = new FetchError ( `Invalid response body while trying to fetch ${ this . url } : ${ err . message } ` , 'system' , err ) ;
6061 } ) ;
6162 }
6263}
6364
6465Body . prototype = {
66+ get body ( ) {
67+ return this [ INTERNALS ] . body ;
68+ } ,
69+
6570 get bodyUsed ( ) {
66- return this [ DISTURBED ] ;
71+ return this [ INTERNALS ] . disturbed ;
6772 } ,
6873
6974 /**
@@ -139,6 +144,16 @@ Body.prototype = {
139144
140145} ;
141146
147+ // In browsers, all properties are enumerable.
148+ Object . defineProperties ( Body . prototype , {
149+ body : { enumerable : true } ,
150+ bodyUsed : { enumerable : true } ,
151+ arrayBuffer : { enumerable : true } ,
152+ blob : { enumerable : true } ,
153+ json : { enumerable : true } ,
154+ text : { enumerable : true }
155+ } ) ;
156+
142157Body . mixIn = function ( proto ) {
143158 for ( const name of Object . getOwnPropertyNames ( Body . prototype ) ) {
144159 // istanbul ignore else: future proof
@@ -150,19 +165,21 @@ Body.mixIn = function (proto) {
150165} ;
151166
152167/**
153- * Decode buffers into utf-8 string
168+ * Consume and convert an entire Body to a Buffer.
169+ *
170+ * Ref: https://fetch.spec.whatwg.org/#concept-body-consume-body
154171 *
155172 * @return Promise
156173 */
157- function consumeBody ( body ) {
158- if ( this [ DISTURBED ] ) {
159- return Body . Promise . reject ( new Error ( `body used already for: ${ this . url } ` ) ) ;
174+ function consumeBody ( ) {
175+ if ( this [ INTERNALS ] . disturbed ) {
176+ return Body . Promise . reject ( new TypeError ( `body used already for: ${ this . url } ` ) ) ;
160177 }
161178
162- this [ DISTURBED ] = true ;
179+ this [ INTERNALS ] . disturbed = true ;
163180
164- if ( this [ ERROR ] ) {
165- return Body . Promise . reject ( this [ ERROR ] ) ;
181+ if ( this [ INTERNALS ] . error ) {
182+ return Body . Promise . reject ( this [ INTERNALS ] . error ) ;
166183 }
167184
168185 // body is null
@@ -309,21 +326,21 @@ function convertBody(buffer, headers) {
309326 * @return String
310327 */
311328function isURLSearchParams ( obj ) {
312- // Duck-typing as a necessary condition.
313- if ( typeof obj !== 'object' ||
314- typeof obj . append !== 'function' ||
315- typeof obj . delete !== 'function' ||
316- typeof obj . get !== 'function' ||
317- typeof obj . getAll !== 'function' ||
318- typeof obj . has !== 'function' ||
319- typeof obj . set !== 'function' ) {
320- return false ;
321- }
322-
323- // Brand-checking and more duck-typing as optional condition.
324- return obj . constructor . name === 'URLSearchParams' ||
325- Object . prototype . toString . call ( obj ) === '[object URLSearchParams]' ||
326- typeof obj . sort === 'function' ;
329+ // Duck-typing as a necessary condition.
330+ if ( typeof obj !== 'object' ||
331+ typeof obj . append !== 'function' ||
332+ typeof obj . delete !== 'function' ||
333+ typeof obj . get !== 'function' ||
334+ typeof obj . getAll !== 'function' ||
335+ typeof obj . has !== 'function' ||
336+ typeof obj . set !== 'function' ) {
337+ return false ;
338+ }
339+
340+ // Brand-checking and more duck-typing as optional condition.
341+ return obj . constructor . name === 'URLSearchParams' ||
342+ Object . prototype . toString . call ( obj ) === '[object URLSearchParams]' ||
343+ typeof obj . sort === 'function' ;
327344}
328345
329346/**
@@ -350,7 +367,7 @@ export function clone(instance) {
350367 body . pipe ( p1 ) ;
351368 body . pipe ( p2 ) ;
352369 // set instance body to teed body and return the other teed body
353- instance . body = p1 ;
370+ instance [ INTERNALS ] . body = p1 ;
354371 body = p2 ;
355372 }
356373
@@ -362,7 +379,7 @@ export function clone(instance) {
362379 * specified in the specification:
363380 * https://fetch.spec.whatwg.org/#concept-bodyinit-extract
364381 *
365- * This function assumes that instance.body is present and non-null .
382+ * This function assumes that instance.body is present.
366383 *
367384 * @param Mixed instance Response or Request instance
368385 */
0 commit comments