Fix up ArrayBufferView support (#464)

Also add more test coverage.

Fixes: #482
Closes: #484
This commit is contained in:
Timothy Gu 2018-07-21 22:13:01 -07:00 committed by GitHub
parent 287bc3bdcf
commit b091ab5917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 7 deletions

View File

@ -39,11 +39,11 @@ export default function Body(body, {
} else if (body instanceof Blob) {
// body is blob
} else if (Buffer.isBuffer(body)) {
// body is Buffer
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
// body is ArrayBuffer
} else if (body instanceof ArrayBuffer) {
// body is ArrayBufferView
} else if (ArrayBuffer.isView(body)) {
// body is array buffer view
// body is ArrayBufferView
} else if (body instanceof Stream) {
// body is stream
} else {
@ -207,10 +207,15 @@ function consumeBody() {
}
// body is ArrayBuffer
if (this.body instanceof ArrayBuffer) {
if (Object.prototype.toString.call(this.body) === '[object ArrayBuffer]') {
return Body.Promise.resolve(Buffer.from(this.body));
}
// body is ArrayBufferView
if (ArrayBuffer.isView(this.body)) {
return Body.Promise.resolve(Buffer.from(this.body.buffer, this.body.byteOffset, this.body.byteLength));
}
// istanbul ignore if: should never happen
if (!(this.body instanceof Stream)) {
return Body.Promise.resolve(Buffer.alloc(0));
@ -418,7 +423,7 @@ export function extractContentType(instance) {
} else if (Buffer.isBuffer(body)) {
// body is buffer
return null;
} else if (body instanceof ArrayBuffer) {
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
// body is ArrayBuffer
return null;
} else if (ArrayBuffer.isView(body)) {
@ -462,7 +467,7 @@ export function getTotalBytes(instance) {
} else if (Buffer.isBuffer(body)) {
// body is buffer
return body.length;
} else if (body instanceof ArrayBuffer) {
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
// body is ArrayBuffer
return body.byteLength;
} else if (ArrayBuffer.isView(body)) {
@ -510,7 +515,7 @@ export function writeToStream(dest, instance) {
// body is buffer
dest.write(body);
dest.end()
} else if (body instanceof ArrayBuffer) {
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
// body is ArrayBuffer
dest.write(Buffer.from(body));
dest.end()

View File

@ -18,6 +18,12 @@ const path = require('path');
const stream = require('stream');
const { parse: parseURL, URLSearchParams } = require('url');
const { lookup } = require('dns');
const vm = require('vm');
const {
ArrayBuffer: VMArrayBuffer,
Uint8Array: VMUint8Array
} = vm.runInNewContext('this');
let convert;
try { convert = require('encoding').convert; } catch(e) { }
@ -876,6 +882,27 @@ describe('node-fetch', () => {
});
});
it('should allow POST request with ArrayBuffer body from a VM context', function() {
// TODO: Node.js v4 doesn't support ArrayBuffer from other contexts, so we skip this test, drop this check once Node.js v4 support is not needed
try {
Buffer.from(new VMArrayBuffer());
} catch (err) {
this.skip();
}
const url = `${base}inspect`;
const opts = {
method: 'POST',
body: new VMUint8Array(Buffer.from('Hello, world!\n')).buffer
};
return fetch(url, opts).then(res => res.json()).then(res => {
expect(res.method).to.equal('POST');
expect(res.body).to.equal('Hello, world!\n');
expect(res.headers['transfer-encoding']).to.be.undefined;
expect(res.headers['content-type']).to.be.undefined;
expect(res.headers['content-length']).to.equal('14');
});
});
it('should allow POST request with ArrayBufferView (Uint8Array) body', function() {
const url = `${base}inspect`;
const opts = {
@ -906,6 +933,27 @@ describe('node-fetch', () => {
});
});
it('should allow POST request with ArrayBufferView (Uint8Array) body from a VM context', function() {
// TODO: Node.js v4 doesn't support ArrayBufferView from other contexts, so we skip this test, drop this check once Node.js v4 support is not needed
try {
Buffer.from(new VMArrayBuffer());
} catch (err) {
this.skip();
}
const url = `${base}inspect`;
const opts = {
method: 'POST',
body: new VMUint8Array(Buffer.from('Hello, world!\n'))
};
return fetch(url, opts).then(res => res.json()).then(res => {
expect(res.method).to.equal('POST');
expect(res.body).to.equal('Hello, world!\n');
expect(res.headers['transfer-encoding']).to.be.undefined;
expect(res.headers['content-type']).to.be.undefined;
expect(res.headers['content-length']).to.equal('14');
});
});
// TODO: Node.js v4 doesn't support necessary Buffer API, so we skip this test, drop this check once Node.js v4 support is not needed
(Buffer.from.length === 3 ? it : it.skip)('should allow POST request with ArrayBufferView (Uint8Array, offset, length) body', function() {
const url = `${base}inspect`;
@ -1919,6 +1967,20 @@ describe('Response', function () {
});
});
it('should support Uint8Array as body', function() {
const res = new Response(new Uint8Array(stringToArrayBuffer('a=1')));
return res.text().then(result => {
expect(result).to.equal('a=1');
});
});
it('should support DataView as body', function() {
const res = new Response(new DataView(stringToArrayBuffer('a=1')));
return res.text().then(result => {
expect(result).to.equal('a=1');
});
});
it('should default to null as body', function() {
const res = new Response();
expect(res.body).to.equal(null);
@ -2124,6 +2186,26 @@ describe('Request', function () {
expect(result).to.equal('a=1');
});
});
it('should support Uint8Array as body', function() {
const req = new Request('', {
method: 'POST',
body: new Uint8Array(stringToArrayBuffer('a=1'))
});
return req.text().then(result => {
expect(result).to.equal('a=1');
});
});
it('should support DataView as body', function() {
const req = new Request('', {
method: 'POST',
body: new DataView(stringToArrayBuffer('a=1'))
});
return req.text().then(result => {
expect(result).to.equal('a=1');
});
});
});
function streamToPromise(stream, dataHandler) {