From b6de322e07c3f1f0b444ee0512688203c677503f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Thu, 25 Apr 2019 11:24:23 +0200 Subject: [PATCH 1/4] Support making request with any blob that have stream() method --- src/body.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/body.js b/src/body.js index c70b41052..f80994825 100644 --- a/src/body.js +++ b/src/body.js @@ -37,9 +37,10 @@ export default function Body(body, { } else if (isURLSearchParams(body)) { // body is a URLSearchParams body = Buffer.from(body.toString()); - } else if (body instanceof Blob) { + } else if (isBlob(body)) { // body is blob - body = body[BUFFER]; + this.blobSize = body.size; + body = body.stream(); } else if (Buffer.isBuffer(body)) { // body is Buffer } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') { @@ -355,6 +356,24 @@ function isURLSearchParams(obj) { typeof obj.sort === 'function'; } +/** + * Check if `obj` is a W3C `Blob` object (which `File` inherits from) + * @param {*} obj + * @return {boolean} + */ +function isBlob(obj) { + return typeof obj === 'object' && + typeof obj.arrayBuffer === 'function' && + typeof obj.slice === 'function' && + typeof obj.text === 'function' && + typeof obj.type === 'string' && + typeof obj.stream === 'function' && + typeof obj.constructor === 'function' && + typeof obj.constructor.name === 'string' && + /^(Blob|File)$/.test(obj.constructor.name) && + /^(Blob|File)$/.test(obj[Symbol.toStringTag]) +} + /** * Clone body given Res/Req instance * @@ -460,8 +479,7 @@ export function getTotalBytes(instance) { return null; } else { // body is stream - // can't really do much about this - return null; + return instance.blobSize || null; } } From 91a5034f21d81a4bc3cc124ef25626b4efe8936e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Thu, 25 Apr 2019 12:02:27 +0200 Subject: [PATCH 2/4] don't clone blob when cloning request using a own blobSize was a bad idea --- src/body.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/body.js b/src/body.js index f80994825..362e2e38b 100644 --- a/src/body.js +++ b/src/body.js @@ -39,8 +39,6 @@ export default function Body(body, { body = Buffer.from(body.toString()); } else if (isBlob(body)) { // body is blob - this.blobSize = body.size; - body = body.stream(); } else if (Buffer.isBuffer(body)) { // body is Buffer } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') { @@ -192,18 +190,25 @@ function consumeBody() { return Body.Promise.reject(this[INTERNALS].error); } + let body = this.body; + // body is null - if (this.body === null) { + if (body === null) { return Body.Promise.resolve(Buffer.alloc(0)); } + // body is blob + if (isBlob(body)) { + body = body.stream(); + } + // body is buffer - if (Buffer.isBuffer(this.body)) { - return Body.Promise.resolve(this.body); + if (Buffer.isBuffer(body)) { + return Body.Promise.resolve(body); } // istanbul ignore if: should never happen - if (!(this.body instanceof Stream)) { + if (!(body instanceof Stream)) { return Body.Promise.resolve(Buffer.alloc(0)); } @@ -225,7 +230,7 @@ function consumeBody() { } // handle stream errors - this.body.on('error', err => { + body.on('error', err => { if (err.name === 'AbortError') { // if the request was aborted, reject with this Error abort = true; @@ -236,7 +241,7 @@ function consumeBody() { } }); - this.body.on('data', chunk => { + body.on('data', chunk => { if (abort || chunk === null) { return; } @@ -251,7 +256,7 @@ function consumeBody() { accum.push(chunk); }); - this.body.on('end', () => { + body.on('end', () => { if (abort) { return; } @@ -426,7 +431,7 @@ export function extractContentType(body) { } else if (isURLSearchParams(body)) { // body is a URLSearchParams return 'application/x-www-form-urlencoded;charset=UTF-8'; - } else if (body instanceof Blob) { + } else if (isBlob(body)) { // body is blob return body.type || null; } else if (Buffer.isBuffer(body)) { @@ -467,6 +472,8 @@ export function getTotalBytes(instance) { if (body === null) { // body is null return 0; + } else if (isBlob(body)) { + return body.size; } else if (Buffer.isBuffer(body)) { // body is buffer return body.length; @@ -479,7 +486,7 @@ export function getTotalBytes(instance) { return null; } else { // body is stream - return instance.blobSize || null; + return instance.size || null; } } @@ -495,6 +502,8 @@ export function writeToStream(dest, instance) { if (body === null) { // body is null dest.end(); + } else if (isBlob(body)) { + body.stream().pipe(dest); } else if (Buffer.isBuffer(body)) { // body is buffer dest.write(body); From 1a89c70a706ab4065ef8b9eda190e13f3756ea79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20W=C3=A4rting?= Date: Mon, 29 Apr 2019 10:52:38 +0200 Subject: [PATCH 3/4] =?UTF-8?q?Don=E2=80=99t=20check=20for=20everything?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/body.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/body.js b/src/body.js index 362e2e38b..659c7ee99 100644 --- a/src/body.js +++ b/src/body.js @@ -368,10 +368,6 @@ function isURLSearchParams(obj) { */ function isBlob(obj) { return typeof obj === 'object' && - typeof obj.arrayBuffer === 'function' && - typeof obj.slice === 'function' && - typeof obj.text === 'function' && - typeof obj.type === 'string' && typeof obj.stream === 'function' && typeof obj.constructor === 'function' && typeof obj.constructor.name === 'string' && From ae3916dd2958dfa1235bcd6a5d01e4c67e078832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20W=C3=A4rting?= Date: Mon, 29 Apr 2019 10:54:34 +0200 Subject: [PATCH 4/4] Added back type and array buffer --- src/body.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/body.js b/src/body.js index 659c7ee99..4e7d66d8e 100644 --- a/src/body.js +++ b/src/body.js @@ -368,6 +368,8 @@ function isURLSearchParams(obj) { */ function isBlob(obj) { return typeof obj === 'object' && + typeof obj.arrayBuffer === 'function' && + typeof obj.type === 'string' && typeof obj.stream === 'function' && typeof obj.constructor === 'function' && typeof obj.constructor.name === 'string' &&