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

Allow third party blob implementation #629

Merged
merged 4 commits into from May 1, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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