Skip to content

Commit

Permalink
Allow third party blob implementation (#629)
Browse files Browse the repository at this point in the history
* Support making request with any blob that have stream() method
* don't clone blob when cloning request
* check for blob api that node-fetch uses
  • Loading branch information
bitinn committed May 1, 2019
1 parent d8f5ba0 commit 0fc414c
Showing 1 changed file with 37 additions and 12 deletions.
49 changes: 37 additions & 12 deletions src/body.js
Expand Up @@ -37,9 +37,8 @@ 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];
} else if (Buffer.isBuffer(body)) {
// body is Buffer
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
Expand Down Expand Up @@ -191,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));
}

Expand All @@ -224,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;
Expand All @@ -235,7 +241,7 @@ function consumeBody() {
}
});

this.body.on('data', chunk => {
body.on('data', chunk => {
if (abort || chunk === null) {
return;
}
Expand All @@ -250,7 +256,7 @@ function consumeBody() {
accum.push(chunk);
});

this.body.on('end', () => {
body.on('end', () => {
if (abort) {
return;
}
Expand Down Expand Up @@ -355,6 +361,22 @@ 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.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
*
Expand Down Expand Up @@ -407,7 +429,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)) {
Expand Down Expand Up @@ -448,6 +470,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;
Expand All @@ -460,8 +484,7 @@ export function getTotalBytes(instance) {
return null;
} else {
// body is stream
// can't really do much about this
return null;
return instance.size || null;
}
}

Expand All @@ -477,6 +500,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);
Expand Down

0 comments on commit 0fc414c

Please sign in to comment.